Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-09-02 08:36:17

0001 #include "L1Trigger/CSCTriggerPrimitives/interface/CSCMotherboard.h"
0002 #include <iostream>
0003 #include <memory>
0004 
0005 // Default values of configuration parameters.
0006 const unsigned int CSCMotherboard::def_mpc_block_me1a = 1;
0007 const unsigned int CSCMotherboard::def_alct_trig_enable = 0;
0008 const unsigned int CSCMotherboard::def_clct_trig_enable = 0;
0009 const unsigned int CSCMotherboard::def_match_trig_enable = 1;
0010 const unsigned int CSCMotherboard::def_match_trig_window_size = 7;
0011 const unsigned int CSCMotherboard::def_tmb_l1a_window_size = 7;
0012 
0013 CSCMotherboard::CSCMotherboard(unsigned endcap,
0014                                unsigned station,
0015                                unsigned sector,
0016                                unsigned subsector,
0017                                unsigned chamber,
0018                                const edm::ParameterSet& conf)
0019     : CSCBaseboard(endcap, station, sector, subsector, chamber, conf) {
0020   // Normal constructor.  -JM
0021   // Pass ALCT, CLCT, and common parameters on to ALCT and CLCT processors.
0022   static std::atomic<bool> config_dumped{false};
0023 
0024   mpc_block_me1a = tmbParams_.getParameter<unsigned int>("mpcBlockMe1a");
0025   alct_trig_enable = tmbParams_.getParameter<unsigned int>("alctTrigEnable");
0026   clct_trig_enable = tmbParams_.getParameter<unsigned int>("clctTrigEnable");
0027   match_trig_enable = tmbParams_.getParameter<unsigned int>("matchTrigEnable");
0028   match_trig_window_size = tmbParams_.getParameter<unsigned int>("matchTrigWindowSize");
0029   tmb_l1a_window_size =  // Common to CLCT and TMB
0030       tmbParams_.getParameter<unsigned int>("tmbL1aWindowSize");
0031 
0032   // configuration handle for number of early time bins
0033   early_tbins = tmbParams_.getParameter<int>("tmbEarlyTbins");
0034 
0035   // whether to not reuse CLCTs that were used by previous matching ALCTs
0036   drop_used_clcts = tmbParams_.getParameter<bool>("tmbDropUsedClcts");
0037 
0038   // whether to readout only the earliest two LCTs in readout window
0039   readout_earliest_2 = tmbParams_.getParameter<bool>("tmbReadoutEarliest2");
0040 
0041   match_earliest_clct_only_ = tmbParams_.getParameter<bool>("matchEarliestClctOnly");
0042 
0043   infoV = tmbParams_.getParameter<int>("verbosity");
0044 
0045   alctProc = std::make_unique<CSCAnodeLCTProcessor>(endcap, station, sector, subsector, chamber, conf);
0046   clctProc = std::make_unique<CSCCathodeLCTProcessor>(endcap, station, sector, subsector, chamber, conf);
0047 
0048   // Check and print configuration parameters.
0049   checkConfigParameters();
0050   if (infoV > 0 && !config_dumped) {
0051     dumpConfigParams();
0052     config_dumped = true;
0053   }
0054 
0055   allLCTs_.setMatchTrigWindowSize(match_trig_window_size);
0056 
0057   // get the preferred CLCT BX match array
0058   preferred_bx_match_ = tmbParams_.getParameter<std::vector<int>>("preferredBxMatch");
0059 
0060   // quality assignment
0061   qualityAssignment_ = std::make_unique<LCTQualityAssignment>(endcap, station, sector, subsector, chamber, conf);
0062 
0063   // quality control of stubs
0064   qualityControl_ = std::make_unique<LCTQualityControl>(endcap, station, sector, subsector, chamber, conf);
0065 
0066   // shower-trigger source
0067   showerSource_ = showerParams_.getParameter<std::vector<unsigned>>("source");
0068 
0069   unsigned csc_idx = CSCDetId::iChamberType(theStation, theRing) - 2;
0070   thisShowerSource_ = showerSource_[csc_idx];
0071 
0072   // shower readout window
0073   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - tmb_l1a_window_size / 2;
0074   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + tmb_l1a_window_size / 2;
0075   assert(tmb_l1a_window_size / 2 <= CSCConstants::LCT_CENTRAL_BX);
0076 
0077   // enable the upgrade processors for ring 1 stations
0078   if (runPhase2_ and theRing == 1) {
0079     clctProc = std::make_unique<CSCUpgradeCathodeLCTProcessor>(endcap, station, sector, subsector, chamber, conf);
0080     if (enableAlctPhase2_) {
0081       alctProc = std::make_unique<CSCUpgradeAnodeLCTProcessor>(endcap, station, sector, subsector, chamber, conf);
0082     }
0083   }
0084 
0085   // set up helper class to check if ALCT and CLCT cross
0086   ignoreAlctCrossClct_ = tmbParams_.getParameter<bool>("ignoreAlctCrossClct");
0087   if (!ignoreAlctCrossClct_) {
0088     cscOverlap_ = std::make_unique<CSCALCTCrossCLCT>(endcap, station, theRing, ignoreAlctCrossClct_, conf);
0089   }
0090 }
0091 
0092 void CSCMotherboard::clear() {
0093   // clear the processors
0094   if (alctProc)
0095     alctProc->clear();
0096   if (clctProc)
0097     clctProc->clear();
0098 
0099   // clear the ALCT and CLCT containers
0100   alctV.clear();
0101   clctV.clear();
0102   lctV.clear();
0103 
0104   allLCTs_.clear();
0105 
0106   for (int bx = 0; bx < CSCConstants::MAX_LCT_TBINS; bx++) {
0107     showers_[bx].clear();
0108   }
0109 }
0110 
0111 // Set configuration parameters obtained via EventSetup mechanism.
0112 void CSCMotherboard::setConfigParameters(const CSCDBL1TPParameters* conf) {
0113   static std::atomic<bool> config_dumped{false};
0114 
0115   // Config. parameters for the TMB itself.
0116   mpc_block_me1a = conf->tmbMpcBlockMe1a();
0117   alct_trig_enable = conf->tmbAlctTrigEnable();
0118   clct_trig_enable = conf->tmbClctTrigEnable();
0119   match_trig_enable = conf->tmbMatchTrigEnable();
0120   match_trig_window_size = conf->tmbMatchTrigWindowSize();
0121   tmb_l1a_window_size = conf->tmbTmbL1aWindowSize();
0122 
0123   // Config. paramteres for ALCT and CLCT processors.
0124   alctProc->setConfigParameters(conf);
0125   clctProc->setConfigParameters(conf);
0126 
0127   // Check and print configuration parameters.
0128   checkConfigParameters();
0129   if (!config_dumped) {
0130     dumpConfigParams();
0131     config_dumped = true;
0132   }
0133   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - tmb_l1a_window_size / 2;
0134   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + tmb_l1a_window_size / 2;
0135 }
0136 
0137 void CSCMotherboard::setESLookupTables(const CSCL1TPLookupTableCCLUT* conf) { lookupTableCCLUT_ = conf; }
0138 
0139 void CSCMotherboard::setESLookupTables(const CSCL1TPLookupTableME11ILT* conf) { lookupTableME11ILT_ = conf; }
0140 
0141 void CSCMotherboard::setESLookupTables(const CSCL1TPLookupTableME21ILT* conf) { lookupTableME21ILT_ = conf; }
0142 
0143 void CSCMotherboard::run(const CSCWireDigiCollection* wiredc, const CSCComparatorDigiCollection* compdc) {
0144   // Step 1: Setup
0145   clear();
0146 
0147   // Check for existing processors
0148   if (!(alctProc && clctProc)) {
0149     edm::LogError("CSCMotherboard|SetupError") << "+++ run() called for non-existing ALCT/CLCT processor! +++ \n";
0150     return;
0151   }
0152 
0153   // set geometry
0154   alctProc->setCSCGeometry(cscGeometry_);
0155   clctProc->setCSCGeometry(cscGeometry_);
0156 
0157   // set CCLUT parameters if necessary
0158   if (runCCLUT_) {
0159     clctProc->setESLookupTables(lookupTableCCLUT_);
0160   }
0161 
0162   // Step 2: Run the processors
0163   alctV = alctProc->run(wiredc);  // run anodeLCT
0164   clctV = clctProc->run(compdc);  // run cathodeLCT
0165 
0166   // Step 2b: encode high multiplicity bits (independent of LCT construction)
0167   encodeHighMultiplicityBits();
0168 
0169   // if there are no ALCTs and no CLCTs, it does not make sense to run this TMB
0170   if (alctV.empty() and clctV.empty())
0171     return;
0172 
0173   // step 3: match the ALCTs to the CLCTs
0174   matchALCTCLCT();
0175 
0176   // Step 4: Select at most 2 LCTs per BX
0177   selectLCTs();
0178 }
0179 
0180 void CSCMotherboard::matchALCTCLCT() {
0181   // array to mask CLCTs
0182   bool used_clct_mask[CSCConstants::MAX_CLCT_TBINS] = {false};
0183 
0184   // Step 3: ALCT-centric ALCT-to-CLCT matching
0185   int bx_clct_matched = 0;  // bx of last matched CLCT
0186   for (int bx_alct = 0; bx_alct < CSCConstants::MAX_ALCT_TBINS; bx_alct++) {
0187     // There should be at least one valid CLCT or ALCT for a
0188     // correlated LCT to be formed.  Decision on whether to reject
0189     // non-complete LCTs (and if yes of which type) is made further
0190     // upstream.
0191     if (alctProc->getBestALCT(bx_alct).isValid()) {
0192       // Look for CLCTs within the match-time window.  The window is
0193       // centered at the ALCT bx; therefore, we make an assumption
0194       // that anode and cathode hits are perfectly synchronized.  This
0195       // is always true for MC, but only an approximation when the
0196       // data is analyzed (which works fairly good as long as wide
0197       // windows are used).  To get rid of this assumption, one would
0198       // need to access "full BX" words, which are not readily
0199       // available.
0200       bool is_matched = false;
0201       // loop on the preferred "delta BX" array
0202       for (unsigned mbx = 0; mbx < match_trig_window_size; mbx++) {
0203         // evaluate the preffered CLCT BX, taking into account that there is an offset in the simulation
0204         int bx_clct = bx_alct + preferred_bx_match_[mbx] - CSCConstants::ALCT_CLCT_OFFSET;
0205         // check that the CLCT BX is valid
0206         if (bx_clct >= CSCConstants::MAX_CLCT_TBINS or bx_clct < 0)
0207           continue;
0208         // do not consider previously matched CLCTs
0209         if (drop_used_clcts && used_clct_mask[bx_clct])
0210           continue;
0211         // only consider >=4 layer CLCTs for ALCT-CLCT type LCTs
0212         // this condition is lowered to >=3 layers for CLCTs in the
0213         // matchALCTCLCTGEM function
0214         if (clctProc->getBestCLCT(bx_clct).getQuality() <= 3)
0215           continue;
0216         // a valid CLCT with sufficient layers!
0217         if (clctProc->getBestCLCT(bx_clct).isValid()) {
0218           if (infoV > 1)
0219             LogTrace("CSCMotherboard") << "Successful ALCT-CLCT match: bx_alct = " << bx_alct
0220                                        << "; bx_clct = " << bx_clct << "; mbx = " << mbx;
0221           // now correlate the ALCT and CLCT into LCT.
0222           // smaller mbx means more preferred!
0223           correlateLCTs(alctProc->getBestALCT(bx_alct),
0224                         alctProc->getSecondALCT(bx_alct),
0225                         clctProc->getBestCLCT(bx_clct),
0226                         clctProc->getSecondCLCT(bx_clct),
0227                         allLCTs_(bx_alct, mbx, 0),
0228                         allLCTs_(bx_alct, mbx, 1),
0229                         CSCCorrelatedLCTDigi::ALCTCLCT);
0230           // when the first LCT is valid, you can mask the matched CLCT and/or
0231           // move on to the next ALCT if match_earliest_clct_only_ is set to true
0232           if (allLCTs_(bx_alct, mbx, 0).isValid()) {
0233             is_matched = true;
0234             used_clct_mask[bx_clct] = true;
0235             bx_clct_matched = bx_clct;
0236             if (match_earliest_clct_only_)
0237               break;
0238           }
0239         }
0240       }
0241       // No CLCT within the match time interval found: report ALCT-only LCT
0242       // (use dummy CLCTs).
0243       if (!is_matched) {
0244         if (infoV > 1)
0245           LogTrace("CSCMotherboard") << "Unsuccessful ALCT-CLCT match (ALCT only): bx_alct = " << bx_alct
0246                                      << " first ALCT " << alctProc->getBestALCT(bx_alct);
0247         if (alct_trig_enable)
0248           correlateLCTs(alctProc->getBestALCT(bx_alct),
0249                         alctProc->getSecondALCT(bx_alct),
0250                         clctProc->getBestCLCT(bx_alct),
0251                         clctProc->getSecondCLCT(bx_alct),
0252                         allLCTs_(bx_alct, 0, 0),
0253                         allLCTs_(bx_alct, 0, 1),
0254                         CSCCorrelatedLCTDigi::ALCTONLY);
0255       }
0256     }
0257     // No valid ALCTs; attempt to make CLCT-only LCT.  Use only CLCTs
0258     // which have zeroth chance to be matched at later cathode times.
0259     // (I am not entirely sure this perfectly matches the firmware logic.)
0260     // Use dummy ALCTs.
0261     else {
0262       int bx_clct = bx_alct - match_trig_window_size / 2;
0263       if (bx_clct >= 0 && bx_clct > bx_clct_matched) {
0264         if (clctProc->getBestCLCT(bx_clct).isValid() and clct_trig_enable) {
0265           if (infoV > 1)
0266             LogTrace("CSCMotherboard") << "Unsuccessful ALCT-CLCT match (CLCT only): bx_clct = " << bx_clct;
0267           correlateLCTs(alctProc->getBestALCT(bx_alct),
0268                         alctProc->getSecondALCT(bx_alct),
0269                         clctProc->getBestCLCT(bx_clct),
0270                         clctProc->getSecondCLCT(bx_clct),
0271                         allLCTs_(bx_clct, 0, 0),
0272                         allLCTs_(bx_clct, 0, 1),
0273                         CSCCorrelatedLCTDigi::CLCTONLY);
0274         }
0275       }
0276     }
0277   }
0278 }
0279 
0280 // Returns vector of read-out correlated LCTs, if any.  Starts with
0281 // the vector of all found LCTs and selects the ones in the read-out
0282 // time window.
0283 std::vector<CSCCorrelatedLCTDigi> CSCMotherboard::readoutLCTs() const {
0284   // temporary container for further selection
0285   std::vector<CSCCorrelatedLCTDigi> tmpV;
0286 
0287   /*
0288     LCTs in the BX window [early_tbin,...,late_tbin] are considered good for physics
0289     The central LCT BX is time bin 8.
0290     For tmb_l1a_window_size set to 7 (Run-1, Run-2), the window is [5, 6, 7, 8, 9, 10, 11]
0291     For tmb_l1a_window_size set to 5 (Run-3), the window is [6, 7, 8, 9, 10]
0292     For tmb_l1a_window_size set to 3 (Run-4?), the window is [ 7, 8, 9]
0293   */
0294   const unsigned delta_tbin = tmb_l1a_window_size / 2;
0295   int early_tbin = CSCConstants::LCT_CENTRAL_BX - delta_tbin;
0296   int late_tbin = CSCConstants::LCT_CENTRAL_BX + delta_tbin;
0297   /*
0298      Special case for an even-numbered time-window,
0299      For instance tmb_l1a_window_size set to 6: [5, 6, 7, 8, 9, 10]
0300   */
0301   if (tmb_l1a_window_size % 2 == 0)
0302     late_tbin = CSCConstants::LCT_CENTRAL_BX + delta_tbin - 1;
0303   const int max_late_tbin = CSCConstants::MAX_LCT_TBINS - 1;
0304 
0305   // debugging messages when early_tbin or late_tbin has a suspicious value
0306   if (early_tbin < 0) {
0307     edm::LogWarning("CSCMotherboard|SuspiciousParameters")
0308         << "Early time bin (early_tbin) smaller than minimum allowed, which is 0. set early_tbin to 0.";
0309     early_tbin = 0;
0310   }
0311   if (late_tbin > max_late_tbin) {
0312     edm::LogWarning("CSCMotherboard|SuspiciousParameters")
0313         << "Late time bin (late_tbin) larger than maximum allowed, which is " << max_late_tbin
0314         << ". set early_tbin to max allowed";
0315     late_tbin = CSCConstants::MAX_LCT_TBINS - 1;
0316   }
0317 
0318   // Start from the vector of all found correlated LCTs and select
0319   // those within the LCT*L1A coincidence window.
0320   int bx_readout = -1;
0321   for (const auto& lct : lctV) {
0322     // extra check on invalid LCTs
0323     if (!lct.isValid()) {
0324       continue;
0325     }
0326 
0327     const int bx = lct.getBX();
0328     // Skip LCTs found too early relative to L1Accept.
0329     if (bx < early_tbin) {
0330       if (infoV > 1)
0331         LogDebug("CSCMotherboard") << " Do not report correlated LCT on key halfstrip " << lct.getStrip()
0332                                    << " and key wire " << lct.getKeyWG() << ": found at bx " << bx
0333                                    << ", whereas the earliest allowed bx is " << early_tbin;
0334       continue;
0335     }
0336 
0337     // Skip LCTs found too late relative to L1Accept.
0338     if (bx > late_tbin) {
0339       if (infoV > 1)
0340         LogDebug("CSCMotherboard") << " Do not report correlated LCT on key halfstrip " << lct.getStrip()
0341                                    << " and key wire " << lct.getKeyWG() << ": found at bx " << bx
0342                                    << ", whereas the latest allowed bx is " << late_tbin;
0343       continue;
0344     }
0345 
0346     // Do not report LCTs found in ME1/A if mpc_block_me1a is set.
0347     if (mpc_block_me1a and isME11_ and lct.getStrip() > CSCConstants::MAX_HALF_STRIP_ME1B) {
0348       continue;
0349     }
0350 
0351     // If (readout_earliest_2) take only LCTs in the earliest bx in the read-out window:
0352     // in digi->raw step, LCTs have to be packed into the TMB header, and
0353     // currently there is room just for two.
0354     if (readout_earliest_2) {
0355       if (bx_readout == -1 || bx == bx_readout) {
0356         tmpV.push_back(lct);
0357         if (bx_readout == -1)
0358           bx_readout = bx;
0359       }
0360     }
0361     // if readout_earliest_2 == false, save all LCTs
0362     else {
0363       tmpV.push_back(lct);
0364     }
0365   }
0366 
0367   // do a final check on the LCTs in readout
0368   qualityControl_->checkMultiplicityBX(tmpV);
0369   for (const auto& lct : tmpV) {
0370     qualityControl_->checkValid(lct);
0371     /*std::cout << "\n########################################## Emu LCT ##########################################\n" << std::endl;
0372     std::cout << "Emu LCT: " << lct << std::endl;
0373     std::cout << "\n########################################## THE END ##########################################\n" << std::endl;*/
0374   }
0375 
0376   return tmpV;
0377 }
0378 
0379 std::vector<CSCShowerDigi> CSCMotherboard::readoutShower() const {
0380   unsigned minBXdiff = 2 * tmb_l1a_window_size;  //impossible value
0381   unsigned minBX = 0;
0382   std::vector<CSCShowerDigi> showerOut;
0383   for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++) {
0384     unsigned bx_diff = (bx > bx - CSCConstants::LCT_CENTRAL_BX) ? bx - CSCConstants::LCT_CENTRAL_BX
0385                                                                 : CSCConstants::LCT_CENTRAL_BX - bx;
0386     if (showers_[bx].isValid() and bx_diff < minBXdiff) {
0387       minBXdiff = bx_diff;
0388       minBX = bx;
0389     }
0390   }
0391 
0392   for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++)
0393     if (bx == minBX)
0394       showerOut.push_back(showers_[bx]);
0395   return showerOut;
0396 }
0397 
0398 void CSCMotherboard::correlateLCTs(const CSCALCTDigi& bALCT,
0399                                    const CSCALCTDigi& sALCT,
0400                                    const CSCCLCTDigi& bCLCT,
0401                                    const CSCCLCTDigi& sCLCT,
0402                                    CSCCorrelatedLCTDigi& bLCT,
0403                                    CSCCorrelatedLCTDigi& sLCT,
0404                                    int type) const {
0405   CSCALCTDigi bestALCT = bALCT;
0406   CSCALCTDigi secondALCT = sALCT;
0407   CSCCLCTDigi bestCLCT = bCLCT;
0408   CSCCLCTDigi secondCLCT = sCLCT;
0409 
0410   // extra check to make sure that both CLCTs have at least 4 layers
0411   // for regular ALCT-CLCT type LCTs. A check was already done on the
0412   // best CLCT, but not yet on the second best CLCT. The check on best
0413   // CLCT is repeated for completeness
0414   if (bestCLCT.getQuality() <= 3)
0415     bestCLCT.clear();
0416   if (secondCLCT.getQuality() <= 3)
0417     secondCLCT.clear();
0418 
0419   // if the best ALCT/CLCT is valid, but the second ALCT/CLCT is not,
0420   // the information is copied over
0421   copyValidToInValidALCT(bestALCT, secondALCT);
0422   copyValidToInValidCLCT(bestCLCT, secondCLCT);
0423 
0424   // ALCT-only LCTs
0425   const bool bestCase1(alct_trig_enable and bestALCT.isValid());
0426   // CLCT-only LCTs
0427   const bool bestCase2(clct_trig_enable and bestCLCT.isValid());
0428   /*
0429     Normal case: ALCT-CLCT matched LCTs. We require ALCT and CLCT to be valid.
0430     Optionally, we can check if the ALCT cross the CLCT. This check will always return true
0431     for a valid ALCT-CLCT pair in non-ME1/1 chambers. For ME1/1 chambers, it returns true,
0432     only when the ALCT-CLCT pair crosses and when the parameter "checkAlctCrossClct" is set to True.
0433     It is recommended to keep "checkAlctCrossClct" set to False, so that the EMTF receives
0434     all information, even if it's unphysical.
0435   */
0436   const bool bestCase3(match_trig_enable and bestALCT.isValid() and bestCLCT.isValid() and
0437                        doesALCTCrossCLCT(bestALCT, bestCLCT));
0438 
0439   // at least one of the cases must be valid
0440   if (bestCase1 or bestCase2 or bestCase3) {
0441     constructLCTs(bestALCT, bestCLCT, type, 1, bLCT);
0442   }
0443 
0444   // ALCT-only LCTs
0445   const bool secondCase1(alct_trig_enable and secondALCT.isValid());
0446   // CLCT-only LCTs
0447   const bool secondCase2(clct_trig_enable and secondCLCT.isValid());
0448   /*
0449     Normal case: ALCT-CLCT matched LCTs. We require ALCT and CLCT to be valid.
0450     Optionally, we can check if the ALCT cross the CLCT. This check will always return true
0451     for a valid ALCT-CLCT pair in non-ME1/1 chambers. For ME1/1 chambers, it returns true,
0452     only when the ALCT-CLCT pair crosses and when the parameter "checkAlctCrossClct" is set to True.
0453     It is recommended to keep "checkAlctCrossClct" set to False, so that the EMTF receives
0454     all information, even if it's unphysical.
0455   */
0456   const bool secondCase3(match_trig_enable and secondALCT.isValid() and secondCLCT.isValid() and
0457                          doesALCTCrossCLCT(secondALCT, secondCLCT));
0458 
0459   // at least one component must be different in order to consider the secondLCT
0460   if ((secondALCT != bestALCT) or (secondCLCT != bestCLCT)) {
0461     // at least one of the cases must be valid
0462     if (secondCase1 or secondCase2 or secondCase3)
0463       constructLCTs(secondALCT, secondCLCT, type, 2, sLCT);
0464   }
0465 }
0466 
0467 // copy the valid ALCT/CLCT information to the valid ALCT
0468 void CSCMotherboard::copyValidToInValidALCT(CSCALCTDigi& bestALCT, CSCALCTDigi& secondALCT) const {
0469   if (bestALCT.isValid() and !secondALCT.isValid())
0470     secondALCT = bestALCT;
0471 }
0472 
0473 // copy the valid CLCT information to the valid CLCT
0474 void CSCMotherboard::copyValidToInValidCLCT(CSCCLCTDigi& bestCLCT, CSCCLCTDigi& secondCLCT) const {
0475   if (bestCLCT.isValid() and !secondCLCT.isValid())
0476     secondCLCT = bestCLCT;
0477 }
0478 
0479 bool CSCMotherboard::doesALCTCrossCLCT(const CSCALCTDigi& alct, const CSCCLCTDigi& clct) const {
0480   if (ignoreAlctCrossClct_)
0481     return true;
0482   else
0483     return cscOverlap_->doesALCTCrossCLCT(alct, clct);
0484 }
0485 
0486 // This method calculates all the TMB words and then passes them to the
0487 // constructor of correlated LCTs.
0488 void CSCMotherboard::constructLCTs(
0489     const CSCALCTDigi& aLCT, const CSCCLCTDigi& cLCT, int type, int trknmb, CSCCorrelatedLCTDigi& thisLCT) const {
0490   thisLCT.setValid(true);
0491   thisLCT.setType(type);
0492   // make sure to shift the ALCT BX from 8 to 3 and the CLCT BX from 8 to 7!
0493   thisLCT.setALCT(getBXShiftedALCT(aLCT));
0494   thisLCT.setCLCT(getBXShiftedCLCT(cLCT));
0495   thisLCT.setPattern(encodePattern(cLCT.getPattern()));
0496   thisLCT.setMPCLink(0);
0497   thisLCT.setBX0(0);
0498   thisLCT.setSyncErr(0);
0499   thisLCT.setCSCID(theTrigChamber);
0500   thisLCT.setTrknmb(trknmb);
0501   thisLCT.setWireGroup(aLCT.getKeyWG());
0502   thisLCT.setStrip(cLCT.getKeyStrip());
0503   thisLCT.setBend(cLCT.getBend());
0504   // Bunch crossing: get it from cathode LCT if anode LCT is not there.
0505   int bx = aLCT.isValid() ? aLCT.getBX() : cLCT.getBX();
0506   thisLCT.setBX(bx);
0507   thisLCT.setQuality(qualityAssignment_->findQuality(aLCT, cLCT));
0508   if (runCCLUT_) {
0509     thisLCT.setRun3(true);
0510     // 4-bit slope value derived with the CCLUT algorithm
0511     thisLCT.setSlope(cLCT.getSlope());
0512     thisLCT.setQuartStripBit(cLCT.getQuartStripBit());
0513     thisLCT.setEighthStripBit(cLCT.getEighthStripBit());
0514     thisLCT.setRun3Pattern(cLCT.getRun3Pattern());
0515   }
0516 }
0517 
0518 // CLCT pattern number: encodes the pattern number itself
0519 unsigned int CSCMotherboard::encodePattern(const int ptn) const {
0520   const int kPatternBitWidth = 4;
0521 
0522   // In the TMB07 firmware, LCT pattern is just a 4-bit CLCT pattern.
0523   unsigned int pattern = (abs(ptn) & ((1 << kPatternBitWidth) - 1));
0524 
0525   return pattern;
0526 }
0527 
0528 void CSCMotherboard::selectLCTs() {
0529   // in each of the LCT time bins
0530   for (int bx = 0; bx < CSCConstants::MAX_LCT_TBINS; bx++) {
0531     unsigned nLCTs = 0;
0532 
0533     std::vector<CSCCorrelatedLCTDigi> tempV;
0534     // check each of the preferred combinations
0535     for (unsigned int mbx = 0; mbx < match_trig_window_size; mbx++) {
0536       // select at most 2
0537       for (int i = 0; i < CSCConstants::MAX_LCTS_PER_CSC; i++) {
0538         if (allLCTs_(bx, mbx, i).isValid() and nLCTs < 2) {
0539           tempV.push_back(allLCTs_(bx, mbx, i));
0540           ++nLCTs;
0541         }
0542       }
0543     }
0544     // store the best 2
0545     for (const auto& lct : tempV) {
0546       lctV.push_back(lct);
0547     }
0548   }
0549 
0550   // Show the pre-selected LCTs. They're not final yet. Some selection is done in the readoutLCTs function
0551   if (infoV > 0) {
0552     for (const auto& lct : lctV) {
0553       LogDebug("CSCMotherboard") << "Selected LCT" << lct;
0554     }
0555   }
0556 }
0557 
0558 void CSCMotherboard::checkConfigParameters() {
0559   // Make sure that the parameter values are within the allowed range.
0560 
0561   // Max expected values.
0562   static const unsigned int max_mpc_block_me1a = 1 << 1;
0563   static const unsigned int max_alct_trig_enable = 1 << 1;
0564   static const unsigned int max_clct_trig_enable = 1 << 1;
0565   static const unsigned int max_match_trig_enable = 1 << 1;
0566   static const unsigned int max_match_trig_window_size = 1 << 4;
0567   static const unsigned int max_tmb_l1a_window_size = 1 << 4;
0568 
0569   // Checks.
0570   CSCBaseboard::checkConfigParameters(mpc_block_me1a, max_mpc_block_me1a, def_mpc_block_me1a, "mpc_block_me1a");
0571   CSCBaseboard::checkConfigParameters(alct_trig_enable, max_alct_trig_enable, def_alct_trig_enable, "alct_trig_enable");
0572   CSCBaseboard::checkConfigParameters(clct_trig_enable, max_clct_trig_enable, def_clct_trig_enable, "clct_trig_enable");
0573   CSCBaseboard::checkConfigParameters(
0574       match_trig_enable, max_match_trig_enable, def_match_trig_enable, "match_trig_enable");
0575   CSCBaseboard::checkConfigParameters(
0576       match_trig_window_size, max_match_trig_window_size, def_match_trig_window_size, "match_trig_window_size");
0577   CSCBaseboard::checkConfigParameters(
0578       tmb_l1a_window_size, max_tmb_l1a_window_size, def_tmb_l1a_window_size, "tmb_l1a_window_size");
0579   assert(tmb_l1a_window_size / 2 <= CSCConstants::LCT_CENTRAL_BX);
0580 }
0581 
0582 void CSCMotherboard::dumpConfigParams() const {
0583   std::ostringstream strm;
0584   strm << "\n";
0585   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
0586   strm << "+                   TMB configuration parameters:                  +\n";
0587   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
0588   strm << " mpc_block_me1a [block/not block triggers which come from ME1/A] = " << mpc_block_me1a << "\n";
0589   strm << " alct_trig_enable [allow ALCT-only triggers] = " << alct_trig_enable << "\n";
0590   strm << " clct_trig_enable [allow CLCT-only triggers] = " << clct_trig_enable << "\n";
0591   strm << " match_trig_enable [allow matched ALCT-CLCT triggers] = " << match_trig_enable << "\n";
0592   strm << " match_trig_window_size [ALCT-CLCT match window width, in 25 ns] = " << match_trig_window_size << "\n";
0593   strm << " tmb_l1a_window_size [L1Accept window width, in 25 ns bins] = " << tmb_l1a_window_size << "\n";
0594   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
0595   LogDebug("CSCMotherboard") << strm.str();
0596 }
0597 
0598 CSCALCTDigi CSCMotherboard::getBXShiftedALCT(const CSCALCTDigi& aLCT) const {
0599   CSCALCTDigi aLCT_shifted = aLCT;
0600   aLCT_shifted.setBX(aLCT_shifted.getBX() - (CSCConstants::LCT_CENTRAL_BX - CSCConstants::ALCT_CENTRAL_BX));
0601   return aLCT_shifted;
0602 }
0603 
0604 CSCCLCTDigi CSCMotherboard::getBXShiftedCLCT(const CSCCLCTDigi& cLCT) const {
0605   CSCCLCTDigi cLCT_shifted = cLCT;
0606   cLCT_shifted.setBX(cLCT_shifted.getBX() - CSCConstants::ALCT_CLCT_OFFSET);
0607   return cLCT_shifted;
0608 }
0609 
0610 void CSCMotherboard::matchShowers(CSCShowerDigi* anode_showers, CSCShowerDigi* cathode_showers, bool andlogic) {
0611   CSCShowerDigi ashower, cshower;
0612   bool used_cshower_mask[CSCConstants::MAX_CLCT_TBINS] = {false};
0613   for (unsigned bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
0614     ashower = anode_showers[bx];
0615     cshower = CSCShowerDigi();  //use empty shower digi to initialize cshower
0616     if (ashower.isValid()) {
0617       for (unsigned mbx = 0; mbx < match_trig_window_size; mbx++) {
0618         int cbx = bx + preferred_bx_match_[mbx] - CSCConstants::ALCT_CLCT_OFFSET;
0619         //check bx range [0, CSCConstants::MAX_LCT_TBINS]
0620         if (cbx < 0 || cbx >= CSCConstants::MAX_CLCT_TBINS)
0621           continue;
0622         if (cathode_showers[cbx].isValid() and not used_cshower_mask[cbx]) {
0623           cshower = cathode_showers[cbx];
0624           used_cshower_mask[cbx] = true;
0625           break;
0626         }
0627       }
0628     } else
0629       cshower = cathode_showers[bx];  //if anode shower is not valid, use the cshower from this bx
0630 
0631     //matched HMT, with and/or logic
0632     unsigned matchHMT = 0;
0633     if (andlogic) {
0634       if (ashower.isTightInTime() and cshower.isTightInTime())
0635         matchHMT = 3;
0636       else if (ashower.isNominalInTime() and cshower.isNominalInTime())
0637         matchHMT = 2;
0638       else if (ashower.isLooseInTime() and cshower.isLooseInTime())
0639         matchHMT = 1;
0640     } else {
0641       if (ashower.isTightInTime() or cshower.isTightInTime())
0642         matchHMT = 3;
0643       else if (ashower.isNominalInTime() or cshower.isNominalInTime())
0644         matchHMT = 2;
0645       else if (ashower.isLooseInTime() or cshower.isLooseInTime())
0646         matchHMT = 1;
0647     }
0648     //LCTShower with showerType = 3
0649     showers_[bx] = CSCShowerDigi(matchHMT & 3,
0650                                  false,
0651                                  ashower.getCSCID(),
0652                                  bx,
0653                                  CSCShowerDigi::ShowerType::kLCTShower,
0654                                  ashower.getWireNHits(),
0655                                  cshower.getComparatorNHits());
0656   }
0657 }
0658 
0659 void CSCMotherboard::encodeHighMultiplicityBits() {
0660   // get the high multiplicity
0661   // for anode this reflects what is already in the anode CSCShowerDigi object
0662   CSCShowerDigi cathode_showers[CSCConstants::MAX_CLCT_TBINS];
0663   CSCShowerDigi anode_showers[CSCConstants::MAX_ALCT_TBINS];
0664   auto cshowers_v = clctProc->getAllShower();
0665   auto ashowers_v = alctProc->getAllShower();
0666 
0667   std::copy(cshowers_v.begin(), cshowers_v.end(), cathode_showers);
0668   std::copy(ashowers_v.begin(), ashowers_v.end(), anode_showers);
0669 
0670   // set the value according to source
0671   switch (thisShowerSource_) {
0672     case 0:
0673       std::copy(std::begin(cathode_showers), std::end(cathode_showers), std::begin(showers_));
0674       break;
0675     case 1:
0676       std::copy(std::begin(anode_showers), std::end(anode_showers), std::begin(showers_));
0677       break;
0678     case 2:
0679       matchShowers(anode_showers, cathode_showers, false);
0680       break;
0681     case 3:
0682       matchShowers(anode_showers, cathode_showers, true);
0683       break;
0684     default:
0685       std::copy(std::begin(anode_showers), std::end(anode_showers), std::begin(showers_));
0686       break;
0687   };
0688 }