Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions sbncode/BeamSpillInfoRetriever/POTTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,36 @@ namespace sbn::pot{
}
}

std::vector<PTBInfo_t> extractAllPTBInfo(art::Handle<std::vector<artdaq::Fragment> > cont_frags) {
std::vector<PTBInfo_t> 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;
double currTS_candidate = std::bitset<64>(RawcurrPTBTimeStamp).to_ullong()/50e6;
PTBInfo.prevPTBTimeStamp = std::bitset<64>(RawprevPTBTimeStamp).to_ullong()/50e6;
PTBInfo.currPTBTimeStamp = currTS_candidate;
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<std::vector<artdaq::Fragment> > cont_frags) {

double TDCTimeStamp = 0;
Expand Down
13 changes: 12 additions & 1 deletion sbncode/BeamSpillInfoRetriever/POTTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@

#include "sbncode/BeamSpillInfoRetriever/MWRData.h"
#include "larcorealg/CoreUtils/counter.h"
#include <vector>

namespace sbn::pot{

typedef struct PTBInfo_t {
double currPTBTimeStamp = 1e20;
double prevPTBTimeStamp = 0;
unsigned int GateCounter = 0;
bool isHLT = false;
uint64_t triggerWord = 0;
} PTBInfo_t;

typedef struct TriggerInfo_t {
Expand All @@ -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<std::vector<artdaq::Fragment> > 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<PTBInfo_t> extractAllPTBInfo(art::Handle<std::vector<artdaq::Fragment> > cont_frags);
Copy link
Member

@PetrilloAtWork PetrilloAtWork Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend this function to get the fragment directly:

Suggested change
std::vector<PTBInfo_t> extractAllPTBInfo(art::Handle<std::vector<artdaq::Fragment> > cont_frags);
std::vector<PTBInfo_t> extractAllPTBInfo(std::vector<artdaq::Fragment> const& cont_frags);

and let the caller extract the data from the handle: it decouples better from the framework (plus, the caller can decide how to... handle an invalid handle).


/**
* @brief Extracts information from TDC for use in SBND POT accounting.
*
Expand Down
19 changes: 19 additions & 0 deletions sbncode/CAFMaker/CAFMaker_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1711,6 +1713,23 @@ 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<artdaq::Fragments> ptb_frags_handle;
evt.getByLabel(PTB_itag, ptb_frags_handle);
if (ptb_frags_handle.isValid()) {
try {
std::vector<sbn::pot::PTBInfo_t> ptb_triggers = sbn::pot::extractAllPTBInfo(ptb_frags_handle);
FillPTBTriggersSBND(ptb_triggers, srtrigger);
}
catch (...) {
std::cout << "CAFMaker: Failed to extract PTB triggers" << std::endl;
}
Comment on lines +1723 to +1729
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly recommend to be more precise on this check (general guideline: [CE-03]). Do you have experienced exceptions during testing?
For what I can see, sbn::pot::extractAllPTBInfo() should never throw an exception, and FillPTBTriggersSBND() also does not throw exceptions (well, it may throw std::out_of_memory on push_back(), and then you really want to abort).
If an exception occurs, we want to know because it may be a bug somewhere.

}
}

// 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.
Expand Down
1 change: 1 addition & 0 deletions sbncode/CAFMaker/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions sbncode/CAFMaker/FillTrigger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,28 @@ namespace caf
caf_softInfo.flash_peakpe = softInfo.peakPE;
caf_softInfo.flash_peaktime = softInfo.peaktime + softInfo.trig_ts*1e-3;
}

void FillPTBTriggersSBND(const std::vector<sbn::pot::PTBInfo_t>& 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) {
std::uint64_t triggerWord = trig.triggerWord;
for(int bit = 0; bit < 64; ++bit) {
std::uint64_t bitMask = 1ULL << bit;
if(triggerWord & bitMask) {
Comment on lines +85 to +88
Copy link
Member

@PetrilloAtWork PetrilloAtWork Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be more expressively be handles with bitsets:

Suggested change
std::uint64_t triggerWord = trig.triggerWord;
for(int bit = 0; bit < 64; ++bit) {
std::uint64_t bitMask = 1ULL << bit;
if(triggerWord & bitMask) {
std::bitset<64> const triggerWord { trig.triggerWord };
for(int bit = 0; bit < triggerWord.size(); ++bit) {
if(!triggerWord[bit]) continue;

(here I have also integrated another suggestion, which is to reduce the nesting within the loop by flipping the check and using continue).
This is just a suggestion.

if(trig.isHLT) {
triggerInfo.ptb_hlt_timestamp.push_back(trig.currPTBTimeStamp);
triggerInfo.ptb_hlt_bit.push_back(bit);
} else {
triggerInfo.ptb_llt_timestamp.push_back(trig.currPTBTimeStamp);
triggerInfo.ptb_llt_bit.push_back(bit);
}
Comment on lines +89 to +95
Copy link
Member

@PetrilloAtWork PetrilloAtWork Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reduce code duplication, I suggest to determine the destination(s) separately from the copy.
Outside the loop:

        // choose whether to add this trigger to the HLT or LLT list
        auto& ptb_timestamp = trig.isHLT? triggerInfo.ptb_hlt_timestamp: triggerInfo.ptb_hlt_timestamp;
        auto& ptb_bit = trig.isHLT? triggerInfo.ptb_hlt_bit: triggerInfo.ptb_hlt_bit;

and here:

Suggested change
if(trig.isHLT) {
triggerInfo.ptb_hlt_timestamp.push_back(trig.currPTBTimeStamp);
triggerInfo.ptb_hlt_bit.push_back(bit);
} else {
triggerInfo.ptb_llt_timestamp.push_back(trig.currPTBTimeStamp);
triggerInfo.ptb_llt_bit.push_back(bit);
}
ptb_timestamp.push_back(trig.currPTBTimeStamp);
ptb_bit.push_back(bit);

This also makes it more obvious that all the triggers in one PTB record are either HLT or LLT.

}
}
}
}
}
3 changes: 3 additions & 0 deletions sbncode/CAFMaker/FillTrigger.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -30,6 +31,8 @@ namespace caf
art::Handle<bool> const& passedTrig,
caf::SRTrigger& triggerInfo);
void FillSoftwareTriggerSBND(const sbnd::trigger::pmtSoftwareTrigger& softInfo, caf::SRSoftwareTrigger& caf_softInfo);

void FillPTBTriggersSBND(const std::vector<sbn::pot::PTBInfo_t>& ptb_triggers, caf::SRTrigger& triggerInfo);
}

#endif