diff --git a/sbncode/BeamSpillInfoRetriever/POTTools.cpp b/sbncode/BeamSpillInfoRetriever/POTTools.cpp index 585fdba5b..e43dce397 100644 --- a/sbncode/BeamSpillInfoRetriever/POTTools.cpp +++ b/sbncode/BeamSpillInfoRetriever/POTTools.cpp @@ -20,11 +20,11 @@ namespace sbn::pot{ if (ctb_frag.Trigger(word_i)->IsHLT() && ctb_frag.Trigger(word_i)->IsTrigger(HLT)) { foundHLT = true; - uint64_t RawprevPTBTimeStamp = ctb_frag.PTBWord(word_i)->prevTS * 20; - uint64_t RawcurrPTBTimeStamp = ctb_frag.Trigger(word_i)->timestamp * 20; - double currTS_candidate = std::bitset<64>(RawcurrPTBTimeStamp/20).to_ullong()/50e6; + uint64_t RawprevPTBTimeStamp = ctb_frag.PTBWord(word_i)->prevTS; + uint64_t RawcurrPTBTimeStamp = ctb_frag.Trigger(word_i)->timestamp; + std::uint64_t currTS_candidate = std::bitset<64>(RawcurrPTBTimeStamp).to_ullong() * 20; if(currTS_candidate < PTBInfo.currPTBTimeStamp){ - PTBInfo.prevPTBTimeStamp = std::bitset<64>(RawprevPTBTimeStamp / 20).to_ullong()/50e6; + PTBInfo.prevPTBTimeStamp = std::bitset<64>(RawprevPTBTimeStamp).to_ullong() * 20; PTBInfo.currPTBTimeStamp = currTS_candidate; PTBInfo.GateCounter = ctb_frag.Trigger(word_i)->gate_counter; } @@ -43,6 +43,35 @@ namespace sbn::pot{ } } + std::vector extractAllPTBInfo(std::vector const& cont_frags) { + std::vector PTBInfoVec; + for (auto const& cont : cont_frags) + { + artdaq::ContainerFragment cont_frag(cont); + for (size_t fragi = 0; fragi < cont_frag.block_count(); ++fragi) + { + artdaq::Fragment frag = *cont_frag[fragi]; + sbndaq::CTBFragment ctb_frag(frag); + for(size_t word_i = 0; word_i < ctb_frag.NWords(); ++word_i) + { + if(ctb_frag.Trigger(word_i)){ + PTBInfo_t PTBInfo; + uint64_t RawprevPTBTimeStamp = ctb_frag.PTBWord(word_i)->prevTS; + uint64_t RawcurrPTBTimeStamp = ctb_frag.Trigger(word_i)->timestamp; + PTBInfo.prevPTBTimeStamp = std::bitset<64>(RawprevPTBTimeStamp).to_ullong() * 20; + PTBInfo.currPTBTimeStamp = std::bitset<64>(RawcurrPTBTimeStamp).to_ullong() * 20; + PTBInfo.GateCounter = ctb_frag.Trigger(word_i)->gate_counter; + PTBInfo.isHLT = ctb_frag.Trigger(word_i)->IsHLT(); + PTBInfo.triggerWord = ctb_frag.Trigger(word_i)->trigger_word; + PTBInfoVec.push_back(PTBInfo); + } + } + } + } + + return PTBInfoVec; + } + double extractTDCTimeStamp(art::Handle > cont_frags) { double TDCTimeStamp = 0; diff --git a/sbncode/BeamSpillInfoRetriever/POTTools.h b/sbncode/BeamSpillInfoRetriever/POTTools.h index cb78fe686..1e54647a8 100644 --- a/sbncode/BeamSpillInfoRetriever/POTTools.h +++ b/sbncode/BeamSpillInfoRetriever/POTTools.h @@ -13,18 +13,21 @@ #include "sbncode/BeamSpillInfoRetriever/MWRData.h" #include "larcorealg/CoreUtils/counter.h" +#include namespace sbn::pot{ typedef struct PTBInfo_t { - double currPTBTimeStamp = 1e20; - double prevPTBTimeStamp = 0; + std::uint64_t currPTBTimeStamp = UINT64_MAX; ///< Timestamp in UTC nanoseconds since Unix epoch (converted from 20ns clock ticks) + std::uint64_t prevPTBTimeStamp = 0; unsigned int GateCounter = 0; + bool isHLT = false; + uint64_t triggerWord = 0; ///< Timestamp in s since beam extraction signal } PTBInfo_t; typedef struct TriggerInfo_t { int gate_type = 0; ///< Source of the spill: `1`: BNB, `2`: NuMI - double t_current_event = 0; + double t_current_event = 0; ///< Timestamp in UTC seconds since Unix epoch (converted from 20ns clock ticks) double t_previous_event = 0; unsigned int number_of_gates_since_previous_event = 0; std::int64_t WR_to_Spill_conversion = 0; @@ -36,13 +39,21 @@ namespace sbn::pot{ } MWRdata_t; /** - * @brief Extracts information from PTB for use in SBND POT accounting. + * @brief Extracts information from PTB for a single HLT for use in SBND POT accounting. * * @param cont_frags The PTB fragments to examine. * @param HLT The high level trigger we are searching for. */ PTBInfo_t extractPTBInfo(art::Handle > cont_frags, int HLT); + /** + * @brief Extracts ALL PTB information for using in SBND CAF files. + * + * @param cont_frags The PTB fragments to examine. + * @return Vector of PTBInfo_t containing all triggers found. + */ + std::vector extractAllPTBInfo(std::vector const& cont_frags); + /** * @brief Extracts information from TDC for use in SBND POT accounting. * diff --git a/sbncode/BeamSpillInfoRetriever/SBNDBNBRetriever/SBNDBNBRetriever_module.cc b/sbncode/BeamSpillInfoRetriever/SBNDBNBRetriever/SBNDBNBRetriever_module.cc index 779be4053..e6465d45b 100644 --- a/sbncode/BeamSpillInfoRetriever/SBNDBNBRetriever/SBNDBNBRetriever_module.cc +++ b/sbncode/BeamSpillInfoRetriever/SBNDBNBRetriever/SBNDBNBRetriever_module.cc @@ -123,13 +123,13 @@ sbn::pot::TriggerInfo_t sbn::SBNDBNBRetriever::extractTriggerInfo(art::Event con else{ // If missing TDC, use PTB instead mf::LogDebug("SBNDBNBRetriever") << " Missing TDC Container Fragments!!! " << std::endl; - triggerInfo.t_current_event = PTBInfo.currPTBTimeStamp - fBESOffset; + triggerInfo.t_current_event = PTBInfo.currPTBTimeStamp / 1e9 - fBESOffset; } - triggerInfo.t_previous_event = PTBInfo.prevPTBTimeStamp - fBESOffset; + triggerInfo.t_previous_event = PTBInfo.prevPTBTimeStamp / 1e9 - fBESOffset; triggerInfo.number_of_gates_since_previous_event = PTBInfo.GateCounter; - double PTBandCurrOffset = PTBInfo.currPTBTimeStamp - triggerInfo.t_current_event - fBESOffset; + double PTBandCurrOffset = PTBInfo.currPTBTimeStamp / 1e9 - triggerInfo.t_current_event - fBESOffset; // Catch for an issue seen a few times where PTB off by a second. // Only need to correct prevTS because either currTS is from TDC diff --git a/sbncode/BeamSpillInfoRetriever/SBNDBNBZEROBIASRetriever/SBNDBNBZEROBIASRetriever_module.cc b/sbncode/BeamSpillInfoRetriever/SBNDBNBZEROBIASRetriever/SBNDBNBZEROBIASRetriever_module.cc index c22c70411..298e0df91 100644 --- a/sbncode/BeamSpillInfoRetriever/SBNDBNBZEROBIASRetriever/SBNDBNBZEROBIASRetriever_module.cc +++ b/sbncode/BeamSpillInfoRetriever/SBNDBNBZEROBIASRetriever/SBNDBNBZEROBIASRetriever_module.cc @@ -126,13 +126,13 @@ sbn::pot::TriggerInfo_t sbn::SBNDBNBZEROBIASRetriever::extractTriggerInfo(art::E else{ // If missing TDC, use PTB instead mf::LogDebug("SBNDBNBZEROBIASRetriever") << " Missing TDC Container Fragments!!!" << std::endl; - triggerInfo.t_current_event = PTBInfo.currPTBTimeStamp - fBESOffset; + triggerInfo.t_current_event = PTBInfo.currPTBTimeStamp / 1e9 - fBESOffset; } - triggerInfo.t_previous_event = PTBInfo.prevPTBTimeStamp - fBESOffset; + triggerInfo.t_previous_event = PTBInfo.prevPTBTimeStamp / 1e9 - fBESOffset; triggerInfo.number_of_gates_since_previous_event = PTBInfo.GateCounter; - double PTBandCurrOffset = PTBInfo.currPTBTimeStamp - triggerInfo.t_current_event - fBESOffset; + double PTBandCurrOffset = PTBInfo.currPTBTimeStamp / 1e9 - triggerInfo.t_current_event - fBESOffset; // Catch for an issue seen a few times where PTB off by a second. // Only need to correct prevTS because either currTS is from TDC diff --git a/sbncode/CAFMaker/CAFMaker_module.cc b/sbncode/CAFMaker/CAFMaker_module.cc index 9f2c01590..29ead35da 100644 --- a/sbncode/CAFMaker/CAFMaker_module.cc +++ b/sbncode/CAFMaker/CAFMaker_module.cc @@ -115,6 +115,8 @@ #include "sbnobj/Common/POTAccounting/BNBSpillInfo.h" #include "sbnobj/Common/POTAccounting/EXTCountInfo.h" #include "sbnobj/Common/POTAccounting/NuMISpillInfo.h" +#include "sbncode/BeamSpillInfoRetriever/POTTools.h" +#include "artdaq-core/Data/ContainerFragment.hh" #include "sbnobj/Common/Trigger/ExtraTriggerInfo.h" #include "sbnobj/Common/Reco/CRUMBSResult.h" #include "sbnobj/Common/Reco/OpT0FinderResult.h" @@ -1378,6 +1380,7 @@ bool CAFMaker::GetPsetParameter(const fhicl::ParameterSet& pset, //...................................................................... void CAFMaker::produce(art::Event& evt) noexcept { + mf::LogInfo("CAFMaker") << "CAFMaker::produce called for event: " << evt.id(); bool const firstInFile = (fIndexInFile++ == 0); @@ -1711,6 +1714,24 @@ void CAFMaker::produce(art::Event& evt) noexcept { FillTriggerEmulation(monpulses_handle, monpulse_sizes_handle, pairs_handle, trigemu_handle, srtrigger); } + + // Fill PTB (Penn Trigger Board) information for SBND real data + if (isRealData && fDet == kSBND) { + art::InputTag PTB_itag("daq", "ContainerPTB"); + art::Handle ptb_frags_handle; + evt.getByLabel(PTB_itag, ptb_frags_handle); + if (ptb_frags_handle.isValid()) { + mf::LogDebug("CAFMaker") << "Found ContainerPTB, extracting PTB triggers..."; + std::vector ptb_triggers = sbn::pot::extractAllPTBInfo(*ptb_frags_handle); + mf::LogDebug("CAFMaker") << "Extracted " << ptb_triggers.size() << " PTB triggers"; + FillPTBTriggersSBND(ptb_triggers, srtrigger); + mf::LogDebug("CAFMaker") << "PTB HLT triggers: " << srtrigger.ptb_hlt_timestamp.size() + << ", LLT triggers: " << srtrigger.ptb_llt_timestamp.size(); + } else { + mf::LogDebug("CAFMaker") << "ContainerPTB not found for event " << evt.id(); + } + } + // If not real data, fill in enough of the SRTrigger to make (e.g.) the CRT // time referencing work. TODO: add more stuff to a "MC"-Trigger? // No longer needed with incorporation of trigger emulation in the MC. diff --git a/sbncode/CAFMaker/CMakeLists.txt b/sbncode/CAFMaker/CMakeLists.txt index 5dd4f2a8f..24228ba3f 100644 --- a/sbncode/CAFMaker/CMakeLists.txt +++ b/sbncode/CAFMaker/CMakeLists.txt @@ -50,6 +50,7 @@ art_make_library( LIBRARY_NAME sbncode_CAFMaker ${GENIE_LIB_LIST} nugen::EventGeneratorBase_GENIE sbndaq_artdaq_core::sbndaq-artdaq-core_Obj_SBND + sbn_POTTools ) cet_build_plugin ( CAFMaker art::module diff --git a/sbncode/CAFMaker/FillTrigger.cxx b/sbncode/CAFMaker/FillTrigger.cxx index fab6ae074..10805371e 100644 --- a/sbncode/CAFMaker/FillTrigger.cxx +++ b/sbncode/CAFMaker/FillTrigger.cxx @@ -1,4 +1,5 @@ #include +#include #include "sbncode/CAFMaker/FillTrigger.h" namespace caf @@ -73,4 +74,27 @@ namespace caf caf_softInfo.flash_peakpe = softInfo.peakPE; caf_softInfo.flash_peaktime = softInfo.peaktime + softInfo.trig_ts*1e-3; } + + void FillPTBTriggersSBND(const std::vector& ptb_triggers, caf::SRTrigger& triggerInfo) { + triggerInfo.ptb_hlt_timestamp.clear(); + triggerInfo.ptb_hlt_bit.clear(); + triggerInfo.ptb_llt_timestamp.clear(); + triggerInfo.ptb_llt_bit.clear(); + + // Decode trigger words: each set bit becomes a separate entry with the same timestamp + for(const auto& trig : ptb_triggers) { + // Choose destination vectors based on trigger type + auto& ptb_timestamp = trig.isHLT ? triggerInfo.ptb_hlt_timestamp : triggerInfo.ptb_llt_timestamp; + auto& ptb_bit = trig.isHLT ? triggerInfo.ptb_hlt_bit : triggerInfo.ptb_llt_bit; + + std::bitset<64> const triggerWord { trig.triggerWord }; + // currPTBTimeStamp is already in nanoseconds (uint64_t), use directly + // Loop variable is uint8_t since we know bit values are 0-63 (fits in uint8_t) + for(std::uint8_t bit = 0; bit < triggerWord.size(); ++bit) { + if(!triggerWord[bit]) continue; + ptb_timestamp.push_back(trig.currPTBTimeStamp); + ptb_bit.push_back(bit); + } + } + } } diff --git a/sbncode/CAFMaker/FillTrigger.h b/sbncode/CAFMaker/FillTrigger.h index 2c2ada243..203fbe57c 100644 --- a/sbncode/CAFMaker/FillTrigger.h +++ b/sbncode/CAFMaker/FillTrigger.h @@ -9,6 +9,7 @@ #include "lardataobj/RawData/TriggerData.h" #include "art/Framework/Principal/Handle.h" #include "sbndaq-artdaq-core/Obj/SBND/pmtSoftwareTrigger.hh" +#include "sbncode/BeamSpillInfoRetriever/POTTools.h" namespace caf { @@ -30,6 +31,8 @@ namespace caf art::Handle const& passedTrig, caf::SRTrigger& triggerInfo); void FillSoftwareTriggerSBND(const sbnd::trigger::pmtSoftwareTrigger& softInfo, caf::SRSoftwareTrigger& caf_softInfo); + + void FillPTBTriggersSBND(const std::vector& ptb_triggers, caf::SRTrigger& triggerInfo); } #endif