diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index dd5a777309..49d26715b1 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -710,6 +710,38 @@ int Fun4AllStreamingInputManager::FillIntt() } } + // hit duplication:add hits in N + [1..M] * shift BCOs + if (m_InttHitDuplication) + { + if (m_InttHitCarryOverShiftMaxMultiple < 1) + { + std::cout << __FILE__ << ":" << __PRETTY_FUNCTION__ << ":" << __LINE__ << ": m_InttHitDuplication is set to true but m_InttHitCarryOverShiftMaxMultiple=" << m_InttHitCarryOverShiftMaxMultiple << "is not positive. Default to 1" << std::endl; + m_InttHitCarryOverShiftMaxMultiple = 1; + } + + const uint64_t max_shift = m_InttHitCarryOverShift * m_InttHitCarryOverShiftMaxMultiple; + const uint64_t bco_duplicate_high = select_crossings + max_shift; + + // now fill the pool until the highest bco in the map is higher than the duplication threshold, which is the select_crossings + the maximum shift we want to do + while (m_InttRawHitMap.rbegin()->first < bco_duplicate_high) // if the highest bco is still smaller than the duplication threshold, keep duplicating + { + const uint64_t previous_high_bco = m_InttRawHitMap.rbegin()->first; + iret = FillInttPool(); + if (iret) + { + break; // if FillInttPool returns non zero, there is no more data to read and we can stop trying to duplicate + } + // Note: need this guard. FillInttPool() only returns non-0 if m_InttRawHitMap is empty + // FillInttPool() calls SingleInttPoolInput::FillPool() returns regardless of whether it actually fill new data or not + // So if FillInttPool() is called and there is no new data to pool, it will return 0 but m_InttRawHitMap will not have changed (non-empty) + // If we don't check for this, it would cause an infinite loop + if (m_InttRawHitMap.rbegin()->first == previous_high_bco) + { + break; + } + } + } + unsigned int refbcobitshift = m_RefBCO & 0x3FU; bool allpackets = true; int allpacketsallfees = 0; @@ -777,7 +809,7 @@ int Fun4AllStreamingInputManager::FillIntt() h_taggedAllFee_intt->Fill(refbcobitshift); } - for (auto& [bco, hitinfo] : m_InttRawHitMap) + for (auto &[bco, hitinfo] : m_InttRawHitMap) { if (bco > select_crossings) { @@ -794,6 +826,69 @@ int Fun4AllStreamingInputManager::FillIntt() } inttcont->AddHit(intthititer); } + + // The duplication consists of 2 passes + // Pass 1: Insert duplication of hits in N + [1..M] * shift BCOs + // the "second" pass duplicates hits whose FPHX BCO was reset to 0 + // Also, the "second" pass needs to handle the case where the hits with FPHX BCO = 0 are already duplicated from the "first" pass + // This happens when target_refbco = bco % m_InttHitCarryOverShift is 0 and reset_shift = m_InttHitCarryOverShift * s + // If this is the case, do not duplicate the hits again + if (m_InttHitDuplication) + { + const uint64_t target_refbco = bco % m_InttHitCarryOverShift; + + for (int shift_multiple = 1; shift_multiple <= m_InttHitCarryOverShiftMaxMultiple; ++shift_multiple) + { + const uint64_t shift = m_InttHitCarryOverShift * shift_multiple; + const uint64_t source_bco = bco + shift; + auto source_iter = m_InttRawHitMap.find(source_bco); + + if (source_iter != m_InttRawHitMap.end()) + { + for (auto *source_hit : source_iter->second.InttRawHitVector) + { + if (source_hit->get_bco() < shift) + { + continue; + } + + auto *copied_hit = inttcont->AddHit(source_hit); + copied_hit->set_bco(source_hit->get_bco() - shift); + } + } + + if (target_refbco == 0) + { + continue; // if target_refbco is 0, the hits with FPHX BCO = 0 are already duplicated in the first pass, so skip the second pass to avoid double duplication + } + + const uint64_t reset_shift = shift - target_refbco; + const uint64_t reset_source_bco = bco + reset_shift; + auto reset_source_iter = m_InttRawHitMap.find(reset_source_bco); + if (reset_source_iter == m_InttRawHitMap.end()) + { + continue; + } + + for (auto *source_hit : reset_source_iter->second.InttRawHitVector) + { + // skip hits whose FPHX BCO is not 0 + if (source_hit->get_FPHX_BCO() != 0) + { + continue; + } + + // also skip hits whose strobe BCO is smaller than the reset shift + if (source_hit->get_bco() < reset_shift) + { + continue; + } + + auto *copied_hit = inttcont->AddHit(source_hit); + copied_hit->set_bco(source_hit->get_bco() - reset_shift); + } + } + } } return 0; } @@ -974,7 +1069,7 @@ int Fun4AllStreamingInputManager::FillMvtx() uint64_t lower_limit = m_mvtx_is_triggered ? select_crossings : select_crossings - m_mvtx_bco_range - m_mvtx_negative_bco; uint64_t upper_limit = m_mvtx_is_triggered ? select_crossings + m_mvtx_bco_range : select_crossings; - for (auto& [bco, hitinfo] : m_MvtxRawHitMap) + for (auto &[bco, hitinfo] : m_MvtxRawHitMap) { if (bco < lower_limit) { diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h index e51a59c549..c4e416cad3 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h @@ -10,6 +10,7 @@ #include #include #include +#include class SingleStreamingInput; class Gl1Packet; @@ -69,6 +70,10 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager void runMvtxTriggered(bool b = true) { m_mvtx_is_triggered = b; } + // configuration for INTT hit carry-over issue mitigation (hit duplication) + void EnableInttHitDuplication(bool b = true) { m_InttHitDuplication = b; } + void InttHitCarryOverShiftMaxMultiple(const int i) { m_InttHitCarryOverShiftMaxMultiple = i; } + private: struct MvtxRawHitInfo { @@ -159,6 +164,10 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager TH1 *h_taggedAllFees_intt[8]{nullptr}; TH1 *h_gl1taggedfee_intt[8][14]{{nullptr}}; TH2 *h_bcodiff_intt[8]{nullptr}; -}; + // for INTT hit carry-over issue mitigation (hit duplication) + bool m_InttHitDuplication{false}; // default to false; Should be set to true when running streaming data + const unsigned int m_InttHitCarryOverShift{120}; // 120 BCOs as the default shift. Fixed value + int m_InttHitCarryOverShiftMaxMultiple{4}; // the max multiple of the shift. For a max multiple of M, duplicate hits from N + [1..M] * shift BCOs to N +}; #endif /* FUN4ALL_FUN4ALLSTREAMINGINPUTMANAGER_H */