Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 14:22:11

0001 #include "L1Trigger/GlobalCaloTrigger/interface/L1GlobalCaloTrigger.h"
0002 
0003 #include "CondFormats/L1TObjects/interface/L1GctJetFinderParams.h"
0004 #include "CondFormats/L1TObjects/interface/L1GctChannelMask.h"
0005 
0006 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctJetEtCalibrationLut.h"
0007 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctEmLeafCard.h"
0008 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctWheelJetFpga.h"
0009 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctWheelEnergyFpga.h"
0010 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctJetFinalStage.h"
0011 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctGlobalEnergyAlgos.h"
0012 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctGlobalHfSumAlgos.h"
0013 #include "L1Trigger/GlobalCaloTrigger/interface/L1GctElectronFinalSort.h"
0014 
0015 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0016 
0017 using std::vector;
0018 
0019 //DEFINE STATICS
0020 const int L1GlobalCaloTrigger::N_JET_LEAF_CARDS = 6;
0021 const int L1GlobalCaloTrigger::N_EM_LEAF_CARDS = 2;
0022 const int L1GlobalCaloTrigger::N_WHEEL_CARDS = 2;
0023 
0024 // constructor
0025 L1GlobalCaloTrigger::L1GlobalCaloTrigger(const L1GctJetLeafCard::jetFinderType jfType, unsigned jetLeafMask)
0026     : theJetLeafCards(N_JET_LEAF_CARDS),
0027       theJetFinders(N_JET_LEAF_CARDS * 3),
0028       theEmLeafCards(N_EM_LEAF_CARDS),
0029       theIsoElectronSorters(N_EM_LEAF_CARDS * 2),
0030       theNonIsoElectronSorters(N_EM_LEAF_CARDS * 2),
0031       theWheelJetFpgas(N_WHEEL_CARDS),
0032       theWheelEnergyFpgas(N_WHEEL_CARDS),
0033       m_jetFinderParams(nullptr),
0034       m_jetEtCalLuts(),
0035       m_inputChannelMask(nullptr),
0036       m_bxRangeAuto(true),
0037       m_bxStart(0),
0038       m_numOfBx(1),
0039       m_allInputEmCands(),
0040       m_allInputRegions() {
0041   // construct hardware
0042   build(jfType, jetLeafMask);
0043 }
0044 
0045 /// GCT Destructor
0046 L1GlobalCaloTrigger::~L1GlobalCaloTrigger() {
0047   // Delete the components of the GCT that we made in build()
0048   // (But not the LUTs, since these don't belong to us)
0049 
0050   if (theNonIsoEmFinalStage != nullptr)
0051     delete theNonIsoEmFinalStage;
0052 
0053   if (theIsoEmFinalStage != nullptr)
0054     delete theIsoEmFinalStage;
0055 
0056   if (theEnergyFinalStage != nullptr)
0057     delete theEnergyFinalStage;
0058 
0059   if (theJetFinalStage != nullptr)
0060     delete theJetFinalStage;
0061 
0062   for (unsigned i = 0; i < theWheelEnergyFpgas.size(); ++i) {
0063     if (theWheelEnergyFpgas.at(i) != nullptr)
0064       delete theWheelEnergyFpgas.at(i);
0065   }
0066   theWheelEnergyFpgas.clear();
0067 
0068   for (unsigned i = 0; i < theWheelJetFpgas.size(); ++i) {
0069     if (theWheelJetFpgas.at(i) != nullptr)
0070       delete theWheelJetFpgas.at(i);
0071   }
0072   theWheelJetFpgas.clear();
0073 
0074   for (unsigned i = 0; i < theEmLeafCards.size(); ++i) {
0075     if (theEmLeafCards.at(i) != nullptr)
0076       delete theEmLeafCards.at(i);
0077   }
0078   theEmLeafCards.clear();
0079 
0080   for (unsigned i = 0; i < theJetLeafCards.size(); ++i) {
0081     if (theJetLeafCards.at(i) != nullptr)
0082       delete theJetLeafCards.at(i);
0083   }
0084   theJetLeafCards.clear();
0085 }
0086 
0087 ///=================================================================================================
0088 ///
0089 /// Methods to reset all processors and process an event (consisting of multiple bunch crossings)
0090 ///
0091 void L1GlobalCaloTrigger::reset() {
0092   // Input data
0093   m_allInputEmCands.clear();
0094   m_allInputRegions.clear();
0095 
0096   if (m_bxRangeAuto) {
0097     m_bxStart = 0;
0098     m_numOfBx = 1;
0099   }
0100 
0101   // EM Leaf Card
0102   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0103     theEmLeafCards.at(i)->reset();
0104   }
0105 
0106   // Jet Leaf cards
0107   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0108     theJetLeafCards.at(i)->reset();
0109   }
0110 
0111   // Jet Finders
0112   for (int i = 0; i < N_JET_LEAF_CARDS * 3; i++) {
0113     theJetFinders.at(i)->reset();
0114   }
0115 
0116   // Wheel Cards
0117   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0118     theWheelJetFpgas.at(i)->reset();
0119   }
0120 
0121   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0122     theWheelEnergyFpgas.at(i)->reset();
0123   }
0124 
0125   // Electron Final Stage
0126   theIsoEmFinalStage->reset();
0127   theNonIsoEmFinalStage->reset();
0128 
0129   // Jet Final Stage
0130   theJetFinalStage->reset();
0131 
0132   // Energy Final Stage
0133   theEnergyFinalStage->reset();
0134 }
0135 
0136 void L1GlobalCaloTrigger::process() {
0137   // Shouldn't get here unless the setup has been completed
0138   if (setupOk()) {
0139     /// Sort the input data by bunch crossing number
0140     sortInputData();
0141     // Extract the earliest and latest bunch crossing
0142     // in the input if required, and forward to the processors
0143     // to determine the size of the output vectors
0144     bxSetup();
0145 
0146     vector<L1CaloEmCand>::iterator emc = m_allInputEmCands.begin();
0147     vector<L1CaloRegion>::iterator rgn = m_allInputRegions.begin();
0148     int bx = m_bxStart;
0149 
0150     // Loop over bunch crossings
0151     for (int i = 0; i < m_numOfBx; i++) {
0152       // Perform partial reset (reset processing logic but preserve pipeline contents)
0153       bxReset(bx);
0154       // Fill input data into processors for this bunch crossing
0155       fillEmCands(emc, bx);
0156       fillRegions(rgn, bx);
0157       // Process this bunch crossing
0158       bxProcess(bx);
0159       bx++;
0160     }
0161   }
0162 }
0163 
0164 /// Sort the input data by bunch crossing number
0165 void L1GlobalCaloTrigger::sortInputData() {
0166   std::sort(m_allInputEmCands.begin(), m_allInputEmCands.end(), emcBxComparator);
0167   std::sort(m_allInputRegions.begin(), m_allInputRegions.end(), rgnBxComparator);
0168 }
0169 
0170 /// Setup bunch crossing range (depending on input data)
0171 void L1GlobalCaloTrigger::bxSetup() {
0172   // Assume input data have been sorted by bunch crossing number
0173   if (m_bxRangeAuto) {
0174     // Find parameters defining the range of bunch crossings to be processed
0175     int16_t firstBxEmCand = (m_allInputEmCands.empty() ? 0 : m_allInputEmCands.front().bx());
0176     int16_t firstBxRegion = (m_allInputRegions.empty() ? 0 : m_allInputRegions.front().bx());
0177     int16_t lastBxEmCand = (m_allInputEmCands.empty() ? 0 : m_allInputEmCands.back().bx());
0178     int16_t lastBxRegion = (m_allInputRegions.empty() ? 0 : m_allInputRegions.back().bx());
0179     m_bxStart = std::min(firstBxEmCand, firstBxRegion);
0180     m_numOfBx = std::max(lastBxEmCand, lastBxRegion) - m_bxStart + 1;
0181   } else {
0182     // Remove any input from before the start of the requested range
0183     for (vector<L1CaloEmCand>::iterator emc = m_allInputEmCands.begin(); emc != m_allInputEmCands.end(); emc++) {
0184       if (emc->bx() >= m_bxStart)
0185         break;
0186       m_allInputEmCands.erase(emc);
0187     }
0188 
0189     for (vector<L1CaloRegion>::iterator rgn = m_allInputRegions.begin(); rgn != m_allInputRegions.end(); rgn++) {
0190       if (rgn->bx() >= m_bxStart)
0191         break;
0192       m_allInputRegions.erase(rgn);
0193     }
0194   }
0195 
0196   // Setup pipeline lengths
0197   // EM Leaf Card
0198   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0199     theEmLeafCards.at(i)->setBxRange(m_bxStart, m_numOfBx);
0200   }
0201 
0202   // Jet Leaf cards
0203   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0204     theJetLeafCards.at(i)->setBxRange(m_bxStart, m_numOfBx);
0205   }
0206 
0207   // Wheel Cards
0208   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0209     theWheelJetFpgas.at(i)->setBxRange(m_bxStart, m_numOfBx);
0210   }
0211 
0212   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0213     theWheelEnergyFpgas.at(i)->setBxRange(m_bxStart, m_numOfBx);
0214   }
0215 
0216   // Electron Final Stage
0217   theIsoEmFinalStage->setBxRange(m_bxStart, m_numOfBx);
0218   theNonIsoEmFinalStage->setBxRange(m_bxStart, m_numOfBx);
0219 
0220   // Jet Final Stage
0221   theJetFinalStage->setBxRange(m_bxStart, m_numOfBx);
0222 
0223   // Energy Final Stage
0224   theEnergyFinalStage->setBxRange(m_bxStart, m_numOfBx);
0225 }
0226 
0227 /// Partial reset for a new bunch crossing
0228 void L1GlobalCaloTrigger::bxReset(const int bx) {
0229   // EM Leaf Card
0230   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0231     theEmLeafCards.at(i)->setNextBx(bx);
0232   }
0233 
0234   // Jet Leaf cards
0235   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0236     theJetLeafCards.at(i)->setNextBx(bx);
0237   }
0238 
0239   // Wheel Cards
0240   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0241     theWheelJetFpgas.at(i)->setNextBx(bx);
0242   }
0243 
0244   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0245     theWheelEnergyFpgas.at(i)->setNextBx(bx);
0246   }
0247 
0248   // Electron Final Stage
0249   theIsoEmFinalStage->setNextBx(bx);
0250   theNonIsoEmFinalStage->setNextBx(bx);
0251 
0252   // Jet Final Stage
0253   theJetFinalStage->setNextBx(bx);
0254 
0255   // Energy Final Stage
0256   theEnergyFinalStage->setNextBx(bx);
0257 }
0258 
0259 /// Process a new bunch crossing
0260 void L1GlobalCaloTrigger::bxProcess(const int bx) {
0261   // EM Leaf Card
0262   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0263     theEmLeafCards.at(i)->fetchInput();
0264     theEmLeafCards.at(i)->process();
0265   }
0266 
0267   // Jet Leaf cards - first stage processing
0268   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0269     theJetLeafCards.at(i)->fetchInput();
0270   }
0271 
0272   // Jet Leaf cards - second stage processing
0273   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0274     theJetLeafCards.at(i)->process();
0275   }
0276 
0277   // Wheel Cards
0278   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0279     theWheelJetFpgas.at(i)->fetchInput();
0280     theWheelJetFpgas.at(i)->process();
0281   }
0282 
0283   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0284     theWheelEnergyFpgas.at(i)->fetchInput();
0285     theWheelEnergyFpgas.at(i)->process();
0286   }
0287 
0288   // Electron Final Stage
0289   theIsoEmFinalStage->fetchInput();
0290   theIsoEmFinalStage->process();
0291 
0292   theNonIsoEmFinalStage->fetchInput();
0293   theNonIsoEmFinalStage->process();
0294 
0295   // Jet Final Stage
0296   theJetFinalStage->fetchInput();
0297   theJetFinalStage->process();
0298 
0299   // Energy Final Stage
0300   theEnergyFinalStage->fetchInput();
0301   theEnergyFinalStage->process();
0302 }
0303 
0304 ///=================================================================================================
0305 /// Configuration options for the GCT
0306 ///
0307 /// setup the Jet Finder parameters
0308 void L1GlobalCaloTrigger::setJetFinderParams(const L1GctJetFinderParams* const jfpars) {
0309   // Some parameters not (yet?) implemented
0310   if ((jfpars->getCenForJetEtaBoundary() == 7) && (jfpars->getCenJetEtSeedGct() == jfpars->getTauJetEtSeedGct())) {
0311     m_jetFinderParams = jfpars;
0312     // Need to propagate the new parameters to all the JetFinders
0313     for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0314       theJetLeafCards.at(i)->getJetFinderA()->setJetFinderParams(jfpars);
0315       theJetLeafCards.at(i)->getJetFinderB()->setJetFinderParams(jfpars);
0316       theJetLeafCards.at(i)->getJetFinderC()->setJetFinderParams(jfpars);
0317     }
0318     // Also send to the final energy calculation (for missing Ht)
0319     theEnergyFinalStage->setJetFinderParams(jfpars);
0320   }
0321 }
0322 
0323 /// setup the Jet Calibration Lut
0324 void L1GlobalCaloTrigger::setJetEtCalibrationLuts(const L1GlobalCaloTrigger::lutPtrVector& jfluts) {
0325   m_jetEtCalLuts = jfluts;
0326   // Need to propagate the new lut to all the JetFinders
0327   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0328     theJetLeafCards.at(i)->getJetFinderA()->setJetEtCalibrationLuts(jfluts);
0329     theJetLeafCards.at(i)->getJetFinderB()->setJetEtCalibrationLuts(jfluts);
0330     theJetLeafCards.at(i)->getJetFinderC()->setJetEtCalibrationLuts(jfluts);
0331   }
0332 }
0333 
0334 /// Setup the tau algorithm parameters
0335 void L1GlobalCaloTrigger::setupTauAlgo(const bool useImprovedAlgo, const bool ignoreVetoBitsForIsolation) {
0336   // Need to propagate the new parameters to all the JetFinders
0337   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0338     theJetLeafCards.at(i)->getJetFinderA()->setupTauAlgo(useImprovedAlgo, ignoreVetoBitsForIsolation);
0339     theJetLeafCards.at(i)->getJetFinderB()->setupTauAlgo(useImprovedAlgo, ignoreVetoBitsForIsolation);
0340     theJetLeafCards.at(i)->getJetFinderC()->setupTauAlgo(useImprovedAlgo, ignoreVetoBitsForIsolation);
0341   }
0342 }
0343 
0344 /// setup scale for missing Ht
0345 void L1GlobalCaloTrigger::setHtMissScale(const L1CaloEtScale* const scale) {
0346   if (theEnergyFinalStage != nullptr) {
0347     theEnergyFinalStage->setHtMissScale(scale);
0348   }
0349 }
0350 
0351 /// setup Hf sum LUTs
0352 void L1GlobalCaloTrigger::setupHfSumLuts(const L1CaloEtScale* const scale) {
0353   if (getHfSumProcessor() != nullptr) {
0354     getHfSumProcessor()->setupLuts(scale);
0355   }
0356 }
0357 
0358 /// setup the input channel mask
0359 void L1GlobalCaloTrigger::setChannelMask(const L1GctChannelMask* const mask) {
0360   m_inputChannelMask = mask;
0361   // Need to propagate the new mask to all the JetFinders
0362   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0363     theJetLeafCards.at(i)->getJetFinderA()->setEnergySumMasks(mask);
0364     theJetLeafCards.at(i)->getJetFinderB()->setEnergySumMasks(mask);
0365     theJetLeafCards.at(i)->getJetFinderC()->setEnergySumMasks(mask);
0366   }
0367 }
0368 
0369 /// check we have done all the setup
0370 bool L1GlobalCaloTrigger::setupOk() const {
0371   bool result = true;
0372   result &= (m_inputChannelMask != nullptr);
0373   // EM Leaf Card
0374   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0375     result &= theEmLeafCards.at(i)->setupOk();
0376   }
0377 
0378   // Jet Leaf cards
0379   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0380     result &= theJetLeafCards.at(i)->setupOk();
0381   }
0382 
0383   // Jet Finders
0384   for (int i = 0; i < N_JET_LEAF_CARDS * 3; i++) {
0385     result &= theJetFinders.at(i)->setupOk();
0386   }
0387 
0388   // Wheel Cards
0389   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0390     result &= theWheelJetFpgas.at(i)->setupOk();
0391   }
0392 
0393   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0394     result &= theWheelEnergyFpgas.at(i)->setupOk();
0395   }
0396 
0397   // Electron Final Stage
0398   result &= theIsoEmFinalStage->setupOk();
0399   result &= theNonIsoEmFinalStage->setupOk();
0400 
0401   // Jet Final Stage
0402   result &= theJetFinalStage->setupOk();
0403 
0404   // Energy Final Stage
0405   result &= theEnergyFinalStage->setupOk();
0406 
0407   // All done.
0408   return result;
0409 }
0410 
0411 /// provide access to hf sum processor
0412 L1GctGlobalHfSumAlgos* L1GlobalCaloTrigger::getHfSumProcessor() const {
0413   L1GctGlobalHfSumAlgos* result = nullptr;
0414   if (theEnergyFinalStage != nullptr) {
0415     result = theEnergyFinalStage->getHfSumProcessor();
0416   }
0417   return result;
0418 }
0419 
0420 /// setup the bunch crossing range to be processed
0421 /// process crossings from (firstBx) to (lastBx)
0422 void L1GlobalCaloTrigger::setBxRange(const int firstBx, const int lastBx) {
0423   m_bxStart = firstBx;
0424   m_numOfBx = lastBx - firstBx + 1;
0425   m_bxRangeAuto = false;
0426 }
0427 /// process crossings from (-numOfBx) to (numOfBx)
0428 void L1GlobalCaloTrigger::setBxRangeSymmetric(const int numOfBx) {
0429   m_bxStart = -numOfBx;
0430   m_numOfBx = 2 * numOfBx + 1;
0431   m_bxRangeAuto = false;
0432 }
0433 /// process all crossings present in the input (and only those crossings)
0434 void L1GlobalCaloTrigger::setBxRangeAutomatic() {
0435   m_bxStart = 0;
0436   m_numOfBx = 1;
0437   m_bxRangeAuto = true;
0438 }
0439 
0440 ///=================================================================================================
0441 /// Input data set methods
0442 ///
0443 /// Use the following two methods for full emulator operation
0444 /// set jet regions from the RCT at the input to be processed
0445 void L1GlobalCaloTrigger::fillRegions(const vector<L1CaloRegion>& rgn) {
0446   // To enable multiple bunch crossing operation, we copy the input regions into a vector,
0447   // from which they will be extracted one bunch crossing at a time and sent to the processors
0448   vector<L1CaloRegion>::iterator itr = m_allInputRegions.end();
0449   m_allInputRegions.insert(itr, rgn.begin(), rgn.end());
0450 }
0451 
0452 /// set electrons from the RCT at the input to be processed
0453 void L1GlobalCaloTrigger::fillEmCands(const vector<L1CaloEmCand>& em) {
0454   // To enable multiple bunch crossing operation, we copy the input electrons into a vector,
0455   // from which they will be extracted one bunch crossing at a time and sent to the processors
0456   vector<L1CaloEmCand>::iterator itr = m_allInputEmCands.end();
0457   m_allInputEmCands.insert(itr, em.begin(), em.end());
0458 }
0459 
0460 /// Private method to send one bunch crossing's worth of regions to the processors
0461 void L1GlobalCaloTrigger::fillRegions(vector<L1CaloRegion>::iterator& rgn, const int bx) {
0462   while (rgn != m_allInputRegions.end() && rgn->bx() == bx) {
0463     setRegion(*rgn++);
0464   }
0465 }
0466 
0467 /// Private method to send one bunch crossing's worth of electrons to the processors
0468 void L1GlobalCaloTrigger::fillEmCands(vector<L1CaloEmCand>::iterator& emc, const int bx) {
0469   while (emc != m_allInputEmCands.end() && emc->bx() == bx) {
0470     if (emc->isolated()) {
0471       setIsoEm(*emc);
0472     } else {
0473       setNonIsoEm(*emc);
0474     }
0475     emc++;
0476   }
0477 }
0478 
0479 /// Set a jet region at the input to be processed
0480 /// Called from fillRegions() above - also available to be called directly
0481 /// (but the "user" has to take care of any multiple bunch crossing issues)
0482 void L1GlobalCaloTrigger::setRegion(const L1CaloRegion& region) {
0483   if (!m_inputChannelMask->regionMask(region.gctEta(), region.gctPhi())) {
0484     unsigned crate = region.rctCrate();
0485     // Find the relevant jetFinders
0486     static const unsigned NPHI = L1CaloRegionDetId::N_PHI / 2;
0487     unsigned prevphi = crate % NPHI;
0488     unsigned thisphi = (crate + 1) % NPHI;
0489     unsigned nextphi = (crate + 2) % NPHI;
0490 
0491     // Send the region to six jetFinders.
0492     theJetFinders.at(thisphi)->setInputRegion(region);
0493     theJetFinders.at(nextphi)->setInputRegion(region);
0494     theJetFinders.at(prevphi)->setInputRegion(region);
0495     theJetFinders.at(thisphi + NPHI)->setInputRegion(region);
0496     theJetFinders.at(nextphi + NPHI)->setInputRegion(region);
0497     theJetFinders.at(prevphi + NPHI)->setInputRegion(region);
0498   }
0499 }
0500 
0501 /// Construct a jet region and set it at the input to be processed.
0502 /// For testing/debugging only.
0503 void L1GlobalCaloTrigger::setRegion(
0504     const unsigned et, const unsigned ieta, const unsigned iphi, const bool overFlow, const bool fineGrain) {
0505   //  L1CaloRegion temp = L1CaloRegion::makeRegionFromGctIndices(et, overFlow, fineGrain, false, false, ieta, iphi, 0);
0506   L1CaloRegion temp(et, overFlow, fineGrain, false, false, ieta, iphi, 0);
0507   setRegion(temp);
0508 }
0509 
0510 /// Set an isolated EM candidate to be processed
0511 /// Called from fillEmCands() above - also available to be called directly
0512 /// (but the "user" has to take care of any multiple bunch crossing issues)
0513 void L1GlobalCaloTrigger::setIsoEm(const L1CaloEmCand& em) {
0514   if (!m_inputChannelMask->emCrateMask(em.rctCrate()))
0515     theIsoElectronSorters.at(sorterNo(em))->setInputEmCand(em);
0516 }
0517 
0518 /// Set a non-isolated EM candidate to be processed
0519 /// Called from fillEmCands() above - also available to be called directly
0520 /// (but the "user" has to take care of any multiple bunch crossing issues)
0521 void L1GlobalCaloTrigger::setNonIsoEm(const L1CaloEmCand& em) {
0522   if (!m_inputChannelMask->emCrateMask(em.rctCrate()))
0523     theNonIsoElectronSorters.at(sorterNo(em))->setInputEmCand(em);
0524 }
0525 
0526 ///=================================================================================================
0527 /// Print method
0528 ///
0529 void L1GlobalCaloTrigger::print() {
0530   using edm::LogInfo;
0531   using std::endl;
0532 
0533   LogInfo("L1GlobalCaloTrigger") << "=== Global Calo Trigger ===" << endl;
0534   LogInfo("L1GlobalCaloTrigger") << "=== START DEBUG OUTPUT  ===" << endl;
0535 
0536   LogInfo("L1GlobalCaloTrigger") << endl;
0537   LogInfo("L1GlobalCaloTrigger") << "N Jet Leaf Cards " << theJetLeafCards.size() << endl;
0538   LogInfo("L1GlobalCaloTrigger") << "N Wheel Jet Fpgas " << theWheelJetFpgas.size() << endl;
0539   LogInfo("L1GlobalCaloTrigger") << "N Wheel Energy Fpgas " << theWheelEnergyFpgas.size() << endl;
0540   LogInfo("L1GlobalCaloTrigger") << "N Em Leaf Cards " << theEmLeafCards.size() << endl;
0541   LogInfo("L1GlobalCaloTrigger") << endl;
0542 
0543   for (unsigned i = 0; i < theJetLeafCards.size(); i++) {
0544     LogInfo("L1GlobalCaloTrigger") << "Jet Leaf Card " << i << " : " << theJetLeafCards.at(i) << endl;
0545     LogInfo("L1GlobalCaloTrigger") << (*theJetLeafCards.at(i));
0546   }
0547   LogInfo("L1GlobalCaloTrigger") << endl;
0548 
0549   for (unsigned i = 0; i < theWheelJetFpgas.size(); i++) {
0550     LogInfo("L1GlobalCaloTrigger") << "Wheel Jet FPGA " << i << " : " << theWheelJetFpgas.at(i) << endl;
0551     LogInfo("L1GlobalCaloTrigger") << (*theWheelJetFpgas.at(i));
0552   }
0553   LogInfo("L1GlobalCaloTrigger") << endl;
0554 
0555   for (unsigned i = 0; i < theWheelEnergyFpgas.size(); i++) {
0556     LogInfo("L1GlobalCaloTrigger") << "Wheel Energy FPGA " << i << " : " << theWheelEnergyFpgas.at(i) << endl;
0557     LogInfo("L1GlobalCaloTrigger") << (*theWheelEnergyFpgas.at(i));
0558   }
0559   LogInfo("L1GlobalCaloTrigger") << endl;
0560 
0561   LogInfo("L1GlobalCaloTrigger") << (*theJetFinalStage);
0562   LogInfo("L1GlobalCaloTrigger") << endl;
0563 
0564   LogInfo("L1GlobalCaloTrigger") << (*theEnergyFinalStage);
0565   LogInfo("L1GlobalCaloTrigger") << endl;
0566 
0567   for (unsigned i = 0; i < theEmLeafCards.size(); i++) {
0568     LogInfo("L1GlobalCaloTrigger") << ((i == 0) ? "Positive eta " : "Negative eta ");
0569     LogInfo("L1GlobalCaloTrigger") << "EM Leaf Card " << i << " : " << theEmLeafCards.at(i) << endl;
0570     LogInfo("L1GlobalCaloTrigger") << (*theEmLeafCards.at(i));
0571   }
0572   LogInfo("L1GlobalCaloTrigger") << endl;
0573 
0574   LogInfo("L1GlobalCaloTrigger") << (*theIsoEmFinalStage);
0575   LogInfo("L1GlobalCaloTrigger") << endl;
0576 
0577   LogInfo("L1GlobalCaloTrigger") << (*theNonIsoEmFinalStage);
0578 
0579   LogInfo("L1GlobalCaloTrigger") << "=== Global Calo Trigger ===" << endl;
0580   LogInfo("L1GlobalCaloTrigger") << "===  END DEBUG OUTPUT   ===" << endl;
0581 }
0582 
0583 ///=================================================================================================
0584 /// Output data get methods
0585 ///
0586 // isolated EM outputs
0587 L1GctEmCandCollection L1GlobalCaloTrigger::getIsoElectrons() const { return theIsoEmFinalStage->getOutputCands(); }
0588 
0589 // non isolated EM outputs
0590 L1GctEmCandCollection L1GlobalCaloTrigger::getNonIsoElectrons() const {
0591   return theNonIsoEmFinalStage->getOutputCands();
0592 }
0593 
0594 // central jet outputs to GT
0595 L1GctJetCandCollection L1GlobalCaloTrigger::getCentralJets() const { return theJetFinalStage->getCentralJets(); }
0596 
0597 // forward jet outputs to GT
0598 L1GctJetCandCollection L1GlobalCaloTrigger::getForwardJets() const { return theJetFinalStage->getForwardJets(); }
0599 
0600 // tau jet outputs to GT
0601 L1GctJetCandCollection L1GlobalCaloTrigger::getTauJets() const { return theJetFinalStage->getTauJets(); }
0602 
0603 /// all jets from jetfinders in raw format
0604 L1GctInternJetDataCollection L1GlobalCaloTrigger::getInternalJets() const {
0605   L1GctInternJetDataCollection allJets, jfJets;
0606 
0607   // Loop over jetfinders, find the internal jets and add them to the list
0608   for (unsigned jf = 0; jf < theJetFinders.size(); jf++) {
0609     jfJets = theJetFinders.at(jf)->getInternalJets();
0610     allJets.insert(allJets.end(), jfJets.begin(), jfJets.end());
0611   }
0612 
0613   return allJets;
0614 }
0615 
0616 // total Et output
0617 L1GctEtTotalCollection L1GlobalCaloTrigger::getEtSumCollection() const {
0618   L1GctEtTotalCollection result(m_numOfBx);
0619   int bx = m_bxStart;
0620   for (int i = 0; i < m_numOfBx; i++) {
0621     L1GctEtTotal temp(
0622         theEnergyFinalStage->getEtSumColl().at(i).value(), theEnergyFinalStage->getEtSumColl().at(i).overFlow(), bx++);
0623     result.at(i) = temp;
0624   }
0625   return result;
0626 }
0627 
0628 L1GctEtHadCollection L1GlobalCaloTrigger::getEtHadCollection() const {
0629   L1GctEtHadCollection result(m_numOfBx);
0630   int bx = m_bxStart;
0631   for (int i = 0; i < m_numOfBx; i++) {
0632     L1GctEtHad temp(
0633         theEnergyFinalStage->getEtHadColl().at(i).value(), theEnergyFinalStage->getEtHadColl().at(i).overFlow(), bx++);
0634     result.at(i) = temp;
0635   }
0636   return result;
0637 }
0638 
0639 L1GctEtMissCollection L1GlobalCaloTrigger::getEtMissCollection() const {
0640   L1GctEtMissCollection result(m_numOfBx);
0641   int bx = m_bxStart;
0642   for (int i = 0; i < m_numOfBx; i++) {
0643     L1GctEtMiss temp(theEnergyFinalStage->getEtMissColl().at(i).value(),
0644                      theEnergyFinalStage->getEtMissPhiColl().at(i).value(),
0645                      theEnergyFinalStage->getEtMissColl().at(i).overFlow(),
0646                      bx++);
0647     result.at(i) = temp;
0648   }
0649   return result;
0650 }
0651 
0652 L1GctHtMissCollection L1GlobalCaloTrigger::getHtMissCollection() const {
0653   L1GctHtMissCollection result(m_numOfBx);
0654   int bx = m_bxStart;
0655   for (int i = 0; i < m_numOfBx; i++) {
0656     L1GctHtMiss temp(theEnergyFinalStage->getHtMissColl().at(i).value(),
0657                      theEnergyFinalStage->getHtMissPhiColl().at(i).value(),
0658                      theEnergyFinalStage->getHtMissColl().at(i).overFlow(),
0659                      bx++);
0660     result.at(i) = temp;
0661   }
0662   return result;
0663 }
0664 
0665 L1GctInternEtSumCollection L1GlobalCaloTrigger::getInternalEtSums() const {
0666   L1GctInternEtSumCollection allSums, procSums;
0667 
0668   // Go through all the processor types that process et sums
0669   // JetFinders
0670   for (unsigned jf = 0; jf < theJetFinders.size(); jf++) {
0671     procSums = theJetFinders.at(jf)->getInternalEtSums();
0672     allSums.insert(allSums.end(), procSums.begin(), procSums.end());
0673   }
0674 
0675   // Jet Leaf cards
0676   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0677     procSums = theJetLeafCards.at(i)->getInternalEtSums();
0678     allSums.insert(allSums.end(), procSums.begin(), procSums.end());
0679   }
0680 
0681   // Wheel Cards
0682   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0683     procSums = theWheelEnergyFpgas.at(i)->getInternalEtSums();
0684     allSums.insert(allSums.end(), procSums.begin(), procSums.end());
0685   }
0686 
0687   return allSums;
0688 }
0689 
0690 L1GctInternHtMissCollection L1GlobalCaloTrigger::getInternalHtMiss() const {
0691   L1GctInternHtMissCollection allSums, procSums;
0692 
0693   // Go through all the processor types that process et sums
0694   // JetFinders
0695   for (unsigned jf = 0; jf < theJetFinders.size(); jf++) {
0696     procSums = theJetFinders.at(jf)->getInternalHtMiss();
0697     allSums.insert(allSums.end(), procSums.begin(), procSums.end());
0698   }
0699 
0700   // Jet Leaf cards
0701   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0702     procSums = theJetLeafCards.at(i)->getInternalHtMiss();
0703     allSums.insert(allSums.end(), procSums.begin(), procSums.end());
0704   }
0705 
0706   // Wheel Cards
0707   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0708     procSums = theWheelJetFpgas.at(i)->getInternalHtMiss();
0709     allSums.insert(allSums.end(), procSums.begin(), procSums.end());
0710   }
0711 
0712   return allSums;
0713 }
0714 
0715 L1GctHFBitCountsCollection L1GlobalCaloTrigger::getHFBitCountsCollection() const {
0716   L1GctHFBitCountsCollection result(m_numOfBx);
0717   if (getHfSumProcessor() != nullptr) {
0718     int bx = m_bxStart;
0719     for (int i = 0; i < m_numOfBx; i++) {
0720       L1GctHFBitCounts temp = L1GctHFBitCounts::fromGctEmulator(
0721           static_cast<int16_t>(bx),
0722           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::bitCountPosEtaRing1).at(i),
0723           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::bitCountNegEtaRing1).at(i),
0724           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::bitCountPosEtaRing2).at(i),
0725           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::bitCountNegEtaRing2).at(i));
0726       result.at(i) = temp;
0727       bx++;
0728     }
0729   }
0730   return result;
0731 }
0732 
0733 L1GctHFRingEtSumsCollection L1GlobalCaloTrigger::getHFRingEtSumsCollection() const {
0734   L1GctHFRingEtSumsCollection result(m_numOfBx);
0735   if (getHfSumProcessor() != nullptr) {
0736     int bx = m_bxStart;
0737     for (int i = 0; i < m_numOfBx; i++) {
0738       L1GctHFRingEtSums temp = L1GctHFRingEtSums::fromGctEmulator(
0739           static_cast<int16_t>(bx),
0740           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::etSumPosEtaRing1).at(i),
0741           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::etSumNegEtaRing1).at(i),
0742           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::etSumPosEtaRing2).at(i),
0743           getHfSumProcessor()->hfSumsOutput(L1GctHfEtSumsLut::etSumNegEtaRing2).at(i));
0744       result.at(i) = temp;
0745       bx++;
0746     }
0747   }
0748   return result;
0749 }
0750 
0751 /// control output messages
0752 void L1GlobalCaloTrigger::setVerbose() {
0753   // EM Leaf Card
0754   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0755     theEmLeafCards.at(i)->setVerbose();
0756   }
0757 
0758   // Jet Leaf cards
0759   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0760     theJetLeafCards.at(i)->setVerbose();
0761   }
0762 
0763   // Jet Finders
0764   for (int i = 0; i < N_JET_LEAF_CARDS * 3; i++) {
0765     theJetFinders.at(i)->setVerbose();
0766   }
0767 
0768   // Wheel Cards
0769   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0770     theWheelJetFpgas.at(i)->setVerbose();
0771   }
0772 
0773   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0774     theWheelEnergyFpgas.at(i)->setVerbose();
0775   }
0776 
0777   // Electron Final Stage
0778   theIsoEmFinalStage->setVerbose();
0779   theNonIsoEmFinalStage->setVerbose();
0780 
0781   // Jet Final Stage
0782   theJetFinalStage->setVerbose();
0783 
0784   // Energy Final Stage
0785   theEnergyFinalStage->setVerbose();
0786 }
0787 
0788 void L1GlobalCaloTrigger::setTerse() {
0789   // EM Leaf Card
0790   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0791     theEmLeafCards.at(i)->setTerse();
0792   }
0793 
0794   // Jet Leaf cards
0795   for (int i = 0; i < N_JET_LEAF_CARDS; i++) {
0796     theJetLeafCards.at(i)->setTerse();
0797   }
0798 
0799   // Jet Finders
0800   for (int i = 0; i < N_JET_LEAF_CARDS * 3; i++) {
0801     theJetFinders.at(i)->setTerse();
0802   }
0803 
0804   // Wheel Cards
0805   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0806     theWheelJetFpgas.at(i)->setTerse();
0807   }
0808 
0809   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0810     theWheelEnergyFpgas.at(i)->setTerse();
0811   }
0812 
0813   // Electron Final Stage
0814   theIsoEmFinalStage->setTerse();
0815   theNonIsoEmFinalStage->setTerse();
0816 
0817   // Jet Final Stage
0818   theJetFinalStage->setTerse();
0819 
0820   // Energy Final Stage
0821   theEnergyFinalStage->setTerse();
0822 }
0823 
0824 /* PRIVATE METHODS */
0825 
0826 // instantiate hardware/algorithms
0827 void L1GlobalCaloTrigger::build(L1GctJetLeafCard::jetFinderType jfType, unsigned jetLeafMask) {
0828   // The first half of the jet leaf cards are at negative eta,
0829   // followed by positive eta
0830   // Jet Leaf cards
0831   if (jetLeafMask == 0) {
0832     for (int jlc = 0; jlc < N_JET_LEAF_CARDS; jlc++) {
0833       theJetLeafCards.at(jlc) = new L1GctJetLeafCard(jlc, jlc % 3, jfType);
0834       theJetFinders.at(3 * jlc) = theJetLeafCards.at(jlc)->getJetFinderA();
0835       theJetFinders.at(3 * jlc + 1) = theJetLeafCards.at(jlc)->getJetFinderB();
0836       theJetFinders.at(3 * jlc + 2) = theJetLeafCards.at(jlc)->getJetFinderC();
0837     }
0838   } else {
0839     // Setup for hardware testing with reduced number of leaf cards
0840     unsigned mask = jetLeafMask;
0841     for (int jlc = 0; jlc < N_JET_LEAF_CARDS; jlc++) {
0842       if ((mask & 1) == 0) {
0843         theJetLeafCards.at(jlc) = new L1GctJetLeafCard(jlc, jlc % 3, jfType);
0844       } else {
0845         theJetLeafCards.at(jlc) = new L1GctJetLeafCard(jlc, jlc % 3, L1GctJetLeafCard::nullJetFinder);
0846       }
0847       theJetFinders.at(3 * jlc) = theJetLeafCards.at(jlc)->getJetFinderA();
0848       theJetFinders.at(3 * jlc + 1) = theJetLeafCards.at(jlc)->getJetFinderB();
0849       theJetFinders.at(3 * jlc + 2) = theJetLeafCards.at(jlc)->getJetFinderC();
0850       mask = mask >> 1;
0851     }
0852   }
0853 
0854   //Link jet leaf cards together
0855   vector<L1GctJetLeafCard*> neighbours(2);
0856   for (int jlc = 0; jlc < N_JET_LEAF_CARDS / 2; jlc++) {
0857     // Define local constant for ease of typing
0858     static const int NL = N_JET_LEAF_CARDS / 2;
0859     int nlc = (jlc + 1) % NL;
0860     int mlc = (jlc + (NL - 1)) % NL;
0861     neighbours.at(0) = theJetLeafCards.at(mlc);
0862     neighbours.at(1) = theJetLeafCards.at(nlc);
0863     theJetLeafCards.at(jlc)->setNeighbourLeafCards(neighbours);
0864     neighbours.at(0) = theJetLeafCards.at(NL + mlc);
0865     neighbours.at(1) = theJetLeafCards.at(NL + nlc);
0866     theJetLeafCards.at(NL + jlc)->setNeighbourLeafCards(neighbours);
0867   }
0868 
0869   // EM leaf cards
0870   // Card 0 is positive eta, card 1 is negative eta
0871   for (int i = 0; i < N_EM_LEAF_CARDS; i++) {
0872     theEmLeafCards.at(i) = new L1GctEmLeafCard(i);
0873     theIsoElectronSorters.at(2 * i) = theEmLeafCards.at(i)->getIsoElectronSorterU1();
0874     theIsoElectronSorters.at(2 * i + 1) = theEmLeafCards.at(i)->getIsoElectronSorterU2();
0875     theNonIsoElectronSorters.at(2 * i) = theEmLeafCards.at(i)->getNonIsoElectronSorterU1();
0876     theNonIsoElectronSorters.at(2 * i + 1) = theEmLeafCards.at(i)->getNonIsoElectronSorterU2();
0877   }
0878 
0879   // Wheel Fpgas
0880   vector<L1GctJetLeafCard*> wheelJetLeafCards(3);
0881   vector<L1GctJetLeafCard*> wheelEnergyLeafCards(3);
0882 
0883   // The first wheel card is at negative eta,
0884   // the second one is at positive eta
0885   for (int i = 0; i < N_WHEEL_CARDS; i++) {
0886     for (int j = 0; j < 3; j++) {
0887       wheelJetLeafCards.at(j) = theJetLeafCards.at(i * 3 + j);
0888       wheelEnergyLeafCards.at(j) = theJetLeafCards.at(i * 3 + j);
0889     }
0890     theWheelJetFpgas.at(i) = new L1GctWheelJetFpga(i, wheelJetLeafCards);
0891     theWheelEnergyFpgas.at(i) = new L1GctWheelEnergyFpga(i, wheelEnergyLeafCards);
0892   }
0893 
0894   // Jet Final Stage
0895   theJetFinalStage = new L1GctJetFinalStage(theWheelJetFpgas);
0896 
0897   // Electron Final Sort
0898   theIsoEmFinalStage = new L1GctElectronFinalSort(true, theEmLeafCards.at(0), theEmLeafCards.at(1));
0899   theNonIsoEmFinalStage = new L1GctElectronFinalSort(false, theEmLeafCards.at(0), theEmLeafCards.at(1));
0900 
0901   // Global Energy Algos
0902   theEnergyFinalStage = new L1GctGlobalEnergyAlgos(theWheelEnergyFpgas, theWheelJetFpgas);
0903 }
0904 
0905 /// ordering of the electron sorters to give the correct
0906 /// priority to the candidates in the final sort
0907 /// The priority ordering is:
0908 ///    crates  4 - 8 : priority 0 (highest)
0909 ///    crates  0 - 3 : priority 1
0910 ///    crates 13 -17 : priority 2
0911 ///    crates  9 -12 : priority 3 (lowest)
0912 unsigned L1GlobalCaloTrigger::sorterNo(const L1CaloEmCand& em) const {
0913   unsigned crate = em.rctCrate();
0914   unsigned result = (((crate % 9) < 4) ? 1 : 0);
0915   if (crate >= 9)
0916     result += 2;
0917   if (crate >= 18)
0918     result = 0;
0919   return result;
0920 }