diff --git a/DataProducts/CMakeLists.txt b/DataProducts/CMakeLists.txt index e0e4d33c2b..87acfa656d 100644 --- a/DataProducts/CMakeLists.txt +++ b/DataProducts/CMakeLists.txt @@ -6,6 +6,7 @@ cet_make_library( src/CrystalId.cc src/ExtMonFNALChipId.cc src/ExtMonFNALPixelId.cc + src/FilterFraction.cc src/GenVector.cc src/PDGCode.cc src/STMChannel.cc @@ -27,7 +28,7 @@ art_dictionary( NO_CHECK_CLASS_VERSION # For some reason this segfaults Offline::DataProducts ) -if( BUILD_PYTHON_INTERFACE ) +if( BUILD_PYTHON_INTERFACE ) mu2e_swig(DataProducts_swig src/pywrap.i DataProducts) endif() diff --git a/DataProducts/inc/FilterFraction.hh b/DataProducts/inc/FilterFraction.hh new file mode 100644 index 0000000000..77751a2151 --- /dev/null +++ b/DataProducts/inc/FilterFraction.hh @@ -0,0 +1,40 @@ +// +// art product to record the selection fraction of a filter. This product could be +// part of the raw data output (trigger prescale) or simulation presampling. +// Original author: Dave Brown (LBNL) 2026 +// +#ifndef DataProducts_FilterFraction_hh +#define DataProducts_FilterFraction_hh +#include +namespace mu2e { + class FilterFraction { + public: + enum FilterType { constant=0, nonominal, chained, unknown}; + // chained means multiple filtering steps have been chained together + FilterFraction(FilterType type, double nominal, uint64_t nseen, uint64_t npassed) : + type_(type),nominal_(nominal), nseen_(nseen), npassed_(npassed) {} + // use this constructor when there is no nominal selection fraction + FilterFraction(uint64_t nseen, uint64_t npassed) : + type_(nonominal),nominal_(-1.0), nseen_(nseen), npassed_(npassed) {} + // default + FilterFraction(){} + // accessors + FilterType type() const { return type_; } + bool hasNominalValue() const { return type() == nonominal; } + double nominalFraction() const { return nominal_; } + double actualFraction() const { return nseen_ > 0 ? double(npassed_)/double(nseen_) : 0.0; } + uint64_t nSeen() const { return nseen_; } + uint64_t nPassed() const { return npassed_; } + // concatenate multiple subruns in the same path + FilterFraction& operator +=(FilterFraction const& other); + FilterFraction operator + (FilterFraction const& other) const; + // concatenate with an upstream filter. The values must match! + FilterFraction chain(FilterFraction const& upstream) const; + private: + FilterType type_ = unknown; // type of filtering performed + double nominal_ = -1; // nominal fraction (<1) of events expected to be kept by the filter + uint64_t nseen_ = 0; // number of events processed by this filter + uint64_t npassed_ = 0; // number of events passed by this filter + }; +} +#endif diff --git a/DataProducts/src/FilterFraction.cc b/DataProducts/src/FilterFraction.cc new file mode 100644 index 0000000000..dc5c083ee3 --- /dev/null +++ b/DataProducts/src/FilterFraction.cc @@ -0,0 +1,22 @@ +#include "Offline/DataProducts/inc/FilterFraction.hh" +#include + +namespace mu2e { + FilterFraction& FilterFraction::operator +=(FilterFraction const& other) { + if(other.type() != type() || (type()<= nonominal && other.nominalFraction() != nominalFraction())) + throw std::runtime_error("nominal filter fractions conflict"); + nseen_ += other.nSeen(); + npassed_ += other.nPassed(); + return *this; + } + FilterFraction FilterFraction::operator + (FilterFraction const& other) const { + auto retval = *this; + retval += other; + return retval; + } + // concatenate with an upstream filter. The values must match! + FilterFraction FilterFraction::chain(FilterFraction const& upstream) const { + if(upstream.nPassed() != nSeen())throw std::runtime_error("Filter counts conflict"); + return FilterFraction(chained,-1.0,upstream.nSeen(),nPassed()); + } +} diff --git a/DataProducts/src/classes.h b/DataProducts/src/classes.h index 3d600aa584..8bb337728a 100644 --- a/DataProducts/src/classes.h +++ b/DataProducts/src/classes.h @@ -59,5 +59,8 @@ #include "Offline/DataProducts/inc/STMChannel.hh" #include "Offline/DataProducts/inc/STMTestBeamEventInfo.hh" +// Filter +#include "Offline/DataProducts/inc/FilterFraction.hh" + // General #include "Offline/DataProducts/inc/SurfaceId.hh" diff --git a/DataProducts/src/classes_def.xml b/DataProducts/src/classes_def.xml index b8a8d73418..8b605cad06 100644 --- a/DataProducts/src/classes_def.xml +++ b/DataProducts/src/classes_def.xml @@ -58,9 +58,14 @@ - + + + + + + diff --git a/Filters/src/RandomPrescaleFilter_module.cc b/Filters/src/RandomPrescaleFilter_module.cc index 6befcddf37..f4657391b7 100644 --- a/Filters/src/RandomPrescaleFilter_module.cc +++ b/Filters/src/RandomPrescaleFilter_module.cc @@ -13,6 +13,7 @@ #include "messagefacility/MessageLogger/MessageLogger.h" #include "Offline/SeedService/inc/SeedService.hh" #include "CLHEP/Random/RandFlat.h" +#include "Offline/DataProducts/inc/FilterFraction.hh" namespace mu2e { @@ -39,13 +40,14 @@ namespace mu2e RandomPrescaleFilter & operator = (RandomPrescaleFilter &&) = delete; bool filter(art::Event & e) override; - virtual bool endRun(art::Run& run ) override; + bool endSubRun(art::SubRun& subrun ) override; private: art::RandomNumberGenerator::base_engine_t& engine_; CLHEP::RandFlat randflat_; int debug_; - unsigned nevt_, npass_; + double frac_; + uint64_t nevt_, npass_; }; RandomPrescaleFilter::RandomPrescaleFilter(const Parameters& conf) : @@ -53,8 +55,11 @@ namespace mu2e engine_(createEngine( art::ServiceHandle()->getSeed())), randflat_( engine_, 0.0, conf().nPrescale() ), debug_(conf().debugLevel()), + frac_(1.0/double(conf().nPrescale())), nevt_(0), npass_(0) - {} + { + produces(); + } inline bool RandomPrescaleFilter::filter(art::Event & event) { @@ -64,10 +69,14 @@ namespace mu2e return retval; } - bool RandomPrescaleFilter::endRun( art::Run& run ) { + bool RandomPrescaleFilter::endSubRun( art::SubRun& subrun ) { + auto ff = std::make_unique(FilterFraction::constant,frac_, nevt_,npass_); + subrun.put(std::move(ff),"",art::fullSubRun()); if(debug_ > 0 && nevt_ > 0){ std::cout << moduleDescription().moduleLabel() << " passed " << npass_ << " events out of " << nevt_ << " for a ratio of " << float(npass_)/float(nevt_) << std::endl; } + // reset + npass_ = 0; nevt_ = 0; return true; } diff --git a/Print/CMakeLists.txt b/Print/CMakeLists.txt index 01d7deaa37..185295d02d 100644 --- a/Print/CMakeLists.txt +++ b/Print/CMakeLists.txt @@ -19,6 +19,7 @@ cet_make_library( src/CrvStepPrinter.cc src/EventWindowMarkerPrinter.cc src/GenParticlePrinter.cc + src/FilterFractionPrinter.cc src/HelixSeedPrinter.cc src/KalRepPrinter.cc src/KalSeedPrinter.cc @@ -87,21 +88,21 @@ cet_build_plugin(DataProductDump art::module REG_SOURCE src/DataProductDump_module.cc LIBRARIES REG Offline::Print - + ) cet_build_plugin(PrintModule art::module REG_SOURCE src/PrintModule_module.cc LIBRARIES REG Offline::Print - + ) cet_build_plugin(RunSubrunEvent art::module REG_SOURCE src/RunSubrunEvent_module.cc LIBRARIES REG Offline::Print - + ) diff --git a/Print/fcl/printCosmicLivetime.fcl b/Print/fcl/printCosmicLivetime.fcl index 1370cf2c31..3ea1e8d45d 100644 --- a/Print/fcl/printCosmicLivetime.fcl +++ b/Print/fcl/printCosmicLivetime.fcl @@ -1,4 +1,3 @@ - # # print products with a moderate amount of output - includes cuts on energy # diff --git a/Print/fcl/printFilterFraction.fcl b/Print/fcl/printFilterFraction.fcl new file mode 100644 index 0000000000..eb682d909f --- /dev/null +++ b/Print/fcl/printFilterFraction.fcl @@ -0,0 +1,37 @@ +# +# print products with a moderate amount of output - includes cuts on energy +# + +#include "Offline/fcl/minimalMessageService.fcl" +#include "Offline/fcl/standardServices.fcl" + +process_name : print + +services : { + message : @local::default_message + GlobalConstantsService : { inputFile : "Offline/GlobalConstantsService/data/globalConstants_01.txt" } +} + +physics :{ + analyzers: { + + printModule : { + module_type : PrintModule + PrintEvent : false + verbose : 0 + PrintSubRun : true + FilterFractionPrinter : { + verbose : 1 + } + } # printModule + + + } # analyzers + + ana : [ printModule ] + end_paths : [ ana ] + +} + +services.message.destinations.log.categories.ArtSummary.limit : 0 +services.message.destinations.statistics.stats : @local::mf_null diff --git a/Print/inc/FilterFractionPrinter.hh b/Print/inc/FilterFractionPrinter.hh new file mode 100644 index 0000000000..48a1a3914e --- /dev/null +++ b/Print/inc/FilterFractionPrinter.hh @@ -0,0 +1,37 @@ +// +// Utility class to print FilterFraction +// +#ifndef Print_inc_FilterFractionPrinter_hh +#define Print_inc_FilterFractionPrinter_hh + +#include +#include + +#include "Offline/DataProducts/inc/FilterFraction.hh" +#include "Offline/Print/inc/ProductPrinter.hh" +#include "art/Framework/Principal/Handle.h" +#include "canvas/Persistency/Common/Ptr.h" + +namespace mu2e { + +class FilterFractionPrinter : public ProductPrinter { + public: + FilterFractionPrinter() {} + FilterFractionPrinter(const Config& conf) : ProductPrinter(conf) {} + + // all the ways to request a printout + void Print(art::Event const& event, std::ostream& os = std::cout) override; + void PrintSubRun(art::SubRun const& subrun, + std::ostream& os = std::cout) override; + void Print(const art::Handle& handle, + std::ostream& os = std::cout); + void Print(const art::ValidHandle& handle, + std::ostream& os = std::cout); + void Print(const mu2e::FilterFraction& obj, int ind = -1, + std::ostream& os = std::cout); + void PrintHeader(const std::string& tag, std::ostream& os = std::cout); + private: +}; + +} // namespace mu2e +#endif diff --git a/Print/src/FilterFractionPrinter.cc b/Print/src/FilterFractionPrinter.cc new file mode 100644 index 0000000000..30ea553298 --- /dev/null +++ b/Print/src/FilterFractionPrinter.cc @@ -0,0 +1,79 @@ +#include "Offline/Print/inc/FilterFractionPrinter.hh" +#include "art/Framework/Principal/Provenance.h" +#include "canvas/Persistency/Common/Sampled.h" +#include "canvas/Persistency/Provenance/SampledInfo.h" +#include +#include + +void mu2e::FilterFractionPrinter::Print(art::Event const& event, std::ostream& os) {} + +void mu2e::FilterFractionPrinter::PrintSubRun(art::SubRun const& subrun, std::ostream& os) { + if (verbose() < 1) return; + if (tags().empty()) { + // if a list of instances not specified, print all instances + std::vector > ffl = + subrun.getMany(); + for (auto const& cl : ffl) Print(cl); + // also look for sampled instances + auto ffs = subrun.getMany>(); + if(ffs.size() > 0){ + for (auto const& ff : ffs){ + std::cout << "SampledFilterFraction with tag " << ff->originalInputTag() << std::endl; + auto sinfomh = subrun.getHandle("SamplingInput"); + if(sinfomh.isValid()){ + auto const& sinfom = *sinfomh; + for(auto sinfoit = sinfom.begin(); sinfoit != sinfom.end(); ++sinfoit) { + if(sinfoit->first.find("Cosmic") != std::string::npos){ + std::cout << "With SampledSubRunInfo entry for dataset " << sinfoit->first << " Has the following FilterFractions: " << std::endl; + for(auto const& sr : sinfoit->second.ids){ + std::cout << sr << " : "; + auto ffp = ff->get(sinfoit->first,sr); + if(!ffp.empty()) Print(*ffp); + } + } + } + } + } + } + + } else { + // print requested instances + for (const auto& tag : tags()) { + auto ff = subrun.getValidHandle(tag); + Print(ff); + } + } +} + +void mu2e::FilterFractionPrinter::Print( + const art::Handle& handle, std::ostream& os) { + if (verbose() < 1) return; + // the product tags with all four fields, with underscores + std::string tag = handle.provenance()->productDescription().branchName(); + tag.pop_back(); // remove trailing dot + PrintHeader(tag, os); + Print(*handle); +} + +void mu2e::FilterFractionPrinter::Print( + const art::ValidHandle& handle, std::ostream& os) { + if (verbose() < 1) return; + // the product tags with all four fields, with underscores + std::string tag = handle.provenance()->productDescription().branchName(); + tag.pop_back(); // remove trailing dot + PrintHeader(tag, os); + Print(*handle); +} + +void mu2e::FilterFractionPrinter::Print(const mu2e::FilterFraction& obj, + int ind, std::ostream& os) { + os << std::setiosflags(std::ios::fixed | std::ios::right); + + os << " Type " << obj.type() << " Nominal fraction " << obj.nominalFraction() << " Actual Fraction " << obj.actualFraction() << " N Seen " << obj.nSeen() << std::endl; +} + +void mu2e::FilterFractionPrinter::PrintHeader(const std::string& tag, + std::ostream& os) { + if (verbose() < 1) return; + os << "\nProductPrint " << tag << "\n"; +} diff --git a/Print/src/PrintModule_module.cc b/Print/src/PrintModule_module.cc index 01fee939b6..fd116847ae 100644 --- a/Print/src/PrintModule_module.cc +++ b/Print/src/PrintModule_module.cc @@ -18,6 +18,7 @@ #include "Offline/Print/inc/CaloShowerStepPrinter.hh" #include "Offline/Print/inc/ComboHitPrinter.hh" #include "Offline/Print/inc/CosmicLivetimePrinter.hh" +#include "Offline/Print/inc/FilterFractionPrinter.hh" #include "Offline/Print/inc/CrvCoincidenceClusterPrinter.hh" #include "Offline/Print/inc/CrvDigiMCPrinter.hh" #include "Offline/Print/inc/CrvDigiPrinter.hh" @@ -77,6 +78,8 @@ class PrintModule : public art::EDAnalyzer { fhicl::Name("ProtonBunchIntensityPrinter")}; fhicl::Table CosmicLivetimePrinter{ fhicl::Name("CosmicLivetimePrinter")}; + fhicl::Table FilterFractionPrinter{ + fhicl::Name("FilterFractionPrinter")}; fhicl::Table EventWindowMarkerPrinter{ fhicl::Name("EventWindowMarkerPrinter")}; fhicl::Table genParticlePrinter{ @@ -190,6 +193,8 @@ mu2e::PrintModule::PrintModule(const Parameters& conf) : art::EDAnalyzer(conf), conf().ProtonBunchIntensityPrinter())); _printers.push_back( make_unique(conf().CosmicLivetimePrinter())); + _printers.push_back( + make_unique(conf().FilterFractionPrinter())); _printers.push_back( make_unique(conf().EventWindowMarkerPrinter())); _printers.push_back( diff --git a/Trigger/src/PrescaleEvent_module.cc b/Trigger/src/PrescaleEvent_module.cc index a008d40733..fab5f71d76 100644 --- a/Trigger/src/PrescaleEvent_module.cc +++ b/Trigger/src/PrescaleEvent_module.cc @@ -17,12 +17,13 @@ #include "fhiclcpp/types/Table.h" #include "canvas/Utilities/InputTag.h" #include "messagefacility/MessageLogger/MessageLogger.h" -// #include "RecoDataProducts/inc/TriggerInfo.hh" #include "Offline/DataProducts/inc/EventWindowMarker.hh" +#include "Offline/DataProducts/inc/FilterFraction.hh" #include "artdaq-core-mu2e/Data/EventHeader.hh" #include #include +#include namespace mu2e { @@ -40,9 +41,10 @@ namespace mu2e }; struct EventMode { - EventWindowMarker::SpillType _type; - int _prescale; - EventMode(EventWindowMarker::SpillType type, int prescale) : _type(type), _prescale(prescale) {} + EventWindowMarker::SpillType type_; + int prescale_; + std::string name_; + EventMode(EventWindowMarker::SpillType type, int prescale, std::string const& name ) : type_(type), prescale_(prescale), name_(name) {} }; struct Config { @@ -63,68 +65,66 @@ namespace mu2e PrescaleEvent & operator = (PrescaleEvent &&) = delete; bool filter(art::Event & e) override; - virtual bool endRun(art::Run& run ) override; + bool endSubRun(art::SubRun& subrun ) override; private: - art::ProductToken const _ewmtoken; - std::vector _eventMode; - int _debug; - unsigned _nevt, _npass; - + art::ProductToken const ewmtoken_; + std::vector eventMode_; + std::vector nevt_, npass_; + int debug_; }; PrescaleEvent::PrescaleEvent(Parameters const & config) : art::EDFilter{config}, - _ewmtoken{consumes(config().EWM())}, - _debug (config().debug()), - _nevt(0), _npass(0){ + ewmtoken_{consumes(config().EWM())}, + nevt_(config().eventMode().size(),0), + npass_(config().eventMode().size(),0), + debug_ (config().debug()) { for(const auto& mode : config().eventMode()) { - if(mode.eventMode() == "OffSpill") _eventMode.push_back(EventMode(EventWindowMarker::offspill, mode.prescale())); - else if(mode.eventMode() == "OnSpill") _eventMode.push_back(EventMode(EventWindowMarker::onspill, mode.prescale())); + if(mode.eventMode() == "OffSpill") eventMode_.push_back(EventMode(EventWindowMarker::offspill, mode.prescale(),mode.eventMode())); + else if(mode.eventMode() == "OnSpill") eventMode_.push_back(EventMode(EventWindowMarker::onspill, mode.prescale(),mode.eventMode())); else throw cet::exception("TRIGGER") << "Unknown prescale mode " << mode.eventMode(); + produces(mode.eventMode()); } } inline bool PrescaleEvent::filter(art::Event & e) { - ++_nevt; - // Check for the prescale corresponding to the current event mode - auto ewmH = e.getValidHandle(_ewmtoken); + auto ewmH = e.getValidHandle(ewmtoken_); const EventWindowMarker& ewm(*ewmH); - int ps(0); // default to filtering all events - for (const auto& mode : _eventMode) { - uint8_t spillType = mode._type; + for (size_t imode = 0; imode < eventMode_.size(); imode++){ + auto const& mode = eventMode_[imode]; + uint8_t spillType = mode.type_; if (spillType == ewm.spillType()){ - ps = mode._prescale; - break; - } - } - - // Default to false - bool retval(false); - - // Apply the prescale, if requested for this event type - if(ps > 0) { - retval = e.event() % ps == 0; - if (retval){ - ++_npass; + ++nevt_[imode]; + // Apply the prescale + bool retval = mode.prescale_ > 0 ? e.event() % mode.prescale_ == 0 : false; + if (retval) ++npass_[imode]; + return retval; } } - - // Return the result - return retval; + // If no matching event type is found, return false + return false; } - bool PrescaleEvent::endRun( art::Run& run ) { - if(_debug > 0){ - std::cout << moduleDescription().moduleLabel() << " passed " << _npass << " events out of " << _nevt - << " for a ratio of " << ((_nevt > 0) ? float(_npass)/float(_nevt) : 0.f) << std::endl; + bool PrescaleEvent::endSubRun( art::SubRun& subrun ) { + for (size_t imode = 0; imode < eventMode_.size(); imode++){ + auto const& mode = eventMode_[imode]; + double frac = mode.prescale_ > 0 ? 1.0/double(mode.prescale_) : 0; + auto ff = std::make_unique(FilterFraction::constant, frac, nevt_[imode],npass_[imode]); + subrun.put(std::move(ff),mode.name_,art::fullSubRun()); + if(debug_ > 0){ + std::cout << moduleDescription().moduleLabel() << " mode " << mode.name_ << " passed " << npass_[imode] << " events out of " << nevt_[imode] + << " for a ratio of " << ((nevt_[imode] > 0) ? double(npass_[imode])/double(nevt_[imode]) : 0.f) << std::endl; + } + // reset + npass_[imode] = 0; nevt_[imode] = 0; } return true; } - } + using mu2e::PrescaleEvent; DEFINE_ART_MODULE(PrescaleEvent)