diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/Legacy/PMTBeamSignal.h similarity index 79% rename from icaruscode/IcarusObj/PMTBeamSignal.h rename to icaruscode/IcarusObj/Legacy/PMTBeamSignal.h index 842af0375..443371cb6 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/Legacy/PMTBeamSignal.h @@ -1,12 +1,14 @@ /** - * @file icaruscode/IcarusObj/PMTBeamSignal.h + * @file icaruscode/IcarusObj/Legacy/PMTBeamSignal.h * @brief Holds the event-by-event RWM or EW times - * @author Matteo Vicenzi (mvicenzi@bnl.gov) - * @date March 14 2024 + * @author Matteo Vicenzi (mvicenzi@bnl.gov), moved to legacy by A. Heggestuen + * @date March 14 2024, moved June 3, 2025 + * @note PLEASE NOTE : This is an old/LEGACY header for the previous namespace. + @see sbnobj/Common/PMT/Data/PMTBeamSignal.hh for new/current data product. */ -#ifndef ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H -#define ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H +#ifndef ICARUSCODE_ICARUSOBJ_LEGACY_PMTBEAMSIGNAL_H +#define ICARUSCODE_ICARUSOBJ_LEGACY_PMTBEAMSIGNAL_H // C/C++ standard libraries #include @@ -66,4 +68,4 @@ namespace icarus::timing } // namespace icarus::timing -#endif // ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H +#endif // ICARUSCODE_ICARUSOBJ_LEGACY_PMTBEAMSIGNAL_H diff --git a/icaruscode/IcarusObj/classes.h b/icaruscode/IcarusObj/classes.h index 05e6001ae..1f8d689cb 100644 --- a/icaruscode/IcarusObj/classes.h +++ b/icaruscode/IcarusObj/classes.h @@ -6,7 +6,7 @@ #include "icaruscode/IcarusObj/CRTTPCMatchingInfo.h" #include "icaruscode/IcarusObj/OpDetWaveformMeta.h" #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" -#include "icaruscode/IcarusObj/PMTBeamSignal.h" +#include "icaruscode/IcarusObj/Legacy/PMTBeamSignal.h" #include "icaruscode/IcarusObj/Hit.h" //#include "icaruscode/IcarusObj/CRTPMTMatching.h" diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index cb684dbfc..22e3d14f7 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -38,7 +38,7 @@ #include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" #include "icaruscode/CRT/CRTUtils/CRTPMTMatchingUtils.h" #include "sbnobj/Common/CRT/CRTPMTMatching.hh" -#include "icaruscode/IcarusObj/PMTBeamSignal.h" +#include "sbnobj/Common/PMT/Data/PMTBeamSignal.hh" // ROOT libraries #include "TTree.h" @@ -156,7 +156,7 @@ class opana::ICARUSBeamStructureAna : public art::EDAnalyzer std::vector m_crtregion; // RWM times - std::vector fRWMTimes; + std::vector fRWMTimes; }; // -------------------------------------------------------------------------- @@ -289,9 +289,9 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) // ---- // RWM times - fRWMTimes = e.getProduct>(fRWMLabel); + fRWMTimes = e.getProduct>(fRWMLabel); if (fRWMTimes.empty()) - mf::LogTrace("ICARUSBeamStructureAna") << "Data product std::vector for '" << fRWMLabel.label() + mf::LogTrace("ICARUSBeamStructureAna") << "Data product std::vector for '" << fRWMLabel.label() << "' is empty in " << m_gate_name << " event!"; // ---- @@ -420,11 +420,11 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) m_hit_rise_time_rwm.push_back(getRWMRelativeTime(ch, risemap[ch])); m_hit_pe.push_back(pemap[ch]); } - + // get the flash interaction time w.r.t. RWM // this is currently the mean between the first ophits on opposite walls m_flash_time_rwm = getFlashBunchTime(m_channel_id, m_hit_rise_time_rwm); - + fOpFlashTrees[iFlashLabel]->Fill(); clear(); @@ -461,7 +461,7 @@ double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) { if (fRWMTimes.empty()) - return icarus::timing::NoTime; + return sbn::timing::NoTime; auto rwm = fRWMTimes.at(channel); if (!rwm.isValid()) @@ -470,7 +470,7 @@ double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel << ", SpecialChannel " << rwm.specialChannel << ")" << " in event " << m_event << " gate " << m_gate_name; - return icarus::timing::NoTime; + return sbn::timing::NoTime; } double rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] @@ -486,9 +486,9 @@ double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channel double tfirst_right = std::numeric_limits::max(); // if no RWM info available, all pmt_start_time_rwm are invalid - // return icarus::timing::NoTime as well for the flash + // return sbn::timing::NoTime as well for the flash if (fRWMTimes.empty()) - return icarus::timing::NoTime; + return sbn::timing::NoTime; int nleft = 0; int nright = 0; @@ -501,9 +501,9 @@ double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channel // if any RWM copy is missing (therefore missing for an entire PMT crate), // it might not be possible to use the first hits (they might not have a RMW time) - // so return icarus::timing::NoTime as in other bad cases + // so return sbn::timing::NoTime as in other bad cases if (!fRWMTimes[i].isValid()) - return icarus::timing::NoTime; + return sbn::timing::NoTime; // count hits separetely on the two walls if (side == 0) diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index acd96a95e..ff0909af8 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -42,7 +42,7 @@ #include "lardataobj/Simulation/BeamGateInfo.h" #include "lardataobj/RawData/TriggerData.h" #include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" -#include "icaruscode/IcarusObj/PMTBeamSignal.h" +#include "sbnobj/Common/PMT/Data/PMTBeamSignal.hh" #include "sbnobj/ICARUS/PMT/Data/WaveformBaseline.h" #include "TTree.h" @@ -102,7 +102,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer fhicl::Atom RWMLabel{ Name("RWMLabel"), - Comment("Tag for the RWM std::vector data product")}; + Comment("Tag for the RWM std::vector data product")}; fhicl::Atom PEOpHitThreshold{ Name("PEOpHitThreshold"), @@ -251,7 +251,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer geo::GeometryCore const* fGeom; geo::WireReadoutGeom const* fChannelMapAlg; - std::vector fRWMTimes; + std::vector fRWMTimes; }; // ---------------------------------------------------------------------------- @@ -485,7 +485,7 @@ float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { if (fRWMTimes.empty()) - return icarus::timing::NoTime; + return sbn::timing::NoTime; auto rwm = fRWMTimes.at(channel); if (!rwm.isValid()) @@ -494,7 +494,7 @@ float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel << ", SpecialChannel " << rwm.specialChannel << ")" << " in event " << m_event << " gate " << m_gate_name; - return icarus::timing::NoTime; + return sbn::timing::NoTime; } float rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] @@ -511,9 +511,9 @@ float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_ float tfirst_right = std::numeric_limits::max(); // if no RWM info available, all pmt_start_time_rwm are invalid - // return icarus::timing::NoTime as well for the flash + // return sbn::timing::NoTime as well for the flash if (fRWMTimes.empty()) - return icarus::timing::NoTime; + return sbn::timing::NoTime; int nleft = 0; int nright = 0; @@ -530,9 +530,9 @@ float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_ // if any RWM copy is missing (therefore missing for an entire PMT crate), // it might not be possible to use the first hits (they might not have a RMW time) - // so return icarus::timing::NoTime as in other bad cases + // so return sbn::timing::NoTime as in other bad cases if (!fRWMTimes[i].isValid()) - return icarus::timing::NoTime; + return sbn::timing::NoTime; // count hits separetely on the two walls if (side == 0) @@ -768,9 +768,9 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const &e) if (!fRWMLabel.empty()) { - fRWMTimes = e.getProduct>(fRWMLabel); + fRWMTimes = e.getProduct>(fRWMLabel); if (fRWMTimes.empty()) - mf::LogTrace("ICARUSFlashAssAna") << "Data product std::vector for '" + mf::LogTrace("ICARUSFlashAssAna") << "Data product std::vector for '" << fRWMLabel.label() << "' is empty in " << m_gate_name << " event!"; } diff --git a/icaruscode/Timing/CMakeLists.txt b/icaruscode/Timing/CMakeLists.txt index 85fc1cc05..5e9d6603c 100644 --- a/icaruscode/Timing/CMakeLists.txt +++ b/icaruscode/Timing/CMakeLists.txt @@ -37,6 +37,8 @@ cet_build_plugin( PMTTimingCorrectionService art::service LIBRARIES PUBLIC ${SER cet_build_plugin( PMTBeamSignalsExtractor art::producer LIBRARIES PUBLIC ${MODULE_LIBRARIES}) +cet_build_plugin( PMTBeamSignalNamespaceConverter art::producer LIBRARIES PUBLIC ${MODULE_LIBRARIES}) + install_headers() install_fhicl() install_source() diff --git a/icaruscode/Timing/PMTBeamSignalNamespaceConverter_module.cc b/icaruscode/Timing/PMTBeamSignalNamespaceConverter_module.cc new file mode 100644 index 000000000..36e7566c8 --- /dev/null +++ b/icaruscode/Timing/PMTBeamSignalNamespaceConverter_module.cc @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////// +// Class: PMTBeamSignalNameSpaceConverter_module +// Plugin Type: producer (Unknown Unknown) +// File: PMTBeamSignalNameSpaceConverter_module.cc +// +// Generated at Thu Jun 5 14:59:32 2025 by Anna Heggestuen using cetskelgen +// from cetlib version 3.18.02. +//////////////////////////////////////////////////////////////////////// +#include "sbnobj/Common/PMT/Data/PMTBeamSignal.hh" +#include "icaruscode/IcarusObj/Legacy/PMTBeamSignal.h" + +#include "art/Framework/Core/EDProducer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Principal/SubRun.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include + +namespace icarus::timing { + class PMTBeamSignalNamespaceConverter; +} +/** + * @brief Copy PMTBeamSignal data product from icaruscode/IcarusObj namespace to sbnobj/Common + * + * This producer module simply copies what is stored in the icaruscode/IcarusObj data product + * `std::vector` to a new sbnobj/Common data product + * `std::vector`. This is to help with backward compatibility for + * files that are produced with the `icarus::timing::PMTBeamSignal` data product. Converting + * the icarus::timing namespace to sbn::timing allows us to fill this variable in the CAFs. + + * This module is set up to convert either the "RWM" or "EW" instance of the data product + * following what is set in the `SignalLabel` input parameter. + * + * Input parameters + * ------------------------ + * * `SignalLabel` (input tag): tag for the "RWM" or "EW" instance of the + * std::vector data product. + * + * Output products + * ------------------------- + * This module produces a `std::vector` with 360 elements + * representing the "RWM" or "EW" time for the corresponding PMT channel. + * + */ + +class icarus::timing::PMTBeamSignalNamespaceConverter : public art::EDProducer { +public: + explicit PMTBeamSignalNamespaceConverter(fhicl::ParameterSet const& p); + // The compiler-generated destructor is fine for non-base + // classes without bare pointers or other resource use. + + // Plugins should not be copied or assigned. + PMTBeamSignalNamespaceConverter(PMTBeamSignalNamespaceConverter const&) = delete; + PMTBeamSignalNamespaceConverter(PMTBeamSignalNamespaceConverter&&) = delete; + PMTBeamSignalNamespaceConverter& operator=(PMTBeamSignalNamespaceConverter const&) = delete; + PMTBeamSignalNamespaceConverter& operator=(PMTBeamSignalNamespaceConverter&&) = delete; + + // Required functions. + void produce(art::Event& e) override; + +private: + + // RWM or EW waveform instance label from fcl + art::InputTag const fSignalLabel; + + // Vector for input data product + std::vector fPMTBeamSignal; +}; + + +icarus::timing::PMTBeamSignalNamespaceConverter::PMTBeamSignalNamespaceConverter(fhicl::ParameterSet const& p) + : EDProducer{p}, + fSignalLabel(p.get("SignalLabel")) +{ + // Call appropriate produces<>() functions here. + produces>(fSignalLabel.instance()); + + // Call appropriate consumes<>() for any products to be retrieved by this module. + consumes>(fSignalLabel); +} + +void icarus::timing::PMTBeamSignalNamespaceConverter::produce(art::Event& e) +{ + //old `icarus::timing::PMTBeamSignal` data product + fPMTBeamSignal = e.getProduct>(fSignalLabel); + + //new `sbn::timing::PMTBeamSignal` data product + auto PMTBeamSignalColl = std::make_unique>(); + + if (fPMTBeamSignal.empty()) + mf::LogTrace("ICARUSBeamStructureAna") << "Data product std::vector for '" << fSignalLabel.label() + << "' is empty in event!"; + else{ + for (size_t i = 0; i < fPMTBeamSignal.size(); i++){ + sbn::timing::PMTBeamSignal newPMTBeamSignal; + newPMTBeamSignal.specialChannel = fPMTBeamSignal[i].specialChannel; + newPMTBeamSignal.digitizerLabel = fPMTBeamSignal[i].digitizerLabel; + newPMTBeamSignal.crate = fPMTBeamSignal[i].crate; + newPMTBeamSignal.sample = fPMTBeamSignal[i].sample; + newPMTBeamSignal.startTimeAbs = fPMTBeamSignal[i].startTimeAbs; + newPMTBeamSignal.startTime = fPMTBeamSignal[i].startTime; + PMTBeamSignalColl->push_back(newPMTBeamSignal); + } + } + e.put(std::move(PMTBeamSignalColl), fSignalLabel.instance()); +} + +DEFINE_ART_MODULE(icarus::timing::PMTBeamSignalNamespaceConverter) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index c190f770f..b4400c58a 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -18,7 +18,7 @@ #include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" #include "icaruscode/Decode/ChannelMapping/IICARUSChannelMap.h" #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" -#include "icaruscode/IcarusObj/PMTBeamSignal.h" +#include "sbnobj/Common/PMT/Data/PMTBeamSignal.hh" #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time #include "lardataalg/Utilities/quantities/spacetime.h" #include "lardataobj/RawData/OpDetWaveform.h" @@ -91,7 +91,7 @@ namespace icarus::timing * Output products * ------------------------- * - * This modules produces two `std::vector` + * This modules produces two `std::vector` * with 360 elements each, representing the relevent RWM or EW time for * the corresponding PMT channel. When the discrimination algorithm decides * the "peak" on a waveform to be noise, the corresponding entries are placed @@ -208,10 +208,10 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer std::vector m_wf; // prepare pointers for data products - using BeamSignalCollection = std::vector; + using BeamSignalCollection = std::vector; using BeamSignalCollectionPtr = std::unique_ptr; - std::map> fBeamSignals; + std::map> fBeamSignals; std::map fSignalCollection; }; @@ -234,8 +234,8 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete consumes>(fRWMlabel); // Call appropriate produces<>() functions here. - produces>("RWM"); - produces>("EW"); + produces>("RWM"); + produces>("EW"); } // ----------------------------------------------------------------------------- @@ -382,7 +382,7 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & // get the start sample of the signals, one instance per PMT crate // use threshold to skip spikes from electric crosstalk see SBN-doc-34928, slides 4-5. - // if no signal is found, set both times to icarus::timing::NoTime + // if no signal is found, set both times to sbn::timing::NoTime // so that `isValid()` in PMTBeamSignal will complain if someone checks it for (auto const &wave : waveforms) { @@ -394,12 +394,12 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & m_channel = wave.ChannelNumber(); m_wfstart = tstart.value(); - m_utime_abs = (m_sample != icarus::timing::NoSample) ? tstart.value() + fPMTsamplingTick * m_sample : icarus::timing::NoTime; - m_time_abs = (m_sample != icarus::timing::NoSample) ? m_utime_abs + getTriggerCorrection(m_channel) : icarus::timing::NoTime; - m_time = (m_sample != icarus::timing::NoSample) ? m_time_abs - ftriggerTime : icarus::timing::NoTime; + m_utime_abs = (m_sample != sbn::timing::NoSample) ? tstart.value() + fPMTsamplingTick * m_sample : sbn::timing::NoTime; + m_time_abs = (m_sample != sbn::timing::NoSample) ? m_utime_abs + getTriggerCorrection(m_channel) : sbn::timing::NoTime; + m_time = (m_sample != sbn::timing::NoSample) ? m_time_abs - ftriggerTime : sbn::timing::NoTime; std::string crate = getCrate(m_channel); - icarus::timing::PMTBeamSignal beamTime{m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time}; + sbn::timing::PMTBeamSignal beamTime{m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time}; fBeamSignals[l].emplace(crate, std::move(beamTime)); if (fDebugTrees) @@ -471,7 +471,7 @@ std::size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample(std::vector< auto delta = vv[maxbin] - vv[minbin]; if (delta < thres) // just noise - return icarus::timing::NoSample; // return no sample + return sbn::timing::NoSample; // return no sample for (std::size_t bin = maxbin; bin < minbin; bin++) { diff --git a/icaruscode/Timing/pmtbeamsignalnsconverter.fcl b/icaruscode/Timing/pmtbeamsignalnsconverter.fcl new file mode 100644 index 000000000..6312d92b4 --- /dev/null +++ b/icaruscode/Timing/pmtbeamsignalnsconverter.fcl @@ -0,0 +1,8 @@ +BEGIN_PROLOG + +pmtbeamsignalnsconverter:{ + module_type: "PMTBeamSignalNamespaceConverter" + SignalLabel: "beamTiming:RWM" +} + +END_PROLOG \ No newline at end of file diff --git a/icaruscode/Timing/pmtbeamsignalnsconverter_icarus.fcl b/icaruscode/Timing/pmtbeamsignalnsconverter_icarus.fcl new file mode 100644 index 000000000..b2836df4a --- /dev/null +++ b/icaruscode/Timing/pmtbeamsignalnsconverter_icarus.fcl @@ -0,0 +1,48 @@ +#include "pmtbeamsignalnsconverter.fcl" + +process_name: PMTBeamSignalNamespaceConverter + +services: +{ + scheduler: { defaultExceptions: false } # Make all uncaught exceptions fatal. + + # Load the service that manages root files for histograms. + TFileService: { fileName: "supplemental-%ifb-%p.root" } +} + +# The 'source' section tells the script to expect an input file with art::Event records. +source: +{ + module_type: RootInput + # Number of events to analyze; "-1" means all of the events in the input + # file. You can override this value with the "-n" option on the command line. + maxEvents: -1 +} + +outputs: +{ + out1: + { + module_type: RootOutput + fileName: "%ifb_%tc_reco.root" + dataTier: "reconstructed" + saveMemoryObjectThreshold: 0 + compressionLevel: 1 + fastCloning: false + } +} + +physics: +{ + producers: + { + beamTiming: @local::pmtbeamsignalnsconverter + } + # Schedule job step(s) for execution by defining the analysis module for this job. + reco: [ beamTiming ] + stream1: [ out1 ] + trigger_paths: [reco] + # "end_paths" is a keyword and contains the modules that do not modify the art::Event; + # i.e., analyzers and output streams. + end_paths: [ stream1 ] +} \ No newline at end of file