From 058a1eaab2d7a3805a34ed6f21af63e076cb8050 Mon Sep 17 00:00:00 2001 From: mitaylor Date: Wed, 21 Sep 2022 04:30:29 +0200 Subject: [PATCH] Update GlobalBoard class with FDL for fractional prescales, to match firmware --- L1Trigger/L1TGlobal/interface/GlobalBoard.h | 45 ++++++++-- L1Trigger/L1TGlobal/src/GlobalBoard.cc | 98 ++++++++++++--------- 2 files changed, 95 insertions(+), 48 deletions(-) diff --git a/L1Trigger/L1TGlobal/interface/GlobalBoard.h b/L1Trigger/L1TGlobal/interface/GlobalBoard.h index 894951209f4bd..fadeb972a2311 100644 --- a/L1Trigger/L1TGlobal/interface/GlobalBoard.h +++ b/L1Trigger/L1TGlobal/interface/GlobalBoard.h @@ -16,9 +16,12 @@ #include #include #include +#include // user include files #include "FWCore/Utilities/interface/typedefs.h" +#include "FWCore/Utilities/interface/Exception.h" + #include "DataFormats/L1TGlobal/interface/GlobalObjectMapRecord.h" #include "L1Trigger/L1TGlobal/interface/AlgorithmEvaluation.h" @@ -165,10 +168,6 @@ namespace l1t { /// pointer to Tau data list inline const BXVector* getCandL1External() const { return m_candL1External; } - //initializer prescale counter using a semi-random value between [1, prescale value] - static const std::vector semirandomNumber(const edm::Event& iEvent, - const std::vector& prescaleFactorsAlgoTrig); - /* Drop individual EtSums for Now /// pointer to ETM data list inline const l1t::EtSum* getCandL1ETM() const @@ -246,9 +245,6 @@ namespace l1t { // cache of maps std::vector m_conditionResultMaps; - /// prescale counters: NumberPhysTriggers counters per bunch cross in event - std::vector> m_prescaleCounterAlgoTrig; - bool m_firstEv; bool m_firstEvLumiSegment; uint m_currentLumi; @@ -277,7 +273,40 @@ namespace l1t { // start the PS counter from a random value between [1,PS] instead of PS bool m_semiRandomInitialPSCounters = false; + + // step-size in prescale counter corresponding to 10^p, + // where p is the precision allowed for non-integer prescales; + // since the introduction of L1T fractional prescales, p == 2 + static constexpr size_t m_singlestep = 100; + + // struct to increment the prescale according to fractional prescale logic in firmware + struct PrescaleCounter { + const size_t prescale_count; + size_t trigger_counter = 0; + + PrescaleCounter(double prescale) : prescale_count(std::lround(prescale * m_singlestep)) { + if (prescale_count != 0 and (prescale_count < m_singlestep or prescale < 0)) { + throw cms::Exception("PrescaleCounterConstructor") + << "invalid initialisation of PrescaleCounter: prescale = " << prescale + << ", prescale_count = " << prescale_count << " (< " << m_singlestep << " = m_singlestep)"; + } + } + + // function to increment the prescale counter and return the decision + bool accept(); + }; + + // prescale counters: NumberPhysTriggers counters per bunch cross in event + std::vector> m_prescaleCounterAlgoTrig; + + // create prescale counters, initialising trigger_counter to a semirandom number between 0 and prescale_count - 1 inclusive + static const std::vector semirandomNumber(const edm::Event& iEvent, + const std::vector& prescaleFactorsAlgoTrig); + + // create prescale counters, initialising trigger_counter to zero + static const std::vector zeroPrescaleCounters(const std::vector& prescaleFactorsAlgoTrig); }; } // namespace l1t -#endif + +#endif \ No newline at end of file diff --git a/L1Trigger/L1TGlobal/src/GlobalBoard.cc b/L1Trigger/L1TGlobal/src/GlobalBoard.cc index bf82d690d8961..1995e769c0703 100644 --- a/L1Trigger/L1TGlobal/src/GlobalBoard.cc +++ b/L1Trigger/L1TGlobal/src/GlobalBoard.cc @@ -50,7 +50,6 @@ #include "L1Trigger/L1TGlobal/interface/CorrCondition.h" #include "L1Trigger/L1TGlobal/interface/CorrThreeBodyCondition.h" #include "L1Trigger/L1TGlobal/interface/CorrWithOverlapRemovalCondition.h" -#include "FWCore/Utilities/interface/Exception.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "FWCore/MessageLogger/interface/MessageDrop.h" @@ -971,14 +970,14 @@ void l1t::GlobalBoard::runFDL(edm::Event& iEvent, // prescale counters are reset at the beginning of the luminosity segment if (m_firstEv) { // prescale counters: numberPhysTriggers counters per bunch cross - m_prescaleCounterAlgoTrig.reserve(totalBxInEvent); - - auto const& prescaleCountersAlgoTrig = - m_semiRandomInitialPSCounters ? semirandomNumber(iEvent, prescaleFactorsAlgoTrig) : prescaleFactorsAlgoTrig; + auto const& prescaleCountersAlgoTrig = m_semiRandomInitialPSCounters + ? semirandomNumber(iEvent, prescaleFactorsAlgoTrig) + : zeroPrescaleCounters(prescaleFactorsAlgoTrig); for (int iBxInEvent = 0; iBxInEvent <= totalBxInEvent; ++iBxInEvent) { m_prescaleCounterAlgoTrig.push_back(prescaleCountersAlgoTrig); } + m_firstEv = false; m_currentLumi = iEvent.luminosityBlock(); } @@ -986,13 +985,14 @@ void l1t::GlobalBoard::runFDL(edm::Event& iEvent, // update and clear prescales at the beginning of the luminosity segment if (m_firstEvLumiSegment || (m_currentLumi != iEvent.luminosityBlock() && m_resetPSCountersEachLumiSec)) { m_prescaleCounterAlgoTrig.clear(); + m_prescaleCounterAlgoTrig.reserve(totalBxInEvent + 1); + auto const& prescaleCountersAlgoTrig = m_semiRandomInitialPSCounters + ? semirandomNumber(iEvent, prescaleFactorsAlgoTrig) + : zeroPrescaleCounters(prescaleFactorsAlgoTrig); for (int iBxInEvent = 0; iBxInEvent <= totalBxInEvent; ++iBxInEvent) { - if (m_semiRandomInitialPSCounters) { - m_prescaleCounterAlgoTrig.push_back(semirandomNumber(iEvent, prescaleFactorsAlgoTrig)); - } else { - m_prescaleCounterAlgoTrig.push_back(prescaleFactorsAlgoTrig); - } + m_prescaleCounterAlgoTrig.push_back(prescaleCountersAlgoTrig); } + m_firstEvLumiSegment = false; m_currentLumi = iEvent.luminosityBlock(); } @@ -1011,15 +1011,14 @@ void l1t::GlobalBoard::runFDL(edm::Event& iEvent, bool temp_algPrescaledOr = false; bool alreadyReported = false; for (unsigned int iBit = 0; iBit < numberPhysTriggers; ++iBit) { - bool bitValue = m_uGtAlgBlk.getAlgoDecisionInitial(iBit); + const bool bitValue = m_uGtAlgBlk.getAlgoDecisionInitial(iBit); if (bitValue) { // Make sure algo bit in range, warn otherwise if (iBit < prescaleFactorsAlgoTrig.size()) { if (prescaleFactorsAlgoTrig.at(iBit) != 1) { - (m_prescaleCounterAlgoTrig.at(inBxInEvent).at(iBit))--; - if (m_prescaleCounterAlgoTrig.at(inBxInEvent).at(iBit) == 0) { - // bit already true in algoDecisionWord, just reset counter - m_prescaleCounterAlgoTrig.at(inBxInEvent).at(iBit) = prescaleFactorsAlgoTrig.at(iBit); + const bool triggered = m_prescaleCounterAlgoTrig.at(inBxInEvent).at(iBit).accept(); + + if (triggered) { temp_algPrescaledOr = true; } else { // change bit to false in prescaled word and final decision word @@ -1055,7 +1054,7 @@ void l1t::GlobalBoard::runFDL(edm::Event& iEvent, bool temp_algFinalOr = false; bool alreadyReported = false; for (unsigned int iBit = 0; iBit < numberPhysTriggers; ++iBit) { - bool bitValue = m_uGtAlgBlk.getAlgoDecisionInterm(iBit); + const bool bitValue = m_uGtAlgBlk.getAlgoDecisionInterm(iBit); if (bitValue) { //bool isMasked = ( triggerMaskAlgoTrig.at(iBit) == 0 ); @@ -1068,7 +1067,7 @@ void l1t::GlobalBoard::runFDL(edm::Event& iEvent, << std::endl; } - bool passMask = (bitValue && !isMasked); + const bool passMask = (bitValue && !isMasked); if (passMask) temp_algFinalOr = true; @@ -1168,35 +1167,54 @@ void l1t::GlobalBoard::printGmtData(const int iBxInEvent) const { LogTrace("L1TGlobal") << std::endl; } -//initializer prescale counter using a semi-random value between [1, prescale value] -const std::vector l1t::GlobalBoard::semirandomNumber(const edm::Event& iEvent, - const std::vector& prescaleFactorsAlgoTrig) { - auto out = prescaleFactorsAlgoTrig; +// initializer prescale counters using a semi-random value between [0, prescale value * 10 ^ precision - 1] +const std::vector l1t::GlobalBoard::semirandomNumber( + const edm::Event& iEvent, const std::vector& prescaleFactorsAlgoTrig) { // pick a random number from a combination of run, lumi, event numbers - std::srand(iEvent.id().run()); - std::srand(std::rand() + iEvent.id().luminosityBlock()); // this causes different (semi)random number number for different streams // reminder: different streams have different initial event number + std::srand(iEvent.id().run()); + std::srand(std::rand() + iEvent.id().luminosityBlock()); std::srand(std::rand() + iEvent.id().event()); + // very large (semi)random number - double const semirandom = std::rand(); - for (auto& ps : out) { - // if the ps is smaller than 1 (e.g. ps=0, ps=1), it is not changed - // else, replace ps with a semirandom integer in the [1,ps] range - if (ps > 1) { - auto nps = semirandom - floor(semirandom / ps) * ps; - // if nps=0 or a wrong value (<0,>ps) use PS value (standard method) - if (nps > 0 and nps <= ps) - ps = nps; - else { - if (nps != 0) // complain only if nps <0 or nps >PS - edm::LogWarning("L1TGlobal::semirandomNumber") - << "\n The inital prescale counter obtained by L1TGlobal::semirandomNumber is wrong." - << "\n This is probably do to the floating-point precision. Using the PS value." - << "\n semirandom = " << semirandom << "\n PS = " << ps << "\n nps = " << nps - << " <-- it should be in the range [0 , " << ps << "]" << std::endl; - } + const int semirandom = std::rand(); + std::vector out; + out.reserve(prescaleFactorsAlgoTrig.size()); + + for (size_t iAlgo = 0; iAlgo < prescaleFactorsAlgoTrig.size(); iAlgo++) { + // for prescaled triggers, initialise trigger_counter to + // a semirandom integer between 0 and prescale_count - 1 (inclusive) + out.emplace_back(PrescaleCounter(prescaleFactorsAlgoTrig[iAlgo])); + + auto& prescaleCounter = out.back(); + if (prescaleCounter.prescale_count > 0) { + prescaleCounter.trigger_counter = semirandom % prescaleCounter.prescale_count; } } + return out; } + +// initialize prescale counters to zero +const std::vector l1t::GlobalBoard::zeroPrescaleCounters( + const std::vector& prescaleFactorsAlgoTrig) { + std::vector out; + out.reserve(prescaleFactorsAlgoTrig.size()); + for (size_t iAlgo = 0; iAlgo < prescaleFactorsAlgoTrig.size(); iAlgo++) { + out.emplace_back(PrescaleCounter(prescaleFactorsAlgoTrig[iAlgo])); + } + + return out; +} + +bool l1t::GlobalBoard::PrescaleCounter::accept() { + trigger_counter += m_singlestep; + + if (prescale_count == 0 or trigger_counter < prescale_count) + return false; + + trigger_counter -= prescale_count; + + return true; +} \ No newline at end of file