From 3c0a6d6ec2e4e04a9a6b965b3a668eb2ed1b62e2 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 14 Mar 2024 21:37:35 -0500 Subject: [PATCH 01/52] first pass at official RWM extraction --- icaruscode/Timing/CMakeLists.txt | 14 + .../Timing/PMTBeamSignalsExtractor_module.cc | 345 ++++++++++++++++++ 2 files changed, 359 insertions(+) create mode 100644 icaruscode/Timing/PMTBeamSignalsExtractor_module.cc diff --git a/icaruscode/Timing/CMakeLists.txt b/icaruscode/Timing/CMakeLists.txt index 0e652408e..da8b44da6 100644 --- a/icaruscode/Timing/CMakeLists.txt +++ b/icaruscode/Timing/CMakeLists.txt @@ -4,6 +4,18 @@ set( MODULE_LIBRARIES lardataobj::RecoBase larcore::Geometry_Geometry_service lardata::DetectorInfoServices_DetectorClocksServiceStandard_service + art_root_io::TFileService_service + art_root_io::tfile_support + lardataobj::RawData + art::Framework_Core + art::Framework_Principal + art::Utilities + canvas::canvas + messagefacility::MF_MessageLogger + fhiclcpp::fhiclcpp + cetlib::cetlib + cetlib_except::cetlib_except + ROOT::Tree ) set( LIB_LIBRARIES art::Framework_Services_Registry @@ -30,6 +42,8 @@ cet_build_plugin( OpHitTimingCorrection art::module LIBRARIES PUBLIC ${MODULE_LI cet_build_plugin( PMTTimingCorrectionService art::service LIBRARIES PUBLIC ${SERVICE_LIBRARIES}) +cet_build_plugin( PMTBeamSignalsExtractor art::producer LIBRARIES PUBLIC ${MODULE_LIBRARIES}) + install_headers() install_fhicl() install_source() diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc new file mode 100644 index 000000000..cd8878293 --- /dev/null +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -0,0 +1,345 @@ +//////////////////////////////////////////////////////////////////////// +// Class: PMTBeamSignalsExtractor +// Plugin Type: producer (Unknown Unknown) +// File: PMTBeamSignalsExtractor_module.cc +// +// Generated at Sun Feb 11 11:37:14 2024 by Matteo Vicenzi using cetskelgen +// from version . +//////////////////////////////////////////////////////////////////////// + +#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 "fhiclcpp/types/Atom.h" +#include "fhiclcpp/types/Table.h" +#include "messagefacility/MessageLogger/MessageLogger.h" +#include "art_root_io/TFileService.h" + +#include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" +#include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "lardataalg/DetectorInfo/DetectorTimings.h" +#include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time +#include "lardataobj/RawData/OpDetWaveform.h" + +#include "TTree.h" + +#include +#include +#include +#include + +namespace icarus { + namespace timing { + class PMTBeamSignalsExtractor; + } +} + + +class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { +public: + + explicit PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset); + + //process waveforms + template T Median(std::vector data) const; + template static size_t getMaxBin(std::vector const& vv, size_t startElement, size_t endElement); + template static size_t getMinBin(std::vector const& vv, size_t startElement, size_t endElement); + template static size_t getStartSample( std::vector const& vv, T thres ); + + //trigger-hardware timing correction + double getTriggerCorrection(int channel, std::vector const& corrections); + + // Plugins should not be copied or assigned. + PMTBeamSignalsExtractor(PMTBeamSignalsExtractor const&) = delete; + PMTBeamSignalsExtractor(PMTBeamSignalsExtractor&&) = delete; + PMTBeamSignalsExtractor& operator=(PMTBeamSignalsExtractor const&) = delete; + PMTBeamSignalsExtractor& operator=(PMTBeamSignalsExtractor&&) = delete; + + void beginJob(); + void produce(art::Event& e) override; + +private: + + art::ServiceHandle tfs; + bool fDebugTrees; + bool fSaveWaveforms; + art::InputTag fTriggerCorrectionLabel; + short int fADCThreshold; + std::vector fBoardSetup; + + std::map boardBySpecialChannel; + + TTree* fRWMTree; + TTree* fEWTree; + + int m_run; + int m_event; + int m_timestamp; + double m_trigger_time; + + // rwm signal + int m_n_rwm; + int m_rwm_channel; + double m_rwm_wfstart; + double m_rwm_utime; + double m_rwm_time; + std::vector m_rwm_wf; + + // ew signal + int m_n_ew; + int m_ew_channel; + double m_ew_wfstart; + double m_ew_utime; + double m_ew_time; + std::vector m_ew_wf; + + // these channels have been chosen because they + // were not affected by the mapping change + // (they stayed on the same board) + // FIXME: get it from the mapping db + + std::map< std::string, int> singleChannelPerBoard = + { + { "EE-BOT-C", 14 }, + { "EE-BOT-B", 24 }, + { "EE-TOP-C", 54 }, + { "EE-TOP-B", 74 }, + { "EW-BOT-C", 104 }, + { "EW-BOT-B", 114 }, + { "EW-TOP-C", 144 }, + { "EW-TOP-B", 164 }, + { "WE-BOT-C", 194 }, + { "WE-BOT-B", 204 }, + { "WE-TOP-C", 234 }, + { "WE-TOP-B", 254 }, + { "WW-BOT-C", 284 }, + { "WW-BOT-B", 294 }, + { "WW-TOP-C", 324 }, + { "WW-TOP-B", 344 }, + }; + +}; + + +icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset) + : EDProducer{pset} + , fDebugTrees( pset.get("DebugTrees") ) + , fSaveWaveforms( pset.get("SaveWaveforms") ) + , fTriggerCorrectionLabel( pset.get("TriggerCorrectionLabel") ) + , fADCThreshold( pset.get("ADCThreshold") ) + , fBoardSetup( pset.get>("BoardSetup") ) +{ + + for (fhicl::ParameterSet const& setup : fBoardSetup ) { + auto innerSet = setup.get>("SpecialChannels"); + boardBySpecialChannel[ innerSet[0].get("Channel") ] = setup.get("Name"); + } + + // Call appropriate produces<>() functions here. + + // Call appropriate consumes<>() for any products to be retrieved by this module. +} + +// ----------------------------------------------------------------------------- + +void icarus::timing::PMTBeamSignalsExtractor::beginJob() +{ + if( !fDebugTrees ) return; + + fRWMTree = tfs->make("rwmtree","RWM info"); + fRWMTree->Branch("run",&m_run); + fRWMTree->Branch("event",&m_event); + fRWMTree->Branch("timestamp",&m_timestamp); + fRWMTree->Branch("trigger_time",&m_trigger_time); + fRWMTree->Branch("n_rwm",&m_n_rwm); + fRWMTree->Branch("rwm_channel",&m_rwm_channel); + fRWMTree->Branch("rwm_wfstart", &m_rwm_wfstart); + fRWMTree->Branch("rwm_utime", &m_rwm_utime); + fRWMTree->Branch("rwm_time", &m_rwm_time); + + fEWTree = tfs->make("ewtree","EW info"); + fEWTree->Branch("run",&m_run); + fEWTree->Branch("event",&m_event); + fEWTree->Branch("timestamp",&m_timestamp); + fEWTree->Branch("trigger_time",&m_trigger_time); + fEWTree->Branch("n_ew",&m_n_ew); + fEWTree->Branch("ew_channel",&m_ew_channel); + fEWTree->Branch("ew_wfstart", &m_ew_wfstart); + fEWTree->Branch("ew_utime", &m_ew_utime); + fEWTree->Branch("ew_time", &m_ew_time); + + if(fSaveWaveforms){ + fRWMTree->Branch("rwm_wf",&m_rwm_wf); + fEWTree->Branch("ew_wf",&m_ew_wf); + } + +} + +// ----------------------------------------------------------------------------- + +void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) +{ + m_run = e.id().run(); + m_event = e.id().event(); + m_timestamp = e.time().timeHigh(); // precision to the second + + detinfo::DetectorTimings const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); + m_trigger_time = detTimings.TriggerTime().value(); + + m_rwm_wf.clear(); + m_ew_wf.clear(); + + auto const& wfCorrections = e.getProduct>(fTriggerCorrectionLabel); + int ntrig = wfCorrections.size(); + + if( ntrig < 1 ) + mf::LogError("PMTBeamSignalsExtractor") << "Not found PMTWaveformTimeCorrections with label '" + << fTriggerCorrectionLabel.label() << "'"; + else if ( ntrig < 360 ) + mf::LogError("PMTBeamSignalsExtractor") << "Missing some PMTWaveformTimeCorrections with label '" + << fTriggerCorrectionLabel.label() << "'"; + + auto const& ewWaveforms = e.getProduct>("daqPMT:EW"); + auto const& rwmWaveforms = e.getProduct>("daqPMT:RWM"); + m_n_ew = ewWaveforms.size(); + m_n_rwm = rwmWaveforms.size(); + if( m_n_ew< 1 ) + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label 'daqPMT:EW'"; + if( m_n_rwm< 1 ) + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label 'daqPMT:RWM'"; + + for( auto const & wave : ewWaveforms ){ + + detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; + double sample_rise = getStartSample( wave.Waveform(), fADCThreshold ); + + m_ew_channel = wave.ChannelNumber(); + m_ew_wfstart = tstart.value() ; + m_ew_utime = (sample_rise > 0) ? tstart.value() + 0.002*sample_rise : -1; + m_ew_time = (sample_rise > 0) ? m_ew_utime + getTriggerCorrection(m_ew_channel, wfCorrections) : -1; + if(fSaveWaveforms) m_ew_wf = wave.Waveform(); + + fEWTree->Fill(); + } + + for( auto const & wave : rwmWaveforms ){ + + detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; + double sample_rise = getStartSample( wave.Waveform(), fADCThreshold ); + + m_rwm_channel = wave.ChannelNumber(); + m_rwm_wfstart = tstart.value() ; + m_rwm_utime = (sample_rise > 0) ? tstart.value() + 0.002*sample_rise : -1; + m_rwm_time = (sample_rise > 0) ? m_rwm_utime + getTriggerCorrection(m_rwm_channel, wfCorrections) : -1; + if(fSaveWaveforms) m_rwm_wf = wave.Waveform(); + + fRWMTree->Fill(); + } + +} + +// --------------------------------------------------------------------------- + +template T icarus::timing::PMTBeamSignalsExtractor::Median( std::vector data ) const { + + std::nth_element( data.begin(), data.begin() + data.size()/2, data.end() ); + return data[ data.size()/2 ]; + +} + +// ----------------------------------------------------------------------------- + +template + size_t icarus::timing::PMTBeamSignalsExtractor::getMinBin( + std::vector const& vv, size_t startElement, size_t endElement ){ + + auto minel = + std::min_element( vv.begin()+startElement, vv.begin()+endElement ); + size_t minsample = std::distance( vv.begin()+startElement, minel ); + + return minsample; +} + +// ----------------------------------------------------------------------------- + +template + size_t icarus::timing::PMTBeamSignalsExtractor::getMaxBin( + std::vector const& vv, size_t startElement, size_t endElement){ + + auto maxel = + std::max_element( vv.begin()+startElement, vv.begin()+endElement ); + + size_t maxsample = std::distance( vv.begin()+startElement, maxel ); + + return maxsample; +} + +// ----------------------------------------------------------------------------- + +template + size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample( std::vector const& vv, T thres ){ + + // We are thinking in inverted polarity + size_t minbin = getMinBin( vv, 0, vv.size() ); + + //Search only a cropped region of the waveform backward from the min + size_t maxbin = minbin-20; + + // Now we crawl betweem maxbin and minbin and we stop when: + // bin value > (maxbin value - bin value )*0.2 + size_t startbin = maxbin; + auto delta = vv[maxbin]-vv[minbin]; + + if( delta < thres ) //just noise + return 0; //return first bin + + for( size_t bin=maxbin; bin= 0.2*delta ){ //20% + startbin = bin - 1; + break; + } + } + + if( startbin < maxbin ){ + startbin=maxbin; + } + + return startbin; +} + +// ----------------------------------------------------------------------------- + +double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel, + std::vector const& corrections){ + + // get the board name, convert to digitizer_label + std::string board = boardBySpecialChannel[channel]; + + std::string head = "icaruspmt"; + std::string dash = "-"; + std::string letter = (board.substr(board.size()-2, board.size())=="02") ? "B" : "C"; + + board.erase( board.find(head), head.size() ); + std::transform(board.begin(), board.end(), board.begin(), ::toupper); + board.insert( 2, dash); + board.insert( 6, dash); + std::string digitizer_label = board.substr(0,board.size()-2) + letter; + + // trigger-hardware corrections are shared by all channels on the same board + // mapping currently does not expose channel<->board relationship + // using ad-hoc configuration... FIXME! + int pmtch = singleChannelPerBoard[digitizer_label]; + + // trigger-hardware correction are in order + // index of vector is pmtch + return corrections.at(pmtch).startTime; + +} + +DEFINE_ART_MODULE(icarus::timing::PMTBeamSignalsExtractor) From 47cedd50d0cd8814e60833ca536414e30e1cccd3 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 14 Mar 2024 22:04:53 -0500 Subject: [PATCH 02/52] add fhicl file --- .../Timing/PMTBeamSignalsExtractor_module.cc | 28 +++++++++---------- icaruscode/Timing/timing_beam.fcl | 15 ++++++++++ 2 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 icaruscode/Timing/timing_beam.fcl diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index cd8878293..786feafd1 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -72,7 +72,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { short int fADCThreshold; std::vector fBoardSetup; - std::map boardBySpecialChannel; + std::map fBoardBySpecialChannel; TTree* fRWMTree; TTree* fEWTree; @@ -103,24 +103,24 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { // (they stayed on the same board) // FIXME: get it from the mapping db - std::map< std::string, int> singleChannelPerBoard = + std::map< std::string, int> fSingleChannelPerBoard = { - { "EE-BOT-C", 14 }, + { "EE-BOT-C", 4 }, { "EE-BOT-B", 24 }, { "EE-TOP-C", 54 }, - { "EE-TOP-B", 74 }, - { "EW-BOT-C", 104 }, + { "EE-TOP-B", 64 }, + { "EW-BOT-C", 94 }, { "EW-BOT-B", 114 }, { "EW-TOP-C", 144 }, - { "EW-TOP-B", 164 }, - { "WE-BOT-C", 194 }, + { "EW-TOP-B", 154 }, + { "WE-BOT-C", 184 }, { "WE-BOT-B", 204 }, { "WE-TOP-C", 234 }, - { "WE-TOP-B", 254 }, - { "WW-BOT-C", 284 }, + { "WE-TOP-B", 244 }, + { "WW-BOT-C", 274 }, { "WW-BOT-B", 294 }, - { "WW-TOP-C", 324 }, - { "WW-TOP-B", 344 }, + { "WW-TOP-C", 320 }, + { "WW-TOP-B", 339 }, }; }; @@ -137,7 +137,7 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete for (fhicl::ParameterSet const& setup : fBoardSetup ) { auto innerSet = setup.get>("SpecialChannels"); - boardBySpecialChannel[ innerSet[0].get("Channel") ] = setup.get("Name"); + fBoardBySpecialChannel[ innerSet[0].get("Channel") ] = setup.get("Name"); } // Call appropriate produces<>() functions here. @@ -319,7 +319,7 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel std::vector const& corrections){ // get the board name, convert to digitizer_label - std::string board = boardBySpecialChannel[channel]; + std::string board = fBoardBySpecialChannel[channel]; std::string head = "icaruspmt"; std::string dash = "-"; @@ -334,7 +334,7 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel // trigger-hardware corrections are shared by all channels on the same board // mapping currently does not expose channel<->board relationship // using ad-hoc configuration... FIXME! - int pmtch = singleChannelPerBoard[digitizer_label]; + int pmtch = fSingleChannelPerBoard[digitizer_label]; // trigger-hardware correction are in order // index of vector is pmtch diff --git a/icaruscode/Timing/timing_beam.fcl b/icaruscode/Timing/timing_beam.fcl new file mode 100644 index 000000000..fa45720d6 --- /dev/null +++ b/icaruscode/Timing/timing_beam.fcl @@ -0,0 +1,15 @@ +#include "CAEN_V1730_setup_icarus.fcl" + +BEGIN_PROLOG + +beam_signal_extractor: +{ + module_type: "PMTBeamSignalsExtractor" + TriggerCorrectionLabel: "daqPMT:globtrg" + ADCThreshold: 200 + BoardSetup: @local::icarus_V1730_setup + DebugTrees: true + SaveWaveforms: false +} + +END_PROLOG From fd0497152efbe3f54cda0ff86a8c7b9f20b1f250 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 14 Mar 2024 23:45:04 -0500 Subject: [PATCH 03/52] first attempt at data product --- icaruscode/IcarusObj/PMTBeamSignal.h | 44 ++++++++++++ .../Timing/PMTBeamSignalsExtractor_module.cc | 72 ++++++++++++++++--- 2 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 icaruscode/IcarusObj/PMTBeamSignal.h diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h new file mode 100644 index 000000000..429a29724 --- /dev/null +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -0,0 +1,44 @@ +/** + * @file icaruscode/IcarusObj/PMTBeamSignal.h + * @brief Holds the event-by-event RWM or EW time + * @author Matteo Vicenzi (mvicenzi@bnl.gov) + * @date March 14 2024 + */ + +#ifndef ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H +#define ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H + +// C/C++ standard libraries +#include + +namespace icarus::timing{ + + struct PMTBeamSignal { + + /// Special value to denote no special channel information + static constexpr auto NoChannel = std::numeric_limits::max(); + + /// The special channel this time was extracted from + unsigned int channel = NoChannel; + /// Board on which the special channel is on + std::string digitizerLabel = ""; + /// Crate this time applies to + std::string crate = ""; + /// Sample within the waveform where the reference signal is found + size_t sample = std::numeric_limits::lowest(); + /// Start time w.r.t. trigger time [us] + double startTime = 0.0; + + PMTBeamSignal(unsigned int ch, std::string b, std::string c, + size_t s, double t): + channel(ch), digitizerLabel(b), crate(c), sample(s), + startTime(t) {}; + + /// Returns whether the time is valid. + bool isValid() const { return channel != NoChannel; } + + }; + +} // namespace icarus::timing + +#endif //ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 786feafd1..5bce8883c 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -21,6 +21,7 @@ #include "art_root_io/TFileService.h" #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" +#include "icaruscode/IcarusObj/PMTBeamSignal.h" #include "lardata/DetectorInfoServices/DetectorClocksService.h" #include "lardataalg/DetectorInfo/DetectorTimings.h" #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time @@ -32,6 +33,7 @@ #include #include #include +#include namespace icarus { namespace timing { @@ -53,6 +55,8 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { //trigger-hardware timing correction double getTriggerCorrection(int channel, std::vector const& corrections); + std::string getDigitizerLabel(int channel); + std::string getCrate(int channel); // Plugins should not be copied or assigned. PMTBeamSignalsExtractor(PMTBeamSignalsExtractor const&) = delete; @@ -64,14 +68,15 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { void produce(art::Event& e) override; private: - + + // configuration parameters art::ServiceHandle tfs; bool fDebugTrees; bool fSaveWaveforms; art::InputTag fTriggerCorrectionLabel; short int fADCThreshold; std::vector fBoardSetup; - + std::map fBoardBySpecialChannel; TTree* fRWMTree; @@ -89,7 +94,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { double m_rwm_utime; double m_rwm_time; std::vector m_rwm_wf; - + // ew signal int m_n_ew; int m_ew_channel; @@ -123,8 +128,15 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { { "WW-TOP-B", 339 }, }; + using BeamSignalCollection = std::vector; + using BeamSignalCollectionPtr = std::unique_ptr; + + BeamSignalCollectionPtr fRWMcollection; + BeamSignalCollectionPtr fEWcollection; + }; +// ----------------------------------------------------------------------------- icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset) : EDProducer{pset} @@ -141,8 +153,8 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete } // Call appropriate produces<>() functions here. - - // Call appropriate consumes<>() for any products to be retrieved by this module. + produces>("RWM"); + produces>("EW"); } // ----------------------------------------------------------------------------- @@ -184,6 +196,11 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) { + + // initialize the data product + fEWcollection = std::make_unique(); + fRWMcollection = std::make_unique(); + m_run = e.id().run(); m_event = e.id().event(); m_timestamp = e.time().timeHigh(); // precision to the second @@ -222,8 +239,11 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) m_ew_wfstart = tstart.value() ; m_ew_utime = (sample_rise > 0) ? tstart.value() + 0.002*sample_rise : -1; m_ew_time = (sample_rise > 0) ? m_ew_utime + getTriggerCorrection(m_ew_channel, wfCorrections) : -1; + + fRWMcollection->emplace_back( m_ew_channel, getDigitizerLabel(m_ew_channel), getCrate(m_ew_channel), + sample_rise, m_ew_time ); + if(fSaveWaveforms) m_ew_wf = wave.Waveform(); - fEWTree->Fill(); } @@ -236,11 +256,23 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) m_rwm_wfstart = tstart.value() ; m_rwm_utime = (sample_rise > 0) ? tstart.value() + 0.002*sample_rise : -1; m_rwm_time = (sample_rise > 0) ? m_rwm_utime + getTriggerCorrection(m_rwm_channel, wfCorrections) : -1; + + fRWMcollection->emplace_back( m_rwm_channel, getDigitizerLabel(m_rwm_channel), getCrate(m_rwm_channel), + sample_rise, m_rwm_time ); + if(fSaveWaveforms) m_rwm_wf = wave.Waveform(); - fRWMTree->Fill(); } + // place the data products in the stream + // fix the cable swap for part of Run 2 + if( m_run > 9704 && m_run < 11443 ){ + e.put(std::move(fRWMcollection),"EW"); + e.put(std::move(fEWcollection),"RWM"); + } else { + e.put(std::move(fRWMcollection),"RWM"); + e.put(std::move(fEWcollection),"EW"); + } } // --------------------------------------------------------------------------- @@ -314,10 +346,9 @@ template } // ----------------------------------------------------------------------------- - -double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel, - std::vector const& corrections){ +std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int channel){ + // get the board name, convert to digitizer_label std::string board = fBoardBySpecialChannel[channel]; @@ -329,7 +360,26 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel std::transform(board.begin(), board.end(), board.begin(), ::toupper); board.insert( 2, dash); board.insert( 6, dash); - std::string digitizer_label = board.substr(0,board.size()-2) + letter; + + return board.substr(0,board.size()-2) + letter; + +} + +// ----------------------------------------------------------------------------- + +std::string icarus::timing::PMTBeamSignalsExtractor::getCrate(int channel){ + + std::string digitizer_label = getDigitizerLabel(channel); + return digitizer_label.substr( 0, digitizer_label.size()-2 ); + +} + +// ----------------------------------------------------------------------------- + +double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel, + std::vector const& corrections){ + + std::string digitizer_label = getDigitizerLabel(channel); // trigger-hardware corrections are shared by all channels on the same board // mapping currently does not expose channel<->board relationship From ba196e3a8859a84f5b113c63c2edbc53ddaa098e Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 14 Mar 2024 23:46:45 -0500 Subject: [PATCH 04/52] fix default debug flag --- icaruscode/Timing/timing_beam.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/timing_beam.fcl b/icaruscode/Timing/timing_beam.fcl index fa45720d6..84b4580a7 100644 --- a/icaruscode/Timing/timing_beam.fcl +++ b/icaruscode/Timing/timing_beam.fcl @@ -8,7 +8,7 @@ beam_signal_extractor: TriggerCorrectionLabel: "daqPMT:globtrg" ADCThreshold: 200 BoardSetup: @local::icarus_V1730_setup - DebugTrees: true + DebugTrees: false SaveWaveforms: false } From 482e407b7b4a734e624360e9820b7634a04e022a Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Fri, 15 Mar 2024 16:04:19 -0500 Subject: [PATCH 05/52] some improvements, new data products --- icaruscode/IcarusObj/PMTBeamSignal.h | 20 ++-- .../Timing/PMTBeamSignalsExtractor_module.cc | 113 ++++++++++++------ icaruscode/Timing/timing_beam.fcl | 2 + 3 files changed, 92 insertions(+), 43 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index 429a29724..d06e0e0b6 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -12,12 +12,14 @@ #include namespace icarus::timing{ + + /// Special value to denote no special channel information + static constexpr auto NoChannel = std::numeric_limits::max(); + /// Special value to denote no time channel information + static constexpr auto NoTime = std::numeric_limits::lowest(); struct PMTBeamSignal { - /// Special value to denote no special channel information - static constexpr auto NoChannel = std::numeric_limits::max(); - /// The special channel this time was extracted from unsigned int channel = NoChannel; /// Board on which the special channel is on @@ -26,16 +28,18 @@ namespace icarus::timing{ std::string crate = ""; /// Sample within the waveform where the reference signal is found size_t sample = std::numeric_limits::lowest(); - /// Start time w.r.t. trigger time [us] - double startTime = 0.0; + /// Start time in electronics time [us] + double startTimeAbs = NoTime; + /// Start time relative to trigger time [us] + double startTime = NoTime; PMTBeamSignal(unsigned int ch, std::string b, std::string c, - size_t s, double t): + size_t s, double t, double tt): channel(ch), digitizerLabel(b), crate(c), sample(s), - startTime(t) {}; + startTimeAbs(t), startTime(tt) {}; /// Returns whether the time is valid. - bool isValid() const { return channel != NoChannel; } + bool isValid() const { return startTimeAbs > NoTime; } }; diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 5bce8883c..48763660e 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -16,7 +16,6 @@ #include "canvas/Utilities/InputTag.h" #include "fhiclcpp/ParameterSet.h" #include "fhiclcpp/types/Atom.h" -#include "fhiclcpp/types/Table.h" #include "messagefacility/MessageLogger/MessageLogger.h" #include "art_root_io/TFileService.h" @@ -69,45 +68,55 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { private: - // configuration parameters art::ServiceHandle tfs; + + /// Save plain ROOT TTrees for debugging bool fDebugTrees; + /// Save raw waveforms in debug TTrees bool fSaveWaveforms; + /// RWM waveform instance label + art::InputTag fRWMlabel; + /// EW waveform instance label + art::InputTag fEWlabel; + /// Trigger-hardware correction instance art::InputTag fTriggerCorrectionLabel; + /// Threshold for pulse selection short int fADCThreshold; + /// V1730 special channels setup std::vector fBoardSetup; std::map fBoardBySpecialChannel; + // output TTrees TTree* fRWMTree; TTree* fEWTree; int m_run; int m_event; int m_timestamp; - double m_trigger_time; - // rwm signal int m_n_rwm; int m_rwm_channel; double m_rwm_wfstart; double m_rwm_utime; + size_t m_rwm_sample; double m_rwm_time; + double m_rwm_time_abs; std::vector m_rwm_wf; - // ew signal int m_n_ew; int m_ew_channel; double m_ew_wfstart; double m_ew_utime; + size_t m_ew_sample; double m_ew_time; + double m_ew_time_abs; std::vector m_ew_wf; // these channels have been chosen because they // were not affected by the mapping change // (they stayed on the same board) - // FIXME: get it from the mapping db - + // FIXME: get it from the mapping db std::map< std::string, int> fSingleChannelPerBoard = { { "EE-BOT-C", 4 }, @@ -128,6 +137,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { { "WW-TOP-B", 339 }, }; + // prepare pointers for data products using BeamSignalCollection = std::vector; using BeamSignalCollectionPtr = std::unique_ptr; @@ -142,16 +152,24 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete : EDProducer{pset} , fDebugTrees( pset.get("DebugTrees") ) , fSaveWaveforms( pset.get("SaveWaveforms") ) + , fRWMlabel( pset.get("RWMlabel") ) + , fEWlabel( pset.get("EWlabel") ) , fTriggerCorrectionLabel( pset.get("TriggerCorrectionLabel") ) , fADCThreshold( pset.get("ADCThreshold") ) , fBoardSetup( pset.get>("BoardSetup") ) { - + + // unpack the V1730 special channels settings in a useful way + // saving special_channel <-> board association in a map for (fhicl::ParameterSet const& setup : fBoardSetup ) { auto innerSet = setup.get>("SpecialChannels"); fBoardBySpecialChannel[ innerSet[0].get("Channel") ] = setup.get("Name"); } + // Call appropriate consumes<>() functions here. + consumes>(fEWlabel); + consumes>(fRWMlabel); + // Call appropriate produces<>() functions here. produces>("RWM"); produces>("EW"); @@ -161,30 +179,35 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete void icarus::timing::PMTBeamSignalsExtractor::beginJob() { + // prepare outupt TTrees if requested if( !fDebugTrees ) return; fRWMTree = tfs->make("rwmtree","RWM info"); fRWMTree->Branch("run",&m_run); fRWMTree->Branch("event",&m_event); fRWMTree->Branch("timestamp",&m_timestamp); - fRWMTree->Branch("trigger_time",&m_trigger_time); fRWMTree->Branch("n_rwm",&m_n_rwm); fRWMTree->Branch("rwm_channel",&m_rwm_channel); fRWMTree->Branch("rwm_wfstart", &m_rwm_wfstart); + fRWMTree->Branch("rwm_sample", &m_rwm_sample); fRWMTree->Branch("rwm_utime", &m_rwm_utime); fRWMTree->Branch("rwm_time", &m_rwm_time); + fRWMTree->Branch("rwm_time_abs",&m_rwm_time_abs); fEWTree = tfs->make("ewtree","EW info"); fEWTree->Branch("run",&m_run); fEWTree->Branch("event",&m_event); fEWTree->Branch("timestamp",&m_timestamp); - fEWTree->Branch("trigger_time",&m_trigger_time); fEWTree->Branch("n_ew",&m_n_ew); fEWTree->Branch("ew_channel",&m_ew_channel); fEWTree->Branch("ew_wfstart", &m_ew_wfstart); + fEWTree->Branch("ew_sample", &m_ew_sample); fEWTree->Branch("ew_utime", &m_ew_utime); fEWTree->Branch("ew_time", &m_ew_time); + fEWTree->Branch("ew_time_abs",&m_ew_time_abs); + // add std::vector with full waveforms + // this can quickly make the TTrees quite heavy if(fSaveWaveforms){ fRWMTree->Branch("rwm_wf",&m_rwm_wf); fEWTree->Branch("ew_wf",&m_ew_wf); @@ -197,20 +220,23 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) { - // initialize the data product + // initialize the data products fEWcollection = std::make_unique(); fRWMcollection = std::make_unique(); + // extract meta event information m_run = e.id().run(); m_event = e.id().event(); m_timestamp = e.time().timeHigh(); // precision to the second - - detinfo::DetectorTimings const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); - m_trigger_time = detTimings.TriggerTime().value(); - - m_rwm_wf.clear(); - m_ew_wf.clear(); - + auto const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); + double trigger_time = detTimings.TriggerTime().value(); + + // get the trigger-hardware corrections that are applied on all signal waveforms + // if EW or RWM is to be compared to the PMT signals, it must be applied on them as well + // it also takes care of board-to-board offsets (see SBN-doc-34631, slide 5) + // Note: this a vector of 360 elements, one correction for each signal channel + // however, corrections are the same for all channels on the same board + // for EW/RWM, we pick the correction from any of the other channels on the same board auto const& wfCorrections = e.getProduct>(fTriggerCorrectionLabel); int ntrig = wfCorrections.size(); @@ -221,51 +247,68 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) mf::LogError("PMTBeamSignalsExtractor") << "Missing some PMTWaveformTimeCorrections with label '" << fTriggerCorrectionLabel.label() << "'"; - auto const& ewWaveforms = e.getProduct>("daqPMT:EW"); - auto const& rwmWaveforms = e.getProduct>("daqPMT:RWM"); + // now the main course: EW and RWM waveforms + auto const& ewWaveforms = e.getProduct>(fEWlabel); + auto const& rwmWaveforms = e.getProduct>(fRWMlabel); m_n_ew = ewWaveforms.size(); m_n_rwm = rwmWaveforms.size(); if( m_n_ew< 1 ) - mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label 'daqPMT:EW'"; + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << fEWlabel.label() << "'"; if( m_n_rwm< 1 ) - mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label 'daqPMT:RWM'"; - + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << fRWMlabel.label() << "'"; + + m_rwm_wf.clear(); + m_ew_wf.clear(); + + // get the start sample of both signals, using threshold to skip spikes from electronical-crosstalk + // see SBN-doc-34928, slides 4-5 + // if no signal is found, set both time to "NoTime" so that it triggers the isValid() call of PMTBeamSignal + // save the digitizer_label as well as the crate for future use + // (namenly, each ophit will be corrected with the RWM/EW coming digitized in the same crate) + for( auto const & wave : ewWaveforms ){ detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; - double sample_rise = getStartSample( wave.Waveform(), fADCThreshold ); + + // if nothing is found, first sample is returned (0) + m_ew_sample = getStartSample( wave.Waveform(), fADCThreshold ); m_ew_channel = wave.ChannelNumber(); m_ew_wfstart = tstart.value() ; - m_ew_utime = (sample_rise > 0) ? tstart.value() + 0.002*sample_rise : -1; - m_ew_time = (sample_rise > 0) ? m_ew_utime + getTriggerCorrection(m_ew_channel, wfCorrections) : -1; + m_ew_utime = (m_ew_sample > 0) ? tstart.value() + 0.002*m_ew_sample : icarus::timing::NoTime; + m_ew_time_abs = (m_ew_sample > 0) ? m_ew_utime + getTriggerCorrection(m_ew_channel, wfCorrections) : icarus::timing::NoTime; + m_ew_time = (m_ew_sample > 0) ? m_ew_time_abs-trigger_time : icarus::timing::NoTime; fRWMcollection->emplace_back( m_ew_channel, getDigitizerLabel(m_ew_channel), getCrate(m_ew_channel), - sample_rise, m_ew_time ); + m_ew_sample, m_ew_time_abs, m_ew_time ); if(fSaveWaveforms) m_ew_wf = wave.Waveform(); - fEWTree->Fill(); + if(fDebugTrees) fEWTree->Fill(); } for( auto const & wave : rwmWaveforms ){ detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; - double sample_rise = getStartSample( wave.Waveform(), fADCThreshold ); + + // if nothing is found, first sample is returned (0) + m_rwm_sample = getStartSample( wave.Waveform(), fADCThreshold ); m_rwm_channel = wave.ChannelNumber(); m_rwm_wfstart = tstart.value() ; - m_rwm_utime = (sample_rise > 0) ? tstart.value() + 0.002*sample_rise : -1; - m_rwm_time = (sample_rise > 0) ? m_rwm_utime + getTriggerCorrection(m_rwm_channel, wfCorrections) : -1; - + m_rwm_utime = (m_rwm_sample > 0) ? tstart.value() + 0.002*m_rwm_sample : icarus::timing::NoTime; + m_rwm_time_abs = (m_rwm_sample > 0) ? m_rwm_utime + getTriggerCorrection(m_rwm_channel, wfCorrections) : icarus::timing::NoTime; + m_rwm_time = (m_rwm_sample > 0) ? m_rwm_time_abs-trigger_time : icarus::timing::NoTime; + fRWMcollection->emplace_back( m_rwm_channel, getDigitizerLabel(m_rwm_channel), getCrate(m_rwm_channel), - sample_rise, m_rwm_time ); + m_rwm_sample, m_rwm_time_abs, m_rwm_time ); if(fSaveWaveforms) m_rwm_wf = wave.Waveform(); - fRWMTree->Fill(); + if(fDebugTrees) fRWMTree->Fill(); } // place the data products in the stream - // fix the cable swap for part of Run 2 + // fix the cable swap for part of Run 2 right here + // see SBN-doc-34631 for details if( m_run > 9704 && m_run < 11443 ){ e.put(std::move(fRWMcollection),"EW"); e.put(std::move(fEWcollection),"RWM"); diff --git a/icaruscode/Timing/timing_beam.fcl b/icaruscode/Timing/timing_beam.fcl index 84b4580a7..0d2a2c3bf 100644 --- a/icaruscode/Timing/timing_beam.fcl +++ b/icaruscode/Timing/timing_beam.fcl @@ -5,6 +5,8 @@ BEGIN_PROLOG beam_signal_extractor: { module_type: "PMTBeamSignalsExtractor" + EWlabel: "daqPMT:EW" + RWMlabel: "daqPMT:RWM" TriggerCorrectionLabel: "daqPMT:globtrg" ADCThreshold: 200 BoardSetup: @local::icarus_V1730_setup From 801d523bc281ed2340959620baceddeb8bd022e3 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Sat, 16 Mar 2024 17:35:12 -0500 Subject: [PATCH 06/52] fix typo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 48763660e..9796968bd 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -279,7 +279,7 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) m_ew_time_abs = (m_ew_sample > 0) ? m_ew_utime + getTriggerCorrection(m_ew_channel, wfCorrections) : icarus::timing::NoTime; m_ew_time = (m_ew_sample > 0) ? m_ew_time_abs-trigger_time : icarus::timing::NoTime; - fRWMcollection->emplace_back( m_ew_channel, getDigitizerLabel(m_ew_channel), getCrate(m_ew_channel), + fEWcollection->emplace_back( m_ew_channel, getDigitizerLabel(m_ew_channel), getCrate(m_ew_channel), m_ew_sample, m_ew_time_abs, m_ew_time ); if(fSaveWaveforms) m_ew_wf = wave.Waveform(); From dd75911d5db20fc0768a43592930576da933bbce Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 21 Mar 2024 18:22:47 -0500 Subject: [PATCH 07/52] removing hardcoded mapping --- .../Timing/PMTBeamSignalsExtractor_module.cc | 43 +++++++------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 9796968bd..9925a7f21 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -19,6 +19,7 @@ #include "messagefacility/MessageLogger/MessageLogger.h" #include "art_root_io/TFileService.h" +#include "icaruscode/Decode/ChannelMapping/IICARUSChannelMap.h" #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" #include "icaruscode/IcarusObj/PMTBeamSignal.h" #include "lardata/DetectorInfoServices/DetectorClocksService.h" @@ -69,7 +70,9 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { private: art::ServiceHandle tfs; - + + /// Channel mappping + icarusDB::IICARUSChannelMap const & fChannelMap; /// Save plain ROOT TTrees for debugging bool fDebugTrees; /// Save raw waveforms in debug TTrees @@ -113,29 +116,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { double m_ew_time_abs; std::vector m_ew_wf; - // these channels have been chosen because they - // were not affected by the mapping change - // (they stayed on the same board) - // FIXME: get it from the mapping db - std::map< std::string, int> fSingleChannelPerBoard = - { - { "EE-BOT-C", 4 }, - { "EE-BOT-B", 24 }, - { "EE-TOP-C", 54 }, - { "EE-TOP-B", 64 }, - { "EW-BOT-C", 94 }, - { "EW-BOT-B", 114 }, - { "EW-TOP-C", 144 }, - { "EW-TOP-B", 154 }, - { "WE-BOT-C", 184 }, - { "WE-BOT-B", 204 }, - { "WE-TOP-C", 234 }, - { "WE-TOP-B", 244 }, - { "WW-BOT-C", 274 }, - { "WW-BOT-B", 294 }, - { "WW-TOP-C", 320 }, - { "WW-TOP-B", 339 }, - }; + std::map< std::string, int> fBoardEffFragmentID; // prepare pointers for data products using BeamSignalCollection = std::vector; @@ -150,6 +131,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset) : EDProducer{pset} + , fChannelMap( *(art::ServiceHandle{}) ) , fDebugTrees( pset.get("DebugTrees") ) , fSaveWaveforms( pset.get("SaveWaveforms") ) , fRWMlabel( pset.get("RWMlabel") ) @@ -166,6 +148,12 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete fBoardBySpecialChannel[ innerSet[0].get("Channel") ] = setup.get("Name"); } + // pre-save the association between digitizer_label and effective fragment ID + for (unsigned int fragid=0; fragid() functions here. consumes>(fEWlabel); consumes>(fRWMlabel); @@ -425,9 +413,10 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel std::string digitizer_label = getDigitizerLabel(channel); // trigger-hardware corrections are shared by all channels on the same board - // mapping currently does not expose channel<->board relationship - // using ad-hoc configuration... FIXME! - int pmtch = fSingleChannelPerBoard[digitizer_label]; + // we can pick the first channel on the desired board + int fragID = fBoardEffFragmentID[digitizer_label]; + auto pmtinfo = fChannelMap.getPMTchannelInfo(fragID)[0]; //pick first ch on board + int pmtch = pmtinfo.channelID; // trigger-hardware correction are in order // index of vector is pmtch From 8363015c5b88f2c7bad64a646c019f07227bd1a9 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 26 Mar 2024 15:49:28 -0500 Subject: [PATCH 08/52] check beam gate type, skip offbeam events --- icaruscode/Timing/CMakeLists.txt | 1 + .../Timing/PMTBeamSignalsExtractor_module.cc | 24 ++++++++++++++++++- icaruscode/Timing/timing_beam.fcl | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/icaruscode/Timing/CMakeLists.txt b/icaruscode/Timing/CMakeLists.txt index da8b44da6..4611ca0f7 100644 --- a/icaruscode/Timing/CMakeLists.txt +++ b/icaruscode/Timing/CMakeLists.txt @@ -2,6 +2,7 @@ cet_enable_asserts() set( MODULE_LIBRARIES lardataobj::RecoBase + sbnobj::Common_Trigger larcore::Geometry_Geometry_service lardata::DetectorInfoServices_DetectorClocksServiceStandard_service art_root_io::TFileService_service diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 9925a7f21..51e7764bb 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -19,6 +19,7 @@ #include "messagefacility/MessageLogger/MessageLogger.h" #include "art_root_io/TFileService.h" +#include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" #include "icaruscode/Decode/ChannelMapping/IICARUSChannelMap.h" #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" #include "icaruscode/IcarusObj/PMTBeamSignal.h" @@ -77,6 +78,8 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { bool fDebugTrees; /// Save raw waveforms in debug TTrees bool fSaveWaveforms; + /// Trigger instance label + art::InputTag fTriggerLabel; /// RWM waveform instance label art::InputTag fRWMlabel; /// EW waveform instance label @@ -134,6 +137,7 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete , fChannelMap( *(art::ServiceHandle{}) ) , fDebugTrees( pset.get("DebugTrees") ) , fSaveWaveforms( pset.get("SaveWaveforms") ) + , fTriggerLabel( pset.get("TriggerLabel") ) , fRWMlabel( pset.get("RWMlabel") ) , fEWlabel( pset.get("EWlabel") ) , fTriggerCorrectionLabel( pset.get("TriggerCorrectionLabel") ) @@ -219,6 +223,24 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) auto const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); double trigger_time = detTimings.TriggerTime().value(); + // this module should run on beam-only events + // check the current beam gate + auto const trigger_handle = e.getProduct(fTriggerLabel); + sbn::triggerSource const gateType = trigger_handle.sourceType; + std::string beamType = ""; + + switch (gateType) { + case sbn::triggerSource::BNB: + beamType = "BNB"; + case sbn::triggerSource::NuMI: + beamType = "NuMI"; + default: + mf::LogTrace("PMTBeamSignalsExtractor") << "Skipping offbeam gate '" << name(gateType) << "'"; + e.put(std::move(fRWMcollection),"RWM"); + e.put(std::move(fEWcollection),"EW"); + return; + } + // get the trigger-hardware corrections that are applied on all signal waveforms // if EW or RWM is to be compared to the PMT signals, it must be applied on them as well // it also takes care of board-to-board offsets (see SBN-doc-34631, slide 5) @@ -297,7 +319,7 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) // place the data products in the stream // fix the cable swap for part of Run 2 right here // see SBN-doc-34631 for details - if( m_run > 9704 && m_run < 11443 ){ + if( beamType=="BNB" && m_run > 9704 && m_run < 11443 ){ e.put(std::move(fRWMcollection),"EW"); e.put(std::move(fEWcollection),"RWM"); } else { diff --git a/icaruscode/Timing/timing_beam.fcl b/icaruscode/Timing/timing_beam.fcl index 0d2a2c3bf..1a2250df2 100644 --- a/icaruscode/Timing/timing_beam.fcl +++ b/icaruscode/Timing/timing_beam.fcl @@ -5,6 +5,7 @@ BEGIN_PROLOG beam_signal_extractor: { module_type: "PMTBeamSignalsExtractor" + TriggerLabel: "daqTrigger" EWlabel: "daqPMT:EW" RWMlabel: "daqPMT:RWM" TriggerCorrectionLabel: "daqPMT:globtrg" From 6052cd15cbc1d0738464356017bfc1f7347b9b93 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 26 Mar 2024 16:55:16 -0500 Subject: [PATCH 09/52] fix switch logic --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 51e7764bb..ab6b79af0 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -232,8 +232,10 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) switch (gateType) { case sbn::triggerSource::BNB: beamType = "BNB"; + break; case sbn::triggerSource::NuMI: beamType = "NuMI"; + break; default: mf::LogTrace("PMTBeamSignalsExtractor") << "Skipping offbeam gate '" << name(gateType) << "'"; e.put(std::move(fRWMcollection),"RWM"); From 5bc735a74760c512a7da148d0271aef2325388d3 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 2 May 2024 17:25:57 -0500 Subject: [PATCH 10/52] reworked data product, simplified code w/ support functions --- icaruscode/IcarusObj/PMTBeamSignal.h | 33 +- .../Timing/PMTBeamSignalsExtractor_module.cc | 340 +++++++++++------- 2 files changed, 229 insertions(+), 144 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index d06e0e0b6..753bdecac 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -1,6 +1,6 @@ /** * @file icaruscode/IcarusObj/PMTBeamSignal.h - * @brief Holds the event-by-event RWM or EW time + * @brief Holds the event-by-event RWM or EW times * @author Matteo Vicenzi (mvicenzi@bnl.gov) * @date March 14 2024 */ @@ -16,30 +16,39 @@ namespace icarus::timing{ /// Special value to denote no special channel information static constexpr auto NoChannel = std::numeric_limits::max(); /// Special value to denote no time channel information - static constexpr auto NoTime = std::numeric_limits::lowest(); + static constexpr double NoTime = 0.; + /// Special value to denote no sample information + static constexpr size_t NoSample = 0; struct PMTBeamSignal { - /// The special channel this time was extracted from - unsigned int channel = NoChannel; - /// Board on which the special channel is on + /// Special channel this time was extracted from + unsigned int specialChannel = NoChannel; + + /// Board on which the special channel is on std::string digitizerLabel = ""; - /// Crate this time applies to + + /// Crate this time applies to std::string crate = ""; - /// Sample within the waveform where the reference signal is found - size_t sample = std::numeric_limits::lowest(); - /// Start time in electronics time [us] + + /// Sample within the waveform where the reference signal is found + size_t sample = NoSample; + + /// Start time in electronics time [us] double startTimeAbs = NoTime; - /// Start time relative to trigger time [us] + + /// Start time relative to trigger time [us] double startTime = NoTime; PMTBeamSignal(unsigned int ch, std::string b, std::string c, size_t s, double t, double tt): - channel(ch), digitizerLabel(b), crate(c), sample(s), + specialChannel(ch), digitizerLabel(b), crate(c), sample(s), startTimeAbs(t), startTime(tt) {}; + + PMTBeamSignal(){}; /// Returns whether the time is valid. - bool isValid() const { return startTimeAbs > NoTime; } + bool isValid() const { return ((sample != NoSample) && (startTime != NoTime)); } }; diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index ab6b79af0..5fc7fd81b 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -42,20 +42,82 @@ namespace icarus { } } +/** + * @brief Extracts RWM and EW times from special waveforms. + * + * This module extracts the RWM and EW from the waveforms recorded in the + * spare PMT channels and associates these times with all the channels + * in the same PMT readout crate. + * + * Input parameters + * ------------------------ + * + * This modules requires the following products: + * + * * `TriggerLabel` (input tag): tag for the `sbn::ExtraTriggerInfo` + * data product. This is required to check if it's a beam event or not. + * * `RWMlabel` (input tag): tag for the `std::vector` + * product containing the RWM special waveforms. + * * `EWlabel` (input tag): tag for the `std::vector` + * product containign the EW special waveforms. + * * `TriggerCorrectionLabel` (input tag): tag for the + * std::vector product that + * stores the channel-by-channel waveform timing corrections + * * `BoardSetup` (fhicl parameter set): description of the current + * V1730 setup from `CAEN_V1730_setup_icarus.fcl` mapping the special signals. + * * `ADCThreshold` (int): detection threshold to avoid cross-talk + * noise if one signal is missing from its waveform. + * * `DebugTrees` (bool): flag to produce plain ROOT trees for debugging. + * * `SaveWaveforms` (bool): flag to save full waveforms in the debug trees. + * + * Signal timing extraction + * ------------------------- + * + * The algorithm is quite unsophisticated and follows what is done for + * the digitized trigger signal in `PMTWaveformTimeCorrectionExtractor`. + * The reference signal is expected to be a sharp square wave in negative + * polarity. The time is based on the front side of that wave: + * + * * the absolute minimum of the waveform is found + * * an interval starting 20 ticks before that minimum is considered + * * the baseline level is defined as the value at the start of that interval + * * if the baseline-minimum is below a threshold, it is assume to be noise + * and no time is returned + * * if not, the start time is set to the exact tick with an amplitude exceeding 20% + * of the miminum of the signal from the baseline + * + * + * Output products + * ------------------------- + * + * This modules produces two `std::vector` + * with 360 elements each, representing the relevent RWM or EW time for + * the corresponding PMT channel. + * + * If the event is offbeam or minbias, these vectors are produced empty. + * + */ + class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { public: explicit PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset); - //process waveforms + // process waveforms + void extractBeamSignalTime(art::Event& e, art::InputTag label ); template T Median(std::vector data) const; template static size_t getMaxBin(std::vector const& vv, size_t startElement, size_t endElement); template static size_t getMinBin(std::vector const& vv, size_t startElement, size_t endElement); template static size_t getStartSample( std::vector const& vv, T thres ); - //trigger-hardware timing correction - double getTriggerCorrection(int channel, std::vector const& corrections); + // associate times to PMT channels + void associateBeamSignalsToChannels(art::InputTag label); + + // trigger-hardware timing correction + double getTriggerCorrection(int channel); + + // quick mapping conversions std::string getDigitizerLabel(int channel); std::string getCrate(int channel); @@ -92,41 +154,32 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { std::vector fBoardSetup; std::map fBoardBySpecialChannel; + std::vector fCorrections; + std::map fBoardEffFragmentID; + double ftrigger_time; // output TTrees - TTree* fRWMTree; - TTree* fEWTree; - + std::map fOutTree; + // event info int m_run; int m_event; int m_timestamp; - // rwm signal - int m_n_rwm; - int m_rwm_channel; - double m_rwm_wfstart; - double m_rwm_utime; - size_t m_rwm_sample; - double m_rwm_time; - double m_rwm_time_abs; - std::vector m_rwm_wf; - // ew signal - int m_n_ew; - int m_ew_channel; - double m_ew_wfstart; - double m_ew_utime; - size_t m_ew_sample; - double m_ew_time; - double m_ew_time_abs; - std::vector m_ew_wf; - - std::map< std::string, int> fBoardEffFragmentID; + // special signal info + int m_n_channels; + int m_channel; + double m_wfstart; + size_t m_sample; + double m_time; + double m_time_abs; + double m_utime_abs; + std::vector m_wf; // prepare pointers for data products using BeamSignalCollection = std::vector; using BeamSignalCollectionPtr = std::unique_ptr; - BeamSignalCollectionPtr fRWMcollection; - BeamSignalCollectionPtr fEWcollection; + std::map> fBeamSignals; + std::map fSignalCollection; }; @@ -174,37 +227,28 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() // prepare outupt TTrees if requested if( !fDebugTrees ) return; - fRWMTree = tfs->make("rwmtree","RWM info"); - fRWMTree->Branch("run",&m_run); - fRWMTree->Branch("event",&m_event); - fRWMTree->Branch("timestamp",&m_timestamp); - fRWMTree->Branch("n_rwm",&m_n_rwm); - fRWMTree->Branch("rwm_channel",&m_rwm_channel); - fRWMTree->Branch("rwm_wfstart", &m_rwm_wfstart); - fRWMTree->Branch("rwm_sample", &m_rwm_sample); - fRWMTree->Branch("rwm_utime", &m_rwm_utime); - fRWMTree->Branch("rwm_time", &m_rwm_time); - fRWMTree->Branch("rwm_time_abs",&m_rwm_time_abs); + std::vector labels = { fRWMlabel.instance(), fEWlabel.instance() }; + for (auto l : labels ){ + std::string name = l + "tree"; + std::string desc = l + " info"; + fOutTree[l] = tfs->make(name.c_str(),desc.c_str()); + fOutTree[l]->Branch("run",&m_run); + fOutTree[l]->Branch("event",&m_event); + fOutTree[l]->Branch("timestamp",&m_timestamp); + fOutTree[l]->Branch("n_channels",&m_n_channels); + fOutTree[l]->Branch("channel",&m_channel); + fOutTree[l]->Branch("wfstart", &m_wfstart); + fOutTree[l]->Branch("sample", &m_sample); + fOutTree[l]->Branch("utime_abs", &m_utime_abs); + fOutTree[l]->Branch("time_abs",&m_time_abs); + fOutTree[l]->Branch("time", &m_time); - fEWTree = tfs->make("ewtree","EW info"); - fEWTree->Branch("run",&m_run); - fEWTree->Branch("event",&m_event); - fEWTree->Branch("timestamp",&m_timestamp); - fEWTree->Branch("n_ew",&m_n_ew); - fEWTree->Branch("ew_channel",&m_ew_channel); - fEWTree->Branch("ew_wfstart", &m_ew_wfstart); - fEWTree->Branch("ew_sample", &m_ew_sample); - fEWTree->Branch("ew_utime", &m_ew_utime); - fEWTree->Branch("ew_time", &m_ew_time); - fEWTree->Branch("ew_time_abs",&m_ew_time_abs); - - // add std::vector with full waveforms - // this can quickly make the TTrees quite heavy - if(fSaveWaveforms){ - fRWMTree->Branch("rwm_wf",&m_rwm_wf); - fEWTree->Branch("ew_wf",&m_ew_wf); + // add std::vector with full waveforms + // this can quickly make the TTrees quite heavy + if(fSaveWaveforms){ + fOutTree[l]->Branch("wf",&m_wf); + } } - } // ----------------------------------------------------------------------------- @@ -213,15 +257,16 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) { // initialize the data products - fEWcollection = std::make_unique(); - fRWMcollection = std::make_unique(); + fBeamSignals.clear(); + fSignalCollection[fRWMlabel.instance()] = std::make_unique(); + fSignalCollection[fEWlabel.instance()] = std::make_unique(); // extract meta event information m_run = e.id().run(); m_event = e.id().event(); m_timestamp = e.time().timeHigh(); // precision to the second auto const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); - double trigger_time = detTimings.TriggerTime().value(); + ftrigger_time = detTimings.TriggerTime().value(); // this module should run on beam-only events // check the current beam gate @@ -238,95 +283,90 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) break; default: mf::LogTrace("PMTBeamSignalsExtractor") << "Skipping offbeam gate '" << name(gateType) << "'"; - e.put(std::move(fRWMcollection),"RWM"); - e.put(std::move(fEWcollection),"EW"); + e.put(std::move(fSignalCollection[fRWMlabel.instance()]),"RWM"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]),"EW"); return; } // get the trigger-hardware corrections that are applied on all signal waveforms // if EW or RWM is to be compared to the PMT signals, it must be applied on them as well // it also takes care of board-to-board offsets (see SBN-doc-34631, slide 5) - // Note: this a vector of 360 elements, one correction for each signal channel - // however, corrections are the same for all channels on the same board - // for EW/RWM, we pick the correction from any of the other channels on the same board - auto const& wfCorrections = e.getProduct>(fTriggerCorrectionLabel); - int ntrig = wfCorrections.size(); + // Note: this is a vector of 360 elements, one correction for each signal channel + fCorrections = e.getProduct>(fTriggerCorrectionLabel); + int ntrig = fCorrections.size(); if( ntrig < 1 ) mf::LogError("PMTBeamSignalsExtractor") << "Not found PMTWaveformTimeCorrections with label '" - << fTriggerCorrectionLabel.label() << "'"; + << fTriggerCorrectionLabel.instance() << "'"; else if ( ntrig < 360 ) - mf::LogError("PMTBeamSignalsExtractor") << "Missing some PMTWaveformTimeCorrections with label '" - << fTriggerCorrectionLabel.label() << "'"; + mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 360-ntrig << " PMTWaveformTimeCorrections with label '" + << fTriggerCorrectionLabel.instance() << "'"; - // now the main course: EW and RWM waveforms - auto const& ewWaveforms = e.getProduct>(fEWlabel); - auto const& rwmWaveforms = e.getProduct>(fRWMlabel); - m_n_ew = ewWaveforms.size(); - m_n_rwm = rwmWaveforms.size(); - if( m_n_ew< 1 ) - mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << fEWlabel.label() << "'"; - if( m_n_rwm< 1 ) - mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << fRWMlabel.label() << "'"; + // now the main course: getting EW and RWM waveforms + // information is stored by PMT crate name + extractBeamSignalTime(e, fRWMlabel); + extractBeamSignalTime(e, fEWlabel); + + // associating the proper RWM and EW time to each PMT channel + associateBeamSignalsToChannels( fRWMlabel ); + associateBeamSignalsToChannels( fEWlabel ); - m_rwm_wf.clear(); - m_ew_wf.clear(); + // place data products in the stream + // fix the cable swap for part of Run 2 right here!! + // see SBN-doc-34631 for details + if( beamType=="BNB" && m_run > 9704 && m_run < 11443 ){ + + e.put(std::move(fSignalCollection[fRWMlabel.instance()]),"EW"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]),"RWM"); + + } else { // STANDARD BEHAVIOR + + e.put(std::move(fSignalCollection[fRWMlabel.instance()]),"RWM"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]),"EW"); + } +} + +// ----------------------------------------------------------------------------- + +void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event& e, art::InputTag label) { + + std::string l = label.instance(); + auto const& waveforms = e.getProduct>(label); + m_n_channels = waveforms.size(); - // get the start sample of both signals, using threshold to skip spikes from electronical-crosstalk - // see SBN-doc-34928, slides 4-5 + if( m_n_channels < 1 ) + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << l << "'"; + else if( m_n_channels < 8 ) + mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 8-m_n_channels << " raw::OpDetWaveform with label '" << l << "'"; + + m_wf.clear(); + + // 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 time to "NoTime" so that it triggers the isValid() call of PMTBeamSignal - // save the digitizer_label as well as the crate for future use - // (namenly, each ophit will be corrected with the RWM/EW coming digitized in the same crate) - for( auto const & wave : ewWaveforms ){ + for( auto const & wave : waveforms ){ detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; // if nothing is found, first sample is returned (0) - m_ew_sample = getStartSample( wave.Waveform(), fADCThreshold ); - - m_ew_channel = wave.ChannelNumber(); - m_ew_wfstart = tstart.value() ; - m_ew_utime = (m_ew_sample > 0) ? tstart.value() + 0.002*m_ew_sample : icarus::timing::NoTime; - m_ew_time_abs = (m_ew_sample > 0) ? m_ew_utime + getTriggerCorrection(m_ew_channel, wfCorrections) : icarus::timing::NoTime; - m_ew_time = (m_ew_sample > 0) ? m_ew_time_abs-trigger_time : icarus::timing::NoTime; - - fEWcollection->emplace_back( m_ew_channel, getDigitizerLabel(m_ew_channel), getCrate(m_ew_channel), - m_ew_sample, m_ew_time_abs, m_ew_time ); + m_sample = getStartSample(wave.Waveform(), fADCThreshold); - if(fSaveWaveforms) m_ew_wf = wave.Waveform(); - if(fDebugTrees) fEWTree->Fill(); - } + m_channel = wave.ChannelNumber(); + m_wfstart = tstart.value() ; + m_utime_abs = (m_sample != icarus::timing::NoSample) ? + tstart.value() + 0.002*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-ftrigger_time : icarus::timing::NoTime; + + std::string crate = getCrate(m_channel); + fBeamSignals[l].insert(std::make_pair( crate, PMTBeamSignal(m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time) )); + + if(fSaveWaveforms) m_wf = wave.Waveform(); + if(fDebugTrees) fOutTree[l]->Fill(); - for( auto const & wave : rwmWaveforms ){ - - detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; - - // if nothing is found, first sample is returned (0) - m_rwm_sample = getStartSample( wave.Waveform(), fADCThreshold ); - - m_rwm_channel = wave.ChannelNumber(); - m_rwm_wfstart = tstart.value() ; - m_rwm_utime = (m_rwm_sample > 0) ? tstart.value() + 0.002*m_rwm_sample : icarus::timing::NoTime; - m_rwm_time_abs = (m_rwm_sample > 0) ? m_rwm_utime + getTriggerCorrection(m_rwm_channel, wfCorrections) : icarus::timing::NoTime; - m_rwm_time = (m_rwm_sample > 0) ? m_rwm_time_abs-trigger_time : icarus::timing::NoTime; - - fRWMcollection->emplace_back( m_rwm_channel, getDigitizerLabel(m_rwm_channel), getCrate(m_rwm_channel), - m_rwm_sample, m_rwm_time_abs, m_rwm_time ); - - if(fSaveWaveforms) m_rwm_wf = wave.Waveform(); - if(fDebugTrees) fRWMTree->Fill(); - } - - // place the data products in the stream - // fix the cable swap for part of Run 2 right here - // see SBN-doc-34631 for details - if( beamType=="BNB" && m_run > 9704 && m_run < 11443 ){ - e.put(std::move(fRWMcollection),"EW"); - e.put(std::move(fEWcollection),"RWM"); - } else { - e.put(std::move(fRWMcollection),"RWM"); - e.put(std::move(fEWcollection),"EW"); } } @@ -383,7 +423,7 @@ template auto delta = vv[maxbin]-vv[minbin]; if( delta < thres ) //just noise - return 0; //return first bin + return icarus::timing::NoSample; //return no sample for( size_t bin=maxbin; bin const& corrections){ +double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel){ std::string digitizer_label = getDigitizerLabel(channel); @@ -444,8 +483,45 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel // trigger-hardware correction are in order // index of vector is pmtch - return corrections.at(pmtch).startTime; + return fCorrections.at(pmtch).startTime; + +} + + +// ----------------------------------------------------------------------------- + +void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art::InputTag label){ + + std::string l = label.instance(); + + // loop through the signals which are one per PMT crate + // for each crate, find the corresponding digitizers + for( auto signal : fBeamSignals[l] ){ + + // build the PMT digitizer labels that live in this crate + // then convert it into fragment id + std::vector letters = { "-A", "-B", "-C" }; + for( auto letter : letters ){ + + std::string digitizer_label = signal.first + letter; + int fragID = fBoardEffFragmentID[digitizer_label]; + + // use the fragment id to access the PMT channels + // mapping works via fragment id (it's very annoying..) + // loop through the PMT channels and set their RWM/EW time + for( auto pmtinfo : fChannelMap.getPMTchannelInfo(fragID) ) { + + size_t channel = pmtinfo.channelID; + // make sure there is enough room in the collection (channel -> vector index) + if (channel >= fSignalCollection[l]->size()) fSignalCollection[l]->resize(channel + 1); + + fSignalCollection[l]->at(channel) = signal.second; + + } //for each channel + } //for each board + } //for each crate } + DEFINE_ART_MODULE(icarus::timing::PMTBeamSignalsExtractor) From e4f874e042d4937fb17b8d9aaf79c18e717b197e Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 2 May 2024 17:34:55 -0500 Subject: [PATCH 11/52] force different trees for different wfs instances --- icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index b47efb8f7..874c8941c 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -144,7 +144,6 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { float fPEOpHitThreshold; bool fDebug; - TTree *fEventTree; std::vector fOpDetWaveformTrees; std::vector fOpFlashTrees; @@ -236,7 +235,6 @@ void opana::ICARUSFlashAssAna::beginJob() { auto const PMTxyz = fGeom->OpDetGeoFromOpChannel(opch).GetCenter(); //std::cout << PMTxyz[0] << " " << PMTxyz[1] << " " << PMTxyz[2] << std::endl; - m_pmt_x.push_back(PMTxyz.X()); m_pmt_y.push_back(PMTxyz.Y()); m_pmt_z.push_back(PMTxyz.Z()); @@ -269,7 +267,7 @@ void opana::ICARUSFlashAssAna::beginJob() { for( auto const & label : fOpDetWaveformLabels ) { - std::string name = label.label()+"wfttree"; + std::string name = label.label()+label.instance()+"wfttree"; std::string info = "TTree with aggregated optical waveform information with label: " + label.label(); TTree* ttree = tfs->make(name.c_str(), info.c_str()); From bf36de66146ccc95f1d8ed16a7ba5ee7258f0afc Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 6 May 2024 12:48:35 -0500 Subject: [PATCH 12/52] preliminary rwm info for calib ntuples --- .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index 874c8941c..afb577cf0 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -40,6 +40,7 @@ #include "lardataobj/Simulation/BeamGateInfo.h" #include "lardataobj/RawData/TriggerData.h" #include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" +#include "icaruscode/IcarusObj/PMTBeamSignal.h" #include "TTree.h" @@ -72,7 +73,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { Name("DumpWaveformsInfo"), Comment("Set the option to save some aggregated waveform information") }; - + fhicl::Sequence OpDetWaveformLabels { Name("OpDetWaveformLabels"), Comment("Tags for the raw::OpDetWaveform data products") @@ -87,6 +88,11 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { Name("FlashLabels"), Comment("Tags for the recob::Flashe data products") }; + + fhicl::Atom RWMLabel { + Name("RWMLabel"), + Comment("Tag for the RWM std::vector data product") + }; fhicl::Atom PEOpHitThreshold { Name("PEOpHitThreshold"), @@ -128,12 +134,15 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { float &sum_pe_left, float &sum_pe_right, float *xyz, std::vector &pmt_start_time, + std::vector &pmt_start_rwm_time, std::vector &pmt_pe, std::vector &pmt_max_amplitude, TTree *ophittree ); static std::string_view firstLine(std::string const& s, const char* endl = "\r"); + float getRWMRelativeTime(int channel, float t); + private: art::InputTag fTriggerLabel; @@ -141,6 +150,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { std::vector fOpDetWaveformLabels; std::vector fOpHitLabels; std::vector fFlashLabels; + art::InputTag fRWMLabel; float fPEOpHitThreshold; bool fDebug; @@ -185,6 +195,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { float m_flash_z; float m_flash_width_z; std::vector m_pmt_time; + std::vector m_pmt_rwm_time; std::vector m_pmt_pe; std::vector m_pmt_max_amplitude; @@ -194,6 +205,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { float m_start_time; float m_peak_time; float m_rise_time; + float m_rwm_time; float m_width; float m_abs_start_time; float m_pe; @@ -204,6 +216,7 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { std::vector m_pmt_z; geo::GeometryCore const* fGeom; + std::vector fRWMTimes; }; @@ -215,6 +228,7 @@ opana::ICARUSFlashAssAna::ICARUSFlashAssAna(Parameters const& config) , fOpDetWaveformLabels( config().OpDetWaveformLabels() ) , fOpHitLabels( config().OpHitLabels() ) , fFlashLabels( config().FlashLabels() ) + , fRWMLabel( config().RWMLabel() ) , fPEOpHitThreshold( config().PEOpHitThreshold() ) , fDebug( config().Debug() ) , fGeom( lar::providerFrom() ) @@ -285,7 +299,6 @@ void opana::ICARUSFlashAssAna::beginJob() { } - // This ttree will hold the ophit information when a flash is not found in the event // NB: information of the optical hits in events where flashes are present are lost @@ -304,6 +317,7 @@ void opana::ICARUSFlashAssAna::beginJob() { ttree->Branch("start_time", &m_start_time, "start_time/F"); ttree->Branch("peak_time", &m_peak_time, "peak_time/F"); ttree->Branch("rise_time", &m_rise_time, "rise_time/F"); + ttree->Branch("rwm_time", &m_rwm_time, "rwm_time/F"); ttree->Branch("abs_start_time", &m_abs_start_time, "abs_start_time/F"); ttree->Branch("pe", &m_pe, "pe/F"); ttree->Branch("width", &m_width, "width/F"); @@ -344,6 +358,7 @@ void opana::ICARUSFlashAssAna::beginJob() { ttree->Branch("pmt_y",&m_pmt_y); ttree->Branch("pmt_z",&m_pmt_z); ttree->Branch("time_pmt", & m_pmt_time); + ttree->Branch("time_pmt_rwm", & m_pmt_rwm_time); ttree->Branch("pe_pmt", & m_pmt_pe ); ttree->Branch("amplitude_pmt", &m_pmt_max_amplitude); @@ -364,6 +379,7 @@ void opana::ICARUSFlashAssAna::beginJob() { ophittree->Branch("start_time", &m_start_time, "start_time/F"); ophittree->Branch("peak_time", &m_peak_time, "peak_time/F"); ophittree->Branch("rise_time", &m_rise_time, "rise_time/F"); + ophittree->Branch("rwm_time", &m_rwm_time, "rwm_time/F"); ophittree->Branch("abs_start_time", &m_abs_start_time, "abs_start_time/F"); ophittree->Branch("pe", &m_pe, "pe/F"); ophittree->Branch("width", &m_width, "width/F"); @@ -423,6 +439,19 @@ int opana::ICARUSFlashAssAna::getSideByChannel( const int channel ) { } +float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { + + if( fRWMTimes.empty() ) return 0; + + auto rwm = fRWMTimes.at(channel); + if ( !rwm.isValid() ) return 0; + + float rwm_trigger = rwm.startTime; //rwm time w.r.t. trigger time [us] + return (t - rwm_trigger); + +} + + void opana::ICARUSFlashAssAna::processOpHits( art::Event const& e, unsigned int cryo ) { @@ -463,6 +492,7 @@ void opana::ICARUSFlashAssAna::processOpHits( art::Event const& e, unsigned int m_start_time = ophit.StartTime(); m_peak_time = ophit.PeakTime(); m_rise_time = ophit.RiseTime(); + m_rwm_time = getRWMRelativeTime(channel_id,m_start_time); m_width = ophit.Width(); m_abs_start_time = ophit.PeakTimeAbs() + (m_start_time - m_peak_time); m_pe = ophit.PE(); @@ -483,6 +513,7 @@ void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vector &pmt_start_time, + std::vector &pmt_start_rwm_time, std::vector &pmt_pe, std::vector &pmt_max_amplitude, TTree *ophittree ) { @@ -505,6 +536,7 @@ void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vectorStartTime(); m_peak_time = ophit->PeakTime(); m_rise_time = ophit->RiseTime(); + m_rwm_time = getRWMRelativeTime(channel_id,m_start_time); m_width = ophit->Width(); m_abs_start_time = ophit->PeakTimeAbs() + (m_start_time - m_peak_time); m_pe = ophit->PE(); @@ -514,6 +546,7 @@ void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vector m_start_time )) { pmt_start_time[channel_id] = m_start_time; + pmt_start_rwm_time[channel_id] = m_rwm_time; pmt_max_amplitude[channel_id] = m_amplitude; } @@ -559,12 +592,10 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { m_event = e.id().event(); m_timestamp = e.time().timeHigh(); // precision to the second - /* This part is for the trigger information */ - // We work out the trigger information here if( !fTriggerLabel.empty() ) { @@ -581,7 +612,6 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { m_beam_type = beamgate.BeamType() ; } - } else { @@ -611,13 +641,21 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { else{ mf::LogError("ICARUSFlashAssAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "\n" ; } - } else { mf::LogError("ICARUSFlashAssAna") << "Trigger Data product " << fTriggerLabel.label() << " not found!\n" ; } + /* + Now fetch RWM times + */ + + fRWMTimes = e.getProduct>(fRWMLabel); + + if ( fRWMTimes.empty() ) + mf::LogWarning("ICARUSFlashAssAna") << "Data product std::vector Date: Sun, 21 Jul 2024 17:18:52 -0500 Subject: [PATCH 13/52] vast update of ICARUSFlassAssAna: new RWM variables, optional waveform dumping, use of shared baselines, general code cleanup --- .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 683 ++++++++++-------- .../Timing/PMTBeamSignalsExtractor_module.cc | 1 + 2 files changed, 387 insertions(+), 297 deletions(-) diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index afb577cf0..89c8847d4 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -6,9 +6,10 @@ // Generated at Tue Jun 29 13:43:54 2021 by Andrea Scarpelli using cetskelgen // from cetlib version v3_11_01. // -// Module that dumps the association between Flashes and OpHit +// Module that dumps the association between Flashes and OpHit. +// These trees make up the optical information in the calibration ntuples. // -// mailto:ascarpel@bnl.gov +// mailto:ascarpel@bnl.gov, mvicenzi@bnl.gov //////////////////////////////////////////////////////////////////////// #include "art/Framework/Core/EDAnalyzer.h" @@ -41,13 +42,14 @@ #include "lardataobj/RawData/TriggerData.h" #include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" #include "icaruscode/IcarusObj/PMTBeamSignal.h" +#include "sbnobj/ICARUS/PMT/Data/WaveformBaseline.h" #include "TTree.h" #include #include #include // std::accumulate - +#include namespace opana { @@ -74,10 +76,25 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { Comment("Set the option to save some aggregated waveform information") }; + fhicl::Atom SaveRawWaveforms { + Name("SaveRawWaveforms"), + Comment("Set to save the full raw::OpDetWaveforms") + }; + + fhicl::Atom UseSharedBaseline { + Name("UseSharedBaseline"), + Comment("Set the option to use icarus::WaveformBaseline") + }; + fhicl::Sequence OpDetWaveformLabels { Name("OpDetWaveformLabels"), Comment("Tags for the raw::OpDetWaveform data products") }; + + fhicl::Sequence BaselineLabels { + Name("BaselineLabels"), + Comment("Tags for the icarus::WaveformBaseline data products") + }; fhicl::Sequence OpHitLabels { Name("OpHitLabels"), @@ -117,42 +134,60 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { ICARUSFlashAssAna& operator=(ICARUSFlashAssAna&&) = delete; void analyze(art::Event const& e) override; - void beginJob() override; - void endJob() override; + /// Compute median of waveform for baseline (fallback option) template T Median( std::vector data ) const; + /// Return cryostat from PMT channel_id geo::CryostatID::CryostatID_t getCryostatByChannel( int channel ); + /// Return wall from PMT channel_id int getSideByChannel( const int channel ); + /// Process OpHits in the absence of flashes void processOpHits( art::Event const& e, unsigned int cryo ); + /// Process Ophits in the presence of flashes void processOpHitsFlash( std::vector> const &ophits, int &multiplicity_left, int &multiplicity_right, float &sum_pe_left, float &sum_pe_right, - float *xyz, std::vector &pmt_start_time, + std::vector &pmt_rise_time, std::vector &pmt_start_rwm_time, std::vector &pmt_pe, - std::vector &pmt_max_amplitude, + std::vector &pmt_amplitude, TTree *ophittree ); + /// ???? static std::string_view firstLine(std::string const& s, const char* endl = "\r"); + /// Return RWM-relative time from a trigger-relative time float getRWMRelativeTime(int channel, float t); + + /// Return the RWM-relative flash interaction time + float getFlashBunchTime(std::vector pmt_start_time_rwm, + std::vector pmt_rise_time); private: + + //---------- + // Input parameters art::InputTag fTriggerLabel; - bool fSaveWaveformInfo; + bool fSaveWaveformInfo; + bool fSaveRawWaveforms; + bool fUseSharedBaseline; std::vector fOpDetWaveformLabels; + std::vector fBaselineLabels; std::vector fOpHitLabels; std::vector fFlashLabels; art::InputTag fRWMLabel; float fPEOpHitThreshold; bool fDebug; + + //---------- + // Output trees TTree *fEventTree; std::vector fOpDetWaveformTrees; @@ -160,14 +195,15 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { std::vector fOpHitTrees; std::vector fOpHitFlashTrees; + //---------------- + // Output variables + + // Common int m_run; int m_event; int m_timestamp; - //int m_nflashes; - //int m_nophit; - short m_baseline; - short m_chargesum; - int m_nticks; + + // Event/trigger tree float m_beam_gate_start=-99999; float m_beam_gate_width=-99999; int m_beam_type=-1; @@ -179,7 +215,10 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { uint64_t m_trigger_gate_diff; uint64_t lvdsCryoE[2]; uint64_t lvdsCryoW[2]; + uint16_t addersCryoE[2]; + uint16_t addersCryoW[2]; + // Flash trees int m_flash_id; int m_multiplicity; int m_multiplicity_left; @@ -188,44 +227,61 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer { float m_sum_pe_left; float m_sum_pe_right; float m_flash_time; - //float m_flash_x; - //float m_flash_width_x; + float m_flash_time_rwm; float m_flash_y; float m_flash_width_y; float m_flash_z; float m_flash_width_z; - std::vector m_pmt_time; - std::vector m_pmt_rwm_time; + std::vector m_pmt_start_time; + std::vector m_pmt_rise_time; + std::vector m_pmt_start_time_rwm; std::vector m_pmt_pe; - std::vector m_pmt_max_amplitude; + std::vector m_pmt_amplitude; + // Ophit trees int m_channel_id; float m_integral; // in ADC x tick float m_amplitude; // in ADC float m_start_time; float m_peak_time; float m_rise_time; - float m_rwm_time; float m_width; float m_abs_start_time; + float m_start_time_rwm; + float m_peak_time_rwm; float m_pe; float m_fast_to_total; + + // Waveform trees + float m_wf_start; + short m_baseline; + short m_chargesum; + int m_nticks; + std::vector m_wf; + // Geometry tree std::vector m_pmt_x; std::vector m_pmt_y; std::vector m_pmt_z; + + //---------- + // Support variables/products geo::GeometryCore const* fGeom; std::vector fRWMTimes; }; +// ---------------------------------------------------------------------------- opana::ICARUSFlashAssAna::ICARUSFlashAssAna(Parameters const& config) : EDAnalyzer(config) , fTriggerLabel( config().TriggerLabel() ) , fSaveWaveformInfo( config().DumpWaveformsInfo() ) + , fSaveRawWaveforms( config().SaveRawWaveforms() ) + , fUseSharedBaseline( config().UseSharedBaseline() ) , fOpDetWaveformLabels( config().OpDetWaveformLabels() ) + , fBaselineLabels( config().BaselineLabels() ) , fOpHitLabels( config().OpHitLabels() ) , fFlashLabels( config().FlashLabels() ) , fRWMLabel( config().RWMLabel() ) @@ -234,11 +290,14 @@ opana::ICARUSFlashAssAna::ICARUSFlashAssAna(Parameters const& config) , fGeom( lar::providerFrom() ) { } +// ---------------------------------------------------------------------------- void opana::ICARUSFlashAssAna::beginJob() { art::ServiceHandle tfs; + // Setting up the GEOMETRY tree + // Channel id corresponds to vector index TTree* fGeoTree = tfs->make("geotree", "geometry information" ); fGeoTree->Branch("pmt_x",&m_pmt_x); fGeoTree->Branch("pmt_y",&m_pmt_y); @@ -247,8 +306,6 @@ void opana::ICARUSFlashAssAna::beginJob() { for(size_t opch=0; opchNOpChannels(); ++opch) { auto const PMTxyz = fGeom->OpDetGeoFromOpChannel(opch).GetCenter(); - - //std::cout << PMTxyz[0] << " " << PMTxyz[1] << " " << PMTxyz[2] << std::endl; m_pmt_x.push_back(PMTxyz.X()); m_pmt_y.push_back(PMTxyz.Y()); m_pmt_z.push_back(PMTxyz.Z()); @@ -257,12 +314,12 @@ void opana::ICARUSFlashAssAna::beginJob() { fGeoTree->Fill(); + // Settinp up the EVENT tree + // Trigger information and LVDS status fEventTree = tfs->make("eventstree", "higher level information on the event" ); fEventTree->Branch("run", &m_run, "run/I"); fEventTree->Branch("event", &m_event, "event/I"); fEventTree->Branch("timestamp", &m_timestamp, "timestamp/I"); - //fEventTree->Branch("nflashes", &m_nflashes, "nflashes/I"); - //fEventTree->Branch("nophits", &m_nophit, "nophits/I"); fEventTree->Branch("beam_gate_start", &m_beam_gate_start, "beam_gate_start/F"); fEventTree->Branch("beam_gate_width", &m_beam_gate_width, "beam_gate_width/F"); fEventTree->Branch("beam_type", &m_beam_type, "beam_type/I"); @@ -274,7 +331,10 @@ void opana::ICARUSFlashAssAna::beginJob() { fEventTree->Branch("trigger_gate_diff", &m_trigger_gate_diff, "trigger_gate_diff/l"); fEventTree->Branch("lvdsCryoE", &lvdsCryoE, "lvdsCryoE[2]/l"); fEventTree->Branch("lvdsCryoW", &lvdsCryoW, "lvdsCryoW[2]/l"); + fEventTree->Branch("addersCryoE", &addersCryoE, "addersCryoE[2]/l"); + fEventTree->Branch("addersCryoW", &addersCryoW, "addersCryoW[2]/l"); + // Setting up the WAVEFORM trees (one per product label) // This tree will hold some aggregated optical waveform information // The flag must be enabled to have the information saved if( !fOpDetWaveformLabels.empty() && fSaveWaveformInfo ) { @@ -289,131 +349,134 @@ void opana::ICARUSFlashAssAna::beginJob() { ttree->Branch("event", &m_event, "event/I"); ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); ttree->Branch("channel_id", &m_channel_id, "channel_id/I"); + ttree->Branch("wf_start",&m_wf_start,"wf_start/F"); ttree->Branch("baseline", &m_baseline, "baseline/s"); ttree->Branch("chargesum", &m_chargesum, "chargesum/s"); ttree->Branch("nticks", &m_nticks, "nticks/I"); - + if ( fSaveRawWaveforms ) ttree->Branch("wf",&m_wf); + fOpDetWaveformTrees.push_back(ttree); } - } + // Setting up the OPHIT trees (one per cryostat) // This ttree will hold the ophit information when a flash is not found in the event // NB: information of the optical hits in events where flashes are present are lost - for( auto const & label : fOpHitLabels ) { - std::string name = label.label()+"_ttree"; - std::string info = "TTree for the recob::OpHit objects with label " + label.label() + " in events without flashes."; - - TTree* ttree = tfs->make(name.c_str(), info.c_str()); - ttree->Branch("run", &m_run, "run/I"); - ttree->Branch("event", &m_event, "event/I"); - ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); - ttree->Branch("channel_id", &m_channel_id, "channel_id/I"); - ttree->Branch("integral", &m_integral, "integral/F"); - ttree->Branch("amplitude", &m_amplitude, "amplitude/F"); - ttree->Branch("start_time", &m_start_time, "start_time/F"); - ttree->Branch("peak_time", &m_peak_time, "peak_time/F"); - ttree->Branch("rise_time", &m_rise_time, "rise_time/F"); - ttree->Branch("rwm_time", &m_rwm_time, "rwm_time/F"); - ttree->Branch("abs_start_time", &m_abs_start_time, "abs_start_time/F"); - ttree->Branch("pe", &m_pe, "pe/F"); - ttree->Branch("width", &m_width, "width/F"); - ttree->Branch("fast_to_total", &m_fast_to_total, "fast_to_total/F"); + std::string name = label.label()+"_ttree"; + std::string info = "TTree for the recob::OpHit objects with label " + label.label() + " in events without flashes."; + + TTree* ttree = tfs->make(name.c_str(), info.c_str()); + ttree->Branch("run", &m_run, "run/I"); + ttree->Branch("event", &m_event, "event/I"); + ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); + ttree->Branch("channel_id", &m_channel_id, "channel_id/I"); + ttree->Branch("integral", &m_integral, "integral/F"); + ttree->Branch("amplitude", &m_amplitude, "amplitude/F"); + ttree->Branch("start_time", &m_start_time, "start_time/F"); + ttree->Branch("peak_time", &m_peak_time, "peak_time/F"); + ttree->Branch("rise_time", &m_rise_time, "rise_time/F"); + ttree->Branch("abs_start_time", &m_abs_start_time, "abs_start_time/F"); + ttree->Branch("start_time_rwm", &m_start_time_rwm, "start_time_rwm/F"); + ttree->Branch("peak_time_rwm", &m_peak_time_rwm, "peak_time_rwm/F"); + ttree->Branch("pe", &m_pe, "pe/F"); + ttree->Branch("width", &m_width, "width/F"); + ttree->Branch("fast_to_total", &m_fast_to_total, "fast_to_total/F"); - fOpHitTrees.push_back(ttree); + fOpHitTrees.push_back(ttree); } - + // Setting up the OPFLASH/OPHITS trees (one per cryostat) + // These ttrees hold the information for the ophits and the flashes + // NB: information of the optical hits is stored differently when flashes are found if ( !fFlashLabels.empty() ) { for( auto const & label : fFlashLabels ) { - // TTree for the flash in a given cryostat - std::string name = label.label()+"_flashtree"; - std::string info = "TTree for the recob::Flashes with label "+label.label(); - - TTree* ttree = tfs->make(name.c_str(), info.c_str() ); - ttree->Branch("run", &m_run, "run/I"); - ttree->Branch("event", &m_event, "event/I"); - ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); - ttree->Branch("flash_id", &m_flash_id, "flash_id/I"); - ttree->Branch("multiplicity", &m_multiplicity, "multiplicity/I"); - ttree->Branch("multiplicity_right", &m_multiplicity_right, "multiplicity_right/I" ); - ttree->Branch("multiplicity_left", &m_multiplicity_left, "multiplicity_left/I" ); - ttree->Branch("sum_pe", &m_sum_pe, "sum_pe/F"); - ttree->Branch("sum_pe_right", &m_sum_pe_right, "sum_pe_right/F"); - ttree->Branch("sum_pe_left", &m_sum_pe_left, "sum_pe_left/F"); - ttree->Branch("flash_time", &m_flash_time, "flash_time/F"); - //ttree->Branch("flash_x", &m_flash_x, "flash_x/F"); - //ttree->Branch("flash_width_x", &m_flash_width_x, "flash_width_x/F"); - ttree->Branch("flash_y", &m_flash_y, "flash_y/F"); - ttree->Branch("flash_width_y", &m_flash_width_y, "flash_width_y/F"); - ttree->Branch("flash_z", &m_flash_z, "flash_z/F"); - ttree->Branch("flash_width_z", &m_flash_width_z, "flash_width_z/F"); - ttree->Branch("pmt_x",&m_pmt_x); - ttree->Branch("pmt_y",&m_pmt_y); - ttree->Branch("pmt_z",&m_pmt_z); - ttree->Branch("time_pmt", & m_pmt_time); - ttree->Branch("time_pmt_rwm", & m_pmt_rwm_time); - ttree->Branch("pe_pmt", & m_pmt_pe ); - ttree->Branch("amplitude_pmt", &m_pmt_max_amplitude); - - fOpFlashTrees.push_back( ttree ); - - // Now the ttree for the OpHit associated in the flash - name = label.label()+"_ophittree"; - info = "Three for the recob::OpHit associated with an OpHitFlash"+label.label(); - - TTree* ophittree = tfs->make(name.c_str(), info.c_str() ); - ophittree->Branch("run", &m_run, "run/I"); - ophittree->Branch("event", &m_event, "event/I"); - ophittree->Branch("timestamp", &m_timestamp, "timestamp/I"); - ophittree->Branch("flash_id", &m_flash_id, "flash_id/I"); - ophittree->Branch("channel_id", &m_channel_id, "channel_id/I"); - ophittree->Branch("integral", &m_integral, "integral/F"); - ophittree->Branch("amplitude", &m_amplitude, "amplitude/F"); - ophittree->Branch("start_time", &m_start_time, "start_time/F"); - ophittree->Branch("peak_time", &m_peak_time, "peak_time/F"); - ophittree->Branch("rise_time", &m_rise_time, "rise_time/F"); - ophittree->Branch("rwm_time", &m_rwm_time, "rwm_time/F"); - ophittree->Branch("abs_start_time", &m_abs_start_time, "abs_start_time/F"); - ophittree->Branch("pe", &m_pe, "pe/F"); - ophittree->Branch("width", &m_width, "width/F"); - ophittree->Branch("fast_to_total", &m_fast_to_total, "fast_to_total/F"); - - fOpHitFlashTrees.push_back( ophittree ); + // TTree for the flash in a given cryostat + std::string name = label.label()+"_flashtree"; + std::string info = "TTree for the recob::Flashes with label "+label.label(); + + TTree* ttree = tfs->make(name.c_str(), info.c_str() ); + ttree->Branch("run", &m_run, "run/I"); + ttree->Branch("event", &m_event, "event/I"); + ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); + ttree->Branch("flash_id", &m_flash_id, "flash_id/I"); + ttree->Branch("multiplicity", &m_multiplicity, "multiplicity/I"); + ttree->Branch("multiplicity_right", &m_multiplicity_right, "multiplicity_right/I" ); + ttree->Branch("multiplicity_left", &m_multiplicity_left, "multiplicity_left/I" ); + ttree->Branch("sum_pe", &m_sum_pe, "sum_pe/F"); + ttree->Branch("sum_pe_right", &m_sum_pe_right, "sum_pe_right/F"); + ttree->Branch("sum_pe_left", &m_sum_pe_left, "sum_pe_left/F"); + ttree->Branch("flash_time", &m_flash_time, "flash_time/F"); + ttree->Branch("flash_time_rwm", &m_flash_time_rwm, "flash_time_rwm/F"); + ttree->Branch("flash_y", &m_flash_y, "flash_y/F"); + ttree->Branch("flash_width_y", &m_flash_width_y, "flash_width_y/F"); + ttree->Branch("flash_z", &m_flash_z, "flash_z/F"); + ttree->Branch("flash_width_z", &m_flash_width_z, "flash_width_z/F"); + ttree->Branch("pmt_x",&m_pmt_x); + ttree->Branch("pmt_y",&m_pmt_y); + ttree->Branch("pmt_z",&m_pmt_z); + ttree->Branch("time_pmt", & m_pmt_start_time); + ttree->Branch("time_pmt_rwm", & m_pmt_start_time_rwm); + ttree->Branch("pe_pmt", & m_pmt_pe ); + ttree->Branch("amplitude_pmt", &m_pmt_amplitude); + + fOpFlashTrees.push_back( ttree ); + + // Now the ttree for the OpHit associated in the flash + name = label.label()+"_ophittree"; + info = "Three for the recob::OpHit associated with an OpHitFlash"+label.label(); + + TTree* ophittree = tfs->make(name.c_str(), info.c_str() ); + ophittree->Branch("run", &m_run, "run/I"); + ophittree->Branch("event", &m_event, "event/I"); + ophittree->Branch("timestamp", &m_timestamp, "timestamp/I"); + ophittree->Branch("flash_id", &m_flash_id, "flash_id/I"); + ophittree->Branch("channel_id", &m_channel_id, "channel_id/I"); + ophittree->Branch("integral", &m_integral, "integral/F"); + ophittree->Branch("amplitude", &m_amplitude, "amplitude/F"); + ophittree->Branch("start_time", &m_start_time, "start_time/F"); + ophittree->Branch("peak_time", &m_peak_time, "peak_time/F"); + ophittree->Branch("rise_time", &m_rise_time, "rise_time/F"); + ophittree->Branch("abs_start_time", &m_abs_start_time, "abs_start_time/F"); + ophittree->Branch("start_time_rwm", &m_start_time_rwm, "start_time_rwm/F"); + ophittree->Branch("peak_time_rwm", &m_peak_time_rwm, "peak_time_rwm/F"); + ophittree->Branch("pe", &m_pe, "pe/F"); + ophittree->Branch("width", &m_width, "width/F"); + ophittree->Branch("fast_to_total", &m_fast_to_total, "fast_to_total/F"); + + fOpHitFlashTrees.push_back( ophittree ); } } } +// ---------------------------------------------------------------------------- + +template T opana::ICARUSFlashAssAna::Median( std::vector data ) const { - -template - T opana::ICARUSFlashAssAna::Median( std::vector data ) const { - - std::nth_element( data.begin(), data.begin() + data.size()/2, data.end() ); - - return data[ data.size()/2 ]; + std::nth_element( data.begin(), data.begin() + data.size()/2, data.end() ); + return data[ data.size()/2 ]; } +// ---------------------------------------------------------------------------- -geo::CryostatID::CryostatID_t opana::ICARUSFlashAssAna::getCryostatByChannel( int channel ) { +geo::CryostatID::CryostatID_t opana::ICARUSFlashAssAna::getCryostatByChannel( int channel ) { const geo::OpDetGeo& opdetgeo = fGeom->OpDetGeoFromOpChannel(channel); geo::CryostatID::CryostatID_t cid = opdetgeo.ID().Cryostat ; - return cid; } +// ---------------------------------------------------------------------------- int opana::ICARUSFlashAssAna::getSideByChannel( const int channel ) { @@ -422,22 +485,18 @@ int opana::ICARUSFlashAssAna::getSideByChannel( const int channel ) { We look in the opposide direction wrt to the beam direction South->North: - Left is the east wall of each cryostat; - - Right is the west side of each cryostat; - - [ 0:89 ] and [180:269] are on the left, the return value of the function is 0; - - [ 90-179 ] and [ 270:359 ] are on the right, the return value of the function is 1; */ - int side = channel / 90; // always round down - return side % 2; } +// ---------------------------------------------------------------------------- float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { @@ -450,107 +509,136 @@ float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { return (t - rwm_trigger); } + +// ---------------------------------------------------------------------------- +float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_time_rwm, + std::vector pmt_rise_time) { -void opana::ICARUSFlashAssAna::processOpHits( art::Event const& e, unsigned int cryo ) { - - - if( fOpHitLabels.empty() ){ - - mf::LogError("ICARUSFlashAssAna") << "No recob::OpHit labels selected."; + float tfirst_left = std::numeric_limits::max(); + float tfirst_right = std::numeric_limits::max(); - return; - } - - for( size_t iOpHitLabel=0; iOpHitLabel> ophit_handle; - e.getByLabel( label, ophit_handle ); + return (tfirst_left + tfirst_right)/2.; +} - // We want our flashes to be valid and not empty - if( !ophit_handle.isValid() || ophit_handle->empty() ) { - mf::LogError("ICARUSFlashAssAna") - << "Invalid recob::OpHit with label '" << label.encode() << "'"; - continue; - } +// ---------------------------------------------------------------------------- +void opana::ICARUSFlashAssAna::processOpHits( art::Event const& e, unsigned int cryo ) { - for( auto const & ophit : *ophit_handle ) { + // if no OpHits have been selected at all (and no flashes as well!) + if( fOpHitLabels.empty() ){ + mf::LogError("ICARUSFlashAssAna") << "No recob::OpHit labels selected."; + return; + } - //auto const & ophit = (*ophit_handle)[idx]; + for( size_t iOpHitLabel=0; iOpHitLabel>(label); + + // we want our ophits to be valid and not empty + if( ophits.empty() ) { + mf::LogError("ICARUSFlashAssAna") << "Invalid recob::OpHit with label '" << label.encode() << "'"; + continue; + } - const int channel_id = ophit.OpChannel(); + for( auto const & ophit : ophits ) { - if( getCryostatByChannel(channel_id) != cryo ){ continue; } + const int channel_id = ophit.OpChannel(); + if( getCryostatByChannel(channel_id) != cryo ){ continue; } - m_channel_id = channel_id; - m_integral = ophit.Area(); // in ADC x tick - m_amplitude = ophit.Amplitude(); // in ADC - m_start_time = ophit.StartTime(); - m_peak_time = ophit.PeakTime(); - m_rise_time = ophit.RiseTime(); - m_rwm_time = getRWMRelativeTime(channel_id,m_start_time); - m_width = ophit.Width(); - m_abs_start_time = ophit.PeakTimeAbs() + (m_start_time - m_peak_time); - m_pe = ophit.PE(); - m_fast_to_total = ophit.FastToTotal(); + m_channel_id = channel_id; + m_integral = ophit.Area(); // in ADC x tick + m_amplitude = ophit.Amplitude(); // in ADC + m_width = ophit.Width(); + m_pe = ophit.PE(); + m_fast_to_total = ophit.FastToTotal(); - fOpHitTrees[iOpHitLabel]->Fill(); + // save times: start, peak, rise + // rise is relative to start + m_start_time = ophit.StartTime(); + m_peak_time = ophit.PeakTime(); + m_rise_time = ophit.RiseTime(); + m_start_time_rwm = getRWMRelativeTime(channel_id,m_start_time); + m_peak_time_rwm = getRWMRelativeTime(channel_id,m_peak_time); + m_abs_start_time = ophit.PeakTimeAbs() + (m_start_time - m_peak_time); - } + fOpHitTrees[iOpHitLabel]->Fill(); + } } - - return; - } +// ---------------------------------------------------------------------------- void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vector> const &ophits, int &multiplicity_left, int &multiplicity_right, - float &sum_pe_left, float &sum_pe_right, - float *xyz, + float &sum_pe_left, float &sum_pe_right, std::vector &pmt_start_time, - std::vector &pmt_start_rwm_time, + std::vector &pmt_rise_time, + std::vector &pmt_start_time_rwm, std::vector &pmt_pe, - std::vector &pmt_max_amplitude, + std::vector &pmt_amplitude, TTree *ophittree ) { + // we calculate the total charge clustered in the flash per channel taking part to the flash + // at the same time we store the times of the first ophit in each channel and its amplitude + // same loop is used to saved OPHITS info - std::unordered_map sumpe_map; - - // We caluclate the total charge clustered in the flash per channel taking part to the flash + std::unordered_map sumpe_map; for( auto const ophit : ophits ) { if ( ophit->PE() < fPEOpHitThreshold ) { continue; } const int channel_id = ophit->OpChannel(); - - sumpe_map[ channel_id ]+=ophit->PE() ; + sumpe_map[channel_id] += ophit->PE() ; m_channel_id = channel_id; m_integral = ophit->Area(); // in ADC x tick m_amplitude = ophit->Amplitude(); // in ADC + m_width = ophit->Width(); + m_pe = ophit->PE(); + m_fast_to_total = ophit->FastToTotal(); + + // save times: start, peak, rise + // rise is relative to start m_start_time = ophit->StartTime(); m_peak_time = ophit->PeakTime(); m_rise_time = ophit->RiseTime(); - m_rwm_time = getRWMRelativeTime(channel_id,m_start_time); - m_width = ophit->Width(); + m_start_time_rwm = getRWMRelativeTime(channel_id,m_start_time); + m_peak_time_rwm = getRWMRelativeTime(channel_id,m_peak_time); m_abs_start_time = ophit->PeakTimeAbs() + (m_start_time - m_peak_time); - m_pe = ophit->PE(); - m_fast_to_total = ophit->FastToTotal(); pmt_pe[channel_id] += ophit->PE(); + // select the first ophit (by time) in each channel if( ( pmt_start_time[channel_id] == 0 ) || ( pmt_start_time[channel_id] > m_start_time )) { pmt_start_time[channel_id] = m_start_time; - pmt_start_rwm_time[channel_id] = m_rwm_time; - pmt_max_amplitude[channel_id] = m_amplitude; + pmt_rise_time[channel_id] = m_rise_time; + pmt_start_time_rwm[channel_id] = m_start_time_rwm; + pmt_amplitude[channel_id] = m_amplitude; } - ophittree->Fill(); } @@ -574,194 +662,200 @@ void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vector::value_type& p) { return getSideByChannel(p.first)==1 ? value+p.second : value ; }); - - //for( int i=0; i<3; i++ ){ xyz[i] /= (m_sum_pe_left+ m_sum_pe_right); } - } -void opana::ICARUSFlashAssAna::endJob() { - -} - +// ---------------------------------------------------------------------------- void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { - + // Collect global event metadata m_run = e.id().run(); m_event = e.id().event(); m_timestamp = e.time().timeHigh(); // precision to the second - /* - This part is for the trigger information - */ - + // ----- + // TRIGGER INFO // We work out the trigger information here + if( !fTriggerLabel.empty() ) { - // Beam information - art::Handle> beamgate_handle; - e.getByLabel( fTriggerLabel, beamgate_handle ); + // Beam gate information + auto const& beamgateInfo = e.getProduct>(fTriggerLabel); - if( beamgate_handle.isValid() ) { - - for( auto const & beamgate : *beamgate_handle ) { - - m_beam_gate_start = beamgate.Start(); - m_beam_gate_width = beamgate.Width(); - m_beam_type = beamgate.BeamType() ; - - } - } - - else { - mf::LogError("ICARUSFlashAssAna") << "No sim::BeamGateInfo associated to label: " << fTriggerLabel.label() << "\n" ; + if( !beamgateInfo.empty() ) { + for( auto const & beamgate : beamgateInfo ) { + m_beam_gate_start = beamgate.Start(); + m_beam_gate_width = beamgate.Width(); + m_beam_type = beamgate.BeamType() ; } + } else { + mf::LogError("ICARUSFlashAssAna") << "No sim::BeamGateInfo associated to label: " << fTriggerLabel.label() << "\n" ; + } - // Now trigger information - art::Handle trigger_handle; - e.getByLabel( fTriggerLabel, trigger_handle ); - - if( trigger_handle.isValid() ) { - - sbn::triggerSource bit = trigger_handle->sourceType; - - m_gate_type = (unsigned int)bit; - m_gate_name = bitName(bit); - m_trigger_type = value( trigger_handle->triggerType ); - m_trigger_timestamp = trigger_handle->triggerTimestamp; - m_gate_start_timestamp = trigger_handle->beamGateTimestamp; - m_trigger_gate_diff = trigger_handle->triggerTimestamp - trigger_handle->beamGateTimestamp; - lvdsCryoE[0] = trigger_handle->cryostats[0].LVDSstatus[0]; - lvdsCryoE[1] = trigger_handle->cryostats[0].LVDSstatus[1]; - lvdsCryoW[0] = trigger_handle->cryostats[1].LVDSstatus[0]; - lvdsCryoW[1] = trigger_handle->cryostats[1].LVDSstatus[1]; - - } - else{ - mf::LogError("ICARUSFlashAssAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "\n" ; - } - } + // Now trigger information + auto const& extraInfo = e.getProduct(fTriggerLabel); - else { - mf::LogError("ICARUSFlashAssAna") << "Trigger Data product " << fTriggerLabel.label() << " not found!\n" ; + if( extraInfo.isValid() ) { + + sbn::triggerSource bit = extraInfo.sourceType; + m_gate_type = (unsigned int)bit; + m_gate_name = bitName(bit); + + m_trigger_type = value( extraInfo.triggerType ); + m_trigger_timestamp = extraInfo.triggerTimestamp; + m_gate_start_timestamp = extraInfo.beamGateTimestamp; + m_trigger_gate_diff = m_trigger_timestamp - m_gate_start_timestamp; + + // majority lvds info + lvdsCryoE[0] = extraInfo.cryostats[0].LVDSstatus[0]; + lvdsCryoE[1] = extraInfo.cryostats[0].LVDSstatus[1]; + lvdsCryoW[0] = extraInfo.cryostats[1].LVDSstatus[0]; + lvdsCryoW[1] = extraInfo.cryostats[1].LVDSstatus[1]; + + // adders lvds info + addersCryoE[0] = extraInfo.cryostats[0].sectorStatus[0]; + addersCryoE[1] = extraInfo.cryostats[0].sectorStatus[1]; + addersCryoW[0] = extraInfo.cryostats[1].sectorStatus[0]; + addersCryoW[1] = extraInfo.cryostats[1].sectorStatus[1]; + + } else { + mf::LogError("ICARUSFlashAssAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!" ; + } + + } else { + mf::LogError("ICARUSFlashAssAna") << "Trigger Data product " << fTriggerLabel.label() << " not found!\n" ; } - /* - Now fetch RWM times - */ + // ----- + // RWM INFO + // We work out the RWM information here + // it might be empty if offbeam or missing, bu that's okay! fRWMTimes = e.getProduct>(fRWMLabel); - if ( fRWMTimes.empty() ) mf::LogWarning("ICARUSFlashAssAna") << "Data product std::vector> wfm_handle; - e.getByLabel( label, wfm_handle ); + // ----- + // WAVEFORM INFO + // Now we work on the waveforms if we are allowed to + // Full raw waveforms are dumped only if option is set explicitly! + // Waveforms are a complex business: if running at stage0, they're all available + // if running at stage1, only on-beam waveforms are available but it's a different product! - if( wfm_handle.isValid() && !wfm_handle->empty() ) { - - for( auto const & wave : *wfm_handle ){ - - m_channel_id = wave.ChannelNumber(); - m_nticks = wave.Waveform().size(); - m_baseline = Median( wave.Waveform() ); - m_chargesum = std::accumulate( wave.Waveform().begin(), wave.Waveform().end(), 0, - [ & ](short x, short y){ return ((m_baseline-x) + (m_baseline-y)) ; } ); - - fOpDetWaveformTrees[i]->Fill(); - - } + if( !fOpDetWaveformLabels.empty() && fSaveWaveformInfo ) { + + for( size_t i=0; i>(wflabel); + auto const& baselines = e.getProduct>(bslabel); + + // waveforms data product ("daqPMT") is dropped after stage0, and only "daqPMTonbeam" is kept + // check if collection is present and print warning otherwise (requires change in fhicl config) + if( !waveforms.empty() ) { + + size_t idx = 0; + for( auto const & wave : waveforms ){ + + m_channel_id = wave.ChannelNumber(); + m_nticks = wave.Waveform().size(); + m_wf_start = wave.TimeStamp(); + + // try using icarus::WaveformBaseline, default to median if not + // doesn't work with daqPMTonbeam as order gets messed up, so check size is the same + // FIXME: move to use art:Assn which can work both for daqPMT and daqPMTonbeam? + m_baseline = (fUseSharedBaseline && (baselines.size()==waveforms.size())) ? + baselines.at(idx).baseline() : Median(wave.Waveform()); + + m_chargesum = std::accumulate( wave.Waveform().begin(), wave.Waveform().end(), 0, + [ & ](short x, short y){ return ((m_baseline-x) + (m_baseline-y)) ; } ); + + // if required, save the full waveforms as well + if( fSaveRawWaveforms ) m_wf = wave.Waveform(); + + fOpDetWaveformTrees[i]->Fill(); } + } else { + mf::LogWarning("ICARUSFlashAssAna") << "Data product std::vector for " << wflabel.label() + << " is missing! Was it dropped before this stage?"; } } + } - - /* - Now we take care of the flashes: we separate the case where we have a flash and the case where we have not a flash - */ + // ----- + // FLASHES/OPHITS INFO + // Now we take care of the flashes: + // we separate the case where we have a flash and the case where we don't have a flash + // the difference is in how ophits are stored... if ( !fFlashLabels.empty() ) { - // Hold the cryostat information + // hold the cryostat information std::vector cids; - for ( size_t iFlashLabel=0; iFlashLabel>(label); - art::Handle> flash_handle; - e.getByLabel( label, flash_handle ); - - // We want our flashes to be valid and not empty - if( !flash_handle.isValid() ) { - mf::LogError("ICARUSFlashAssAna") - << "Not found a recob::OpFlash with label '" << label.encode() << "'"; - } else if ( flash_handle->empty() ) { + // want our flashes to be valid and not empty + if( flashes.empty() ) { mf::LogWarning("ICARUSFlashAssAna") << "No recob::OpFlash in collection with label '" << label.encode() << "'"; } else { - art::FindManyP ophitsPtr( flash_handle, e, label ); + art::FindManyP ophitsPtr( e.getHandle>(label), e, label ); - for ( size_t idx=0; idxsize(); idx++ ) { + size_t idx = 0; + for( auto const& flash : flashes ){ m_pmt_pe.resize(360); - m_pmt_time.resize(360); - m_pmt_rwm_time.resize(360); - m_pmt_max_amplitude.resize(360); + m_pmt_start_time.resize(360); + m_pmt_rise_time.resize(360); + m_pmt_start_time_rwm.resize(360); + m_pmt_amplitude.resize(360); m_flash_id = idx; - auto const & flash = (*flash_handle)[idx]; - m_flash_time = flash.Time(); m_sum_pe = flash.TotalPE(); + m_flash_y = flash.YCenter(); + m_flash_width_y = flash.YWidth(); + m_flash_z = flash.ZCenter(); + m_flash_width_z = flash.ZWidth(); auto const & ophits = ophitsPtr.at(idx); - // We keep track of the cryistats where the flashes are found; + // we keep track of the cryistats where the flashes are found; geo::CryostatID::CryostatID_t cid = getCryostatByChannel(ophits.front()->OpChannel()); - auto const found = std::find(cids.begin(), cids.end(), cid); if( found != cids.end() ){ cids.push_back( cid ); } - // Get the multiplicity, the position and the number of PE per Side - float xyz[3] = {0.0, 0.0, 0.0}; + // get the multiplicity, the number of PE per side, and the RWM-relative flash time + // also store the first ophits for every channel in the flash processOpHitsFlash( ophits, m_multiplicity_left, m_multiplicity_right, - m_sum_pe_left, m_sum_pe_right, xyz, - m_pmt_time, m_pmt_rwm_time, m_pmt_pe, m_pmt_max_amplitude, + m_sum_pe_left, m_sum_pe_right, m_pmt_start_time, + m_pmt_rise_time, m_pmt_start_time_rwm, m_pmt_pe, m_pmt_amplitude, fOpHitFlashTrees[iFlashLabel] ); m_multiplicity = m_multiplicity_left+m_multiplicity_right; - //m_flash_x = 0.0; - //m_flash_width_x = 0.0; - m_flash_y = flash.YCenter(); - m_flash_width_y = flash.YWidth(); - m_flash_z = flash.ZCenter(); - m_flash_width_z = flash.ZWidth(); + // 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_pmt_start_time_rwm, m_pmt_rise_time); fOpFlashTrees[iFlashLabel]->Fill(); m_pmt_pe.clear(); - m_pmt_time.clear(); - m_pmt_rwm_time.clear(); + m_pmt_start_time.clear(); + m_pmt_rise_time.clear(); + m_pmt_start_time_rwm.clear(); } } @@ -773,26 +867,21 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { auto const found = std::find( cids.begin(), cids.end(), cid ); if( found == cids.end() ){ - processOpHits(e, cid); - } + processOpHits(e, cid); + } } } else { - - mf::LogError("ICARUSFlashAssAna") - << "No recob::OpFlash labels selected\n"; + mf::LogError("ICARUSFlashAssAna") << "No recob::OpFlash labels selected"; - // We save the ophits anyways even in absence of flashes + // we save the ophits anyways even in absence of flashes for( unsigned int cid=0; cidNcryostats(); cid++ ){ - processOpHits(e, cid); + processOpHits(e, cid); } - } - fEventTree->Fill(); - } diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 5fc7fd81b..6ae0c4dea 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -308,6 +308,7 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) extractBeamSignalTime(e, fEWlabel); // associating the proper RWM and EW time to each PMT channel + // collections are vectors of 360 elements (one value for each channel) associateBeamSignalsToChannels( fRWMlabel ); associateBeamSignalsToChannels( fEWlabel ); From 5d3243089bb6b1813589c87e35fc3214f52260f5 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 23 Jul 2024 12:55:43 -0500 Subject: [PATCH 14/52] add analyzer, default fcl configs, fixes --- icaruscode/PMT/OpReco/CMakeLists.txt | 4 +- .../OpReco/ICARUSBeamStructureAna_module.cc | 487 ++++++++++++++++++ .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 21 +- .../PMT/OpReco/fcl/icarus_opana_modules.fcl | 13 + 4 files changed, 514 insertions(+), 11 deletions(-) create mode 100644 icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc diff --git a/icaruscode/PMT/OpReco/CMakeLists.txt b/icaruscode/PMT/OpReco/CMakeLists.txt index ac84f4f01..d56ee4ef3 100644 --- a/icaruscode/PMT/OpReco/CMakeLists.txt +++ b/icaruscode/PMT/OpReco/CMakeLists.txt @@ -18,7 +18,8 @@ cet_build_plugin(ICARUSOpHitFinder art::module set( MODULE_LIBRARIES icarusalg::Utilities sbnobj::Common_Trigger - larcorealg::Geometry + icaruscode::Decode_DataProducts + larcorealg::Geometry larcore::Geometry_Geometry_service lardataobj::RecoBase lardataobj::Simulation @@ -61,6 +62,7 @@ cet_build_plugin(ICARUSOpHitAna art::module LIBRARIES ${MODULE_LIBRARIES}) cet_build_plugin(ICARUSOpHitTuple art::module LIBRARIES ${MODULE_LIBRARIES}) cet_build_plugin(ICARUSParticleAna art::module LIBRARIES ${MODULE_LIBRARIES}) cet_build_plugin(TPCPMTBarycenterMatchProducer art::module LIBRARIES ${MODULE_LIBRARIES}) +cet_build_plugin(ICARUSBeamStructureAna art::module LIBRARIES ${MODULE_LIBRARIES}) install_headers() diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc new file mode 100644 index 000000000..5c6dd2746 --- /dev/null +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -0,0 +1,487 @@ +//////////////////////////////////////////////////////////////////////// +// Class: ICARUSBeamStructureAna +// Plugin Type: analyzer (Unknown Unknown) +// File: ICARUSBeamStructureAna_module.cc +// +// Generated at Mon Jul 22 13:50:03 2024 by Matteo Vicenzi using cetskelgen +// from version . +//////////////////////////////////////////////////////////////////////// + +// framework libraries +#include "canvas/Utilities/InputTag.h" +#include "art/Framework/Services/Registry/ServiceHandle.h" +#include "art/Framework/Core/EDAnalyzer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "canvas/Utilities/InputTag.h" +#include "canvas/Utilities/Exception.h" +#include "canvas/Persistency/Common/FindManyP.h" +#include "canvas/Persistency/Common/FindOneP.h" +#include "canvas/Persistency/Common/FindOne.h" +#include "canvas/Persistency/Common/Assns.h" +#include "messagefacility/MessageLogger/MessageLogger.h" +#include "fhiclcpp/types/Atom.h" +#include "fhiclcpp/types/Sequence.h" +#include "art_root_io/TFileService.h" + +// LArSoft libraries +#include "icaruscode/Decode/DataProducts/TriggerConfiguration.h" +#include "lardataobj/RecoBase/OpFlash.h" +#include "lardataobj/RecoBase/OpHit.h" +#include "icaruscode/Decode/ChannelMapping/IICARUSChannelMap.h" +#include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom() +#include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "lardataalg/DetectorInfo/DetectorTimings.h" +#include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time +#include "lardataobj/RawData/OpDetWaveform.h" +#include "lardataobj/Simulation/BeamGateInfo.h" +#include "lardataobj/RawData/TriggerData.h" +#include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" +#include "icaruscode/CRT/CRTUtils/CRTPMTMatchingUtils.h" +#include "sbnobj/Common/CRT/CRTPMTMatching.hh" +#include "icaruscode/IcarusObj/PMTBeamSignal.h" + +// ROOT libraries +#include "TTree.h" +#include "TFile.h" + +// C/C++ standard libraries +#include +#include +#include + +// ----------------------------------------------------------------------------- +namespace opana { class ICARUSBeamStructureAna; } + +class opana::ICARUSBeamStructureAna : public art::EDAnalyzer { + public: + struct Config { + fhicl::Sequence FlashLabels { + fhicl::Name("FlashLabels"), + fhicl::Comment("Tags for the recob::OpFlash data products") + }; + fhicl::Atom TriggerLabel { + fhicl::Name("TriggerLabel"), + fhicl::Comment("Tag for trigger info") + }; + fhicl::Atom RWMLabel { + fhicl::Name("RWMLabel"), + fhicl::Comment("Tag for RWM info") + }; + fhicl::Atom TriggerConfigLabel { + fhicl::Name("TriggerConfigLabel"), + fhicl::Comment("Trigger configuration label") + }; + fhicl::Atom CRTPMTMatchingLabel { + fhicl::Name("CRTPMTMatchingLabel"), + fhicl::Comment("CRTPMT matching label") + }; + }; // struct Config + + using Parameters = art::EDAnalyzer::Table; + + /// constructor + explicit ICARUSBeamStructureAna(Parameters const& config); + + /// Return RWM-relative time from a trigger-relative time + double getRWMRelativeTime(int channel, double t); + + /// Return side/wall from channel id + int getSideByChannel(const int channel); + + /// Return the RWM-relative flash interaction time + double getFlashBunchTime(std::vector hit_rise_time); + + /// Clear all data structures + void clear(); + + void analyze(art::Event const& e) override; + void beginJob(); + void beginRun(const art::Run& run) override; + + private: + + art::ServiceHandle tfs; + icarus::TriggerConfiguration fTriggerConfiguration; + + std::vector fFlashLabels; + art::InputTag fTriggerLabel; + art::InputTag fRWMLabel; + art::InputTag fTriggerConfigurationLabel; + art::InputTag fCRTPMTMatchingLabel; + + /// data members + std::vector fOpFlashTrees; + + int m_run; + int m_event; + int m_timestamp; + + // trigger info + unsigned int m_gate_type; + int m_trigger_type=-1; + std::string m_gate_name; + uint64_t m_trigger_timestamp; + uint64_t m_beam_gate_timestamp; + double m_beam_us; + double m_trigger_us; + double m_beam_gate_width; + + // flash info + int m_cryo; + int m_flash_id; + double m_flash_time; + double m_flash_time_rwm; + double m_flash_z; + double m_flash_y; + double m_flash_pe; + int m_flash_nhits; + std::vector m_channel_id; + std::vector m_hit_start_time; + std::vector m_hit_peak_time; + std::vector m_hit_rise_time; + std::vector m_hit_start_time_rwm; + std::vector m_hit_peak_time_rwm; + std::vector m_hit_rise_time_rwm; + std::vector m_hit_pe; + + //crt-pmt match + int m_flash_classification; + int m_flash_ncrthits; + std::vector m_crthit_x; + std::vector m_crthit_y; + std::vector m_crthit_z; + std::vector m_crttime_us; + std::vector m_crtpmttimediff_ns; + std::vector m_crtsys; + std::vector m_crtregion; + + // RWM times + std::vector fRWMTimes; +}; + +// -------------------------------------------------------------------------- +opana::ICARUSBeamStructureAna::ICARUSBeamStructureAna(Parameters const& config) + : art::EDAnalyzer(config) + , fFlashLabels( config().FlashLabels() ) + , fTriggerLabel( config().TriggerLabel() ) + , fRWMLabel ( config().RWMLabel() ) + , fTriggerConfigurationLabel( config().TriggerConfigLabel() ) + , fCRTPMTMatchingLabel( config().CRTPMTMatchingLabel() ) +{} + +// --------------------------------------------------------------------------- +void opana::ICARUSBeamStructureAna::beginJob() { + + if ( !fFlashLabels.empty() ) { + + for( auto const & label : fFlashLabels ) { + + // TTree for the flash in a given cryostat + std::string name = "beamtiming_"+label.label(); + std::string info = "Beam timing from label "+label.label(); + + TTree* ttree = tfs->make(name.c_str(), info.c_str() ); + ttree->Branch("run",&m_run); + ttree->Branch("event",&m_event); + ttree->Branch("timestamp",&m_timestamp); + + ttree->Branch("gate_type", &m_gate_type); + ttree->Branch("gate_name", &m_gate_name); + ttree->Branch("beam_gate_us", &m_beam_us); + ttree->Branch("trigger_us", &m_trigger_us); + ttree->Branch("beam_gate_width",&m_beam_gate_width); + ttree->Branch("trigger_type", &m_trigger_type, "trigger_type/I"); + ttree->Branch("trigger_timestamp", &m_trigger_timestamp, "trigger_timestamp/l"); + ttree->Branch("beam_gate_timestamp", &m_beam_gate_timestamp, "beam_gate_timestamp/l"); + + ttree->Branch("cryo",&m_cryo); + ttree->Branch("flash_id",&m_flash_id); + ttree->Branch("flash_time",&m_flash_time); + ttree->Branch("flash_time_rwm",&m_flash_time_rwm); + ttree->Branch("flash_pe",&m_flash_pe); + ttree->Branch("flash_z",&m_flash_z); + ttree->Branch("flash_y",&m_flash_y); + ttree->Branch("flash_nhits",&m_flash_nhits); + ttree->Branch("channels",&m_channel_id); + ttree->Branch("hit_start_time",&m_hit_start_time); + ttree->Branch("hit_peak_time",&m_hit_peak_time); + ttree->Branch("hit_rise_time",&m_hit_rise_time); + ttree->Branch("hit_start_time_rwm",&m_hit_start_time_rwm); + ttree->Branch("hit_peak_time_rwm",&m_hit_peak_time_rwm); + ttree->Branch("hit_rise_time_rwm",&m_hit_rise_time); + ttree->Branch("hit_pe",&m_hit_pe); + + ttree->Branch("flash_classification",&m_flash_classification); + ttree->Branch("flash_ncrthits",&m_flash_ncrthits); + ttree->Branch("crthit_x",&m_crthit_x); + ttree->Branch("crthit_y",&m_crthit_y); + ttree->Branch("crthit_z",&m_crthit_z); + ttree->Branch("crthit_sys",&m_crtsys); + ttree->Branch("crthit_region",&m_crtregion); + ttree->Branch("crttime_us",&m_crttime_us); + ttree->Branch("crtpmttimediff_ns",&m_crtpmttimediff_ns); + + fOpFlashTrees.push_back( ttree ); + } + } else { + mf::LogError("ICARUSBeamStructureAna") + << "No flash labels selected!!"; + } +} + +// ------------------------------------------------------------------------------ + +void opana::ICARUSBeamStructureAna::beginRun(const art::Run& r) +{ + fTriggerConfiguration = r.getProduct(fTriggerConfigurationLabel); +} + +// ------------------------------------------------------------------------------- + +void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) +{ + // ---- + // Event metadata information + m_run = e.id().run(); + m_event = e.id().event(); + m_timestamp = e.time().timeHigh(); // precision to the second + + // ---- + // Trigger metadata information + detinfo::DetectorTimings const detTimings = detinfo::makeDetectorTimings( + art::ServiceHandle()->DataFor(e)); + detinfo::timescales::electronics_time triggerTime = detTimings.TriggerTime(); + detinfo::timescales::electronics_time beamGateTime = detTimings.BeamGateTime(); + + if( !fTriggerLabel.empty() ) { + + auto const& extraInfo = e.getProduct(fTriggerLabel); + + if( extraInfo.isValid() ) { + + sbn::triggerSource bit = extraInfo.sourceType; + m_gate_type = (unsigned int)bit; //1 BNB 2 NumI 3 offbeamBNB 4 offbeamNuMi + m_gate_name = bitName(bit); + m_trigger_type = value( extraInfo.triggerType ); //1 majority, 2 minbias + + // absolute timestamp + m_trigger_timestamp = extraInfo.triggerTimestamp; + m_beam_gate_timestamp = extraInfo.beamGateTimestamp; + + // time in electronics time + m_trigger_us = triggerTime.value(); + m_beam_us = beamGateTime.value(); + m_beam_gate_width = fTriggerConfiguration.getGateWidth(m_gate_type); + + } else { + mf::LogError("ICARUSBeamStructureAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!" ; + } + } else { + mf::LogError("ICARUSBeamStructureAna") << "No trigger labels selected!!" ; + } + + // ---- + // RWM times + + fRWMTimes = e.getProduct>(fRWMLabel); + if ( fRWMTimes.empty() ) + mf::LogWarning("ICARUSBeamStructureAna") << "Data product std::vector>(label); + auto const& flashes = *flash_handle; + + // we want our flashes to be valid and not empty + if( !flash_handle.isValid() ) { + mf::LogError("ICARUSBeamStructureAna") << "Not found a recob::OpFlash with label '" << label.encode() << "'"; + } else if ( flashes.empty() ) { + mf::LogWarning("ICARUSBeamStructureAna") << "No recob::OpFlash in collection with label '" << label.encode() << "'"; + } else { + + art::FindManyP ophitsPtr( flash_handle, e, label ); + art::FindOneP matchPtr( flash_handle, e, fCRTPMTMatchingLabel ); + + // loop all flashes + size_t idx = 0; + for ( auto const& flash : flashes ) { + + // Filling flash info... + m_flash_id = idx; + m_flash_time = flash.Time(); + m_flash_pe = flash.TotalPE(); + m_flash_z = flash.ZCenter(); + m_flash_y = flash.YCenter(); + + // ---- + // CRT match info + + auto const & match = matchPtr.at(idx); + + // if there is no match, there is no product + // fill null parameters + if( !match ) { + m_flash_classification = 0; + m_flash_ncrthits = 0; + } else { + m_flash_classification = static_cast(match->flashClassification); + m_flash_ncrthits = match->matchedCRTHits.size(); + + for( auto const& crthit: match->matchedCRTHits ){ + m_crthit_x.push_back(crthit.position.X()); + m_crthit_y.push_back(crthit.position.Y()); + m_crthit_z.push_back(crthit.position.Z()); + m_crttime_us.push_back(crthit.time); + m_crtpmttimediff_ns.push_back(1e3*crthit.PMTTimeDiff); + m_crtsys.push_back(crthit.sys); + m_crtregion.push_back(crthit.region); + } + } + + // ---- + // OPHITS info + + auto const & ophits = ophitsPtr.at(idx); + + m_channel_id.resize(360); + m_hit_start_time.resize(360); + m_hit_peak_time.resize(360); + m_hit_rise_time.resize(360); + m_hit_start_time_rwm.resize(360); + m_hit_peak_time_rwm.resize(360); + m_hit_rise_time_rwm.resize(360); + m_hit_pe.resize(360); + + // loop all hits in the flash: save only the first one + for ( auto const hit : ophits ){ + + const int ch = hit->OpChannel(); + double ts = hit->StartTime(); + double tp = hit->PeakTime(); + double tr = hit->RiseTime(); + double pe = hit->PE(); + + // select the first ophit (by time) in each channel + if( ( m_hit_start_time[ch] == 0 ) || ( m_hit_start_time[ch] > ts )) { + m_channel_id[ch] = ch; + m_hit_start_time[ch] = ts; + m_hit_peak_time[ch] = tp; + m_hit_rise_time[ch] = ts + tr; + m_hit_start_time_rwm[ch] = getRWMRelativeTime(ch, ts); + m_hit_peak_time_rwm[ch] = getRWMRelativeTime(ch, tp); + m_hit_rise_time_rwm[ch] = getRWMRelativeTime(ch, ts+tr); + m_hit_pe[ch] = pe; + } + } + + // 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_hit_rise_time_rwm); + + fOpFlashTrees[iFlashLabel]->Fill(); + clear(); + } + } + } + } +} + +// ----------------------------------------------------------------------------- + +int opana::ICARUSBeamStructureAna::getSideByChannel( const int channel ) { + + /* + Channels are numbered from east to west, from North (cryo side) to South (beam side) + We look in the opposide direction wrt to the beam direction South->North: + - Left is the east wall of each cryostat; + - Right is the west side of each cryostat; + - [ 0:89 ] and [180:269] are on the left, + the return value of the function is 0; + - [ 90-179 ] and [ 270:359 ] are on the right, + the return value of the function is 1; + */ + + int side = channel / 90; // always round down + return side % 2; +} + +// ----------------------------------------------------------------------------- + +double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) { + + if( fRWMTimes.empty() ) return 0; + + auto rwm = fRWMTimes.at(channel); + if ( !rwm.isValid() ) return 0; + + double rwm_trigger = rwm.startTime; //rwm time w.r.t. trigger time [us] + return (t - rwm_trigger); + +} + +// ----------------------------------------------------------------------------- + +double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector hit_rise_time_rwm) { + + float tfirst_left = std::numeric_limits::max(); + float tfirst_right = std::numeric_limits::max(); + + // if no RWM info available, all pmt_start_time_rwm is zero + // return zero as well for the flash + if (fRWMTimes.empty()) return 0; + + for(size_t i=0; i &pmt_amplitude, TTree *ophittree ); - /// ???? - static std::string_view firstLine(std::string const& s, const char* endl = "\r"); - /// Return RWM-relative time from a trigger-relative time float getRWMRelativeTime(int channel, float t); @@ -331,8 +328,8 @@ void opana::ICARUSFlashAssAna::beginJob() { fEventTree->Branch("trigger_gate_diff", &m_trigger_gate_diff, "trigger_gate_diff/l"); fEventTree->Branch("lvdsCryoE", &lvdsCryoE, "lvdsCryoE[2]/l"); fEventTree->Branch("lvdsCryoW", &lvdsCryoW, "lvdsCryoW[2]/l"); - fEventTree->Branch("addersCryoE", &addersCryoE, "addersCryoE[2]/l"); - fEventTree->Branch("addersCryoW", &addersCryoW, "addersCryoW[2]/l"); + fEventTree->Branch("addersCryoE", &addersCryoE, "addersCryoE[2]/s"); + fEventTree->Branch("addersCryoW", &addersCryoW, "addersCryoW[2]/s"); // Setting up the WAVEFORM trees (one per product label) // This tree will hold some aggregated optical waveform information @@ -525,7 +522,7 @@ float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_ for(size_t i=0; iFill(); + fOpDetWaveformTrees[i]->Fill(); + idx++; + } } else { mf::LogWarning("ICARUSFlashAssAna") << "Data product std::vector for " << wflabel.label() @@ -799,7 +798,8 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { for ( size_t iFlashLabel=0; iFlashLabel>(label); + auto const& flash_handle = e.getValidHandle>(label); + auto const& flashes = *flash_handle; // want our flashes to be valid and not empty if( flashes.empty() ) { @@ -808,7 +808,7 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { } else { - art::FindManyP ophitsPtr( e.getHandle>(label), e, label ); + art::FindManyP ophitsPtr( flash_handle, e, label ); size_t idx = 0; for( auto const& flash : flashes ){ @@ -857,6 +857,7 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { m_pmt_rise_time.clear(); m_pmt_start_time_rwm.clear(); + idx++; } } } diff --git a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl index 255b82170..670c1e975 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl @@ -104,11 +104,24 @@ ICARUSFlashAssAna: { module_type: "ICARUSFlashAssAna" TriggerLabel: "daqTrigger" DumpWaveformsInfo: true + SaveRawWaveforms: false + UseSharedBaseline: true OpDetWaveformLabels: ["daqPMT"] + BaselineLabels: ["pmtbaselines"] OpHitLabels: ["ophit"] FlashLabels: ["opflashCryoE", "opflashCryoW"] + RWMLabel: "RWM" PEOpHitThreshold: 0 Debug: false } +ICARUSBeamStructureAna: { + module_type: "ICARUSBeamStructureAna" + FlashLabels: ["opflashCryoE", "opflashCryoW"] + TriggerLabel: "daqTrigger" + RWMLabel: "RWM" + TriggerConfigLabel: "triggerconfig" + CRTPMTMatchingLabel: "crtpmt" +} + END_PROLOG From fdfb1fa47131dd2f17239a0289b30f51206cd8e1 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 24 Jul 2024 17:02:06 -0500 Subject: [PATCH 15/52] some restructuring, fcl updates --- fcl/reco/Definitions/stage0_icarus_defs.fcl | 4 + .../OpReco/ICARUSBeamStructureAna_module.cc | 69 ++++++++++------ .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 14 +++- .../OpReco/driver/run_beamstructure_ana.fcl | 80 +++++++++++++++++++ icaruscode/PMT/OpReco/driver/run_flashana.fcl | 74 +++++++++++++++++ .../PMT/OpReco/fcl/icarus_opana_modules.fcl | 4 +- icaruscode/Timing/timing_beam.fcl | 2 +- 7 files changed, 217 insertions(+), 30 deletions(-) create mode 100644 icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl create mode 100644 icaruscode/PMT/OpReco/driver/run_flashana.fcl diff --git a/fcl/reco/Definitions/stage0_icarus_defs.fcl b/fcl/reco/Definitions/stage0_icarus_defs.fcl index 37841bca0..c783d7e32 100644 --- a/fcl/reco/Definitions/stage0_icarus_defs.fcl +++ b/fcl/reco/Definitions/stage0_icarus_defs.fcl @@ -9,6 +9,7 @@ #include "recowire_icarus.fcl" #include "hitfindermodules_icarus.fcl" #include "timing_icarus.fcl" +#include "timing_beam.fcl" #include "icarus_ophitfinder.fcl" #include "icarus_flashfinder.fcl" #include "trigger_emulation_icarus.fcl" @@ -115,6 +116,9 @@ icarus_stage0_producers: daqPMTonbeam: @local::copyPMTonBeam + ### Beam timing + beam: @local::icarus_beam_signal_extractor + ### Purity monitoring purityana0: { module_type: "ICARUSPurityDQM" } purityana1: { module_type: "ICARUSPurityDQM" } diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index 5c6dd2746..bc6432c58 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -287,8 +287,9 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) fRWMTimes = e.getProduct>(fRWMLabel); if ( fRWMTimes.empty() ) - mf::LogWarning("ICARUSBeamStructureAna") << "Data product std::vector for '" << fRWMLabel.label() + << "' is empty in " << m_gate_name << " event!"; + // ---- // FLASH/CRT timing information @@ -353,15 +354,11 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) auto const & ophits = ophitsPtr.at(idx); - m_channel_id.resize(360); - m_hit_start_time.resize(360); - m_hit_peak_time.resize(360); - m_hit_rise_time.resize(360); - m_hit_start_time_rwm.resize(360); - m_hit_peak_time_rwm.resize(360); - m_hit_rise_time_rwm.resize(360); - m_hit_pe.resize(360); - + std::map startmap; + std::map peakmap; + std::map risemap; + std::map pemap; + // loop all hits in the flash: save only the first one for ( auto const hit : ophits ){ @@ -372,16 +369,34 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) double pe = hit->PE(); // select the first ophit (by time) in each channel - if( ( m_hit_start_time[ch] == 0 ) || ( m_hit_start_time[ch] > ts )) { - m_channel_id[ch] = ch; - m_hit_start_time[ch] = ts; - m_hit_peak_time[ch] = tp; - m_hit_rise_time[ch] = ts + tr; - m_hit_start_time_rwm[ch] = getRWMRelativeTime(ch, ts); - m_hit_peak_time_rwm[ch] = getRWMRelativeTime(ch, tp); - m_hit_rise_time_rwm[ch] = getRWMRelativeTime(ch, ts+tr); - m_hit_pe[ch] = pe; - } + if ( startmap.find(ch) != startmap.end() ){ + if ( ts < startmap[ch] ){ + startmap[ch] = ts; + peakmap[ch] = tp; + risemap[ch] = ts+tr; + pemap[ch] = pe; + } + } else { + startmap[ch] = ts; + peakmap[ch] = tp; + risemap[ch] = ts+tr; + pemap[ch] = pe; + } + } + + // get number of unique PMTs in flash + m_flash_nhits = startmap.size(); + + for(auto it = startmap.begin(); it!=startmap.end(); it++) { + int ch = it->first; + m_channel_id.push_back(ch); + m_hit_start_time.push_back(it->second); + m_hit_peak_time.push_back(peakmap[ch]); + m_hit_rise_time.push_back(risemap[ch]); + m_hit_start_time_rwm.push_back(getRWMRelativeTime(ch,it->second)); + m_hit_peak_time_rwm.push_back(getRWMRelativeTime(ch,peakmap[ch])); + 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 @@ -389,7 +404,9 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) m_flash_time_rwm = getFlashBunchTime(m_hit_rise_time_rwm); fOpFlashTrees[iFlashLabel]->Fill(); - clear(); + + clear(); + idx++; } } } @@ -422,7 +439,13 @@ double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) if( fRWMTimes.empty() ) return 0; auto rwm = fRWMTimes.at(channel); - if ( !rwm.isValid() ) return 0; + if ( !rwm.isValid() ){ + mf::LogTrace("ICARUSBeamStructureAna") << "No RWM signal for channel " << channel << " " + << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel + << ", SpecialChannel " << rwm.specialChannel << ")" + << " in event " << m_event << " gate " << m_gate_name; + return 0; + } double rwm_trigger = rwm.startTime; //rwm time w.r.t. trigger time [us] return (t - rwm_trigger); diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index 9cb3e531a..0914def10 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -500,8 +500,14 @@ float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { if( fRWMTimes.empty() ) return 0; auto rwm = fRWMTimes.at(channel); - if ( !rwm.isValid() ) return 0; - + if ( !rwm.isValid() ){ + mf::LogTrace("ICARUSBeamStructureAna") << "No RWM signal for channel " << channel << " " + << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel + << ", SpecialChannel " << rwm.specialChannel << ")" + << " in event " << m_event << " gate " << m_gate_name; + return 0; + } + float rwm_trigger = rwm.startTime; //rwm time w.r.t. trigger time [us] return (t - rwm_trigger); @@ -731,8 +737,8 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { fRWMTimes = e.getProduct>(fRWMLabel); if ( fRWMTimes.empty() ) - mf::LogWarning("ICARUSFlashAssAna") << "Data product std::vector for '" << fRWMLabel.label() + << "' is empty in " << m_gate_name << " event!"; // ----- // WAVEFORM INFO diff --git a/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl b/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl new file mode 100644 index 000000000..b7e67ca4e --- /dev/null +++ b/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl @@ -0,0 +1,80 @@ +################################################################# +# File: run_beamstructure_ana.fcl +# Author: M. Vicenzi (mvicenzi@bnl.gov) +# +# Description: +# Simple off-the-shelf example to run the beam structure analysis. +# It produces all ingredients for the light-only reconstruction of the beam bunch structure. +# This is meant to be run directly on raw files as it defines all the needed producers. +# Output contains both RWM/EW information and OpFlash/CRT timing information. + +#include "services_common_icarus.fcl" +#include "channelmapping_icarus.fcl" +#include "timing_icarus.fcl" + +#include "decoderdefs_icarus.fcl" +#include "icarus_ophitfinder.fcl" +#include "icarus_flashfinder.fcl" +#include "icarus_opana_modules.fcl" +#include "timing_beam.fcl" + +#include "crt_decoderdefs_icarus.fcl" +#include "crthitproducer.fcl" +#include "crtpmtmatchingproducer.fcl" +#include "icarus_FilterCRTPMTMatching.fcl" + +process_name: beamana + +services: +{ + @table::icarus_art_services # from services_common_icarus.fcl + @table::icarus_basic_services # from services_basic_icarus.fcl + @table::icarus_geometry_services + DetectorClocksService: @local::icarus_detectorclocks + IICARUSChannelMap: @local::icarus_channelmappinggservice + IPMTTimingCorrectionService: @local::icarus_pmttimingservice + TFileService: { fileName: "supplemental-%ifb-%p.root" } +} + +physics: +{ + producers: + { + triggerconfig: @local::extractTriggerConfig + pmtconfig: @local::extractPMTconfig + + daqTrigger: @local::decodeTriggerAutodetect + daqPMT: @local::decodePMT + ophituncorrected: @local::icarus_ophit_data + ophit: @local::icarus_ophit_timing_correction + beam: @local::icarus_beam_signal_extractor + opflashCryoE: @local::ICARUSSimpleFlashDataCryoE + opflashCryoW: @local::ICARUSSimpleFlashDataCryoW + crthit: @local::standard_crthitproducer + crtpmt: @local::standard_crtpmtmatchingproducer + } + + analyzers: + { + beamana: @local::ICARUSBeamStructureAna + } + + my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, ophituncorrected, ophit, + beam, opflashCryoE, opflashCryoW, crthit, crtpmt ] + my_analyzers: [ beamana ] + + trigger_paths: [ my_producers ] + end_paths: [ my_analyzers ] +} + +### REQUIRED PRODUCERS ### +physics.producers.daqTrigger.DecoderTool.Decoders[0].ToolConfig.TrigConfigLabel: triggerconfig +physics.producers.daqTrigger.DecoderTool.Decoders[1].ToolConfig.TrigConfigLabel: triggerconfig +physics.producers.daqTrigger.DecoderTool.Decoders[2].ToolConfig.TrigConfigLabel: triggerconfig + +physics.producers.daqPMT.PMTconfigTag: pmtconfig # required +physics.producers.daqPMT.TriggerTag: daqTrigger # required +physics.producers.ophit.InputLabels: [ "ophituncorrected" ] + +physics.producers.beam.DebugTrees: true +physics.analyzers.beamana.RWMLabel: "beam:RWM" diff --git a/icaruscode/PMT/OpReco/driver/run_flashana.fcl b/icaruscode/PMT/OpReco/driver/run_flashana.fcl new file mode 100644 index 000000000..521be1dda --- /dev/null +++ b/icaruscode/PMT/OpReco/driver/run_flashana.fcl @@ -0,0 +1,74 @@ +####################################################### +# File: run_flashana.fcl +# Author: Matteo Vicenzi (mvicenzi@bnl.gov) +# Description: +# Simple off-the-shelf example to run the light analysis +# directly from raw files + +#include "services_common_icarus.fcl" +#include "channelmapping_icarus.fcl" +#include "timing_icarus.fcl" +#include "timing_beam.fcl" + +#include "decoderdefs_icarus.fcl" +#include "icarus_ophitfinder.fcl" +#include "icarus_flashfinder.fcl" +#include "icarus_opana_modules.fcl" + +process_name: flashana + +services: +{ + @table::icarus_art_services # from services_common_icarus.fcl + @table::icarus_basic_services # from services_basic_icarus.fcl + @table::icarus_geometry_services + DetectorClocksService: @local::icarus_detectorclocks + IICARUSChannelMap: @local::icarus_channelmappinggservice + IPMTTimingCorrectionService: @local::icarus_pmttimingservice + TFileService: { fileName: "supplemental-%ifb-%p.root" } +} + +physics: +{ + producers: + { + triggerconfig: @local::extractTriggerConfig + pmtconfig: @local::extractPMTconfig + + daqTrigger: @local::decodeTriggerAutodetect + daqPMT: @local::decodePMT + + pmtbaselines: @local::icarus_opreco_pedestal_fromchannel_data # from icarus_ophitfinder.fcl + ophituncorrected: @local::icarus_ophit_data + ophit: @local::icarus_ophit_timing_correction + beam: @local::icarus_beam_signal_extractor + opflashCryoE: @local::ICARUSSimpleFlashDataCryoE + opflashCryoW: @local::ICARUSSimpleFlashDataCryoW + } + + analyzers: + { + flashana: @local::ICARUSFlashAssAna + } + + my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, pmtbaselines, ophituncorrected, ophit, beam, opflashCryoE, opflashCryoW ] + my_analyzers: [ flashana ] + + trigger_paths: [ my_producers ] + end_paths: [ my_analyzers ] +} + +### REQUIRED PRODUCERS ### +physics.producers.daqTrigger.DecoderTool.Decoders[0].ToolConfig.TrigConfigLabel: triggerconfig +physics.producers.daqTrigger.DecoderTool.Decoders[1].ToolConfig.TrigConfigLabel: triggerconfig +physics.producers.daqTrigger.DecoderTool.Decoders[2].ToolConfig.TrigConfigLabel: triggerconfig + +physics.producers.daqPMT.PMTconfigTag: pmtconfig # required +physics.producers.daqPMT.TriggerTag: daqTrigger # required + +physics.producers.ophit.InputLabels: [ "ophituncorrected" ] +physics.producers.beam.DebugTrees: false + +physics.analyzers.flashana.DumpWaveformsInfo: true +physics.analyzers.flashana.SaveRawWaveforms: false +physics.analyzers.flashana.UseSharedBaseline: true diff --git a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl index 670c1e975..b45fd5d37 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl @@ -110,7 +110,7 @@ ICARUSFlashAssAna: { BaselineLabels: ["pmtbaselines"] OpHitLabels: ["ophit"] FlashLabels: ["opflashCryoE", "opflashCryoW"] - RWMLabel: "RWM" + RWMLabel: "beam:RWM" PEOpHitThreshold: 0 Debug: false } @@ -119,7 +119,7 @@ ICARUSBeamStructureAna: { module_type: "ICARUSBeamStructureAna" FlashLabels: ["opflashCryoE", "opflashCryoW"] TriggerLabel: "daqTrigger" - RWMLabel: "RWM" + RWMLabel: "beam:RWM" TriggerConfigLabel: "triggerconfig" CRTPMTMatchingLabel: "crtpmt" } diff --git a/icaruscode/Timing/timing_beam.fcl b/icaruscode/Timing/timing_beam.fcl index 1a2250df2..a68836ff5 100644 --- a/icaruscode/Timing/timing_beam.fcl +++ b/icaruscode/Timing/timing_beam.fcl @@ -2,7 +2,7 @@ BEGIN_PROLOG -beam_signal_extractor: +icarus_beam_signal_extractor: { module_type: "PMTBeamSignalsExtractor" TriggerLabel: "daqTrigger" From 834b07a27899f5e4fc198bdba87ea1962f00c358 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 24 Jul 2024 18:11:34 -0500 Subject: [PATCH 16/52] forgot daqCRT... --- icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl b/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl index b7e67ca4e..f14eae7de 100644 --- a/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl +++ b/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl @@ -45,11 +45,14 @@ physics: daqTrigger: @local::decodeTriggerAutodetect daqPMT: @local::decodePMT + daqCRT: @local::crtdaq_icarus + ophituncorrected: @local::icarus_ophit_data ophit: @local::icarus_ophit_timing_correction beam: @local::icarus_beam_signal_extractor opflashCryoE: @local::ICARUSSimpleFlashDataCryoE opflashCryoW: @local::ICARUSSimpleFlashDataCryoW + crthit: @local::standard_crthitproducer crtpmt: @local::standard_crtpmtmatchingproducer } @@ -59,8 +62,7 @@ physics: beamana: @local::ICARUSBeamStructureAna } - my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, ophituncorrected, ophit, - beam, opflashCryoE, opflashCryoW, crthit, crtpmt ] + my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, daqCRT, ophituncorrected, ophit, beam, opflashCryoE, opflashCryoW, crthit, crtpmt ] my_analyzers: [ beamana ] trigger_paths: [ my_producers ] From ab063f0f9e281e972299c0cc7346dad3b412e7c9 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 25 Jul 2024 11:27:40 -0500 Subject: [PATCH 17/52] fix bugs, edge cases --- .../OpReco/ICARUSBeamStructureAna_module.cc | 43 +++++++++++++------ .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 34 ++++++++++++--- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index bc6432c58..fdbcf66fc 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -91,7 +91,7 @@ class opana::ICARUSBeamStructureAna : public art::EDAnalyzer { int getSideByChannel(const int channel); /// Return the RWM-relative flash interaction time - double getFlashBunchTime(std::vector hit_rise_time); + double getFlashBunchTime(std::vector channels, std::vector hit_rise_time); /// Clear all data structures void clear(); @@ -210,7 +210,7 @@ void opana::ICARUSBeamStructureAna::beginJob() { ttree->Branch("hit_rise_time",&m_hit_rise_time); ttree->Branch("hit_start_time_rwm",&m_hit_start_time_rwm); ttree->Branch("hit_peak_time_rwm",&m_hit_peak_time_rwm); - ttree->Branch("hit_rise_time_rwm",&m_hit_rise_time); + ttree->Branch("hit_rise_time_rwm",&m_hit_rise_time_rwm); ttree->Branch("hit_pe",&m_hit_pe); ttree->Branch("flash_classification",&m_flash_classification); @@ -401,7 +401,7 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) // 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_hit_rise_time_rwm); + m_flash_time_rwm = getFlashBunchTime(m_channel_id,m_hit_rise_time_rwm); fOpFlashTrees[iFlashLabel]->Fill(); @@ -454,30 +454,47 @@ double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) // ----------------------------------------------------------------------------- -double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector hit_rise_time_rwm) { +double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channels, std::vector hit_rise_time_rwm) { - float tfirst_left = std::numeric_limits::max(); - float tfirst_right = std::numeric_limits::max(); + double tfirst_left = std::numeric_limits::max(); + double tfirst_right = std::numeric_limits::max(); // if no RWM info available, all pmt_start_time_rwm is zero // return zero as well for the flash if (fRWMTimes.empty()) return 0; + int nleft = 0; + int nright = 0; for(size_t i=0; i pmt_start_ // return zero as well for the flash if (fRWMTimes.empty()) return 0; + int nleft = 0; + int nright = 0; for(size_t i=0; i -1e-10 && t < 1e-10 ) continue; // if RWM is missing for some PMT channels, // it might not be possible to use the first hits (might not have RMW time) // so return zero as in other bad cases if( !fRWMTimes[i].isValid() ) return 0; - - if( (cryo == 0) && (t < tfirst_left) ) - tfirst_left = t; - if( (cryo == 1) && (t < tfirst_right) ) - tfirst_right = t; - } + + // count hits separetely on the two walls + if( side == 0 ){ + nleft++; + if(t < tfirst_left) tfirst_left = t; + } + else if( side == 1 ){ + nright++; + if(t < tfirst_right) tfirst_right = t; + } + } + // if there are no hits in one of the walls... + if( nleft<1 || nright <1 ){ + mf::LogWarning("ICARUSFlashAssAna") << "Flash " << m_flash_id << " doesn't have hits on both walls!" + << "Left: " << nleft << " t " << tfirst_left << " " + << "Right: " << nright << " t " << tfirst_right; + // return what we have... + return (tfirst_left < tfirst_right) ? tfirst_left : tfirst_right; + } + return (tfirst_left + tfirst_right)/2.; } From 529cb663a2989c44802677b1221a91a44630730c Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 25 Jul 2024 16:23:24 -0500 Subject: [PATCH 18/52] add to PMT stage0 path --- fcl/reco/Definitions/stage0_icarus_defs.fcl | 1 + 1 file changed, 1 insertion(+) diff --git a/fcl/reco/Definitions/stage0_icarus_defs.fcl b/fcl/reco/Definitions/stage0_icarus_defs.fcl index c783d7e32..1473b0a69 100644 --- a/fcl/reco/Definitions/stage0_icarus_defs.fcl +++ b/fcl/reco/Definitions/stage0_icarus_defs.fcl @@ -247,6 +247,7 @@ icarus_stage0_PMT: [ triggerconfig, daqTrigger, pmtconfig, daqPMT, + beam, pmtconfigbaselines, pmtthr, pmtbaselines, From 156c925934ff1de1ae4022317bfd204f067fded2 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 13 Aug 2024 17:55:40 -0500 Subject: [PATCH 19/52] fix code + fcl to run smoothly on MC files --- .../Stage1/Run2/stage1_run2_icarus_MC.fcl | 7 ++++- .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 26 +++++++++---------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/fcl/reco/Stage1/Run2/stage1_run2_icarus_MC.fcl b/fcl/reco/Stage1/Run2/stage1_run2_icarus_MC.fcl index 41f8ea1b8..62ff01af7 100644 --- a/fcl/reco/Stage1/Run2/stage1_run2_icarus_MC.fcl +++ b/fcl/reco/Stage1/Run2/stage1_run2_icarus_MC.fcl @@ -50,7 +50,7 @@ physics.producers: { physics.reco: [ @sequence::icarus_reco_Gauss_CryoE , @sequence::icarus_reco_Gauss_CryoW , - @sequence::icarus_reco_fm, + @sequence::icarus_reco_fm, @sequence::icarus_tpcpmtbarycentermatch, caloskimCalorimetryCryoE, caloskimCalorimetryCryoW, mcassociationsGausCryoE, mcassociationsGausCryoW @@ -82,6 +82,11 @@ physics.analyzers.caloskimW.RawDigitproducers: ["MCDecodeTPCROI:PHYSCRATEDATATPC physics.producers.mcassociationsGausCryoE.HitParticleAssociations.HitModuleLabelVec: ["cluster3DCryoE"] physics.producers.mcassociationsGausCryoW.HitParticleAssociations.HitModuleLabelVec: ["cluster3DCryoW"] +# Remove missing products in MC +physics.analyzers.simpleLightAna.TriggerLabel: "" +physics.analyzers.simpleLightAna.RWMLabel: "" +physics.analyzers.simpleLightAna.OpDetWaveformLabels: ["opdaq"] + services.message.destinations : { STDCOUT: diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index d755ceabd..ab714c31b 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -501,10 +501,10 @@ float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { auto rwm = fRWMTimes.at(channel); if ( !rwm.isValid() ){ - mf::LogTrace("ICARUSBeamStructureAna") << "No RWM signal for channel " << channel << " " - << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel - << ", SpecialChannel " << rwm.specialChannel << ")" - << " in event " << m_event << " gate " << m_gate_name; + mf::LogTrace("ICARUSFlashAssAna") << "No RWM signal for channel " << channel << " " + << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel + << ", SpecialChannel " << rwm.specialChannel << ")" + << " in event " << m_event << " gate " << m_gate_name; return 0; } @@ -744,22 +744,22 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { } else { mf::LogError("ICARUSFlashAssAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!" ; - } - - } else { - mf::LogError("ICARUSFlashAssAna") << "Trigger Data product " << fTriggerLabel.label() << " not found!\n" ; - } + } + } // ----- // RWM INFO // We work out the RWM information here // it might be empty if offbeam or missing, bu that's okay! - fRWMTimes = e.getProduct>(fRWMLabel); - if ( fRWMTimes.empty() ) - mf::LogTrace("ICARUSBeamStructureAna") << "Data product std::vector for '" << fRWMLabel.label() - << "' is empty in " << m_gate_name << " event!"; + if( !fRWMLabel.empty() ){ + fRWMTimes = e.getProduct>(fRWMLabel); + if ( fRWMTimes.empty() ) + mf::LogTrace("ICARUSFlashAssAna") << "Data product std::vector for '" + << fRWMLabel.label() << "' is empty in " << m_gate_name << " event!"; + } + // ----- // WAVEFORM INFO // Now we work on the waveforms if we are allowed to From 1f7dba81f3b596f90e46d95a0bcf80fb22b504c9 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 25 Sep 2024 09:28:23 -0500 Subject: [PATCH 20/52] change module label from beam to beamTiming --- fcl/reco/Definitions/stage0_icarus_defs.fcl | 4 ++-- icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl | 8 ++++---- icaruscode/PMT/OpReco/driver/run_flashana.fcl | 6 +++--- icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fcl/reco/Definitions/stage0_icarus_defs.fcl b/fcl/reco/Definitions/stage0_icarus_defs.fcl index 1473b0a69..c22d2f9a9 100644 --- a/fcl/reco/Definitions/stage0_icarus_defs.fcl +++ b/fcl/reco/Definitions/stage0_icarus_defs.fcl @@ -117,7 +117,7 @@ icarus_stage0_producers: daqPMTonbeam: @local::copyPMTonBeam ### Beam timing - beam: @local::icarus_beam_signal_extractor + beamTiming: @local::icarus_beam_signal_extractor ### Purity monitoring purityana0: { module_type: "ICARUSPurityDQM" } @@ -247,7 +247,7 @@ icarus_stage0_PMT: [ triggerconfig, daqTrigger, pmtconfig, daqPMT, - beam, + beamTiming, pmtconfigbaselines, pmtthr, pmtbaselines, diff --git a/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl b/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl index f14eae7de..f279723b9 100644 --- a/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl +++ b/icaruscode/PMT/OpReco/driver/run_beamstructure_ana.fcl @@ -49,7 +49,7 @@ physics: ophituncorrected: @local::icarus_ophit_data ophit: @local::icarus_ophit_timing_correction - beam: @local::icarus_beam_signal_extractor + beamTiming: @local::icarus_beam_signal_extractor opflashCryoE: @local::ICARUSSimpleFlashDataCryoE opflashCryoW: @local::ICARUSSimpleFlashDataCryoW @@ -62,7 +62,7 @@ physics: beamana: @local::ICARUSBeamStructureAna } - my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, daqCRT, ophituncorrected, ophit, beam, opflashCryoE, opflashCryoW, crthit, crtpmt ] + my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, daqCRT, ophituncorrected, ophit, beamTiming, opflashCryoE, opflashCryoW, crthit, crtpmt ] my_analyzers: [ beamana ] trigger_paths: [ my_producers ] @@ -78,5 +78,5 @@ physics.producers.daqPMT.PMTconfigTag: pmtconfig # required physics.producers.daqPMT.TriggerTag: daqTrigger # required physics.producers.ophit.InputLabels: [ "ophituncorrected" ] -physics.producers.beam.DebugTrees: true -physics.analyzers.beamana.RWMLabel: "beam:RWM" +physics.producers.beamTiming.DebugTrees: true +physics.analyzers.beamana.RWMLabel: "beamTiming:RWM" diff --git a/icaruscode/PMT/OpReco/driver/run_flashana.fcl b/icaruscode/PMT/OpReco/driver/run_flashana.fcl index 521be1dda..0e26d3d4f 100644 --- a/icaruscode/PMT/OpReco/driver/run_flashana.fcl +++ b/icaruscode/PMT/OpReco/driver/run_flashana.fcl @@ -41,7 +41,7 @@ physics: pmtbaselines: @local::icarus_opreco_pedestal_fromchannel_data # from icarus_ophitfinder.fcl ophituncorrected: @local::icarus_ophit_data ophit: @local::icarus_ophit_timing_correction - beam: @local::icarus_beam_signal_extractor + beamTiming: @local::icarus_beam_signal_extractor opflashCryoE: @local::ICARUSSimpleFlashDataCryoE opflashCryoW: @local::ICARUSSimpleFlashDataCryoW } @@ -51,7 +51,7 @@ physics: flashana: @local::ICARUSFlashAssAna } - my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, pmtbaselines, ophituncorrected, ophit, beam, opflashCryoE, opflashCryoW ] + my_producers: [ triggerconfig, pmtconfig, daqTrigger, daqPMT, pmtbaselines, ophituncorrected, ophit, beamTiming, opflashCryoE, opflashCryoW ] my_analyzers: [ flashana ] trigger_paths: [ my_producers ] @@ -67,7 +67,7 @@ physics.producers.daqPMT.PMTconfigTag: pmtconfig # required physics.producers.daqPMT.TriggerTag: daqTrigger # required physics.producers.ophit.InputLabels: [ "ophituncorrected" ] -physics.producers.beam.DebugTrees: false +physics.producers.beamTiming.DebugTrees: false physics.analyzers.flashana.DumpWaveformsInfo: true physics.analyzers.flashana.SaveRawWaveforms: false diff --git a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl index b45fd5d37..e64474a00 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl @@ -110,7 +110,7 @@ ICARUSFlashAssAna: { BaselineLabels: ["pmtbaselines"] OpHitLabels: ["ophit"] FlashLabels: ["opflashCryoE", "opflashCryoW"] - RWMLabel: "beam:RWM" + RWMLabel: "beamTiming:RWM" PEOpHitThreshold: 0 Debug: false } @@ -119,7 +119,7 @@ ICARUSBeamStructureAna: { module_type: "ICARUSBeamStructureAna" FlashLabels: ["opflashCryoE", "opflashCryoW"] TriggerLabel: "daqTrigger" - RWMLabel: "beam:RWM" + RWMLabel: "beamTiming:RWM" TriggerConfigLabel: "triggerconfig" CRTPMTMatchingLabel: "crtpmt" } From 1386b6a8289212cbf9045a7b38e1093fe087e019 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 25 Sep 2024 10:19:06 -0500 Subject: [PATCH 21/52] adjust formatting and indentation to 2 spaces --- icaruscode/IcarusObj/PMTBeamSignal.h | 82 +- .../OpReco/ICARUSBeamStructureAna_module.cc | 621 ++++++------ .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 883 +++++++++--------- .../Timing/PMTBeamSignalsExtractor_module.cc | 443 ++++----- 4 files changed, 1049 insertions(+), 980 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index 753bdecac..5ae993ca1 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -11,47 +11,47 @@ // C/C++ standard libraries #include -namespace icarus::timing{ - - /// Special value to denote no special channel information - static constexpr auto NoChannel = std::numeric_limits::max(); - /// Special value to denote no time channel information - static constexpr double NoTime = 0.; - /// Special value to denote no sample information - static constexpr size_t NoSample = 0; - - struct PMTBeamSignal { - - /// Special channel this time was extracted from - unsigned int specialChannel = NoChannel; - - /// Board on which the special channel is on - std::string digitizerLabel = ""; - - /// Crate this time applies to - std::string crate = ""; - - /// Sample within the waveform where the reference signal is found - size_t sample = NoSample; - - /// Start time in electronics time [us] - double startTimeAbs = NoTime; - - /// Start time relative to trigger time [us] - double startTime = NoTime; - - PMTBeamSignal(unsigned int ch, std::string b, std::string c, - size_t s, double t, double tt): - specialChannel(ch), digitizerLabel(b), crate(c), sample(s), - startTimeAbs(t), startTime(tt) {}; - - PMTBeamSignal(){}; - - /// Returns whether the time is valid. - bool isValid() const { return ((sample != NoSample) && (startTime != NoTime)); } - - }; +namespace icarus::timing +{ + + /// Special value to denote no special channel information + static constexpr auto NoChannel = std::numeric_limits::max(); + /// Special value to denote no time channel informatio + static constexpr double NoTime = 0.; + // Special value to denote no sample information + static constexpr size_t NoSample = 0; + + struct PMTBeamSignal + { + + /// Special channel this time was extracted from + unsigned int specialChannel = NoChannel; + + /// Board on which the special channel is on + std::string digitizerLabel = ""; + + /// Crate this time applies to + std::string crate = ""; + + /// Sample within the waveform where the reference signal is found + size_t sample = NoSample; + + /// Start time in electronics time [us] + double startTimeAbs = NoTime; + + /// Start time relative to trigger time [us] + double startTime = NoTime; + + PMTBeamSignal(unsigned int ch, std::string b, std::string c, + size_t s, double t, double tt) : specialChannel(ch), digitizerLabel(b), crate(c), sample(s), + startTimeAbs(t), startTime(tt) {}; + + PMTBeamSignal() {}; + + /// Returns whether the time is valid. + bool isValid() const { return ((sample != NoSample) && (startTime != NoTime)); } + }; } // namespace icarus::timing -#endif //ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H +#endif // ICARUSCODE_ICARUSOBJ_PMTBEAMSIGNAL_H diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index fdbcf66fc..0bee5765c 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -9,7 +9,7 @@ // framework libraries #include "canvas/Utilities/InputTag.h" -#include "art/Framework/Services/Registry/ServiceHandle.h" +#include "art/Framework/Services/Registry/ServiceHandle.h" #include "art/Framework/Core/EDAnalyzer.h" #include "art/Framework/Core/ModuleMacros.h" #include "art/Framework/Principal/Event.h" @@ -52,361 +52,384 @@ #include // ----------------------------------------------------------------------------- -namespace opana { class ICARUSBeamStructureAna; } +namespace opana +{ + class ICARUSBeamStructureAna; +} -class opana::ICARUSBeamStructureAna : public art::EDAnalyzer { - public: - struct Config { - fhicl::Sequence FlashLabels { +class opana::ICARUSBeamStructureAna : public art::EDAnalyzer +{ +public: + struct Config + { + fhicl::Sequence FlashLabels{ fhicl::Name("FlashLabels"), - fhicl::Comment("Tags for the recob::OpFlash data products") - }; - fhicl::Atom TriggerLabel { + fhicl::Comment("Tags for the recob::OpFlash data products")}; + fhicl::Atom TriggerLabel{ fhicl::Name("TriggerLabel"), - fhicl::Comment("Tag for trigger info") - }; - fhicl::Atom RWMLabel { + fhicl::Comment("Tag for trigger info")}; + fhicl::Atom RWMLabel{ fhicl::Name("RWMLabel"), - fhicl::Comment("Tag for RWM info") - }; - fhicl::Atom TriggerConfigLabel { + fhicl::Comment("Tag for RWM info")}; + fhicl::Atom TriggerConfigLabel{ fhicl::Name("TriggerConfigLabel"), - fhicl::Comment("Trigger configuration label") - }; - fhicl::Atom CRTPMTMatchingLabel { + fhicl::Comment("Trigger configuration label")}; + fhicl::Atom CRTPMTMatchingLabel{ fhicl::Name("CRTPMTMatchingLabel"), - fhicl::Comment("CRTPMT matching label") - }; - }; // struct Config - - using Parameters = art::EDAnalyzer::Table; - - /// constructor - explicit ICARUSBeamStructureAna(Parameters const& config); - - /// Return RWM-relative time from a trigger-relative time - double getRWMRelativeTime(int channel, double t); - - /// Return side/wall from channel id - int getSideByChannel(const int channel); - - /// Return the RWM-relative flash interaction time - double getFlashBunchTime(std::vector channels, std::vector hit_rise_time); - - /// Clear all data structures - void clear(); - - void analyze(art::Event const& e) override; - void beginJob(); - void beginRun(const art::Run& run) override; - - private: - - art::ServiceHandle tfs; - icarus::TriggerConfiguration fTriggerConfiguration; - - std::vector fFlashLabels; - art::InputTag fTriggerLabel; - art::InputTag fRWMLabel; - art::InputTag fTriggerConfigurationLabel; - art::InputTag fCRTPMTMatchingLabel; - - /// data members - std::vector fOpFlashTrees; - - int m_run; - int m_event; - int m_timestamp; - - // trigger info - unsigned int m_gate_type; - int m_trigger_type=-1; - std::string m_gate_name; - uint64_t m_trigger_timestamp; - uint64_t m_beam_gate_timestamp; - double m_beam_us; - double m_trigger_us; - double m_beam_gate_width; - - // flash info - int m_cryo; - int m_flash_id; - double m_flash_time; - double m_flash_time_rwm; - double m_flash_z; - double m_flash_y; - double m_flash_pe; - int m_flash_nhits; - std::vector m_channel_id; - std::vector m_hit_start_time; - std::vector m_hit_peak_time; - std::vector m_hit_rise_time; - std::vector m_hit_start_time_rwm; - std::vector m_hit_peak_time_rwm; - std::vector m_hit_rise_time_rwm; - std::vector m_hit_pe; - - //crt-pmt match - int m_flash_classification; - int m_flash_ncrthits; - std::vector m_crthit_x; - std::vector m_crthit_y; - std::vector m_crthit_z; - std::vector m_crttime_us; - std::vector m_crtpmttimediff_ns; - std::vector m_crtsys; - std::vector m_crtregion; - - // RWM times - std::vector fRWMTimes; + fhicl::Comment("CRTPMT matching label")}; + }; // struct Config + + using Parameters = art::EDAnalyzer::Table; + + /// constructor + explicit ICARUSBeamStructureAna(Parameters const &config); + + /// Return RWM-relative time from a trigger-relative time + double getRWMRelativeTime(int channel, double t); + + /// Return side/wall from channel id + int getSideByChannel(const int channel); + + /// Return the RWM-relative flash interaction time + double getFlashBunchTime(std::vector channels, std::vector hit_rise_time); + + /// Clear all data structures + void clear(); + + void analyze(art::Event const &e) override; + void beginJob(); + void beginRun(const art::Run &run) override; + +private: + art::ServiceHandle tfs; + icarus::TriggerConfiguration fTriggerConfiguration; + + std::vector fFlashLabels; + art::InputTag fTriggerLabel; + art::InputTag fRWMLabel; + art::InputTag fTriggerConfigurationLabel; + art::InputTag fCRTPMTMatchingLabel; + + /// data members + std::vector fOpFlashTrees; + + int m_run; + int m_event; + int m_timestamp; + + // trigger info + unsigned int m_gate_type; + int m_trigger_type = -1; + std::string m_gate_name; + uint64_t m_trigger_timestamp; + uint64_t m_beam_gate_timestamp; + double m_beam_us; + double m_trigger_us; + double m_beam_gate_width; + + // flash info + int m_cryo; + int m_flash_id; + double m_flash_time; + double m_flash_time_rwm; + double m_flash_z; + double m_flash_y; + double m_flash_pe; + int m_flash_nhits; + std::vector m_channel_id; + std::vector m_hit_start_time; + std::vector m_hit_peak_time; + std::vector m_hit_rise_time; + std::vector m_hit_start_time_rwm; + std::vector m_hit_peak_time_rwm; + std::vector m_hit_rise_time_rwm; + std::vector m_hit_pe; + + // crt-pmt match + int m_flash_classification; + int m_flash_ncrthits; + std::vector m_crthit_x; + std::vector m_crthit_y; + std::vector m_crthit_z; + std::vector m_crttime_us; + std::vector m_crtpmttimediff_ns; + std::vector m_crtsys; + std::vector m_crtregion; + + // RWM times + std::vector fRWMTimes; }; // -------------------------------------------------------------------------- -opana::ICARUSBeamStructureAna::ICARUSBeamStructureAna(Parameters const& config) - : art::EDAnalyzer(config) - , fFlashLabels( config().FlashLabels() ) - , fTriggerLabel( config().TriggerLabel() ) - , fRWMLabel ( config().RWMLabel() ) - , fTriggerConfigurationLabel( config().TriggerConfigLabel() ) - , fCRTPMTMatchingLabel( config().CRTPMTMatchingLabel() ) -{} +opana::ICARUSBeamStructureAna::ICARUSBeamStructureAna(Parameters const &config) + : art::EDAnalyzer(config), fFlashLabels(config().FlashLabels()), fTriggerLabel(config().TriggerLabel()), fRWMLabel(config().RWMLabel()), fTriggerConfigurationLabel(config().TriggerConfigLabel()), fCRTPMTMatchingLabel(config().CRTPMTMatchingLabel()) +{ +} // --------------------------------------------------------------------------- -void opana::ICARUSBeamStructureAna::beginJob() { +void opana::ICARUSBeamStructureAna::beginJob() +{ + + if (!fFlashLabels.empty()) + { + + for (auto const &label : fFlashLabels) + { - if ( !fFlashLabels.empty() ) { - - for( auto const & label : fFlashLabels ) { - // TTree for the flash in a given cryostat - std::string name = "beamtiming_"+label.label(); - std::string info = "Beam timing from label "+label.label(); - - TTree* ttree = tfs->make(name.c_str(), info.c_str() ); - ttree->Branch("run",&m_run); - ttree->Branch("event",&m_event); - ttree->Branch("timestamp",&m_timestamp); - + std::string name = "beamtiming_" + label.label(); + std::string info = "Beam timing from label " + label.label(); + + TTree *ttree = tfs->make(name.c_str(), info.c_str()); + ttree->Branch("run", &m_run); + ttree->Branch("event", &m_event); + ttree->Branch("timestamp", &m_timestamp); + ttree->Branch("gate_type", &m_gate_type); ttree->Branch("gate_name", &m_gate_name); ttree->Branch("beam_gate_us", &m_beam_us); ttree->Branch("trigger_us", &m_trigger_us); - ttree->Branch("beam_gate_width",&m_beam_gate_width); + ttree->Branch("beam_gate_width", &m_beam_gate_width); ttree->Branch("trigger_type", &m_trigger_type, "trigger_type/I"); ttree->Branch("trigger_timestamp", &m_trigger_timestamp, "trigger_timestamp/l"); ttree->Branch("beam_gate_timestamp", &m_beam_gate_timestamp, "beam_gate_timestamp/l"); - - ttree->Branch("cryo",&m_cryo); - ttree->Branch("flash_id",&m_flash_id); - ttree->Branch("flash_time",&m_flash_time); - ttree->Branch("flash_time_rwm",&m_flash_time_rwm); - ttree->Branch("flash_pe",&m_flash_pe); - ttree->Branch("flash_z",&m_flash_z); - ttree->Branch("flash_y",&m_flash_y); - ttree->Branch("flash_nhits",&m_flash_nhits); - ttree->Branch("channels",&m_channel_id); - ttree->Branch("hit_start_time",&m_hit_start_time); - ttree->Branch("hit_peak_time",&m_hit_peak_time); - ttree->Branch("hit_rise_time",&m_hit_rise_time); - ttree->Branch("hit_start_time_rwm",&m_hit_start_time_rwm); - ttree->Branch("hit_peak_time_rwm",&m_hit_peak_time_rwm); - ttree->Branch("hit_rise_time_rwm",&m_hit_rise_time_rwm); - ttree->Branch("hit_pe",&m_hit_pe); - - ttree->Branch("flash_classification",&m_flash_classification); - ttree->Branch("flash_ncrthits",&m_flash_ncrthits); - ttree->Branch("crthit_x",&m_crthit_x); - ttree->Branch("crthit_y",&m_crthit_y); - ttree->Branch("crthit_z",&m_crthit_z); - ttree->Branch("crthit_sys",&m_crtsys); - ttree->Branch("crthit_region",&m_crtregion); - ttree->Branch("crttime_us",&m_crttime_us); - ttree->Branch("crtpmttimediff_ns",&m_crtpmttimediff_ns); - - fOpFlashTrees.push_back( ttree ); + + ttree->Branch("cryo", &m_cryo); + ttree->Branch("flash_id", &m_flash_id); + ttree->Branch("flash_time", &m_flash_time); + ttree->Branch("flash_time_rwm", &m_flash_time_rwm); + ttree->Branch("flash_pe", &m_flash_pe); + ttree->Branch("flash_z", &m_flash_z); + ttree->Branch("flash_y", &m_flash_y); + ttree->Branch("flash_nhits", &m_flash_nhits); + ttree->Branch("channels", &m_channel_id); + ttree->Branch("hit_start_time", &m_hit_start_time); + ttree->Branch("hit_peak_time", &m_hit_peak_time); + ttree->Branch("hit_rise_time", &m_hit_rise_time); + ttree->Branch("hit_start_time_rwm", &m_hit_start_time_rwm); + ttree->Branch("hit_peak_time_rwm", &m_hit_peak_time_rwm); + ttree->Branch("hit_rise_time_rwm", &m_hit_rise_time_rwm); + ttree->Branch("hit_pe", &m_hit_pe); + + ttree->Branch("flash_classification", &m_flash_classification); + ttree->Branch("flash_ncrthits", &m_flash_ncrthits); + ttree->Branch("crthit_x", &m_crthit_x); + ttree->Branch("crthit_y", &m_crthit_y); + ttree->Branch("crthit_z", &m_crthit_z); + ttree->Branch("crthit_sys", &m_crtsys); + ttree->Branch("crthit_region", &m_crtregion); + ttree->Branch("crttime_us", &m_crttime_us); + ttree->Branch("crtpmttimediff_ns", &m_crtpmttimediff_ns); + + fOpFlashTrees.push_back(ttree); } - } else { + } + else + { mf::LogError("ICARUSBeamStructureAna") - << "No flash labels selected!!"; + << "No flash labels selected!!"; } } -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ -void opana::ICARUSBeamStructureAna::beginRun(const art::Run& r) +void opana::ICARUSBeamStructureAna::beginRun(const art::Run &r) { fTriggerConfiguration = r.getProduct(fTriggerConfigurationLabel); } // ------------------------------------------------------------------------------- -void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) +void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) { // ---- // Event metadata information m_run = e.id().run(); m_event = e.id().event(); - m_timestamp = e.time().timeHigh(); // precision to the second - + m_timestamp = e.time().timeHigh(); // precision to the second + // ---- // Trigger metadata information detinfo::DetectorTimings const detTimings = detinfo::makeDetectorTimings( - art::ServiceHandle()->DataFor(e)); + art::ServiceHandle()->DataFor(e)); detinfo::timescales::electronics_time triggerTime = detTimings.TriggerTime(); - detinfo::timescales::electronics_time beamGateTime = detTimings.BeamGateTime(); + detinfo::timescales::electronics_time beamGateTime = detTimings.BeamGateTime(); + + if (!fTriggerLabel.empty()) + { - if( !fTriggerLabel.empty() ) { + auto const &extraInfo = e.getProduct(fTriggerLabel); - auto const& extraInfo = e.getProduct(fTriggerLabel); - - if( extraInfo.isValid() ) { + if (extraInfo.isValid()) + { sbn::triggerSource bit = extraInfo.sourceType; - m_gate_type = (unsigned int)bit; //1 BNB 2 NumI 3 offbeamBNB 4 offbeamNuMi + m_gate_type = (unsigned int)bit; // 1 BNB 2 NumI 3 offbeamBNB 4 offbeamNuMi m_gate_name = bitName(bit); - m_trigger_type = value( extraInfo.triggerType ); //1 majority, 2 minbias + m_trigger_type = value(extraInfo.triggerType); // 1 majority, 2 minbias // absolute timestamp m_trigger_timestamp = extraInfo.triggerTimestamp; - m_beam_gate_timestamp = extraInfo.beamGateTimestamp; - + m_beam_gate_timestamp = extraInfo.beamGateTimestamp; + // time in electronics time m_trigger_us = triggerTime.value(); m_beam_us = beamGateTime.value(); m_beam_gate_width = fTriggerConfiguration.getGateWidth(m_gate_type); - - } else { - mf::LogError("ICARUSBeamStructureAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!" ; } - } else { - mf::LogError("ICARUSBeamStructureAna") << "No trigger labels selected!!" ; + else + { + mf::LogError("ICARUSBeamStructureAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!"; + } + } + else + { + mf::LogError("ICARUSBeamStructureAna") << "No trigger labels selected!!"; } - + // ---- // RWM times fRWMTimes = e.getProduct>(fRWMLabel); - if ( fRWMTimes.empty() ) + if (fRWMTimes.empty()) mf::LogTrace("ICARUSBeamStructureAna") << "Data product std::vector for '" << fRWMLabel.label() - << "' is empty in " << m_gate_name << " event!"; - + << "' is empty in " << m_gate_name << " event!"; + // ---- // FLASH/CRT timing information - if ( !fFlashLabels.empty() ) { + if (!fFlashLabels.empty()) + { + + for (size_t iFlashLabel = 0; iFlashLabel < fFlashLabels.size(); iFlashLabel++) + { - for ( size_t iFlashLabel=0; iFlashLabel>(label); - auto const& flashes = *flash_handle; + auto const &flash_handle = e.getValidHandle>(label); + auto const &flashes = *flash_handle; // we want our flashes to be valid and not empty - if( !flash_handle.isValid() ) { - mf::LogError("ICARUSBeamStructureAna") << "Not found a recob::OpFlash with label '" << label.encode() << "'"; - } else if ( flashes.empty() ) { - mf::LogWarning("ICARUSBeamStructureAna") << "No recob::OpFlash in collection with label '" << label.encode() << "'"; - } else { - - art::FindManyP ophitsPtr( flash_handle, e, label ); - art::FindOneP matchPtr( flash_handle, e, fCRTPMTMatchingLabel ); - - // loop all flashes - size_t idx = 0; - for ( auto const& flash : flashes ) { - - // Filling flash info... + if (!flash_handle.isValid()) + { + mf::LogError("ICARUSBeamStructureAna") << "Not found a recob::OpFlash with label '" << label.encode() << "'"; + } + else if (flashes.empty()) + { + mf::LogWarning("ICARUSBeamStructureAna") << "No recob::OpFlash in collection with label '" << label.encode() << "'"; + } + else + { + + art::FindManyP ophitsPtr(flash_handle, e, label); + art::FindOneP matchPtr(flash_handle, e, fCRTPMTMatchingLabel); + + // loop all flashes + size_t idx = 0; + for (auto const &flash : flashes) + { + + // Filling flash info... m_flash_id = idx; m_flash_time = flash.Time(); m_flash_pe = flash.TotalPE(); m_flash_z = flash.ZCenter(); m_flash_y = flash.YCenter(); - + // ---- - // CRT match info - - auto const & match = matchPtr.at(idx); - - // if there is no match, there is no product - // fill null parameters - if( !match ) { - m_flash_classification = 0; - m_flash_ncrthits = 0; - } else { - m_flash_classification = static_cast(match->flashClassification); - m_flash_ncrthits = match->matchedCRTHits.size(); - - for( auto const& crthit: match->matchedCRTHits ){ - m_crthit_x.push_back(crthit.position.X()); + // CRT match info + + auto const &match = matchPtr.at(idx); + + // if there is no match, there is no product + // fill null parameters + if (!match) + { + m_flash_classification = 0; + m_flash_ncrthits = 0; + } + else + { + m_flash_classification = static_cast(match->flashClassification); + m_flash_ncrthits = match->matchedCRTHits.size(); + + for (auto const &crthit : match->matchedCRTHits) + { + m_crthit_x.push_back(crthit.position.X()); m_crthit_y.push_back(crthit.position.Y()); m_crthit_z.push_back(crthit.position.Z()); m_crttime_us.push_back(crthit.time); - m_crtpmttimediff_ns.push_back(1e3*crthit.PMTTimeDiff); + m_crtpmttimediff_ns.push_back(1e3 * crthit.PMTTimeDiff); m_crtsys.push_back(crthit.sys); m_crtregion.push_back(crthit.region); } } - + // ---- // OPHITS info - auto const & ophits = ophitsPtr.at(idx); - - std::map startmap; - std::map peakmap; - std::map risemap; - std::map pemap; - + auto const &ophits = ophitsPtr.at(idx); + + std::map startmap; + std::map peakmap; + std::map risemap; + std::map pemap; + // loop all hits in the flash: save only the first one - for ( auto const hit : ophits ){ - + for (auto const hit : ophits) + { + const int ch = hit->OpChannel(); double ts = hit->StartTime(); - double tp = hit->PeakTime(); - double tr = hit->RiseTime(); - double pe = hit->PE(); - + double tp = hit->PeakTime(); + double tr = hit->RiseTime(); + double pe = hit->PE(); + // select the first ophit (by time) in each channel - if ( startmap.find(ch) != startmap.end() ){ - if ( ts < startmap[ch] ){ + if (startmap.find(ch) != startmap.end()) + { + if (ts < startmap[ch]) + { startmap[ch] = ts; - peakmap[ch] = tp; - risemap[ch] = ts+tr; - pemap[ch] = pe; - } - } else { + peakmap[ch] = tp; + risemap[ch] = ts + tr; + pemap[ch] = pe; + } + } + else + { startmap[ch] = ts; peakmap[ch] = tp; - risemap[ch] = ts+tr; + risemap[ch] = ts + tr; pemap[ch] = pe; - } + } } // get number of unique PMTs in flash m_flash_nhits = startmap.size(); - for(auto it = startmap.begin(); it!=startmap.end(); it++) { + for (auto it = startmap.begin(); it != startmap.end(); it++) + { int ch = it->first; m_channel_id.push_back(ch); m_hit_start_time.push_back(it->second); m_hit_peak_time.push_back(peakmap[ch]); m_hit_rise_time.push_back(risemap[ch]); - m_hit_start_time_rwm.push_back(getRWMRelativeTime(ch,it->second)); - m_hit_peak_time_rwm.push_back(getRWMRelativeTime(ch,peakmap[ch])); - m_hit_rise_time_rwm.push_back(getRWMRelativeTime(ch,risemap[ch])); + m_hit_start_time_rwm.push_back(getRWMRelativeTime(ch, it->second)); + m_hit_peak_time_rwm.push_back(getRWMRelativeTime(ch, peakmap[ch])); + 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); + m_flash_time_rwm = getFlashBunchTime(m_channel_id, m_hit_rise_time_rwm); fOpFlashTrees[iFlashLabel]->Fill(); clear(); - idx++; + idx++; } } } @@ -415,14 +438,15 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const& e) // ----------------------------------------------------------------------------- -int opana::ICARUSBeamStructureAna::getSideByChannel( const int channel ) { +int opana::ICARUSBeamStructureAna::getSideByChannel(const int channel) +{ - /* + /* Channels are numbered from east to west, from North (cryo side) to South (beam side) - We look in the opposide direction wrt to the beam direction South->North: + We look in the opposide direction wrt to the beam direction South->North: - Left is the east wall of each cryostat; - Right is the west side of each cryostat; - - [ 0:89 ] and [180:269] are on the left, + - [ 0:89 ] and [180:269] are on the left, the return value of the function is 0; - [ 90-179 ] and [ 270:359 ] are on the right, the return value of the function is 1; @@ -434,92 +458,103 @@ int opana::ICARUSBeamStructureAna::getSideByChannel( const int channel ) { // ----------------------------------------------------------------------------- -double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) { +double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) +{ - if( fRWMTimes.empty() ) return 0; + if (fRWMTimes.empty()) + return 0; auto rwm = fRWMTimes.at(channel); - if ( !rwm.isValid() ){ + if (!rwm.isValid()) + { mf::LogTrace("ICARUSBeamStructureAna") << "No RWM signal for channel " << channel << " " - << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel + << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel << ", SpecialChannel " << rwm.specialChannel << ")" - << " in event " << m_event << " gate " << m_gate_name; + << " in event " << m_event << " gate " << m_gate_name; return 0; } - double rwm_trigger = rwm.startTime; //rwm time w.r.t. trigger time [us] + double rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] return (t - rwm_trigger); - } // ----------------------------------------------------------------------------- -double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channels, std::vector hit_rise_time_rwm) { +double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channels, std::vector hit_rise_time_rwm) +{ double tfirst_left = std::numeric_limits::max(); double tfirst_right = std::numeric_limits::max(); - + // if no RWM info available, all pmt_start_time_rwm is zero // return zero as well for the flash - if (fRWMTimes.empty()) return 0; - + if (fRWMTimes.empty()) + return 0; + int nleft = 0; int nright = 0; - for(size_t i=0; i // std::accumulate #include - -namespace opana { +namespace opana +{ class ICARUSFlashAssAna; } +class opana::ICARUSFlashAssAna : public art::EDAnalyzer +{ -class opana::ICARUSFlashAssAna : public art::EDAnalyzer { - - public: +public: + struct Config + { - struct Config { + using Name = fhicl::Name; + using Comment = fhicl::Comment; - using Name = fhicl::Name; - using Comment = fhicl::Comment; - - fhicl::Atom TriggerLabel { + fhicl::Atom TriggerLabel{ Name("TriggerLabel"), - Comment("Label for the Trigger fragment label") - }; + Comment("Label for the Trigger fragment label")}; - fhicl::Atom DumpWaveformsInfo { + fhicl::Atom DumpWaveformsInfo{ Name("DumpWaveformsInfo"), - Comment("Set the option to save some aggregated waveform information") - }; - - fhicl::Atom SaveRawWaveforms { + Comment("Set the option to save some aggregated waveform information")}; + + fhicl::Atom SaveRawWaveforms{ Name("SaveRawWaveforms"), - Comment("Set to save the full raw::OpDetWaveforms") - }; - - fhicl::Atom UseSharedBaseline { + Comment("Set to save the full raw::OpDetWaveforms")}; + + fhicl::Atom UseSharedBaseline{ Name("UseSharedBaseline"), - Comment("Set the option to use icarus::WaveformBaseline") - }; - - fhicl::Sequence OpDetWaveformLabels { + Comment("Set the option to use icarus::WaveformBaseline")}; + + fhicl::Sequence OpDetWaveformLabels{ Name("OpDetWaveformLabels"), - Comment("Tags for the raw::OpDetWaveform data products") - }; - - fhicl::Sequence BaselineLabels { + Comment("Tags for the raw::OpDetWaveform data products")}; + + fhicl::Sequence BaselineLabels{ Name("BaselineLabels"), - Comment("Tags for the icarus::WaveformBaseline data products") - }; + Comment("Tags for the icarus::WaveformBaseline data products")}; - fhicl::Sequence OpHitLabels { + fhicl::Sequence OpHitLabels{ Name("OpHitLabels"), - Comment("Tags for the recob::OpHit data products") - }; + Comment("Tags for the recob::OpHit data products")}; - fhicl::Sequence FlashLabels { + fhicl::Sequence FlashLabels{ Name("FlashLabels"), - Comment("Tags for the recob::Flashe data products") - }; - - fhicl::Atom RWMLabel { + Comment("Tags for the recob::Flashe data products")}; + + 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 { + fhicl::Atom PEOpHitThreshold{ Name("PEOpHitThreshold"), - Comment("Threshold in PE for an OpHit to be considered in the information calculated for a flash") - }; + Comment("Threshold in PE for an OpHit to be considered in the information calculated for a flash")}; - fhicl::Atom Debug { + fhicl::Atom Debug{ Name("Debug"), Comment("Be more verbose"), - false - }; - - }; - - using Parameters = art::EDAnalyzer::Table; - - explicit ICARUSFlashAssAna(Parameters const& config); - - ICARUSFlashAssAna(ICARUSFlashAssAna const&) = delete; - ICARUSFlashAssAna(ICARUSFlashAssAna&&) = delete; - ICARUSFlashAssAna& operator=(ICARUSFlashAssAna const&) = delete; - ICARUSFlashAssAna& operator=(ICARUSFlashAssAna&&) = delete; - - void analyze(art::Event const& e) override; - void beginJob() override; - - /// Compute median of waveform for baseline (fallback option) - template T Median( std::vector data ) const; - - /// Return cryostat from PMT channel_id - geo::CryostatID::CryostatID_t getCryostatByChannel( int channel ); - - /// Return wall from PMT channel_id - int getSideByChannel( const int channel ); - - /// Process OpHits in the absence of flashes - void processOpHits( art::Event const& e, unsigned int cryo ); - - /// Process Ophits in the presence of flashes - void processOpHitsFlash( std::vector> const &ophits, - int &multiplicity_left, int &multiplicity_right, - float &sum_pe_left, float &sum_pe_right, - std::vector &pmt_start_time, - std::vector &pmt_rise_time, - std::vector &pmt_start_rwm_time, - std::vector &pmt_pe, - std::vector &pmt_amplitude, - TTree *ophittree ); - - /// Return RWM-relative time from a trigger-relative time - float getRWMRelativeTime(int channel, float t); - - /// Return the RWM-relative flash interaction time - float getFlashBunchTime(std::vector pmt_start_time_rwm, - std::vector pmt_rise_time); - - private: - - //---------- - // Input parameters - - art::InputTag fTriggerLabel; - bool fSaveWaveformInfo; - bool fSaveRawWaveforms; - bool fUseSharedBaseline; - std::vector fOpDetWaveformLabels; - std::vector fBaselineLabels; - std::vector fOpHitLabels; - std::vector fFlashLabels; - art::InputTag fRWMLabel; - float fPEOpHitThreshold; - bool fDebug; - - //---------- - // Output trees - - TTree *fEventTree; - std::vector fOpDetWaveformTrees; - std::vector fOpFlashTrees; - std::vector fOpHitTrees; - std::vector fOpHitFlashTrees; - - //---------------- - // Output variables - - // Common - int m_run; - int m_event; - int m_timestamp; - - // Event/trigger tree - float m_beam_gate_start=-99999; - float m_beam_gate_width=-99999; - int m_beam_type=-1; - int m_trigger_type=-1; - unsigned int m_gate_type; - std::string m_gate_name; - uint64_t m_trigger_timestamp; - uint64_t m_gate_start_timestamp; - uint64_t m_trigger_gate_diff; - uint64_t lvdsCryoE[2]; - uint64_t lvdsCryoW[2]; - uint16_t addersCryoE[2]; - uint16_t addersCryoW[2]; - - // Flash trees - int m_flash_id; - int m_multiplicity; - int m_multiplicity_left; - int m_multiplicity_right; - float m_sum_pe; - float m_sum_pe_left; - float m_sum_pe_right; - float m_flash_time; - float m_flash_time_rwm; - float m_flash_y; - float m_flash_width_y; - float m_flash_z; - float m_flash_width_z; - std::vector m_pmt_start_time; - std::vector m_pmt_rise_time; - std::vector m_pmt_start_time_rwm; - std::vector m_pmt_pe; - std::vector m_pmt_amplitude; - - // Ophit trees - int m_channel_id; - float m_integral; // in ADC x tick - float m_amplitude; // in ADC - float m_start_time; - float m_peak_time; - float m_rise_time; - float m_width; - float m_abs_start_time; - float m_start_time_rwm; - float m_peak_time_rwm; - float m_pe; - float m_fast_to_total; - - // Waveform trees - float m_wf_start; - short m_baseline; - short m_chargesum; - int m_nticks; - std::vector m_wf; - - // Geometry tree - std::vector m_pmt_x; - std::vector m_pmt_y; - std::vector m_pmt_z; - - //---------- - // Support variables/products - - geo::GeometryCore const* fGeom; - std::vector fRWMTimes; - + false}; + }; + + using Parameters = art::EDAnalyzer::Table; + + explicit ICARUSFlashAssAna(Parameters const &config); + + ICARUSFlashAssAna(ICARUSFlashAssAna const &) = delete; + ICARUSFlashAssAna(ICARUSFlashAssAna &&) = delete; + ICARUSFlashAssAna &operator=(ICARUSFlashAssAna const &) = delete; + ICARUSFlashAssAna &operator=(ICARUSFlashAssAna &&) = delete; + + void analyze(art::Event const &e) override; + void beginJob() override; + + /// Compute median of waveform for baseline (fallback option) + template + T Median(std::vector data) const; + + /// Return cryostat from PMT channel_id + geo::CryostatID::CryostatID_t getCryostatByChannel(int channel); + + /// Return wall from PMT channel_id + int getSideByChannel(const int channel); + + /// Process OpHits in the absence of flashes + void processOpHits(art::Event const &e, unsigned int cryo); + + /// Process Ophits in the presence of flashes + void processOpHitsFlash(std::vector> const &ophits, + int &multiplicity_left, int &multiplicity_right, + float &sum_pe_left, float &sum_pe_right, + std::vector &pmt_start_time, + std::vector &pmt_rise_time, + std::vector &pmt_start_rwm_time, + std::vector &pmt_pe, + std::vector &pmt_amplitude, + TTree *ophittree); + + /// Return RWM-relative time from a trigger-relative time + float getRWMRelativeTime(int channel, float t); + + /// Return the RWM-relative flash interaction time + float getFlashBunchTime(std::vector pmt_start_time_rwm, + std::vector pmt_rise_time); + +private: + //---------- + // Input parameters + + art::InputTag fTriggerLabel; + bool fSaveWaveformInfo; + bool fSaveRawWaveforms; + bool fUseSharedBaseline; + std::vector fOpDetWaveformLabels; + std::vector fBaselineLabels; + std::vector fOpHitLabels; + std::vector fFlashLabels; + art::InputTag fRWMLabel; + float fPEOpHitThreshold; + bool fDebug; + + //---------- + // Output trees + + TTree *fEventTree; + std::vector fOpDetWaveformTrees; + std::vector fOpFlashTrees; + std::vector fOpHitTrees; + std::vector fOpHitFlashTrees; + + //---------------- + // Output variables + + // Common + int m_run; + int m_event; + int m_timestamp; + + // Event/trigger tree + float m_beam_gate_start = -99999; + float m_beam_gate_width = -99999; + int m_beam_type = -1; + int m_trigger_type = -1; + unsigned int m_gate_type; + std::string m_gate_name; + uint64_t m_trigger_timestamp; + uint64_t m_gate_start_timestamp; + uint64_t m_trigger_gate_diff; + uint64_t lvdsCryoE[2]; + uint64_t lvdsCryoW[2]; + uint16_t addersCryoE[2]; + uint16_t addersCryoW[2]; + + // Flash trees + int m_flash_id; + int m_multiplicity; + int m_multiplicity_left; + int m_multiplicity_right; + float m_sum_pe; + float m_sum_pe_left; + float m_sum_pe_right; + float m_flash_time; + float m_flash_time_rwm; + float m_flash_y; + float m_flash_width_y; + float m_flash_z; + float m_flash_width_z; + std::vector m_pmt_start_time; + std::vector m_pmt_rise_time; + std::vector m_pmt_start_time_rwm; + std::vector m_pmt_pe; + std::vector m_pmt_amplitude; + + // Ophit trees + int m_channel_id; + float m_integral; // in ADC x tick + float m_amplitude; // in ADC + float m_start_time; + float m_peak_time; + float m_rise_time; + float m_width; + float m_abs_start_time; + float m_start_time_rwm; + float m_peak_time_rwm; + float m_pe; + float m_fast_to_total; + + // Waveform trees + float m_wf_start; + short m_baseline; + short m_chargesum; + int m_nticks; + std::vector m_wf; + + // Geometry tree + std::vector m_pmt_x; + std::vector m_pmt_y; + std::vector m_pmt_z; + + //---------- + // Support variables/products + + geo::GeometryCore const *fGeom; + std::vector fRWMTimes; }; // ---------------------------------------------------------------------------- -opana::ICARUSFlashAssAna::ICARUSFlashAssAna(Parameters const& config) - : EDAnalyzer(config) - , fTriggerLabel( config().TriggerLabel() ) - , fSaveWaveformInfo( config().DumpWaveformsInfo() ) - , fSaveRawWaveforms( config().SaveRawWaveforms() ) - , fUseSharedBaseline( config().UseSharedBaseline() ) - , fOpDetWaveformLabels( config().OpDetWaveformLabels() ) - , fBaselineLabels( config().BaselineLabels() ) - , fOpHitLabels( config().OpHitLabels() ) - , fFlashLabels( config().FlashLabels() ) - , fRWMLabel( config().RWMLabel() ) - , fPEOpHitThreshold( config().PEOpHitThreshold() ) - , fDebug( config().Debug() ) - , fGeom( lar::providerFrom() ) -{ } +opana::ICARUSFlashAssAna::ICARUSFlashAssAna(Parameters const &config) + : EDAnalyzer(config), fTriggerLabel(config().TriggerLabel()), fSaveWaveformInfo(config().DumpWaveformsInfo()), fSaveRawWaveforms(config().SaveRawWaveforms()), fUseSharedBaseline(config().UseSharedBaseline()), fOpDetWaveformLabels(config().OpDetWaveformLabels()), fBaselineLabels(config().BaselineLabels()), fOpHitLabels(config().OpHitLabels()), fFlashLabels(config().FlashLabels()), fRWMLabel(config().RWMLabel()), fPEOpHitThreshold(config().PEOpHitThreshold()), fDebug(config().Debug()), fGeom(lar::providerFrom()) +{ +} // ---------------------------------------------------------------------------- -void opana::ICARUSFlashAssAna::beginJob() { +void opana::ICARUSFlashAssAna::beginJob() +{ art::ServiceHandle tfs; // Setting up the GEOMETRY tree // Channel id corresponds to vector index - TTree* fGeoTree = tfs->make("geotree", "geometry information" ); - fGeoTree->Branch("pmt_x",&m_pmt_x); - fGeoTree->Branch("pmt_y",&m_pmt_y); - fGeoTree->Branch("pmt_z",&m_pmt_z); - - for(size_t opch=0; opchNOpChannels(); ++opch) { + TTree *fGeoTree = tfs->make("geotree", "geometry information"); + fGeoTree->Branch("pmt_x", &m_pmt_x); + fGeoTree->Branch("pmt_y", &m_pmt_y); + fGeoTree->Branch("pmt_z", &m_pmt_z); + + for (size_t opch = 0; opch < fGeom->NOpChannels(); ++opch) + { auto const PMTxyz = fGeom->OpDetGeoFromOpChannel(opch).GetCenter(); m_pmt_x.push_back(PMTxyz.X()); m_pmt_y.push_back(PMTxyz.Y()); m_pmt_z.push_back(PMTxyz.Z()); - } fGeoTree->Fill(); // Settinp up the EVENT tree // Trigger information and LVDS status - fEventTree = tfs->make("eventstree", "higher level information on the event" ); + fEventTree = tfs->make("eventstree", "higher level information on the event"); fEventTree->Branch("run", &m_run, "run/I"); fEventTree->Branch("event", &m_event, "event/I"); fEventTree->Branch("timestamp", &m_timestamp, "timestamp/I"); @@ -330,42 +307,45 @@ void opana::ICARUSFlashAssAna::beginJob() { fEventTree->Branch("lvdsCryoW", &lvdsCryoW, "lvdsCryoW[2]/l"); fEventTree->Branch("addersCryoE", &addersCryoE, "addersCryoE[2]/s"); fEventTree->Branch("addersCryoW", &addersCryoW, "addersCryoW[2]/s"); - + // Setting up the WAVEFORM trees (one per product label) // This tree will hold some aggregated optical waveform information // The flag must be enabled to have the information saved - if( !fOpDetWaveformLabels.empty() && fSaveWaveformInfo ) { - - for( auto const & label : fOpDetWaveformLabels ) { + if (!fOpDetWaveformLabels.empty() && fSaveWaveformInfo) + { + + for (auto const &label : fOpDetWaveformLabels) + { - std::string name = label.label()+label.instance()+"wfttree"; + std::string name = label.label() + label.instance() + "wfttree"; std::string info = "TTree with aggregated optical waveform information with label: " + label.label(); - TTree* ttree = tfs->make(name.c_str(), info.c_str()); + TTree *ttree = tfs->make(name.c_str(), info.c_str()); ttree->Branch("run", &m_run, "run/I"); ttree->Branch("event", &m_event, "event/I"); ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); ttree->Branch("channel_id", &m_channel_id, "channel_id/I"); - ttree->Branch("wf_start",&m_wf_start,"wf_start/F"); + ttree->Branch("wf_start", &m_wf_start, "wf_start/F"); ttree->Branch("baseline", &m_baseline, "baseline/s"); ttree->Branch("chargesum", &m_chargesum, "chargesum/s"); ttree->Branch("nticks", &m_nticks, "nticks/I"); - if ( fSaveRawWaveforms ) ttree->Branch("wf",&m_wf); + if (fSaveRawWaveforms) + ttree->Branch("wf", &m_wf); fOpDetWaveformTrees.push_back(ttree); - } } // Setting up the OPHIT trees (one per cryostat) // This ttree will hold the ophit information when a flash is not found in the event // NB: information of the optical hits in events where flashes are present are lost - for( auto const & label : fOpHitLabels ) { + for (auto const &label : fOpHitLabels) + { - std::string name = label.label()+"_ttree"; + std::string name = label.label() + "_ttree"; std::string info = "TTree for the recob::OpHit objects with label " + label.label() + " in events without flashes."; - TTree* ttree = tfs->make(name.c_str(), info.c_str()); + TTree *ttree = tfs->make(name.c_str(), info.c_str()); ttree->Branch("run", &m_run, "run/I"); ttree->Branch("event", &m_event, "event/I"); ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); @@ -381,30 +361,31 @@ void opana::ICARUSFlashAssAna::beginJob() { ttree->Branch("pe", &m_pe, "pe/F"); ttree->Branch("width", &m_width, "width/F"); ttree->Branch("fast_to_total", &m_fast_to_total, "fast_to_total/F"); - - fOpHitTrees.push_back(ttree); + fOpHitTrees.push_back(ttree); } // Setting up the OPFLASH/OPHITS trees (one per cryostat) // These ttrees hold the information for the ophits and the flashes // NB: information of the optical hits is stored differently when flashes are found - if ( !fFlashLabels.empty() ) { + if (!fFlashLabels.empty()) + { - for( auto const & label : fFlashLabels ) { + for (auto const &label : fFlashLabels) + { // TTree for the flash in a given cryostat - std::string name = label.label()+"_flashtree"; - std::string info = "TTree for the recob::Flashes with label "+label.label(); + std::string name = label.label() + "_flashtree"; + std::string info = "TTree for the recob::Flashes with label " + label.label(); - TTree* ttree = tfs->make(name.c_str(), info.c_str() ); + TTree *ttree = tfs->make(name.c_str(), info.c_str()); ttree->Branch("run", &m_run, "run/I"); ttree->Branch("event", &m_event, "event/I"); ttree->Branch("timestamp", &m_timestamp, "timestamp/I"); ttree->Branch("flash_id", &m_flash_id, "flash_id/I"); ttree->Branch("multiplicity", &m_multiplicity, "multiplicity/I"); - ttree->Branch("multiplicity_right", &m_multiplicity_right, "multiplicity_right/I" ); - ttree->Branch("multiplicity_left", &m_multiplicity_left, "multiplicity_left/I" ); + ttree->Branch("multiplicity_right", &m_multiplicity_right, "multiplicity_right/I"); + ttree->Branch("multiplicity_left", &m_multiplicity_left, "multiplicity_left/I"); ttree->Branch("sum_pe", &m_sum_pe, "sum_pe/F"); ttree->Branch("sum_pe_right", &m_sum_pe_right, "sum_pe_right/F"); ttree->Branch("sum_pe_left", &m_sum_pe_left, "sum_pe_left/F"); @@ -414,21 +395,21 @@ void opana::ICARUSFlashAssAna::beginJob() { ttree->Branch("flash_width_y", &m_flash_width_y, "flash_width_y/F"); ttree->Branch("flash_z", &m_flash_z, "flash_z/F"); ttree->Branch("flash_width_z", &m_flash_width_z, "flash_width_z/F"); - ttree->Branch("pmt_x",&m_pmt_x); - ttree->Branch("pmt_y",&m_pmt_y); - ttree->Branch("pmt_z",&m_pmt_z); - ttree->Branch("time_pmt", & m_pmt_start_time); - ttree->Branch("time_pmt_rwm", & m_pmt_start_time_rwm); - ttree->Branch("pe_pmt", & m_pmt_pe ); + ttree->Branch("pmt_x", &m_pmt_x); + ttree->Branch("pmt_y", &m_pmt_y); + ttree->Branch("pmt_z", &m_pmt_z); + ttree->Branch("time_pmt", &m_pmt_start_time); + ttree->Branch("time_pmt_rwm", &m_pmt_start_time_rwm); + ttree->Branch("pe_pmt", &m_pmt_pe); ttree->Branch("amplitude_pmt", &m_pmt_amplitude); - fOpFlashTrees.push_back( ttree ); + fOpFlashTrees.push_back(ttree); // Now the ttree for the OpHit associated in the flash - name = label.label()+"_ophittree"; - info = "Three for the recob::OpHit associated with an OpHitFlash"+label.label(); + name = label.label() + "_ophittree"; + info = "Three for the recob::OpHit associated with an OpHitFlash" + label.label(); - TTree* ophittree = tfs->make(name.c_str(), info.c_str() ); + TTree *ophittree = tfs->make(name.c_str(), info.c_str()); ophittree->Branch("run", &m_run, "run/I"); ophittree->Branch("event", &m_event, "event/I"); ophittree->Branch("timestamp", &m_timestamp, "timestamp/I"); @@ -446,44 +427,43 @@ void opana::ICARUSFlashAssAna::beginJob() { ophittree->Branch("width", &m_width, "width/F"); ophittree->Branch("fast_to_total", &m_fast_to_total, "fast_to_total/F"); - fOpHitFlashTrees.push_back( ophittree ); - + fOpHitFlashTrees.push_back(ophittree); } } - } // ---------------------------------------------------------------------------- - -template T opana::ICARUSFlashAssAna::Median( std::vector data ) const { - std::nth_element( data.begin(), data.begin() + data.size()/2, data.end() ); - return data[ data.size()/2 ]; +template +T opana::ICARUSFlashAssAna::Median(std::vector data) const +{ + std::nth_element(data.begin(), data.begin() + data.size() / 2, data.end()); + return data[data.size() / 2]; } // ---------------------------------------------------------------------------- +geo::CryostatID::CryostatID_t opana::ICARUSFlashAssAna::getCryostatByChannel(int channel) +{ -geo::CryostatID::CryostatID_t opana::ICARUSFlashAssAna::getCryostatByChannel( int channel ) { - - const geo::OpDetGeo& opdetgeo = fGeom->OpDetGeoFromOpChannel(channel); - geo::CryostatID::CryostatID_t cid = opdetgeo.ID().Cryostat ; + const geo::OpDetGeo &opdetgeo = fGeom->OpDetGeoFromOpChannel(channel); + geo::CryostatID::CryostatID_t cid = opdetgeo.ID().Cryostat; return cid; - } // ---------------------------------------------------------------------------- -int opana::ICARUSFlashAssAna::getSideByChannel( const int channel ) { +int opana::ICARUSFlashAssAna::getSideByChannel(const int channel) +{ - /* + /* Channels are numbered from east to west, from North (cryo side) to South (beam side) - We look in the opposide direction wrt to the beam direction South->North: + We look in the opposide direction wrt to the beam direction South->North: - Left is the east wall of each cryostat; - Right is the west side of each cryostat; - - [ 0:89 ] and [180:269] are on the left, + - [ 0:89 ] and [180:269] are on the left, the return value of the function is 0; - [ 90-179 ] and [ 270:359 ] are on the right, the return value of the function is 1; @@ -495,104 +475,123 @@ int opana::ICARUSFlashAssAna::getSideByChannel( const int channel ) { // ---------------------------------------------------------------------------- -float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { +float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) +{ - if( fRWMTimes.empty() ) return 0; + if (fRWMTimes.empty()) + return 0; auto rwm = fRWMTimes.at(channel); - if ( !rwm.isValid() ){ + if (!rwm.isValid()) + { mf::LogTrace("ICARUSFlashAssAna") << "No RWM signal for channel " << channel << " " - << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel + << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel << ", SpecialChannel " << rwm.specialChannel << ")" - << " in event " << m_event << " gate " << m_gate_name; + << " in event " << m_event << " gate " << m_gate_name; return 0; } - - float rwm_trigger = rwm.startTime; //rwm time w.r.t. trigger time [us] - return (t - rwm_trigger); + float rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] + return (t - rwm_trigger); } - + // ---------------------------------------------------------------------------- float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_time_rwm, - std::vector pmt_rise_time) { + std::vector pmt_rise_time) +{ float tfirst_left = std::numeric_limits::max(); float tfirst_right = std::numeric_limits::max(); - + // if no RWM info available, all pmt_start_time_rwm is zero // return zero as well for the flash - if (fRWMTimes.empty()) return 0; - + if (fRWMTimes.empty()) + return 0; + int nleft = 0; int nright = 0; - for(size_t i=0; i -1e-10 && t < 1e-10 ) continue; + if (t > -1e-10 && t < 1e-10) + continue; - // if RWM is missing for some PMT channels, + // if RWM is missing for some PMT channels, // it might not be possible to use the first hits (might not have RMW time) // so return zero as in other bad cases - if( !fRWMTimes[i].isValid() ) return 0; - + if (!fRWMTimes[i].isValid()) + return 0; + // count hits separetely on the two walls - if( side == 0 ){ + if (side == 0) + { nleft++; - if(t < tfirst_left) tfirst_left = t; + if (t < tfirst_left) + tfirst_left = t; } - else if( side == 1 ){ + else if (side == 1) + { nright++; - if(t < tfirst_right) tfirst_right = t; - } + if (t < tfirst_right) + tfirst_right = t; + } } // if there are no hits in one of the walls... - if( nleft<1 || nright <1 ){ + if (nleft < 1 || nright < 1) + { mf::LogWarning("ICARUSFlashAssAna") << "Flash " << m_flash_id << " doesn't have hits on both walls!" - << "Left: " << nleft << " t " << tfirst_left << " " + << "Left: " << nleft << " t " << tfirst_left << " " << "Right: " << nright << " t " << tfirst_right; // return what we have... - return (tfirst_left < tfirst_right) ? tfirst_left : tfirst_right; + return (tfirst_left < tfirst_right) ? tfirst_left : tfirst_right; } - - return (tfirst_left + tfirst_right)/2.; -} + return (tfirst_left + tfirst_right) / 2.; +} // ---------------------------------------------------------------------------- -void opana::ICARUSFlashAssAna::processOpHits( art::Event const& e, unsigned int cryo ) { +void opana::ICARUSFlashAssAna::processOpHits(art::Event const &e, unsigned int cryo) +{ // if no OpHits have been selected at all (and no flashes as well!) - if( fOpHitLabels.empty() ){ + if (fOpHitLabels.empty()) + { mf::LogError("ICARUSFlashAssAna") << "No recob::OpHit labels selected."; return; } - for( size_t iOpHitLabel=0; iOpHitLabel>(label); - + auto const &ophits = e.getProduct>(label); + // we want our ophits to be valid and not empty - if( ophits.empty() ) { - mf::LogError("ICARUSFlashAssAna") << "Invalid recob::OpHit with label '" << label.encode() << "'"; + if (ophits.empty()) + { + mf::LogError("ICARUSFlashAssAna") << "Invalid recob::OpHit with label '" << label.encode() << "'"; continue; } - for( auto const & ophit : ophits ) { + for (auto const &ophit : ophits) + { - const int channel_id = ophit.OpChannel(); - if( getCryostatByChannel(channel_id) != cryo ){ continue; } + const int channel_id = ophit.OpChannel(); + if (getCryostatByChannel(channel_id) != cryo) + { + continue; + } m_channel_id = channel_id; - m_integral = ophit.Area(); // in ADC x tick + m_integral = ophit.Area(); // in ADC x tick m_amplitude = ophit.Amplitude(); // in ADC m_width = ophit.Width(); m_pe = ophit.PE(); @@ -603,41 +602,46 @@ void opana::ICARUSFlashAssAna::processOpHits( art::Event const& e, unsigned int m_start_time = ophit.StartTime(); m_peak_time = ophit.PeakTime(); m_rise_time = ophit.RiseTime(); - m_start_time_rwm = getRWMRelativeTime(channel_id,m_start_time); - m_peak_time_rwm = getRWMRelativeTime(channel_id,m_peak_time); + m_start_time_rwm = getRWMRelativeTime(channel_id, m_start_time); + m_peak_time_rwm = getRWMRelativeTime(channel_id, m_peak_time); m_abs_start_time = ophit.PeakTimeAbs() + (m_start_time - m_peak_time); fOpHitTrees[iOpHitLabel]->Fill(); } } -} +} // ---------------------------------------------------------------------------- -void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vector> const &ophits, - int &multiplicity_left, int &multiplicity_right, - float &sum_pe_left, float &sum_pe_right, - std::vector &pmt_start_time, - std::vector &pmt_rise_time, - std::vector &pmt_start_time_rwm, - std::vector &pmt_pe, - std::vector &pmt_amplitude, - TTree *ophittree ) { +void opana::ICARUSFlashAssAna::processOpHitsFlash(std::vector> const &ophits, + int &multiplicity_left, int &multiplicity_right, + float &sum_pe_left, float &sum_pe_right, + std::vector &pmt_start_time, + std::vector &pmt_rise_time, + std::vector &pmt_start_time_rwm, + std::vector &pmt_pe, + std::vector &pmt_amplitude, + TTree *ophittree) +{ // we calculate the total charge clustered in the flash per channel taking part to the flash // at the same time we store the times of the first ophit in each channel and its amplitude // same loop is used to saved OPHITS info std::unordered_map sumpe_map; - for( auto const ophit : ophits ) { + for (auto const ophit : ophits) + { - if ( ophit->PE() < fPEOpHitThreshold ) { continue; } + if (ophit->PE() < fPEOpHitThreshold) + { + continue; + } - const int channel_id = ophit->OpChannel(); - sumpe_map[channel_id] += ophit->PE() ; + const int channel_id = ophit->OpChannel(); + sumpe_map[channel_id] += ophit->PE(); m_channel_id = channel_id; - m_integral = ophit->Area(); // in ADC x tick + m_integral = ophit->Area(); // in ADC x tick m_amplitude = ophit->Amplitude(); // in ADC m_width = ophit->Width(); m_pe = ophit->PE(); @@ -648,14 +652,15 @@ void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vectorStartTime(); m_peak_time = ophit->PeakTime(); m_rise_time = ophit->RiseTime(); - m_start_time_rwm = getRWMRelativeTime(channel_id,m_start_time); - m_peak_time_rwm = getRWMRelativeTime(channel_id,m_peak_time); + m_start_time_rwm = getRWMRelativeTime(channel_id, m_start_time); + m_peak_time_rwm = getRWMRelativeTime(channel_id, m_peak_time); m_abs_start_time = ophit->PeakTimeAbs() + (m_start_time - m_peak_time); pmt_pe[channel_id] += ophit->PE(); // select the first ophit (by time) in each channel - if( ( pmt_start_time[channel_id] == 0 ) || ( pmt_start_time[channel_id] > m_start_time )) { + if ((pmt_start_time[channel_id] == 0) || (pmt_start_time[channel_id] > m_start_time)) + { pmt_start_time[channel_id] = m_start_time; pmt_rise_time[channel_id] = m_rise_time; pmt_start_time_rwm[channel_id] = m_start_time_rwm; @@ -663,71 +668,72 @@ void opana::ICARUSFlashAssAna::processOpHitsFlash( std::vectorFill(); - } - m_multiplicity_left = std::accumulate( sumpe_map.begin(), sumpe_map.end(), 0, - [&](int value, const std::map::value_type& p) { - return getSideByChannel(p.first)==0 ? ++value : value ; - }); - - m_multiplicity_right =std::accumulate( sumpe_map.begin(), sumpe_map.end(), 0, - [&](int value, const std::map::value_type& p) { - return getSideByChannel(p.first)==1 ? ++value : value ; - }); - - m_sum_pe_left = std::accumulate( sumpe_map.begin(), sumpe_map.end(), 0.0, - [&](float value, const std::map::value_type& p) { - return getSideByChannel(p.first)==0 ? value+p.second : value ; - }); - - m_sum_pe_right = std::accumulate( sumpe_map.begin(), sumpe_map.end(), 0.0, - [&](float value, const std::map::value_type& p) { - return getSideByChannel(p.first)==1 ? value+p.second : value ; - }); -} + m_multiplicity_left = std::accumulate(sumpe_map.begin(), sumpe_map.end(), 0, + [&](int value, const std::map::value_type &p) + { return getSideByChannel(p.first) == 0 ? ++value : value; }); + + m_multiplicity_right = std::accumulate(sumpe_map.begin(), sumpe_map.end(), 0, + [&](int value, const std::map::value_type &p) + { return getSideByChannel(p.first) == 1 ? ++value : value; }); + + m_sum_pe_left = std::accumulate(sumpe_map.begin(), sumpe_map.end(), 0.0, + [&](float value, const std::map::value_type &p) + { return getSideByChannel(p.first) == 0 ? value + p.second : value; }); + m_sum_pe_right = std::accumulate(sumpe_map.begin(), sumpe_map.end(), 0.0, + [&](float value, const std::map::value_type &p) + { return getSideByChannel(p.first) == 1 ? value + p.second : value; }); +} // ---------------------------------------------------------------------------- -void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { +void opana::ICARUSFlashAssAna::analyze(art::Event const &e) +{ // Collect global event metadata m_run = e.id().run(); m_event = e.id().event(); - m_timestamp = e.time().timeHigh(); // precision to the second + m_timestamp = e.time().timeHigh(); // precision to the second // ----- // TRIGGER INFO - // We work out the trigger information here - - if( !fTriggerLabel.empty() ) { + // We work out the trigger information here + + if (!fTriggerLabel.empty()) + { // Beam gate information - auto const& beamgateInfo = e.getProduct>(fTriggerLabel); - - if( !beamgateInfo.empty() ) { - for( auto const & beamgate : beamgateInfo ) { - m_beam_gate_start = beamgate.Start(); - m_beam_gate_width = beamgate.Width(); - m_beam_type = beamgate.BeamType() ; + auto const &beamgateInfo = e.getProduct>(fTriggerLabel); + + if (!beamgateInfo.empty()) + { + for (auto const &beamgate : beamgateInfo) + { + m_beam_gate_start = beamgate.Start(); + m_beam_gate_width = beamgate.Width(); + m_beam_type = beamgate.BeamType(); } - } else { - mf::LogError("ICARUSFlashAssAna") << "No sim::BeamGateInfo associated to label: " << fTriggerLabel.label() << "\n" ; + } + else + { + mf::LogError("ICARUSFlashAssAna") << "No sim::BeamGateInfo associated to label: " << fTriggerLabel.label() << "\n"; } // Now trigger information - auto const& extraInfo = e.getProduct(fTriggerLabel); + auto const &extraInfo = e.getProduct(fTriggerLabel); + + if (extraInfo.isValid()) + { - if( extraInfo.isValid() ) { - sbn::triggerSource bit = extraInfo.sourceType; - m_gate_type = (unsigned int)bit; + m_gate_type = (unsigned int)bit; m_gate_name = bitName(bit); - - m_trigger_type = value( extraInfo.triggerType ); + + m_trigger_type = value(extraInfo.triggerType); m_trigger_timestamp = extraInfo.triggerTimestamp; - m_gate_start_timestamp = extraInfo.beamGateTimestamp; + m_gate_start_timestamp = extraInfo.beamGateTimestamp; m_trigger_gate_diff = m_trigger_timestamp - m_gate_start_timestamp; // majority lvds info @@ -741,25 +747,27 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { addersCryoE[1] = extraInfo.cryostats[0].sectorStatus[1]; addersCryoW[0] = extraInfo.cryostats[1].sectorStatus[0]; addersCryoW[1] = extraInfo.cryostats[1].sectorStatus[1]; - - } else { - mf::LogError("ICARUSFlashAssAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!" ; - } - } + } + else + { + mf::LogError("ICARUSFlashAssAna") << "No raw::Trigger associated to label: " << fTriggerLabel.label() << "!"; + } + } // ----- // RWM INFO - // We work out the RWM information here + // We work out the RWM information here // it might be empty if offbeam or missing, bu that's okay! - - if( !fRWMLabel.empty() ){ + + if (!fRWMLabel.empty()) + { fRWMTimes = e.getProduct>(fRWMLabel); - if ( fRWMTimes.empty() ) + if (fRWMTimes.empty()) mf::LogTrace("ICARUSFlashAssAna") << "Data product std::vector for '" - << fRWMLabel.label() << "' is empty in " << m_gate_name << " event!"; + << fRWMLabel.label() << "' is empty in " << m_gate_name << " event!"; } - + // ----- // WAVEFORM INFO // Now we work on the waveforms if we are allowed to @@ -767,43 +775,49 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { // Waveforms are a complex business: if running at stage0, they're all available // if running at stage1, only on-beam waveforms are available but it's a different product! - if( !fOpDetWaveformLabels.empty() && fSaveWaveformInfo ) { - - for( size_t i=0; i>(wflabel); - auto const& baselines = e.getProduct>(bslabel); + auto const &waveforms = e.getProduct>(wflabel); + auto const &baselines = e.getProduct>(bslabel); // waveforms data product ("daqPMT") is dropped after stage0, and only "daqPMTonbeam" is kept // check if collection is present and print warning otherwise (requires change in fhicl config) - if( !waveforms.empty() ) { + if (!waveforms.empty()) + { size_t idx = 0; - for( auto const & wave : waveforms ){ + for (auto const &wave : waveforms) + { m_channel_id = wave.ChannelNumber(); m_nticks = wave.Waveform().size(); m_wf_start = wave.TimeStamp(); - + // try using icarus::WaveformBaseline, default to median if not // doesn't work with daqPMTonbeam as order gets messed up, so check if size is the same // FIXME: move to use art:Assn which can work both for daqPMT and daqPMTonbeam? - m_baseline = (fUseSharedBaseline && (baselines.size()==waveforms.size())) ? - baselines.at(idx).baseline() : Median(wave.Waveform()); - - m_chargesum = std::accumulate( wave.Waveform().begin(), wave.Waveform().end(), 0, - [ & ](short x, short y){ return ((m_baseline-x) + (m_baseline-y)) ; } ); + m_baseline = (fUseSharedBaseline && (baselines.size() == waveforms.size())) ? baselines.at(idx).baseline() : Median(wave.Waveform()); + + m_chargesum = std::accumulate(wave.Waveform().begin(), wave.Waveform().end(), 0, + [&](short x, short y) + { return ((m_baseline - x) + (m_baseline - y)); }); // if required, save the full waveforms as well - if( fSaveRawWaveforms ) m_wf = wave.Waveform(); + if (fSaveRawWaveforms) + m_wf = wave.Waveform(); - fOpDetWaveformTrees[i]->Fill(); + fOpDetWaveformTrees[i]->Fill(); idx++; - } - } else { + } + else + { mf::LogWarning("ICARUSFlashAssAna") << "Data product std::vector for " << wflabel.label() << " is missing! Was it dropped before this stage?"; } @@ -812,32 +826,37 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { // ----- // FLASHES/OPHITS INFO - // Now we take care of the flashes: + // Now we take care of the flashes: // we separate the case where we have a flash and the case where we don't have a flash // the difference is in how ophits are stored... - if ( !fFlashLabels.empty() ) { + if (!fFlashLabels.empty()) + { // hold the cryostat information - std::vector cids; - - for ( size_t iFlashLabel=0; iFlashLabel cids; + + for (size_t iFlashLabel = 0; iFlashLabel < fFlashLabels.size(); iFlashLabel++) + { auto const label = fFlashLabels[iFlashLabel]; - auto const& flash_handle = e.getValidHandle>(label); - auto const& flashes = *flash_handle; + auto const &flash_handle = e.getValidHandle>(label); + auto const &flashes = *flash_handle; // want our flashes to be valid and not empty - if( flashes.empty() ) { + if (flashes.empty()) + { mf::LogWarning("ICARUSFlashAssAna") - << "No recob::OpFlash in collection with label '" << label.encode() << "'"; + << "No recob::OpFlash in collection with label '" << label.encode() << "'"; } - else { + else + { - art::FindManyP ophitsPtr( flash_handle, e, label ); + art::FindManyP ophitsPtr(flash_handle, e, label); size_t idx = 0; - for( auto const& flash : flashes ){ + for (auto const &flash : flashes) + { m_pmt_pe.resize(360); m_pmt_start_time.resize(360); @@ -848,29 +867,30 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { m_flash_id = idx; m_flash_time = flash.Time(); m_sum_pe = flash.TotalPE(); - m_flash_y = flash.YCenter(); + m_flash_y = flash.YCenter(); m_flash_width_y = flash.YWidth(); m_flash_z = flash.ZCenter(); m_flash_width_z = flash.ZWidth(); - - auto const & ophits = ophitsPtr.at(idx); - // we keep track of the cryistats where the flashes are found; + auto const &ophits = ophitsPtr.at(idx); + + // we keep track of the cryistats where the flashes are found; geo::CryostatID::CryostatID_t cid = getCryostatByChannel(ophits.front()->OpChannel()); auto const found = std::find(cids.begin(), cids.end(), cid); - if( found != cids.end() ){ - cids.push_back( cid ); + if (found != cids.end()) + { + cids.push_back(cid); } // get the multiplicity, the number of PE per side, and the RWM-relative flash time // also store the first ophits for every channel in the flash - processOpHitsFlash( ophits, - m_multiplicity_left, m_multiplicity_right, - m_sum_pe_left, m_sum_pe_right, m_pmt_start_time, - m_pmt_rise_time, m_pmt_start_time_rwm, m_pmt_pe, m_pmt_amplitude, - fOpHitFlashTrees[iFlashLabel] ); + processOpHitsFlash(ophits, + m_multiplicity_left, m_multiplicity_right, + m_sum_pe_left, m_sum_pe_right, m_pmt_start_time, + m_pmt_rise_time, m_pmt_start_time_rwm, m_pmt_pe, m_pmt_amplitude, + fOpHitFlashTrees[iFlashLabel]); - m_multiplicity = m_multiplicity_left+m_multiplicity_right; + m_multiplicity = m_multiplicity_left + m_multiplicity_right; // get the flash interaction time w.r.t. RWM // this is currently the mean between the first ophits on opposite walls @@ -886,24 +906,28 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { idx++; } } - } + } - // If the flashes did not cover all three cryostats.. + // If the flashes did not cover all three cryostats.. // ..well, we save the ophits on what is missing - for( unsigned int cid=0; cidNcryostats(); cid++ ){ + for (unsigned int cid = 0; cid < fGeom->Ncryostats(); cid++) + { - auto const found = std::find( cids.begin(), cids.end(), cid ); - if( found == cids.end() ){ + auto const found = std::find(cids.begin(), cids.end(), cid); + if (found == cids.end()) + { processOpHits(e, cid); } } } - else { - mf::LogError("ICARUSFlashAssAna") << "No recob::OpFlash labels selected"; + else + { + mf::LogError("ICARUSFlashAssAna") << "No recob::OpFlash labels selected"; // we save the ophits anyways even in absence of flashes - for( unsigned int cid=0; cidNcryostats(); cid++ ){ + for (unsigned int cid = 0; cid < fGeom->Ncryostats(); cid++) + { processOpHits(e, cid); } } @@ -911,5 +935,4 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const& e) { fEventTree->Fill(); } - DEFINE_ART_MODULE(opana::ICARUSFlashAssAna) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 6ae0c4dea..cb855dd0f 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -36,22 +36,24 @@ #include #include -namespace icarus { - namespace timing { +namespace icarus +{ + namespace timing + { class PMTBeamSignalsExtractor; } } /** * @brief Extracts RWM and EW times from special waveforms. - * + * * This module extracts the RWM and EW from the waveforms recorded in the - * spare PMT channels and associates these times with all the channels + * spare PMT channels and associates these times with all the channels * in the same PMT readout crate. * * Input parameters * ------------------------ - * + * * This modules requires the following products: * * * `TriggerLabel` (input tag): tag for the `sbn::ExtraTriggerInfo` @@ -60,24 +62,24 @@ namespace icarus { * product containing the RWM special waveforms. * * `EWlabel` (input tag): tag for the `std::vector` * product containign the EW special waveforms. - * * `TriggerCorrectionLabel` (input tag): tag for the + * * `TriggerCorrectionLabel` (input tag): tag for the * std::vector product that * stores the channel-by-channel waveform timing corrections * * `BoardSetup` (fhicl parameter set): description of the current * V1730 setup from `CAEN_V1730_setup_icarus.fcl` mapping the special signals. - * * `ADCThreshold` (int): detection threshold to avoid cross-talk + * * `ADCThreshold` (int): detection threshold to avoid cross-talk * noise if one signal is missing from its waveform. * * `DebugTrees` (bool): flag to produce plain ROOT trees for debugging. * * `SaveWaveforms` (bool): flag to save full waveforms in the debug trees. - * + * * Signal timing extraction * ------------------------- - * + * * The algorithm is quite unsophisticated and follows what is done for * the digitized trigger signal in `PMTWaveformTimeCorrectionExtractor`. * The reference signal is expected to be a sharp square wave in negative * polarity. The time is based on the front side of that wave: - * + * * * the absolute minimum of the waveform is found * * an interval starting 20 ticks before that minimum is considered * * the baseline level is defined as the value at the start of that interval @@ -89,27 +91,30 @@ namespace icarus { * * Output products * ------------------------- - * - * This modules produces two `std::vector` - * with 360 elements each, representing the relevent RWM or EW time for + * + * This modules produces two `std::vector` + * with 360 elements each, representing the relevent RWM or EW time for * the corresponding PMT channel. - * + * * If the event is offbeam or minbias, these vectors are produced empty. * */ - -class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { +class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer +{ public: + explicit PMTBeamSignalsExtractor(fhicl::ParameterSet const &pset); - explicit PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset); - // process waveforms - void extractBeamSignalTime(art::Event& e, art::InputTag label ); - template T Median(std::vector data) const; - template static size_t getMaxBin(std::vector const& vv, size_t startElement, size_t endElement); - template static size_t getMinBin(std::vector const& vv, size_t startElement, size_t endElement); - template static size_t getStartSample( std::vector const& vv, T thres ); + void extractBeamSignalTime(art::Event &e, art::InputTag label); + template + T Median(std::vector data) const; + template + static size_t getMaxBin(std::vector const &vv, size_t startElement, size_t endElement); + template + static size_t getMinBin(std::vector const &vv, size_t startElement, size_t endElement); + template + static size_t getStartSample(std::vector const &vv, T thres); // associate times to PMT channels void associateBeamSignalsToChannels(art::InputTag label); @@ -122,20 +127,19 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { std::string getCrate(int channel); // Plugins should not be copied or assigned. - PMTBeamSignalsExtractor(PMTBeamSignalsExtractor const&) = delete; - PMTBeamSignalsExtractor(PMTBeamSignalsExtractor&&) = delete; - PMTBeamSignalsExtractor& operator=(PMTBeamSignalsExtractor const&) = delete; - PMTBeamSignalsExtractor& operator=(PMTBeamSignalsExtractor&&) = delete; + PMTBeamSignalsExtractor(PMTBeamSignalsExtractor const &) = delete; + PMTBeamSignalsExtractor(PMTBeamSignalsExtractor &&) = delete; + PMTBeamSignalsExtractor &operator=(PMTBeamSignalsExtractor const &) = delete; + PMTBeamSignalsExtractor &operator=(PMTBeamSignalsExtractor &&) = delete; void beginJob(); - void produce(art::Event& e) override; + void produce(art::Event &e) override; private: - art::ServiceHandle tfs; - + /// Channel mappping - icarusDB::IICARUSChannelMap const & fChannelMap; + icarusDB::IICARUSChannelMap const &fChannelMap; /// Save plain ROOT TTrees for debugging bool fDebugTrees; /// Save raw waveforms in debug TTrees @@ -148,29 +152,29 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { art::InputTag fEWlabel; /// Trigger-hardware correction instance art::InputTag fTriggerCorrectionLabel; - /// Threshold for pulse selection + /// Threshold for pulse selection short int fADCThreshold; /// V1730 special channels setup std::vector fBoardSetup; - + std::map fBoardBySpecialChannel; std::vector fCorrections; std::map fBoardEffFragmentID; double ftrigger_time; - // output TTrees - std::map fOutTree; + // output TTrees + std::map fOutTree; // event info int m_run; int m_event; - int m_timestamp; + int m_timestamp; // special signal info int m_n_channels; int m_channel; double m_wfstart; size_t m_sample; double m_time; - double m_time_abs; + double m_time_abs; double m_utime_abs; std::vector m_wf; @@ -180,35 +184,27 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer { std::map> fBeamSignals; std::map fSignalCollection; - }; // ----------------------------------------------------------------------------- -icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::ParameterSet const& pset) - : EDProducer{pset} - , fChannelMap( *(art::ServiceHandle{}) ) - , fDebugTrees( pset.get("DebugTrees") ) - , fSaveWaveforms( pset.get("SaveWaveforms") ) - , fTriggerLabel( pset.get("TriggerLabel") ) - , fRWMlabel( pset.get("RWMlabel") ) - , fEWlabel( pset.get("EWlabel") ) - , fTriggerCorrectionLabel( pset.get("TriggerCorrectionLabel") ) - , fADCThreshold( pset.get("ADCThreshold") ) - , fBoardSetup( pset.get>("BoardSetup") ) +icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::ParameterSet const &pset) + : EDProducer{pset}, fChannelMap(*(art::ServiceHandle{})), fDebugTrees(pset.get("DebugTrees")), fSaveWaveforms(pset.get("SaveWaveforms")), fTriggerLabel(pset.get("TriggerLabel")), fRWMlabel(pset.get("RWMlabel")), fEWlabel(pset.get("EWlabel")), fTriggerCorrectionLabel(pset.get("TriggerCorrectionLabel")), fADCThreshold(pset.get("ADCThreshold")), fBoardSetup(pset.get>("BoardSetup")) { - + // unpack the V1730 special channels settings in a useful way - // saving special_channel <-> board association in a map - for (fhicl::ParameterSet const& setup : fBoardSetup ) { + // saving special_channel <-> board association in a map + for (fhicl::ParameterSet const &setup : fBoardSetup) + { auto innerSet = setup.get>("SpecialChannels"); - fBoardBySpecialChannel[ innerSet[0].get("Channel") ] = setup.get("Name"); + fBoardBySpecialChannel[innerSet[0].get("Channel")] = setup.get("Name"); } // pre-save the association between digitizer_label and effective fragment ID - for (unsigned int fragid=0; fragid() functions here. @@ -225,67 +221,71 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete void icarus::timing::PMTBeamSignalsExtractor::beginJob() { // prepare outupt TTrees if requested - if( !fDebugTrees ) return; + if (!fDebugTrees) + return; - std::vector labels = { fRWMlabel.instance(), fEWlabel.instance() }; - for (auto l : labels ){ + std::vector labels = {fRWMlabel.instance(), fEWlabel.instance()}; + for (auto l : labels) + { std::string name = l + "tree"; std::string desc = l + " info"; - fOutTree[l] = tfs->make(name.c_str(),desc.c_str()); - fOutTree[l]->Branch("run",&m_run); - fOutTree[l]->Branch("event",&m_event); - fOutTree[l]->Branch("timestamp",&m_timestamp); - fOutTree[l]->Branch("n_channels",&m_n_channels); - fOutTree[l]->Branch("channel",&m_channel); + fOutTree[l] = tfs->make(name.c_str(), desc.c_str()); + fOutTree[l]->Branch("run", &m_run); + fOutTree[l]->Branch("event", &m_event); + fOutTree[l]->Branch("timestamp", &m_timestamp); + fOutTree[l]->Branch("n_channels", &m_n_channels); + fOutTree[l]->Branch("channel", &m_channel); fOutTree[l]->Branch("wfstart", &m_wfstart); fOutTree[l]->Branch("sample", &m_sample); fOutTree[l]->Branch("utime_abs", &m_utime_abs); - fOutTree[l]->Branch("time_abs",&m_time_abs); + fOutTree[l]->Branch("time_abs", &m_time_abs); fOutTree[l]->Branch("time", &m_time); - + // add std::vector with full waveforms // this can quickly make the TTrees quite heavy - if(fSaveWaveforms){ - fOutTree[l]->Branch("wf",&m_wf); + if (fSaveWaveforms) + { + fOutTree[l]->Branch("wf", &m_wf); } } } // ----------------------------------------------------------------------------- -void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) +void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) { - - // initialize the data products + + // initialize the data products fBeamSignals.clear(); fSignalCollection[fRWMlabel.instance()] = std::make_unique(); - fSignalCollection[fEWlabel.instance()] = std::make_unique(); + fSignalCollection[fEWlabel.instance()] = std::make_unique(); // extract meta event information m_run = e.id().run(); m_event = e.id().event(); - m_timestamp = e.time().timeHigh(); // precision to the second + m_timestamp = e.time().timeHigh(); // precision to the second auto const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); ftrigger_time = detTimings.TriggerTime().value(); // this module should run on beam-only events // check the current beam gate auto const trigger_handle = e.getProduct(fTriggerLabel); - sbn::triggerSource const gateType = trigger_handle.sourceType; - std::string beamType = ""; - - switch (gateType) { - case sbn::triggerSource::BNB: - beamType = "BNB"; - break; - case sbn::triggerSource::NuMI: - beamType = "NuMI"; - break; - default: - mf::LogTrace("PMTBeamSignalsExtractor") << "Skipping offbeam gate '" << name(gateType) << "'"; - e.put(std::move(fSignalCollection[fRWMlabel.instance()]),"RWM"); - e.put(std::move(fSignalCollection[fEWlabel.instance()]),"EW"); - return; + sbn::triggerSource const gateType = trigger_handle.sourceType; + std::string beamType = ""; + + switch (gateType) + { + case sbn::triggerSource::BNB: + beamType = "BNB"; + break; + case sbn::triggerSource::NuMI: + beamType = "NuMI"; + break; + default: + mf::LogTrace("PMTBeamSignalsExtractor") << "Skipping offbeam gate '" << name(gateType) << "'"; + e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "RWM"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]), "EW"); + return; } // get the trigger-hardware corrections that are applied on all signal waveforms @@ -294,235 +294,246 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event& e) // Note: this is a vector of 360 elements, one correction for each signal channel fCorrections = e.getProduct>(fTriggerCorrectionLabel); int ntrig = fCorrections.size(); - - if( ntrig < 1 ) - mf::LogError("PMTBeamSignalsExtractor") << "Not found PMTWaveformTimeCorrections with label '" - << fTriggerCorrectionLabel.instance() << "'"; - else if ( ntrig < 360 ) - mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 360-ntrig << " PMTWaveformTimeCorrections with label '" - << fTriggerCorrectionLabel.instance() << "'"; - + + if (ntrig < 1) + mf::LogError("PMTBeamSignalsExtractor") << "Not found PMTWaveformTimeCorrections with label '" + << fTriggerCorrectionLabel.instance() << "'"; + else if (ntrig < 360) + mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 360 - ntrig << " PMTWaveformTimeCorrections with label '" + << fTriggerCorrectionLabel.instance() << "'"; + // now the main course: getting EW and RWM waveforms // information is stored by PMT crate name - extractBeamSignalTime(e, fRWMlabel); - extractBeamSignalTime(e, fEWlabel); + extractBeamSignalTime(e, fRWMlabel); + extractBeamSignalTime(e, fEWlabel); // associating the proper RWM and EW time to each PMT channel // collections are vectors of 360 elements (one value for each channel) - associateBeamSignalsToChannels( fRWMlabel ); - associateBeamSignalsToChannels( fEWlabel ); - + associateBeamSignalsToChannels(fRWMlabel); + associateBeamSignalsToChannels(fEWlabel); + // place data products in the stream // fix the cable swap for part of Run 2 right here!! - // see SBN-doc-34631 for details - if( beamType=="BNB" && m_run > 9704 && m_run < 11443 ){ - - e.put(std::move(fSignalCollection[fRWMlabel.instance()]),"EW"); - e.put(std::move(fSignalCollection[fEWlabel.instance()]),"RWM"); + // see SBN-doc-34631 for details + if (beamType == "BNB" && m_run > 9704 && m_run < 11443) + { - } else { // STANDARD BEHAVIOR + e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "EW"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]), "RWM"); + } + else + { // STANDARD BEHAVIOR - e.put(std::move(fSignalCollection[fRWMlabel.instance()]),"RWM"); - e.put(std::move(fSignalCollection[fEWlabel.instance()]),"EW"); + e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "RWM"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]), "EW"); } } // ----------------------------------------------------------------------------- -void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event& e, art::InputTag label) { +void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event &e, art::InputTag label) +{ std::string l = label.instance(); - auto const& waveforms = e.getProduct>(label); + auto const &waveforms = e.getProduct>(label); m_n_channels = waveforms.size(); - - if( m_n_channels < 1 ) - mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << l << "'"; - else if( m_n_channels < 8 ) - mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 8-m_n_channels << " raw::OpDetWaveform with label '" << l << "'"; + + if (m_n_channels < 1) + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << l << "'"; + else if (m_n_channels < 8) + mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 8 - m_n_channels << " raw::OpDetWaveform with label '" << l << "'"; m_wf.clear(); - + // 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 time to "NoTime" so that it triggers the isValid() call of PMTBeamSignal - - for( auto const & wave : waveforms ){ - + + for (auto const &wave : waveforms) + { + detinfo::timescales::electronics_time tstart = util::quantities::points::microsecond{wave.TimeStamp()}; - + // if nothing is found, first sample is returned (0) m_sample = getStartSample(wave.Waveform(), fADCThreshold); - + m_channel = wave.ChannelNumber(); - m_wfstart = tstart.value() ; - m_utime_abs = (m_sample != icarus::timing::NoSample) ? - tstart.value() + 0.002*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-ftrigger_time : icarus::timing::NoTime; + m_wfstart = tstart.value(); + m_utime_abs = (m_sample != icarus::timing::NoSample) ? tstart.value() + 0.002 * 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 - ftrigger_time : icarus::timing::NoTime; std::string crate = getCrate(m_channel); - fBeamSignals[l].insert(std::make_pair( crate, PMTBeamSignal(m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time) )); - - if(fSaveWaveforms) m_wf = wave.Waveform(); - if(fDebugTrees) fOutTree[l]->Fill(); - + fBeamSignals[l].insert(std::make_pair(crate, PMTBeamSignal(m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time))); + + if (fSaveWaveforms) + m_wf = wave.Waveform(); + if (fDebugTrees) + fOutTree[l]->Fill(); } } // --------------------------------------------------------------------------- -template T icarus::timing::PMTBeamSignalsExtractor::Median( std::vector data ) const { - - std::nth_element( data.begin(), data.begin() + data.size()/2, data.end() ); - return data[ data.size()/2 ]; +template +T icarus::timing::PMTBeamSignalsExtractor::Median(std::vector data) const +{ + std::nth_element(data.begin(), data.begin() + data.size() / 2, data.end()); + return data[data.size() / 2]; } // ----------------------------------------------------------------------------- -template - size_t icarus::timing::PMTBeamSignalsExtractor::getMinBin( - std::vector const& vv, size_t startElement, size_t endElement ){ +template +size_t icarus::timing::PMTBeamSignalsExtractor::getMinBin( + std::vector const &vv, size_t startElement, size_t endElement) +{ - auto minel = - std::min_element( vv.begin()+startElement, vv.begin()+endElement ); - size_t minsample = std::distance( vv.begin()+startElement, minel ); + auto minel = + std::min_element(vv.begin() + startElement, vv.begin() + endElement); + size_t minsample = std::distance(vv.begin() + startElement, minel); - return minsample; + return minsample; } // ----------------------------------------------------------------------------- -template - size_t icarus::timing::PMTBeamSignalsExtractor::getMaxBin( - std::vector const& vv, size_t startElement, size_t endElement){ +template +size_t icarus::timing::PMTBeamSignalsExtractor::getMaxBin( + std::vector const &vv, size_t startElement, size_t endElement) +{ + + auto maxel = + std::max_element(vv.begin() + startElement, vv.begin() + endElement); - auto maxel = - std::max_element( vv.begin()+startElement, vv.begin()+endElement ); - - size_t maxsample = std::distance( vv.begin()+startElement, maxel ); + size_t maxsample = std::distance(vv.begin() + startElement, maxel); - return maxsample; -} + return maxsample; +} // ----------------------------------------------------------------------------- -template - size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample( std::vector const& vv, T thres ){ - - // We are thinking in inverted polarity - size_t minbin = getMinBin( vv, 0, vv.size() ); - - //Search only a cropped region of the waveform backward from the min - size_t maxbin = minbin-20; - - // Now we crawl betweem maxbin and minbin and we stop when: - // bin value > (maxbin value - bin value )*0.2 - size_t startbin = maxbin; - auto delta = vv[maxbin]-vv[minbin]; - - if( delta < thres ) //just noise - return icarus::timing::NoSample; //return no sample - - for( size_t bin=maxbin; bin= 0.2*delta ){ //20% - startbin = bin - 1; - break; - } - } +template +size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample(std::vector const &vv, T thres) +{ + + // We are thinking in inverted polarity + size_t minbin = getMinBin(vv, 0, vv.size()); + + // Search only a cropped region of the waveform backward from the min + size_t maxbin = minbin - 20; - if( startbin < maxbin ){ - startbin=maxbin; + // Now we crawl betweem maxbin and minbin and we stop when: + // bin value > (maxbin value - bin value )*0.2 + size_t startbin = maxbin; + auto delta = vv[maxbin] - vv[minbin]; + + if (delta < thres) // just noise + return icarus::timing::NoSample; // return no sample + + for (size_t bin = maxbin; bin < minbin; bin++) + { + auto val = vv[maxbin] - vv[bin]; + if (val >= 0.2 * delta) + { // 20% + startbin = bin - 1; + break; } + } + + if (startbin < maxbin) + { + startbin = maxbin; + } - return startbin; + return startbin; } // ----------------------------------------------------------------------------- -std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int channel){ - +std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int channel) +{ + // get the board name, convert to digitizer_label std::string board = fBoardBySpecialChannel[channel]; - + std::string head = "icaruspmt"; std::string dash = "-"; - std::string letter = (board.substr(board.size()-2, board.size())=="02") ? "B" : "C"; - - board.erase( board.find(head), head.size() ); - std::transform(board.begin(), board.end(), board.begin(), ::toupper); - board.insert( 2, dash); - board.insert( 6, dash); + std::string letter = (board.substr(board.size() - 2, board.size()) == "02") ? "B" : "C"; - return board.substr(0,board.size()-2) + letter; + board.erase(board.find(head), head.size()); + std::transform(board.begin(), board.end(), board.begin(), ::toupper); + board.insert(2, dash); + board.insert(6, dash); + return board.substr(0, board.size() - 2) + letter; } // ----------------------------------------------------------------------------- -std::string icarus::timing::PMTBeamSignalsExtractor::getCrate(int channel){ - - std::string digitizer_label = getDigitizerLabel(channel); - return digitizer_label.substr( 0, digitizer_label.size()-2 ); +std::string icarus::timing::PMTBeamSignalsExtractor::getCrate(int channel) +{ + std::string digitizer_label = getDigitizerLabel(channel); + return digitizer_label.substr(0, digitizer_label.size() - 2); } // ----------------------------------------------------------------------------- - -double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel){ + +double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel) +{ std::string digitizer_label = getDigitizerLabel(channel); // trigger-hardware corrections are shared by all channels on the same board // we can pick the first channel on the desired board int fragID = fBoardEffFragmentID[digitizer_label]; - auto pmtinfo = fChannelMap.getPMTchannelInfo(fragID)[0]; //pick first ch on board + auto pmtinfo = fChannelMap.getPMTchannelInfo(fragID)[0]; // pick first ch on board int pmtch = pmtinfo.channelID; // trigger-hardware correction are in order // index of vector is pmtch return fCorrections.at(pmtch).startTime; - } - // ----------------------------------------------------------------------------- -void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art::InputTag label){ +void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art::InputTag label) +{ std::string l = label.instance(); // loop through the signals which are one per PMT crate // for each crate, find the corresponding digitizers - for( auto signal : fBeamSignals[l] ){ - + for (auto signal : fBeamSignals[l]) + { + // build the PMT digitizer labels that live in this crate // then convert it into fragment id - std::vector letters = { "-A", "-B", "-C" }; - for( auto letter : letters ){ + std::vector letters = {"-A", "-B", "-C"}; + for (auto letter : letters) + { std::string digitizer_label = signal.first + letter; int fragID = fBoardEffFragmentID[digitizer_label]; - + // use the fragment id to access the PMT channels // mapping works via fragment id (it's very annoying..) // loop through the PMT channels and set their RWM/EW time - for( auto pmtinfo : fChannelMap.getPMTchannelInfo(fragID) ) { - + for (auto pmtinfo : fChannelMap.getPMTchannelInfo(fragID)) + { + size_t channel = pmtinfo.channelID; - // make sure there is enough room in the collection (channel -> vector index) - if (channel >= fSignalCollection[l]->size()) fSignalCollection[l]->resize(channel + 1); + // make sure there is enough room in the collection (channel -> vector index) + if (channel >= fSignalCollection[l]->size()) + fSignalCollection[l]->resize(channel + 1); fSignalCollection[l]->at(channel) = signal.second; - } //for each channel - } //for each board - } //for each crate - + } // for each channel + } // for each board + } // for each crate } - DEFINE_ART_MODULE(icarus::timing::PMTBeamSignalsExtractor) From 51526b06670d9618602dd0d239de3775b129676a Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 25 Sep 2024 10:30:41 -0500 Subject: [PATCH 22/52] include cstddef, use std::size_t --- icaruscode/IcarusObj/PMTBeamSignal.h | 10 +++--- .../OpReco/ICARUSBeamStructureAna_module.cc | 7 ++-- .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 15 +++++---- .../Timing/PMTBeamSignalsExtractor_module.cc | 33 ++++++++++--------- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index 5ae993ca1..b086ed366 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -10,6 +10,8 @@ // C/C++ standard libraries #include +#include +#include namespace icarus::timing { @@ -19,7 +21,7 @@ namespace icarus::timing /// Special value to denote no time channel informatio static constexpr double NoTime = 0.; // Special value to denote no sample information - static constexpr size_t NoSample = 0; + static constexpr std::size_t NoSample = 0; struct PMTBeamSignal { @@ -34,7 +36,7 @@ namespace icarus::timing std::string crate = ""; /// Sample within the waveform where the reference signal is found - size_t sample = NoSample; + std::size_t sample = NoSample; /// Start time in electronics time [us] double startTimeAbs = NoTime; @@ -43,8 +45,8 @@ namespace icarus::timing double startTime = NoTime; PMTBeamSignal(unsigned int ch, std::string b, std::string c, - size_t s, double t, double tt) : specialChannel(ch), digitizerLabel(b), crate(c), sample(s), - startTimeAbs(t), startTime(tt) {}; + std::size_t s, double t, double tt) : specialChannel(ch), digitizerLabel(b), crate(c), sample(s), + startTimeAbs(t), startTime(tt) {}; PMTBeamSignal() {}; diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index 0bee5765c..1ead53c74 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -50,6 +50,7 @@ #include #include #include +#include // ----------------------------------------------------------------------------- namespace opana @@ -301,7 +302,7 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) if (!fFlashLabels.empty()) { - for (size_t iFlashLabel = 0; iFlashLabel < fFlashLabels.size(); iFlashLabel++) + for (std::size_t iFlashLabel = 0; iFlashLabel < fFlashLabels.size(); iFlashLabel++) { auto const label = fFlashLabels[iFlashLabel]; @@ -326,7 +327,7 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) art::FindOneP matchPtr(flash_handle, e, fCRTPMTMatchingLabel); // loop all flashes - size_t idx = 0; + std::size_t idx = 0; for (auto const &flash : flashes) { @@ -493,7 +494,7 @@ double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channel int nleft = 0; int nright = 0; - for (size_t i = 0; i < hit_rise_time_rwm.size(); i++) + for (std::size_t i = 0; i < hit_rise_time_rwm.size(); i++) { int ch = channels[i]; diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index 84256c7de..b9e6cfb8b 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -50,6 +50,7 @@ #include #include // std::accumulate #include +#include namespace opana { @@ -277,7 +278,7 @@ void opana::ICARUSFlashAssAna::beginJob() fGeoTree->Branch("pmt_y", &m_pmt_y); fGeoTree->Branch("pmt_z", &m_pmt_z); - for (size_t opch = 0; opch < fGeom->NOpChannels(); ++opch) + for (std::size_t opch = 0; opch < fGeom->NOpChannels(); ++opch) { auto const PMTxyz = fGeom->OpDetGeoFromOpChannel(opch).GetCenter(); @@ -511,7 +512,7 @@ float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_ int nleft = 0; int nright = 0; - for (size_t i = 0; i < pmt_start_time_rwm.size(); i++) + for (std::size_t i = 0; i < pmt_start_time_rwm.size(); i++) { int side = getSideByChannel(i); @@ -568,7 +569,7 @@ void opana::ICARUSFlashAssAna::processOpHits(art::Event const &e, unsigned int c return; } - for (size_t iOpHitLabel = 0; iOpHitLabel < fOpHitLabels.size(); iOpHitLabel++) + for (std::size_t iOpHitLabel = 0; iOpHitLabel < fOpHitLabels.size(); iOpHitLabel++) { auto const label = fOpHitLabels[iOpHitLabel]; @@ -778,7 +779,7 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const &e) if (!fOpDetWaveformLabels.empty() && fSaveWaveformInfo) { - for (size_t i = 0; i < fOpDetWaveformLabels.size(); i++) + for (std::size_t i = 0; i < fOpDetWaveformLabels.size(); i++) { auto const wflabel = fOpDetWaveformLabels[i]; @@ -791,7 +792,7 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const &e) if (!waveforms.empty()) { - size_t idx = 0; + std::size_t idx = 0; for (auto const &wave : waveforms) { @@ -836,7 +837,7 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const &e) // hold the cryostat information std::vector cids; - for (size_t iFlashLabel = 0; iFlashLabel < fFlashLabels.size(); iFlashLabel++) + for (std::size_t iFlashLabel = 0; iFlashLabel < fFlashLabels.size(); iFlashLabel++) { auto const label = fFlashLabels[iFlashLabel]; @@ -854,7 +855,7 @@ void opana::ICARUSFlashAssAna::analyze(art::Event const &e) art::FindManyP ophitsPtr(flash_handle, e, label); - size_t idx = 0; + std::size_t idx = 0; for (auto const &flash : flashes) { diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index cb855dd0f..2ed9dc527 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -35,6 +35,7 @@ #include #include #include +#include namespace icarus { @@ -110,11 +111,11 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer template T Median(std::vector data) const; template - static size_t getMaxBin(std::vector const &vv, size_t startElement, size_t endElement); + static std::size_t getMaxBin(std::vector const &vv, std::size_t startElement, std::size_t endElement); template - static size_t getMinBin(std::vector const &vv, size_t startElement, size_t endElement); + static std::size_t getMinBin(std::vector const &vv, std::size_t startElement, std::size_t endElement); template - static size_t getStartSample(std::vector const &vv, T thres); + static std::size_t getStartSample(std::vector const &vv, T thres); // associate times to PMT channels void associateBeamSignalsToChannels(art::InputTag label); @@ -172,7 +173,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer int m_n_channels; int m_channel; double m_wfstart; - size_t m_sample; + std::size_t m_sample; double m_time; double m_time_abs; double m_utime_abs; @@ -386,13 +387,13 @@ T icarus::timing::PMTBeamSignalsExtractor::Median(std::vector data) const // ----------------------------------------------------------------------------- template -size_t icarus::timing::PMTBeamSignalsExtractor::getMinBin( - std::vector const &vv, size_t startElement, size_t endElement) +std::size_t icarus::timing::PMTBeamSignalsExtractor::getMinBin( + std::vector const &vv, std::size_t startElement, std::size_t endElement) { auto minel = std::min_element(vv.begin() + startElement, vv.begin() + endElement); - size_t minsample = std::distance(vv.begin() + startElement, minel); + std::size_t minsample = std::distance(vv.begin() + startElement, minel); return minsample; } @@ -400,14 +401,14 @@ size_t icarus::timing::PMTBeamSignalsExtractor::getMinBin( // ----------------------------------------------------------------------------- template -size_t icarus::timing::PMTBeamSignalsExtractor::getMaxBin( - std::vector const &vv, size_t startElement, size_t endElement) +std::size_t icarus::timing::PMTBeamSignalsExtractor::getMaxBin( + std::vector const &vv, std::size_t startElement, std::size_t endElement) { auto maxel = std::max_element(vv.begin() + startElement, vv.begin() + endElement); - size_t maxsample = std::distance(vv.begin() + startElement, maxel); + std::size_t maxsample = std::distance(vv.begin() + startElement, maxel); return maxsample; } @@ -415,24 +416,24 @@ size_t icarus::timing::PMTBeamSignalsExtractor::getMaxBin( // ----------------------------------------------------------------------------- template -size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample(std::vector const &vv, T thres) +std::size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample(std::vector const &vv, T thres) { // We are thinking in inverted polarity - size_t minbin = getMinBin(vv, 0, vv.size()); + std::size_t minbin = getMinBin(vv, 0, vv.size()); // Search only a cropped region of the waveform backward from the min - size_t maxbin = minbin - 20; + std::size_t maxbin = minbin - 20; // Now we crawl betweem maxbin and minbin and we stop when: // bin value > (maxbin value - bin value )*0.2 - size_t startbin = maxbin; + std::size_t startbin = maxbin; auto delta = vv[maxbin] - vv[minbin]; if (delta < thres) // just noise return icarus::timing::NoSample; // return no sample - for (size_t bin = maxbin; bin < minbin; bin++) + for (std::size_t bin = maxbin; bin < minbin; bin++) { auto val = vv[maxbin] - vv[bin]; if (val >= 0.2 * delta) @@ -524,7 +525,7 @@ void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art for (auto pmtinfo : fChannelMap.getPMTchannelInfo(fragID)) { - size_t channel = pmtinfo.channelID; + std::size_t channel = pmtinfo.channelID; // make sure there is enough room in the collection (channel -> vector index) if (channel >= fSignalCollection[l]->size()) fSignalCollection[l]->resize(channel + 1); From 999135419ea4216b77ef4da7fd2b3d95edeceae7 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 25 Sep 2024 12:01:42 -0500 Subject: [PATCH 23/52] add more info in comments --- icaruscode/IcarusObj/PMTBeamSignal.h | 34 ++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index b086ed366..2190547d7 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -16,32 +16,48 @@ namespace icarus::timing { - /// Special value to denote no special channel information + /// Special value to denote no special channel information. static constexpr auto NoChannel = std::numeric_limits::max(); - /// Special value to denote no time channel informatio + /// Special value to denote no time channel information. static constexpr double NoTime = 0.; - // Special value to denote no sample information + // Special value to denote no sample information. static constexpr std::size_t NoSample = 0; + /** + * @brief Beam time as seen by a PMT readout board. + * + * This could either be an early warning (EW) or a resistive wall monitor (RWM) time. + * These signals are delivered via fibers and digitized in special PMT channels. + * + * Both the time in @ref DetectorClocksElectronicsTime "electronics time scale" + * and time time relative to the hardware trigger are included. + * + * The information in this object may be missing: its validity should + * always be checked in advance with `isValid()`. + */ + struct PMTBeamSignal { - /// Special channel this time was extracted from + /// Special channel this time was extracted from. + /// These are defined in `CAEN_V1730_setup_icarus.fcl`. unsigned int specialChannel = NoChannel; - /// Board on which the special channel is on + /// Board on which the special channel is on (e.g: WW-TOP-A). + /// Should match the same format as `icarusDB::PMTChannelInfo_t::digitizerLabel`. std::string digitizerLabel = ""; - /// Crate this time applies to + /// Crate this time applies to (e.g.: WW-TOP). + /// Corresponds to the first part of `digitizerLabel`. std::string crate = ""; - /// Sample within the waveform where the reference signal is found + /// Sample within the waveform where the reference signal is found. std::size_t sample = NoSample; - /// Start time in electronics time [us] + /// Start time in electronics time [us]. double startTimeAbs = NoTime; - /// Start time relative to trigger time [us] + /// Start time relative to trigger time [us]. double startTime = NoTime; PMTBeamSignal(unsigned int ch, std::string b, std::string c, From d257a3cf408023de6900ac6b1e3bac19d5315902 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 25 Sep 2024 12:28:55 -0500 Subject: [PATCH 24/52] remove PMTBeamSignal constructors --- icaruscode/IcarusObj/PMTBeamSignal.h | 6 ------ icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 5 +++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index 2190547d7..bc6b7eee7 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -60,12 +60,6 @@ namespace icarus::timing /// Start time relative to trigger time [us]. double startTime = NoTime; - PMTBeamSignal(unsigned int ch, std::string b, std::string c, - std::size_t s, double t, double tt) : specialChannel(ch), digitizerLabel(b), crate(c), sample(s), - startTimeAbs(t), startTime(tt) {}; - - PMTBeamSignal() {}; - /// Returns whether the time is valid. bool isValid() const { return ((sample != NoSample) && (startTime != NoTime)); } }; diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 2ed9dc527..066def5a3 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -171,7 +171,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer int m_timestamp; // special signal info int m_n_channels; - int m_channel; + unsigned int m_channel; double m_wfstart; std::size_t m_sample; double m_time; @@ -365,7 +365,8 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & m_time = (m_sample != icarus::timing::NoSample) ? m_time_abs - ftrigger_time : icarus::timing::NoTime; std::string crate = getCrate(m_channel); - fBeamSignals[l].insert(std::make_pair(crate, PMTBeamSignal(m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time))); + icarus::timing::PMTBeamSignal beamTime{m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time}; + fBeamSignals[l].insert(std::make_pair(crate, beamTime)); if (fSaveWaveforms) m_wf = wave.Waveform(); From 0f471bc34ecfe83516648eec65230547f347f499 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 25 Sep 2024 14:49:08 -0500 Subject: [PATCH 25/52] update icarus::timing::NoTime value --- icaruscode/IcarusObj/PMTBeamSignal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icaruscode/IcarusObj/PMTBeamSignal.h b/icaruscode/IcarusObj/PMTBeamSignal.h index bc6b7eee7..842af0375 100644 --- a/icaruscode/IcarusObj/PMTBeamSignal.h +++ b/icaruscode/IcarusObj/PMTBeamSignal.h @@ -19,7 +19,7 @@ namespace icarus::timing /// Special value to denote no special channel information. static constexpr auto NoChannel = std::numeric_limits::max(); /// Special value to denote no time channel information. - static constexpr double NoTime = 0.; + static constexpr double NoTime = std::numeric_limits::max(); // Special value to denote no sample information. static constexpr std::size_t NoSample = 0; @@ -61,7 +61,7 @@ namespace icarus::timing double startTime = NoTime; /// Returns whether the time is valid. - bool isValid() const { return ((sample != NoSample) && (startTime != NoTime)); } + bool isValid() const { return (sample != NoSample); } }; } // namespace icarus::timing From b40bb52963d029f3db8f014ad8436446235d5fa3 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:52:16 -0400 Subject: [PATCH 26/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 066def5a3..053661138 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -37,12 +37,9 @@ #include #include -namespace icarus +namespace icarus::timing { - namespace timing - { - class PMTBeamSignalsExtractor; - } + class PMTBeamSignalsExtractor; } /** From fef1ed5177e56e1b0c0d5cdee0c0a754e7617e43 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:52:46 -0400 Subject: [PATCH 27/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 053661138..e482abde3 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -81,10 +81,10 @@ namespace icarus::timing * * the absolute minimum of the waveform is found * * an interval starting 20 ticks before that minimum is considered * * the baseline level is defined as the value at the start of that interval - * * if the baseline-minimum is below a threshold, it is assume to be noise + * * if the baseline-minimum difference is below a threshold, it is assume to be noise * and no time is returned * * if not, the start time is set to the exact tick with an amplitude exceeding 20% - * of the miminum of the signal from the baseline + * of the minimum of the signal from the baseline * * * Output products From 0462c1a695f571fac46a4b734626cbd01d01b2f1 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:53:24 -0400 Subject: [PATCH 28/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index e482abde3..79590f121 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -92,7 +92,7 @@ namespace icarus::timing * * This modules produces two `std::vector` * with 360 elements each, representing the relevent RWM or EW time for - * the corresponding PMT channel. + * the corresponding PMT channel. When the discrimination algorithm decides the "peak" on a waveform to be noise, the corresponding entries are placed into the vector with an invalid value (`isValid()` returns `false`, but the identification data fields are correctly set). * * If the event is offbeam or minbias, these vectors are produced empty. * From 8193092ee9c98cfa8367c617b8ef839a73f85208 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:53:37 -0400 Subject: [PATCH 29/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 79590f121..ba93c4bf6 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -15,7 +15,6 @@ #include "art/Framework/Principal/SubRun.h" #include "canvas/Utilities/InputTag.h" #include "fhiclcpp/ParameterSet.h" -#include "fhiclcpp/types/Atom.h" #include "messagefacility/MessageLogger/MessageLogger.h" #include "art_root_io/TFileService.h" From 141f6542f3373d6a01fe02ba4bdc59dec6895a8d Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:53:46 -0400 Subject: [PATCH 30/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index ba93c4bf6..dfe2f6ef4 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -10,9 +10,6 @@ #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" From ec953954a78bd22e9ff24093a9fb66c9a7a3a52e Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:11:51 -0400 Subject: [PATCH 31/52] Update icaruscode/Timing/CMakeLists.txt Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/icaruscode/Timing/CMakeLists.txt b/icaruscode/Timing/CMakeLists.txt index 4611ca0f7..ae52bce4e 100644 --- a/icaruscode/Timing/CMakeLists.txt +++ b/icaruscode/Timing/CMakeLists.txt @@ -8,14 +8,6 @@ set( MODULE_LIBRARIES art_root_io::TFileService_service art_root_io::tfile_support lardataobj::RawData - art::Framework_Core - art::Framework_Principal - art::Utilities - canvas::canvas - messagefacility::MF_MessageLogger - fhiclcpp::fhiclcpp - cetlib::cetlib - cetlib_except::cetlib_except ROOT::Tree ) set( LIB_LIBRARIES From b750cd66458a8663278b0a11fd153d0176098111 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:36:08 -0400 Subject: [PATCH 32/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- .../Timing/PMTBeamSignalsExtractor_module.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index dfe2f6ef4..c4be83c45 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -135,21 +135,21 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer /// Channel mappping icarusDB::IICARUSChannelMap const &fChannelMap; /// Save plain ROOT TTrees for debugging - bool fDebugTrees; + bool const fDebugTrees; /// Save raw waveforms in debug TTrees - bool fSaveWaveforms; + bool const fSaveWaveforms; /// Trigger instance label - art::InputTag fTriggerLabel; + art::InputTag const fTriggerLabel; /// RWM waveform instance label - art::InputTag fRWMlabel; + art::InputTag const fRWMlabel; /// EW waveform instance label - art::InputTag fEWlabel; + art::InputTag const fEWlabel; /// Trigger-hardware correction instance - art::InputTag fTriggerCorrectionLabel; + art::InputTag const fTriggerCorrectionLabel; /// Threshold for pulse selection - short int fADCThreshold; + short int const fADCThreshold; /// V1730 special channels setup - std::vector fBoardSetup; + std::vector const fBoardSetup; std::map fBoardBySpecialChannel; std::vector fCorrections; From f86ac9c1f3b604f9d2a6dd4506222d40ad45604d Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:36:24 -0400 Subject: [PATCH 33/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index c4be83c45..aaf8f79ff 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -28,6 +28,7 @@ #include #include +#include #include #include #include From b91cdc3f605b7042f979725185b3765a7053bea6 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:38:42 -0400 Subject: [PATCH 34/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index aaf8f79ff..061d9b2be 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -191,7 +191,7 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete // saving special_channel <-> board association in a map for (fhicl::ParameterSet const &setup : fBoardSetup) { - auto innerSet = setup.get>("SpecialChannels"); + auto const& innerSet = setup.get>("SpecialChannels"); fBoardBySpecialChannel[innerSet[0].get("Channel")] = setup.get("Name"); } From c4e50703296834148212582a5bd5361d0f5288e1 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:39:05 -0400 Subject: [PATCH 35/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 061d9b2be..6f0a43b58 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -62,6 +62,9 @@ namespace icarus::timing * stores the channel-by-channel waveform timing corrections * * `BoardSetup` (fhicl parameter set): description of the current * V1730 setup from `CAEN_V1730_setup_icarus.fcl` mapping the special signals. + It is meant to be the same configuration as used by the PMT decoding + (see `BoardSetup` configuration parameter in `icarus::DaqDecoderICARUSPMT`). + * * `ADCThreshold` (int): detection threshold to avoid cross-talk * noise if one signal is missing from its waveform. * * `DebugTrees` (bool): flag to produce plain ROOT trees for debugging. From e95fe593b95757200d2efbec41f7b80635860c00 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:39:30 -0400 Subject: [PATCH 36/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 6f0a43b58..5c2942176 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -201,7 +201,7 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete // pre-save the association between digitizer_label and effective fragment ID for (unsigned int fragid = 0; fragid < fChannelMap.nPMTfragmentIDs(); fragid++) { - auto pmtinfo = fChannelMap.getPMTchannelInfo(fragid)[0]; // pick first pmt on board + auto const& pmtinfo = fChannelMap.getPMTchannelInfo(fragid)[0]; // pick first pmt on board fBoardEffFragmentID[pmtinfo.digitizerLabel] = fragid; } From 1973812ab13b083246afaa4f331bda01ed49ee87 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:40:10 -0400 Subject: [PATCH 37/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 5c2942176..1ad451f00 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -130,7 +130,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer PMTBeamSignalsExtractor &operator=(PMTBeamSignalsExtractor const &) = delete; PMTBeamSignalsExtractor &operator=(PMTBeamSignalsExtractor &&) = delete; - void beginJob(); + void beginJob() override; void produce(art::Event &e) override; private: From efb8796bdf629e911a4e57386777ffc4a36085da Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:41:12 -0400 Subject: [PATCH 38/52] Update icaruscode/Timing/PMTBeamSignalsExtractor_module.cc Co-authored-by: Gianluca Petrillo --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 1ad451f00..397d5eed2 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -106,7 +106,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer // process waveforms void extractBeamSignalTime(art::Event &e, art::InputTag label); template - T Median(std::vector data) const; + static T Median(std::vector data); template static std::size_t getMaxBin(std::vector const &vv, std::size_t startElement, std::size_t endElement); template From c66a1ca0252cd4133b168a269f718e0b957ad252 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi <64699641+mvicenzi@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:10:04 -0400 Subject: [PATCH 39/52] change ttree lookup Co-authored-by: Gianluca Petrillo --- .../Timing/PMTBeamSignalsExtractor_module.cc | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 397d5eed2..a21f4137c 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -227,24 +227,25 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() { std::string name = l + "tree"; std::string desc = l + " info"; - fOutTree[l] = tfs->make(name.c_str(), desc.c_str()); - fOutTree[l]->Branch("run", &m_run); - fOutTree[l]->Branch("event", &m_event); - fOutTree[l]->Branch("timestamp", &m_timestamp); - fOutTree[l]->Branch("n_channels", &m_n_channels); - fOutTree[l]->Branch("channel", &m_channel); - fOutTree[l]->Branch("wfstart", &m_wfstart); - fOutTree[l]->Branch("sample", &m_sample); - fOutTree[l]->Branch("utime_abs", &m_utime_abs); - fOutTree[l]->Branch("time_abs", &m_time_abs); - fOutTree[l]->Branch("time", &m_time); + TTree* tree = tfs->make(name.c_str(), desc.c_str()); + tree->Branch("run", &m_run); + tree->Branch("event", &m_event); + tree->Branch("timestamp", &m_timestamp); + tree->Branch("n_channels", &m_n_channels); + tree->Branch("channel", &m_channel); + tree->Branch("wfstart", &m_wfstart); + tree->Branch("sample", &m_sample); + tree->Branch("utime_abs", &m_utime_abs); + tree->Branch("time_abs", &m_time_abs); + tree->Branch("time", &m_time); // add std::vector with full waveforms // this can quickly make the TTrees quite heavy if (fSaveWaveforms) { - fOutTree[l]->Branch("wf", &m_wf); + tree->Branch("wf", &m_wf); } + fOutTree[l] = tree; } } From b7aba88836c028775e0404b6dfb104170c3f925c Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 10:57:41 -0500 Subject: [PATCH 40/52] update comments, remove tfs from class members --- .../Timing/PMTBeamSignalsExtractor_module.cc | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index a21f4137c..0d5088ae3 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -62,8 +62,8 @@ namespace icarus::timing * stores the channel-by-channel waveform timing corrections * * `BoardSetup` (fhicl parameter set): description of the current * V1730 setup from `CAEN_V1730_setup_icarus.fcl` mapping the special signals. - It is meant to be the same configuration as used by the PMT decoding - (see `BoardSetup` configuration parameter in `icarus::DaqDecoderICARUSPMT`). + * It is meant to be the same configuration as used by the PMT decoding + * (see `BoardSetup` configuration parameter in `icarus::DaqDecoderICARUSPMT`). * * `ADCThreshold` (int): detection threshold to avoid cross-talk * noise if one signal is missing from its waveform. @@ -81,7 +81,7 @@ namespace icarus::timing * * the absolute minimum of the waveform is found * * an interval starting 20 ticks before that minimum is considered * * the baseline level is defined as the value at the start of that interval - * * if the baseline-minimum difference is below a threshold, it is assume to be noise + * * if the baseline-minimum difference is below a threshold, it is assumed to be noise * and no time is returned * * if not, the start time is set to the exact tick with an amplitude exceeding 20% * of the minimum of the signal from the baseline @@ -92,9 +92,12 @@ namespace icarus::timing * * 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 into the vector with an invalid value (`isValid()` returns `false`, but the identification data fields are correctly set). + * the corresponding PMT channel. When the discrimination algorithm decides + * the "peak" on a waveform to be noise, the corresponding entries are placed + * into the vector with an invalid value (`isValid()` returns `false`, + * but the identification data fields are correctly set). * - * If the event is offbeam or minbias, these vectors are produced empty. + * If the event is offbeam, these vectors are produced empty. * */ @@ -134,8 +137,6 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer void produce(art::Event &e) override; private: - art::ServiceHandle tfs; - /// Channel mappping icarusDB::IICARUSChannelMap const &fChannelMap; /// Save plain ROOT TTrees for debugging @@ -194,14 +195,14 @@ icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::Paramete // saving special_channel <-> board association in a map for (fhicl::ParameterSet const &setup : fBoardSetup) { - auto const& innerSet = setup.get>("SpecialChannels"); + auto const &innerSet = setup.get>("SpecialChannels"); fBoardBySpecialChannel[innerSet[0].get("Channel")] = setup.get("Name"); } // pre-save the association between digitizer_label and effective fragment ID for (unsigned int fragid = 0; fragid < fChannelMap.nPMTfragmentIDs(); fragid++) { - auto const& pmtinfo = fChannelMap.getPMTchannelInfo(fragid)[0]; // pick first pmt on board + auto const &pmtinfo = fChannelMap.getPMTchannelInfo(fragid)[0]; // pick first pmt on board fBoardEffFragmentID[pmtinfo.digitizerLabel] = fragid; } @@ -222,6 +223,7 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() if (!fDebugTrees) return; + art::ServiceHandle tfs; std::vector labels = {fRWMlabel.instance(), fEWlabel.instance()}; for (auto l : labels) { From fb881ae7dd82ff028d6302b5e31df01fd17a2f8a Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 13:08:04 -0500 Subject: [PATCH 41/52] initialization changes, use of beginRun, move to static function, const for board setup --- .../Timing/PMTBeamSignalsExtractor_module.cc | 74 +++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 0d5088ae3..a6475de7b 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -117,6 +117,9 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer template static std::size_t getStartSample(std::vector const &vv, T thres); + // unpack the V1730 special channels settings in a useful way + static std::map extractBoardBySpecialChannel(std::vector const &setup); + // associate times to PMT channels void associateBeamSignalsToChannels(art::InputTag label); @@ -134,6 +137,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer PMTBeamSignalsExtractor &operator=(PMTBeamSignalsExtractor &&) = delete; void beginJob() override; + void beginRun(art::Run &run) override; void produce(art::Event &e) override; private: @@ -153,10 +157,9 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer art::InputTag const fTriggerCorrectionLabel; /// Threshold for pulse selection short int const fADCThreshold; - /// V1730 special channels setup - std::vector const fBoardSetup; + /// Special channel to board association in a map + std::map const fBoardBySpecialChannel; - std::map fBoardBySpecialChannel; std::vector fCorrections; std::map fBoardEffFragmentID; double ftrigger_time; @@ -188,24 +191,17 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer // ----------------------------------------------------------------------------- icarus::timing::PMTBeamSignalsExtractor::PMTBeamSignalsExtractor(fhicl::ParameterSet const &pset) - : EDProducer{pset}, fChannelMap(*(art::ServiceHandle{})), fDebugTrees(pset.get("DebugTrees")), fSaveWaveforms(pset.get("SaveWaveforms")), fTriggerLabel(pset.get("TriggerLabel")), fRWMlabel(pset.get("RWMlabel")), fEWlabel(pset.get("EWlabel")), fTriggerCorrectionLabel(pset.get("TriggerCorrectionLabel")), fADCThreshold(pset.get("ADCThreshold")), fBoardSetup(pset.get>("BoardSetup")) + : EDProducer{pset}, + fChannelMap(*(art::ServiceHandle{})), + fDebugTrees(pset.get("DebugTrees")), + fSaveWaveforms(pset.get("SaveWaveforms")), + fTriggerLabel(pset.get("TriggerLabel")), + fRWMlabel(pset.get("RWMlabel")), + fEWlabel(pset.get("EWlabel")), + fTriggerCorrectionLabel(pset.get("TriggerCorrectionLabel")), + fADCThreshold(pset.get("ADCThreshold")), + fBoardBySpecialChannel(extractBoardBySpecialChannel(pset.get>("BoardSetup"))) { - - // unpack the V1730 special channels settings in a useful way - // saving special_channel <-> board association in a map - for (fhicl::ParameterSet const &setup : fBoardSetup) - { - auto const &innerSet = setup.get>("SpecialChannels"); - fBoardBySpecialChannel[innerSet[0].get("Channel")] = setup.get("Name"); - } - - // pre-save the association between digitizer_label and effective fragment ID - for (unsigned int fragid = 0; fragid < fChannelMap.nPMTfragmentIDs(); fragid++) - { - auto const &pmtinfo = fChannelMap.getPMTchannelInfo(fragid)[0]; // pick first pmt on board - fBoardEffFragmentID[pmtinfo.digitizerLabel] = fragid; - } - // Call appropriate consumes<>() functions here. consumes>(fEWlabel); consumes>(fRWMlabel); @@ -253,6 +249,21 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() // ----------------------------------------------------------------------------- +void icarus::timing::PMTBeamSignalsExtractor::beginRun(art::Run &run) +{ + // pre-save the association between digitizer_label and effective fragment ID + // needs to be done at the begin of each run in case mapping changed + fBoardEffFragmentID.clear(); + + for (unsigned int fragid = 0; fragid < fChannelMap.nPMTfragmentIDs(); fragid++) + { + auto const &pmtinfo = fChannelMap.getPMTchannelInfo(fragid)[0]; // pick first pmt on board + fBoardEffFragmentID[pmtinfo.digitizerLabel] = fragid; + } +} + +// ----------------------------------------------------------------------------- + void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) { @@ -378,7 +389,7 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & // --------------------------------------------------------------------------- template -T icarus::timing::PMTBeamSignalsExtractor::Median(std::vector data) const +T icarus::timing::PMTBeamSignalsExtractor::Median(std::vector data) { std::nth_element(data.begin(), data.begin() + data.size() / 2, data.end()); @@ -454,11 +465,30 @@ std::size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample(std::vector< // ----------------------------------------------------------------------------- +std::map icarus::timing::PMTBeamSignalsExtractor::extractBoardBySpecialChannel( + std::vector const &setup) +{ + + // map from special PMT channel to corresponding board + std::map boardBySpecialChannel; + + // unpack the V1730 special channels settings in a useful way + for (fhicl::ParameterSet const &s : setup) + { + auto const &innerSet = s.get>("SpecialChannels"); + boardBySpecialChannel[innerSet[0].get("Channel")] = s.get("Name"); + } + + return boardBySpecialChannel; +} + +// ----------------------------------------------------------------------------- + std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int channel) { // get the board name, convert to digitizer_label - std::string board = fBoardBySpecialChannel[channel]; + std::string board = fBoardBySpecialChannel.at(channel); std::string head = "icaruspmt"; std::string dash = "-"; From ae099a32f57b99269efdaada10131d928b8041ec Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 13:18:00 -0500 Subject: [PATCH 42/52] remove beamType, doxygen header --- .../Timing/PMTBeamSignalsExtractor_module.cc | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index a6475de7b..021dbf7d2 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -1,10 +1,10 @@ //////////////////////////////////////////////////////////////////////// -// Class: PMTBeamSignalsExtractor -// Plugin Type: producer (Unknown Unknown) -// File: PMTBeamSignalsExtractor_module.cc -// -// Generated at Sun Feb 11 11:37:14 2024 by Matteo Vicenzi using cetskelgen -// from version . +/** + * @file icaruscode/Timing/PMTBeamSignalsExtractor_module.cc + * @brief `icarus::timing::PMTBeamSignalsExtractor` producer module. + * @author Matteo Vicenzi (mvicenzi@bnl.gov) + * @date Sun Feb 11 11:37:14 2024 + **/ //////////////////////////////////////////////////////////////////////// #include "art/Framework/Core/EDProducer.h" @@ -225,7 +225,7 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() { std::string name = l + "tree"; std::string desc = l + " info"; - TTree* tree = tfs->make(name.c_str(), desc.c_str()); + TTree *tree = tfs->make(name.c_str(), desc.c_str()); tree->Branch("run", &m_run); tree->Branch("event", &m_event); tree->Branch("timestamp", &m_timestamp); @@ -283,15 +283,12 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) // check the current beam gate auto const trigger_handle = e.getProduct(fTriggerLabel); sbn::triggerSource const gateType = trigger_handle.sourceType; - std::string beamType = ""; switch (gateType) { case sbn::triggerSource::BNB: - beamType = "BNB"; break; case sbn::triggerSource::NuMI: - beamType = "NuMI"; break; default: mf::LogTrace("PMTBeamSignalsExtractor") << "Skipping offbeam gate '" << name(gateType) << "'"; @@ -327,7 +324,7 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) // place data products in the stream // fix the cable swap for part of Run 2 right here!! // see SBN-doc-34631 for details - if (beamType == "BNB" && m_run > 9704 && m_run < 11443) + if (gateType == sbn::triggerSource::BNB && m_run > 9704 && m_run < 11443) { e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "EW"); From 6d1ce5c8f14311280a8d21bbffbc80e59fe77647 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 13:46:23 -0500 Subject: [PATCH 43/52] remove use of detTiming for times --- .../PMT/OpReco/ICARUSBeamStructureAna_module.cc | 13 +++---------- .../Timing/PMTBeamSignalsExtractor_module.cc | 16 +++++++--------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index 1ead53c74..110d4c31c 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -30,9 +30,7 @@ #include "lardataobj/RecoBase/OpFlash.h" #include "lardataobj/RecoBase/OpHit.h" #include "icaruscode/Decode/ChannelMapping/IICARUSChannelMap.h" -#include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom() -#include "lardata/DetectorInfoServices/DetectorClocksService.h" -#include "lardataalg/DetectorInfo/DetectorTimings.h" +#include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom() #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time #include "lardataobj/RawData/OpDetWaveform.h" #include "lardataobj/Simulation/BeamGateInfo.h" @@ -251,11 +249,6 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) // ---- // Trigger metadata information - detinfo::DetectorTimings const detTimings = detinfo::makeDetectorTimings( - art::ServiceHandle()->DataFor(e)); - detinfo::timescales::electronics_time triggerTime = detTimings.TriggerTime(); - detinfo::timescales::electronics_time beamGateTime = detTimings.BeamGateTime(); - if (!fTriggerLabel.empty()) { @@ -274,8 +267,8 @@ void opana::ICARUSBeamStructureAna::analyze(art::Event const &e) m_beam_gate_timestamp = extraInfo.beamGateTimestamp; // time in electronics time - m_trigger_us = triggerTime.value(); - m_beam_us = beamGateTime.value(); + m_trigger_us = e.getProduct>(fTriggerLabel).at(0).TriggerTime(); // us + m_beam_us = e.getProduct>(fTriggerLabel).at(0).BeamGateTime(); // us m_beam_gate_width = fTriggerConfiguration.getGateWidth(m_gate_type); } else diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 021dbf7d2..69561fb58 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -19,10 +19,9 @@ #include "icaruscode/Decode/ChannelMapping/IICARUSChannelMap.h" #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" #include "icaruscode/IcarusObj/PMTBeamSignal.h" -#include "lardata/DetectorInfoServices/DetectorClocksService.h" -#include "lardataalg/DetectorInfo/DetectorTimings.h" #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time #include "lardataobj/RawData/OpDetWaveform.h" +#include "lardataobj/RawData/TriggerData.h" #include "TTree.h" @@ -162,7 +161,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer std::vector fCorrections; std::map fBoardEffFragmentID; - double ftrigger_time; + double ftriggerTime; // output TTrees std::map fOutTree; @@ -275,14 +274,13 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) // extract meta event information m_run = e.id().run(); m_event = e.id().event(); - m_timestamp = e.time().timeHigh(); // precision to the second - auto const detTimings = detinfo::makeDetectorTimings(art::ServiceHandle()->DataFor(e)); - ftrigger_time = detTimings.TriggerTime().value(); + m_timestamp = e.time().timeHigh(); // precision to the second + ftriggerTime = e.getProduct>(fTriggerLabel).at(0).TriggerTime(); // us // this module should run on beam-only events // check the current beam gate - auto const trigger_handle = e.getProduct(fTriggerLabel); - sbn::triggerSource const gateType = trigger_handle.sourceType; + auto const &triggerInfo = e.getProduct(fTriggerLabel); + sbn::triggerSource const gateType = triggerInfo.sourceType; switch (gateType) { @@ -370,7 +368,7 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & m_wfstart = tstart.value(); m_utime_abs = (m_sample != icarus::timing::NoSample) ? tstart.value() + 0.002 * 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 - ftrigger_time : icarus::timing::NoTime; + m_time = (m_sample != icarus::timing::NoSample) ? m_time_abs - ftriggerTime : icarus::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}; From b46c5ae0b0073cdac2a7df9f1a1bf0c824f75beb Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 13:59:25 -0500 Subject: [PATCH 44/52] updating CMakeList.txt --- icaruscode/PMT/OpReco/CMakeLists.txt | 8 ++++---- icaruscode/Timing/CMakeLists.txt | 4 ++-- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/icaruscode/PMT/OpReco/CMakeLists.txt b/icaruscode/PMT/OpReco/CMakeLists.txt index d56ee4ef3..129cd515f 100644 --- a/icaruscode/PMT/OpReco/CMakeLists.txt +++ b/icaruscode/PMT/OpReco/CMakeLists.txt @@ -16,10 +16,10 @@ cet_build_plugin(ICARUSOpHitFinder art::module set( MODULE_LIBRARIES - icarusalg::Utilities + icarusalg::Utilities sbnobj::Common_Trigger - icaruscode::Decode_DataProducts - larcorealg::Geometry + icaruscode::Decode_DataProducts + larcorealg::Geometry larcore::Geometry_Geometry_service lardataobj::RecoBase lardataobj::Simulation @@ -49,7 +49,7 @@ set( MODULE_LIBRARIES ROOT::Gdml ROOT::FFTW ROOT::Core - ROOT::Tree + ROOT::Tree ) cet_build_plugin(FakeFlash art::module LIBRARIES ${MODULE_LIBRARIES}) cet_build_plugin(FakePhotoS art::module LIBRARIES ${MODULE_LIBRARIES}) diff --git a/icaruscode/Timing/CMakeLists.txt b/icaruscode/Timing/CMakeLists.txt index ae52bce4e..85fc1cc05 100644 --- a/icaruscode/Timing/CMakeLists.txt +++ b/icaruscode/Timing/CMakeLists.txt @@ -4,7 +4,7 @@ set( MODULE_LIBRARIES lardataobj::RecoBase sbnobj::Common_Trigger larcore::Geometry_Geometry_service - lardata::DetectorInfoServices_DetectorClocksServiceStandard_service + lardata::DetectorClocksService art_root_io::TFileService_service art_root_io::tfile_support lardataobj::RawData @@ -24,7 +24,7 @@ set( SERVICE_LIBRARIES icaruscode_Timing icaruscode_IcarusObj larcore::Geometry_Geometry_service - lardata::DetectorInfoServices_DetectorClocksServiceStandard_service + lardata::DetectorClocksService ) file(GLOB lib_srcs *.cxx) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 69561fb58..7b7c4d99c 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -20,6 +20,7 @@ #include "icaruscode/IcarusObj/PMTWaveformTimeCorrection.h" #include "icaruscode/IcarusObj/PMTBeamSignal.h" #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // electronics_time +#include "lardataalg/Utilities/quantities/spacetime.h" #include "lardataobj/RawData/OpDetWaveform.h" #include "lardataobj/RawData/TriggerData.h" From 016b1d06be5b73257d0c273694ec80edaeead1a7 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 14:30:40 -0500 Subject: [PATCH 45/52] change labels to const, update to debug tree --- .../Timing/PMTBeamSignalsExtractor_module.cc | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 7b7c4d99c..304e63018 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -33,6 +33,7 @@ #include #include #include +#include namespace icarus::timing { @@ -99,6 +100,26 @@ namespace icarus::timing * * If the event is offbeam, these vectors are produced empty. * + * * + * Debugging tree + * --------------- + * + * There are two debugging trees, enabled by `DebugTrees`, one for the Early Warning (EW) signals, + * named after the instance name of `EWlabel`, and one for the Resistive Wall Monitor (RWM) signals, + * named after the instance name of `RWMlabel`. Each entry in the tree represents a single signal + * in an event (thus, typically for ICARUS there are 8 entries per event). + * The content of an entry includes: + * * `run`, `event`: identifier of the event. + * * `timestamp`: timestamp of the event (in UTC), truncated at the second. + * * `n_channels`: the number of special signal channels in the event. + * * `channel`: the special channel nummber assigned to this signal. + * * `wfstart`: (uncorrected) waveform time start. + * * `sample`: the sample number in the waveform at which the signal was found. + * * `utime_abs`: uncorrected signal time [µs] + * * `time_abs`: corrected signal time [µs] + * * `time`: corrected signal time (relative to the trigger time) [µs] + * * `nsize` (only if `SaveWaveforms` is set): number of samples in waveform + * * `wf` (only if `SaveWaveforms` is set): full waveform. */ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer @@ -107,7 +128,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer explicit PMTBeamSignalsExtractor(fhicl::ParameterSet const &pset); // process waveforms - void extractBeamSignalTime(art::Event &e, art::InputTag label); + void extractBeamSignalTime(art::Event &e, art::InputTag const &label); template static T Median(std::vector data); template @@ -121,7 +142,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer static std::map extractBoardBySpecialChannel(std::vector const &setup); // associate times to PMT channels - void associateBeamSignalsToChannels(art::InputTag label); + void associateBeamSignalsToChannels(art::InputTag const &label); // trigger-hardware timing correction double getTriggerCorrection(int channel); @@ -178,6 +199,7 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer double m_time; double m_time_abs; double m_utime_abs; + std::size_t m_nsize; std::vector m_wf; // prepare pointers for data products @@ -220,7 +242,7 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() return; art::ServiceHandle tfs; - std::vector labels = {fRWMlabel.instance(), fEWlabel.instance()}; + std::array const labels = {fRWMlabel.instance(), fEWlabel.instance()}; for (auto l : labels) { std::string name = l + "tree"; @@ -241,6 +263,7 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() // this can quickly make the TTrees quite heavy if (fSaveWaveforms) { + tree->Branch("nsize", &m_nsize); tree->Branch("wf", &m_wf); } fOutTree[l] = tree; @@ -339,10 +362,10 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) // ----------------------------------------------------------------------------- -void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event &e, art::InputTag label) +void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event &e, art::InputTag const &label) { - std::string l = label.instance(); + std::string const &l = label.encode(); auto const &waveforms = e.getProduct>(label); m_n_channels = waveforms.size(); @@ -355,8 +378,8 @@ 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 time to "NoTime" so that it triggers the isValid() call of PMTBeamSignal - + // if no signal is found, set both times to icarus::timing::NoTime + // so that `isValid()` in PMTBeamSignal will complain if someone checks it for (auto const &wave : waveforms) { @@ -375,10 +398,15 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & icarus::timing::PMTBeamSignal beamTime{m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time}; fBeamSignals[l].insert(std::make_pair(crate, beamTime)); - if (fSaveWaveforms) - m_wf = wave.Waveform(); if (fDebugTrees) + { + if (fSaveWaveforms) + { + m_wf = wave.Waveform(); + m_nsize = m_wf.size(); + } fOutTree[l]->Fill(); + } } } @@ -527,10 +555,10 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel // ----------------------------------------------------------------------------- -void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art::InputTag label) +void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art::InputTag const &label) { - std::string l = label.instance(); + std::string const &l = label.instance(); // loop through the signals which are one per PMT crate // for each crate, find the corresponding digitizers From 17312c2007234fab5db1f544901d2addbe367321 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 14:38:55 -0500 Subject: [PATCH 46/52] adding sampling tick as variable --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 304e63018..1c125311e 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -181,6 +181,9 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer /// Special channel to board association in a map std::map const fBoardBySpecialChannel; + /// PMT sample duration [µs] + static constexpr double fPMTsamplingTick = 0.002; + std::vector fCorrections; std::map fBoardEffFragmentID; double ftriggerTime; @@ -390,7 +393,7 @@ 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() + 0.002 * m_sample : icarus::timing::NoTime; + 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; From 378a77df2d08aa5edbdbca6a49214f71c57a44df Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 14:45:33 -0500 Subject: [PATCH 47/52] avoid copies at all costs... --- .../Timing/PMTBeamSignalsExtractor_module.cc | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 1c125311e..09246fae8 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -145,11 +145,11 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer void associateBeamSignalsToChannels(art::InputTag const &label); // trigger-hardware timing correction - double getTriggerCorrection(int channel); + double getTriggerCorrection(int channel) const; // quick mapping conversions - std::string getDigitizerLabel(int channel); - std::string getCrate(int channel); + std::string getDigitizerLabel(int channel) const; + std::string getCrate(int channel) const; // Plugins should not be copied or assigned. PMTBeamSignalsExtractor(PMTBeamSignalsExtractor const &) = delete; @@ -350,17 +350,10 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) // fix the cable swap for part of Run 2 right here!! // see SBN-doc-34631 for details if (gateType == sbn::triggerSource::BNB && m_run > 9704 && m_run < 11443) - { - - e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "EW"); - e.put(std::move(fSignalCollection[fEWlabel.instance()]), "RWM"); - } - else - { // STANDARD BEHAVIOR + std::swap(fSignalCollection[fRWMlabel.instance()], fSignalCollection[fEWlabel.instance()]); - e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "RWM"); - e.put(std::move(fSignalCollection[fEWlabel.instance()]), "EW"); - } + e.put(std::move(fSignalCollection[fRWMlabel.instance()]), "RWM"); + e.put(std::move(fSignalCollection[fEWlabel.instance()]), "EW"); } // ----------------------------------------------------------------------------- @@ -399,7 +392,7 @@ void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event & std::string crate = getCrate(m_channel); icarus::timing::PMTBeamSignal beamTime{m_channel, getDigitizerLabel(m_channel), crate, m_sample, m_time_abs, m_time}; - fBeamSignals[l].insert(std::make_pair(crate, beamTime)); + fBeamSignals[l].emplace(crate, std::move(beamTime)); if (fDebugTrees) { @@ -511,7 +504,7 @@ std::map icarus::timing::PMTBeamSignalsExtractor::extractBoard // ----------------------------------------------------------------------------- -std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int channel) +std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int channel) const { // get the board name, convert to digitizer_label @@ -531,7 +524,7 @@ std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int chann // ----------------------------------------------------------------------------- -std::string icarus::timing::PMTBeamSignalsExtractor::getCrate(int channel) +std::string icarus::timing::PMTBeamSignalsExtractor::getCrate(int channel) const { std::string digitizer_label = getDigitizerLabel(channel); @@ -540,7 +533,7 @@ std::string icarus::timing::PMTBeamSignalsExtractor::getCrate(int channel) // ----------------------------------------------------------------------------- -double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel) +double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel) const { std::string digitizer_label = getDigitizerLabel(channel); @@ -565,12 +558,12 @@ void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art // loop through the signals which are one per PMT crate // for each crate, find the corresponding digitizers - for (auto signal : fBeamSignals[l]) + for (auto const &signal : fBeamSignals[l]) { // build the PMT digitizer labels that live in this crate // then convert it into fragment id - std::vector letters = {"-A", "-B", "-C"}; + std::array const letters = {"-A", "-B", "-C"}; for (auto letter : letters) { From af99a3c3c72abf7a740ccd6a6119023f2e1e46c1 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 14:56:36 -0500 Subject: [PATCH 48/52] prevent selecting negative bins --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 09246fae8..264709f00 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -455,10 +455,10 @@ std::size_t icarus::timing::PMTBeamSignalsExtractor::getStartSample(std::vector< std::size_t minbin = getMinBin(vv, 0, vv.size()); // Search only a cropped region of the waveform backward from the min - std::size_t maxbin = minbin - 20; + std::size_t maxbin = (minbin - 20) ? (minbin - 20) : 0; // Now we crawl betweem maxbin and minbin and we stop when: - // bin value > (maxbin value - bin value )*0.2 + // maxbin value - bin value > (maxbin value - minbin value )*0.2 std::size_t startbin = maxbin; auto delta = vv[maxbin] - vv[minbin]; @@ -540,7 +540,7 @@ double icarus::timing::PMTBeamSignalsExtractor::getTriggerCorrection(int channel // trigger-hardware corrections are shared by all channels on the same board // we can pick the first channel on the desired board - int fragID = fBoardEffFragmentID[digitizer_label]; + int fragID = fBoardEffFragmentID.at(digitizer_label); auto pmtinfo = fChannelMap.getPMTchannelInfo(fragID)[0]; // pick first ch on board int pmtch = pmtinfo.channelID; From b387b3074bd66c2579a17a37d6792c8c80c78e0c Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 15:14:06 -0500 Subject: [PATCH 49/52] char witchcraft --- .../Timing/PMTBeamSignalsExtractor_module.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 264709f00..1f3504a1f 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -508,18 +508,17 @@ std::string icarus::timing::PMTBeamSignalsExtractor::getDigitizerLabel(int chann { // get the board name, convert to digitizer_label - std::string board = fBoardBySpecialChannel.at(channel); + std::string board = fBoardBySpecialChannel.at(channel); // eg. icaruspmtewtop02 std::string head = "icaruspmt"; - std::string dash = "-"; - std::string letter = (board.substr(board.size() - 2, board.size()) == "02") ? "B" : "C"; + char letter = board.back() - '1' + 'A'; // converts 01,02,03 to A,B,C - board.erase(board.find(head), head.size()); - std::transform(board.begin(), board.end(), board.begin(), ::toupper); - board.insert(2, dash); - board.insert(6, dash); + board.erase(board.find(head), head.size()); // eg. ewtop02 + std::transform(board.begin(), board.end(), board.begin(), ::toupper); // eg. EWTOP02 + board.insert(2, 1, '-'); // insert dash at position 2, e.g: EW-TOP02 + board.insert(6, 1, '-'); // insert dash at position 6, e.g: EW-TOP-02 - return board.substr(0, board.size() - 2) + letter; + return board.substr(0, board.size() - 2) + letter; // e.g: EW-TOP-B } // ----------------------------------------------------------------------------- @@ -563,7 +562,7 @@ void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art // build the PMT digitizer labels that live in this crate // then convert it into fragment id - std::array const letters = {"-A", "-B", "-C"}; + std::array const letters{"-A", "-B", "-C"}; for (auto letter : letters) { From 806e3a971ec5bb4b135c3abca1ad46d127f77030 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 15:35:30 -0500 Subject: [PATCH 50/52] pre-allocating size to avoid dynamic resizing --- .../Timing/PMTBeamSignalsExtractor_module.cc | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index 1f3504a1f..de1876ad4 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -183,6 +183,8 @@ class icarus::timing::PMTBeamSignalsExtractor : public art::EDProducer /// PMT sample duration [µs] static constexpr double fPMTsamplingTick = 0.002; + /// Number of PMT channels + static constexpr std::size_t fNPMTChannels = 360; std::vector fCorrections; std::map fBoardEffFragmentID; @@ -322,18 +324,23 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) return; } + // reside the collections to match the expected 360 PMT channels + // this is to avoid dynamic resizing later on + for (auto &collection : fSignalCollection) + collection.second->resize(fNPMTChannels); + // get the trigger-hardware corrections that are applied on all signal waveforms // if EW or RWM is to be compared to the PMT signals, it must be applied on them as well // it also takes care of board-to-board offsets (see SBN-doc-34631, slide 5) // Note: this is a vector of 360 elements, one correction for each signal channel fCorrections = e.getProduct>(fTriggerCorrectionLabel); - int ntrig = fCorrections.size(); + std::size_t ntrig = fCorrections.size(); if (ntrig < 1) mf::LogError("PMTBeamSignalsExtractor") << "Not found PMTWaveformTimeCorrections with label '" << fTriggerCorrectionLabel.instance() << "'"; - else if (ntrig < 360) - mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 360 - ntrig << " PMTWaveformTimeCorrections with label '" + else if (ntrig < fNPMTChannels) + mf::LogError("PMTBeamSignalsExtractor") << "Missing " << fNPMTChannels - ntrig << " PMTWaveformTimeCorrections with label '" << fTriggerCorrectionLabel.instance() << "'"; // now the main course: getting EW and RWM waveforms @@ -576,10 +583,8 @@ void icarus::timing::PMTBeamSignalsExtractor::associateBeamSignalsToChannels(art { std::size_t channel = pmtinfo.channelID; - // make sure there is enough room in the collection (channel -> vector index) - if (channel >= fSignalCollection[l]->size()) - fSignalCollection[l]->resize(channel + 1); - + // collections are resized to fNPMTChannels + // always room in the collection (channel -> vector index) fSignalCollection[l]->at(channel) = signal.second; } // for each channel From 50c80eeae16e5cf0bb6c3ff9f7040a77baf0b924 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 30 Sep 2024 19:57:51 -0500 Subject: [PATCH 51/52] fix segfault --- icaruscode/Timing/PMTBeamSignalsExtractor_module.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc index de1876ad4..c190f770f 100644 --- a/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc +++ b/icaruscode/Timing/PMTBeamSignalsExtractor_module.cc @@ -247,7 +247,7 @@ void icarus::timing::PMTBeamSignalsExtractor::beginJob() return; art::ServiceHandle tfs; - std::array const labels = {fRWMlabel.instance(), fEWlabel.instance()}; + std::array const labels{fRWMlabel.instance(), fEWlabel.instance()}; for (auto l : labels) { std::string name = l + "tree"; @@ -368,14 +368,15 @@ void icarus::timing::PMTBeamSignalsExtractor::produce(art::Event &e) void icarus::timing::PMTBeamSignalsExtractor::extractBeamSignalTime(art::Event &e, art::InputTag const &label) { - std::string const &l = label.encode(); + std::string const &l = label.instance(); auto const &waveforms = e.getProduct>(label); m_n_channels = waveforms.size(); if (m_n_channels < 1) - mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << l << "'"; + mf::LogError("PMTBeamSignalsExtractor") << "Not found raw::OpDetWaveform with label '" << label.encode() << "'"; else if (m_n_channels < 8) - mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 8 - m_n_channels << " raw::OpDetWaveform with label '" << l << "'"; + mf::LogError("PMTBeamSignalsExtractor") << "Missing " << 8 - m_n_channels << " raw::OpDetWaveform with label '" + << label.encode() << "'"; m_wf.clear(); From ab70fc793a8249f07270c1d2f9ec1409805f286b Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 2 Oct 2024 22:18:59 -0500 Subject: [PATCH 52/52] change default to NoTime for missing signal --- .../OpReco/ICARUSBeamStructureAna_module.cc | 27 +++++++++------- .../PMT/OpReco/ICARUSFlashAssAna_module.cc | 32 +++++++++++++------ 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc index 110d4c31c..6771e596c 100644 --- a/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSBeamStructureAna_module.cc @@ -161,7 +161,12 @@ class opana::ICARUSBeamStructureAna : public art::EDAnalyzer // -------------------------------------------------------------------------- opana::ICARUSBeamStructureAna::ICARUSBeamStructureAna(Parameters const &config) - : art::EDAnalyzer(config), fFlashLabels(config().FlashLabels()), fTriggerLabel(config().TriggerLabel()), fRWMLabel(config().RWMLabel()), fTriggerConfigurationLabel(config().TriggerConfigLabel()), fCRTPMTMatchingLabel(config().CRTPMTMatchingLabel()) + : art::EDAnalyzer(config), + fFlashLabels(config().FlashLabels()), + fTriggerLabel(config().TriggerLabel()), + fRWMLabel(config().RWMLabel()), + fTriggerConfigurationLabel(config().TriggerConfigLabel()), + fCRTPMTMatchingLabel(config().CRTPMTMatchingLabel()) { } @@ -456,7 +461,7 @@ double opana::ICARUSBeamStructureAna::getRWMRelativeTime(int channel, double t) { if (fRWMTimes.empty()) - return 0; + return icarus::timing::NoTime; auto rwm = fRWMTimes.at(channel); if (!rwm.isValid()) @@ -465,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 0; + return icarus::timing::NoTime; } double rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] @@ -480,10 +485,10 @@ double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channel double tfirst_left = std::numeric_limits::max(); double tfirst_right = std::numeric_limits::max(); - // if no RWM info available, all pmt_start_time_rwm is zero - // return zero as well for the flash + // if no RWM info available, all pmt_start_time_rwm are invalid + // return icarus::timing::NoTime as well for the flash if (fRWMTimes.empty()) - return 0; + return icarus::timing::NoTime; int nleft = 0; int nright = 0; @@ -494,11 +499,11 @@ double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channel int side = getSideByChannel(ch); double t = hit_rise_time_rwm[i]; // rise time w.r.t. rwm - // if RWM is missing for some PMT channels, - // it might not be possible to use the first hits (might not have RMW time) - // so return zero as in other bad cases + // 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 if (!fRWMTimes[i].isValid()) - return 0; + return icarus::timing::NoTime; // count hits separetely on the two walls if (side == 0) @@ -515,7 +520,7 @@ double opana::ICARUSBeamStructureAna::getFlashBunchTime(std::vector channel } } - // if there are no hits in one of the walls... + // if there are no hits in one of the walls... very rare? if (nleft < 1 || nright < 1) { mf::LogWarning("ICARUSBeamStructureAna") << "Flash " << m_flash_id << " doesn't have hits on both walls!" diff --git a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc index b9e6cfb8b..3943a5664 100644 --- a/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc +++ b/icaruscode/PMT/OpReco/ICARUSFlashAssAna_module.cc @@ -260,7 +260,19 @@ class opana::ICARUSFlashAssAna : public art::EDAnalyzer // ---------------------------------------------------------------------------- opana::ICARUSFlashAssAna::ICARUSFlashAssAna(Parameters const &config) - : EDAnalyzer(config), fTriggerLabel(config().TriggerLabel()), fSaveWaveformInfo(config().DumpWaveformsInfo()), fSaveRawWaveforms(config().SaveRawWaveforms()), fUseSharedBaseline(config().UseSharedBaseline()), fOpDetWaveformLabels(config().OpDetWaveformLabels()), fBaselineLabels(config().BaselineLabels()), fOpHitLabels(config().OpHitLabels()), fFlashLabels(config().FlashLabels()), fRWMLabel(config().RWMLabel()), fPEOpHitThreshold(config().PEOpHitThreshold()), fDebug(config().Debug()), fGeom(lar::providerFrom()) + : EDAnalyzer(config), + fTriggerLabel(config().TriggerLabel()), + fSaveWaveformInfo(config().DumpWaveformsInfo()), + fSaveRawWaveforms(config().SaveRawWaveforms()), + fUseSharedBaseline(config().UseSharedBaseline()), + fOpDetWaveformLabels(config().OpDetWaveformLabels()), + fBaselineLabels(config().BaselineLabels()), + fOpHitLabels(config().OpHitLabels()), + fFlashLabels(config().FlashLabels()), + fRWMLabel(config().RWMLabel()), + fPEOpHitThreshold(config().PEOpHitThreshold()), + fDebug(config().Debug()), + fGeom(lar::providerFrom()) { } @@ -480,7 +492,7 @@ float opana::ICARUSFlashAssAna::getRWMRelativeTime(int channel, float t) { if (fRWMTimes.empty()) - return 0; + return icarus::timing::NoTime; auto rwm = fRWMTimes.at(channel); if (!rwm.isValid()) @@ -489,7 +501,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 0; + return icarus::timing::NoTime; } float rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] @@ -505,10 +517,10 @@ float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_ float tfirst_left = std::numeric_limits::max(); float tfirst_right = std::numeric_limits::max(); - // if no RWM info available, all pmt_start_time_rwm is zero - // return zero as well for the flash + // if no RWM info available, all pmt_start_time_rwm are invalid + // return icarus::timing::NoTime as well for the flash if (fRWMTimes.empty()) - return 0; + return icarus::timing::NoTime; int nleft = 0; int nright = 0; @@ -523,11 +535,11 @@ float opana::ICARUSFlashAssAna::getFlashBunchTime(std::vector pmt_start_ if (t > -1e-10 && t < 1e-10) continue; - // if RWM is missing for some PMT channels, - // it might not be possible to use the first hits (might not have RMW time) - // so return zero as in other bad cases + // 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 if (!fRWMTimes[i].isValid()) - return 0; + return icarus::timing::NoTime; // count hits separetely on the two walls if (side == 0)