Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:19:36

0001 #include "L1Trigger/CSCTriggerPrimitives/interface/CSCCathodeLCTProcessor.h"
0002 
0003 #include <iomanip>
0004 #include <memory>
0005 
0006 // Default values of configuration parameters.
0007 const unsigned int CSCCathodeLCTProcessor::def_fifo_tbins = 12;
0008 const unsigned int CSCCathodeLCTProcessor::def_fifo_pretrig = 7;
0009 const unsigned int CSCCathodeLCTProcessor::def_hit_persist = 6;
0010 const unsigned int CSCCathodeLCTProcessor::def_drift_delay = 2;
0011 const unsigned int CSCCathodeLCTProcessor::def_nplanes_hit_pretrig = 2;
0012 const unsigned int CSCCathodeLCTProcessor::def_nplanes_hit_pattern = 4;
0013 const unsigned int CSCCathodeLCTProcessor::def_pid_thresh_pretrig = 2;
0014 const unsigned int CSCCathodeLCTProcessor::def_min_separation = 10;
0015 const unsigned int CSCCathodeLCTProcessor::def_tmb_l1a_window_size = 7;
0016 
0017 //----------------
0018 // Constructors --
0019 //----------------
0020 
0021 CSCCathodeLCTProcessor::CSCCathodeLCTProcessor(unsigned endcap,
0022                                                unsigned station,
0023                                                unsigned sector,
0024                                                unsigned subsector,
0025                                                unsigned chamber,
0026                                                CSCBaseboard::Parameters& conf)
0027     : CSCBaseboard(endcap, station, sector, subsector, chamber, conf) {
0028   static std::atomic<bool> config_dumped{false};
0029 
0030   // CLCT configuration parameters.
0031   fifo_tbins = conf.clctParams().getParameter<unsigned int>("clctFifoTbins");
0032   hit_persist = conf.clctParams().getParameter<unsigned int>("clctHitPersist");
0033   drift_delay = conf.clctParams().getParameter<unsigned int>("clctDriftDelay");
0034   nplanes_hit_pretrig = conf.clctParams().getParameter<unsigned int>("clctNplanesHitPretrig");
0035   nplanes_hit_pattern = conf.clctParams().getParameter<unsigned int>("clctNplanesHitPattern");
0036 
0037   // Not used yet.
0038   fifo_pretrig = conf.clctParams().getParameter<unsigned int>("clctFifoPretrig");
0039 
0040   pid_thresh_pretrig = conf.clctParams().getParameter<unsigned int>("clctPidThreshPretrig");
0041   min_separation = conf.clctParams().getParameter<unsigned int>("clctMinSeparation");
0042 
0043   start_bx_shift = conf.clctParams().getParameter<int>("clctStartBxShift");
0044 
0045   localShowerZone = conf.clctParams().getParameter<int>("clctLocalShowerZone");
0046 
0047   localShowerThresh = conf.clctParams().getParameter<int>("clctLocalShowerThresh");
0048 
0049   // Motherboard parameters: common for all configurations.
0050   tmb_l1a_window_size =  // Common to CLCT and TMB
0051       conf.tmbParams().getParameter<unsigned int>("tmbL1aWindowSize");
0052 
0053   /*
0054     In Summer 2021 the CLCT readout function was updated so that the
0055     window is based on a number of time bins around the central CLCT
0056     time BX7. In the past the window was based on early_tbins and late_tbins.
0057     The parameter is kept, but is not used.
0058   */
0059   early_tbins = conf.tmbParams().getParameter<int>("tmbEarlyTbins");
0060   if (early_tbins < 0)
0061     early_tbins = fifo_pretrig - CSCConstants::CLCT_EMUL_TIME_OFFSET;
0062 
0063   // wether to readout only the earliest two LCTs in readout window
0064   readout_earliest_2 = conf.tmbParams().getParameter<bool>("tmbReadoutEarliest2");
0065 
0066   // Verbosity level, set to 0 (no print) by default.
0067   infoV = conf.clctParams().getParameter<int>("verbosity");
0068 
0069   // Do not exclude pattern 0 and 1 when the Run-3 patterns are enabled!!
0070   // Valid Run-3 patterns are 0,1,2,3,4
0071   if (runCCLUT_) {
0072     pid_thresh_pretrig = 0;
0073   }
0074 
0075   // Check and print configuration parameters.
0076   checkConfigParameters();
0077   if ((infoV > 0) && !config_dumped) {
0078     dumpConfigParams();
0079     config_dumped = true;
0080   }
0081 
0082   numStrips_ = 0;  // Will be set later.
0083   // Provisional, but should be OK for all stations except ME1.
0084   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0085     if ((i_layer + 1) % 2 == 0)
0086       stagger[i_layer] = 0;
0087     else
0088       stagger[i_layer] = 1;
0089   }
0090 
0091   for (int i = 0; i < CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER; ++i) {
0092     ispretrig_[i] = false;
0093   }
0094 
0095   // which patterns should we use?
0096   if (runCCLUT_) {
0097     clct_pattern_ = CSCPatternBank::clct_pattern_run3_;
0098     // comparator code lookup table algorithm for Phase-2
0099     cclut_ = std::make_unique<ComparatorCodeLUT>(conf.conf());
0100   } else {
0101     clct_pattern_ = CSCPatternBank::clct_pattern_legacy_;
0102   }
0103 
0104   const auto& shower = conf.showerParams().getParameterSet("cathodeShower");
0105   thresholds_ = shower.getParameter<std::vector<unsigned>>("showerThresholds");
0106   showerNumTBins_ = shower.getParameter<unsigned>("showerNumTBins");
0107   minLayersCentralTBin_ = shower.getParameter<unsigned>("minLayersCentralTBin");
0108   peakCheck_ = shower.getParameter<bool>("peakCheck");
0109   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - tmb_l1a_window_size / 2;
0110   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + tmb_l1a_window_size / 2;
0111   assert(tmb_l1a_window_size / 2 <= CSCConstants::LCT_CENTRAL_BX);
0112 
0113   thePreTriggerDigis.clear();
0114 
0115   // quality control of stubs
0116   qualityControl_ = std::make_unique<LCTQualityControl>(endcap, station, sector, subsector, chamber, conf);
0117 }
0118 
0119 void CSCCathodeLCTProcessor::setDefaultConfigParameters() {
0120   // Set default values for configuration parameters.
0121   fifo_tbins = def_fifo_tbins;
0122   fifo_pretrig = def_fifo_pretrig;
0123   hit_persist = def_hit_persist;
0124   drift_delay = def_drift_delay;
0125   nplanes_hit_pretrig = def_nplanes_hit_pretrig;
0126   nplanes_hit_pattern = def_nplanes_hit_pattern;
0127   pid_thresh_pretrig = def_pid_thresh_pretrig;
0128   min_separation = def_min_separation;
0129   tmb_l1a_window_size = def_tmb_l1a_window_size;
0130   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - tmb_l1a_window_size / 2;
0131   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + tmb_l1a_window_size / 2;
0132 }
0133 
0134 // Set configuration parameters obtained via EventSetup mechanism.
0135 void CSCCathodeLCTProcessor::setConfigParameters(const CSCDBL1TPParameters* conf) {
0136   static std::atomic<bool> config_dumped{false};
0137 
0138   fifo_tbins = conf->clctFifoTbins();
0139   fifo_pretrig = conf->clctFifoPretrig();
0140   hit_persist = conf->clctHitPersist();
0141   drift_delay = conf->clctDriftDelay();
0142   nplanes_hit_pretrig = conf->clctNplanesHitPretrig();
0143   nplanes_hit_pattern = conf->clctNplanesHitPattern();
0144   pid_thresh_pretrig = conf->clctPidThreshPretrig();
0145   min_separation = conf->clctMinSeparation();
0146 
0147   // Check and print configuration parameters.
0148   checkConfigParameters();
0149   if (!config_dumped) {
0150     dumpConfigParams();
0151     config_dumped = true;
0152   }
0153   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - tmb_l1a_window_size / 2;
0154   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + tmb_l1a_window_size / 2;
0155 }
0156 
0157 void CSCCathodeLCTProcessor::checkConfigParameters() {
0158   // Make sure that the parameter values are within the allowed range.
0159 
0160   // Max expected values.
0161   static const unsigned int max_fifo_tbins = 1 << 5;
0162   static const unsigned int max_fifo_pretrig = 1 << 5;
0163   static const unsigned int max_hit_persist = 1 << 4;
0164   static const unsigned int max_drift_delay = 1 << 2;
0165   static const unsigned int max_nplanes_hit_pretrig = 1 << 3;
0166   static const unsigned int max_nplanes_hit_pattern = 1 << 3;
0167   static const unsigned int max_pid_thresh_pretrig = 1 << 4;
0168   static const unsigned int max_min_separation = CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER;
0169   static const unsigned int max_tmb_l1a_window_size = 1 << 4;
0170 
0171   // Checks.
0172   CSCBaseboard::checkConfigParameters(fifo_tbins, max_fifo_tbins, def_fifo_tbins, "fifo_tbins");
0173   CSCBaseboard::checkConfigParameters(fifo_pretrig, max_fifo_pretrig, def_fifo_pretrig, "fifo_pretrig");
0174   CSCBaseboard::checkConfigParameters(hit_persist, max_hit_persist, def_hit_persist, "hit_persist");
0175   CSCBaseboard::checkConfigParameters(drift_delay, max_drift_delay, def_drift_delay, "drift_delay");
0176   CSCBaseboard::checkConfigParameters(
0177       nplanes_hit_pretrig, max_nplanes_hit_pretrig, def_nplanes_hit_pretrig, "nplanes_hit_pretrig");
0178   CSCBaseboard::checkConfigParameters(
0179       nplanes_hit_pattern, max_nplanes_hit_pattern, def_nplanes_hit_pattern, "nplanes_hit_pattern");
0180   CSCBaseboard::checkConfigParameters(
0181       pid_thresh_pretrig, max_pid_thresh_pretrig, def_pid_thresh_pretrig, "pid_thresh_pretrig");
0182   CSCBaseboard::checkConfigParameters(min_separation, max_min_separation, def_min_separation, "min_separation");
0183   CSCBaseboard::checkConfigParameters(
0184       tmb_l1a_window_size, max_tmb_l1a_window_size, def_tmb_l1a_window_size, "tmb_l1a_window_size");
0185   assert(tmb_l1a_window_size / 2 <= CSCConstants::LCT_CENTRAL_BX);
0186 }
0187 
0188 void CSCCathodeLCTProcessor::clear() {
0189   thePreTriggerDigis.clear();
0190   thePreTriggerBXs.clear();
0191   for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
0192     bestCLCT[bx].clear();
0193     secondCLCT[bx].clear();
0194     cathode_showers_[bx].clear();
0195     localShowerFlag[bx] = false;  //init with no shower around CLCT
0196   }
0197 }
0198 
0199 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::run(const CSCComparatorDigiCollection* compdc,
0200                                                      const CSCChamber* cscChamber,
0201                                                      const CSCL1TPLookupTableCCLUT* lookupTable) {
0202   // This is the version of the run() function that is called when running
0203   // over the entire detector.  It gets the comparator & timing info from the
0204   // comparator digis and then passes them on to another run() function.
0205 
0206   static std::atomic<bool> config_dumped{false};
0207   if ((infoV > 0) && !config_dumped) {
0208     dumpConfigParams();
0209     config_dumped = true;
0210   }
0211 
0212   // Get the number of strips and stagger of layers for the given chamber.
0213   // Do it only once per chamber.
0214   if (numStrips_ <= 0 or numStrips_ > CSCConstants::MAX_NUM_STRIPS_RUN2) {
0215     if (cscChamber) {
0216       numStrips_ = cscChamber->layer(1)->geometry()->numberOfStrips();
0217 
0218       // ME1/a is known to the readout hardware as strips 65-80 of ME1/1.
0219       // Still need to decide whether we do any special adjustments to
0220       // reconstruct LCTs in this region (3:1 ganged strips); for now, we
0221       // simply allow for hits in ME1/a and apply standard reconstruction
0222       // to them.
0223       // For Phase2 ME1/1 is set to have 4 CFEBs in ME1/b and 3 CFEBs in ME1/a
0224       if (isME11_) {
0225         if (theRing == 4) {
0226           edm::LogError("CSCCathodeLCTProcessor|SetupError")
0227               << "+++ Invalid ring number for this processor " << theRing << " was set in the config."
0228               << " +++\n"
0229               << "+++ CSC geometry looks garbled; no emulation possible +++\n";
0230         }
0231         if (!disableME1a_ && theRing == 1 && !gangedME1a_)
0232           numStrips_ = CSCConstants::MAX_NUM_STRIPS_RUN2;
0233         if (!disableME1a_ && theRing == 1 && gangedME1a_)
0234           numStrips_ = CSCConstants::MAX_NUM_STRIPS_RUN1;
0235         if (disableME1a_ && theRing == 1)
0236           numStrips_ = CSCConstants::NUM_STRIPS_ME1B;
0237       }
0238 
0239       numHalfStrips_ = 2 * numStrips_ + 1;
0240       numCFEBs_ = numStrips_ / CSCConstants::NUM_STRIPS_PER_CFEB;
0241 
0242       if (numStrips_ > CSCConstants::MAX_NUM_STRIPS_RUN2) {
0243         edm::LogError("CSCCathodeLCTProcessor|SetupError")
0244             << "+++ Number of strips, " << numStrips_ << " found in " << theCSCName_ << " (sector " << theSector
0245             << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
0246             << " exceeds max expected, " << CSCConstants::MAX_NUM_STRIPS_RUN2 << " +++\n"
0247             << "+++ CSC geometry looks garbled; no emulation possible +++\n";
0248         numStrips_ = -1;
0249         numHalfStrips_ = -1;
0250         numCFEBs_ = -1;
0251       }
0252       // The strips for a given layer may be offset from the adjacent layers.
0253       // This was done in order to improve resolution.  We need to find the
0254       // 'staggering' for each layer and make necessary conversions in our
0255       // arrays.  -JM
0256       // In the TMB-07 firmware, half-strips in odd layers (layers are
0257       // counted as ly0-ly5) are shifted by -1 half-strip, whereas in
0258       // the previous firmware versions half-strips in even layers
0259       // were shifted by +1 half-strip.  This difference is due to a
0260       // change from ly3 to ly2 in the choice of the key layer, and
0261       // the intention to keep half-strips in the key layer unchanged.
0262       // In the emulator, we use the old way for both cases, to avoid
0263       // negative half-strip numbers.  This will necessitate a
0264       // subtraction of 1 half-strip for TMB-07 later on. -SV.
0265       for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0266         stagger[i_layer] = (cscChamber->layer(i_layer + 1)->geometry()->stagger() + 1) / 2;
0267       }
0268     } else {
0269       edm::LogError("CSCCathodeLCTProcessor|ConfigError")
0270           << " " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
0271           << theTrigChamber << ")"
0272           << " is not defined in current geometry! +++\n"
0273           << "+++ CSC geometry looks garbled; no emulation possible +++\n";
0274       numStrips_ = -1;
0275       numHalfStrips_ = -1;
0276       numCFEBs_ = -1;
0277     }
0278   }
0279 
0280   if (numStrips_ <= 0 or 2 * (unsigned)numStrips_ > qualityControl_->get_csc_max_halfstrip(theStation, theRing)) {
0281     edm::LogError("CSCCathodeLCTProcessor|ConfigError")
0282         << " " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
0283         << theTrigChamber << "):"
0284         << " numStrips_ = " << numStrips_ << "; CLCT emulation skipped! +++";
0285     std::vector<CSCCLCTDigi> emptyV;
0286     return emptyV;
0287   }
0288 
0289   // Get comparator digis in this chamber.
0290   bool hasDigis = getDigis(compdc);
0291 
0292   if (hasDigis) {
0293     // Get halfstrip times from comparator digis.
0294     std::vector<int> halfStripTimes[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER];
0295     readComparatorDigis(halfStripTimes);
0296 
0297     // Pass arrays of halfstrips on to another run() doing the
0298     // LCT search.
0299     // If the number of layers containing digis is smaller than that
0300     // required to trigger, quit right away.  (If LCT-based digi suppression
0301     // is implemented one day, this condition will have to be changed
0302     // to the number of planes required to pre-trigger.)
0303     unsigned int layersHit = 0;
0304     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0305       for (int i_hstrip = 0; i_hstrip < CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER; i_hstrip++) {
0306         if (!halfStripTimes[i_layer][i_hstrip].empty()) {
0307           layersHit++;
0308           break;
0309         }
0310       }
0311     }
0312     // Run the algorithm only if the probability for the pre-trigger
0313     // to fire is not null.  (Pre-trigger decisions are used for the
0314     // strip read-out conditions in DigiToRaw.)
0315     if (layersHit >= nplanes_hit_pretrig)
0316       run(halfStripTimes, lookupTable);
0317 
0318     // Get the high multiplicity bits in this chamber
0319     encodeHighMultiplicityBits();
0320   }
0321 
0322   // Return vector of CLCTs.
0323   std::vector<CSCCLCTDigi> tmpV = getCLCTs();
0324 
0325   // shift the BX from 7 to 8
0326   // the unpacked real data CLCTs have central BX at bin 7
0327   // however in simulation the central BX  is bin 8
0328   // to make a proper comparison with ALCTs we need
0329   // CLCT and ALCT to have the central BX in the same bin
0330   // this shift does not affect the readout of the CLCTs
0331   // emulated CLCTs put in the event should be centered at bin 7 (as in data)
0332   for (auto& p : tmpV) {
0333     p.setBX(p.getBX() + CSCConstants::ALCT_CLCT_OFFSET);
0334   }
0335 
0336   return tmpV;
0337 }
0338 
0339 void CSCCathodeLCTProcessor::run(
0340     const std::vector<int> halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER],
0341     const CSCL1TPLookupTableCCLUT* lookupTable) {
0342   // This version of the run() function can either be called in a standalone
0343   // test, being passed the halfstrip times, or called by the
0344   // run() function above.  It uses the findLCTs() method to find vectors
0345   // of LCT candidates. These candidates are already sorted and the best two per bx
0346   // are returned.
0347 
0348   // initialize the pulse array.
0349   // add 1 for possible stagger
0350   pulse_.initialize(numHalfStrips_ + 1);
0351 
0352   std::vector<CSCCLCTDigi> CLCTlist = findLCTs(halfstrip, lookupTable);
0353 
0354   for (const auto& p : CLCTlist) {
0355     const int bx = p.getBX();
0356     if (bx >= CSCConstants::MAX_CLCT_TBINS) {
0357       if (infoV > 0)
0358         edm::LogWarning("L1CSCTPEmulatorOutOfTimeCLCT")
0359             << "+++ Bx of CLCT candidate, " << bx << ", exceeds max allowed, " << CSCConstants::MAX_CLCT_TBINS - 1
0360             << "; skipping it... +++\n";
0361       continue;
0362     }
0363 
0364     if (!bestCLCT[bx].isValid()) {
0365       bestCLCT[bx] = p;
0366     } else if (!secondCLCT[bx].isValid()) {
0367       secondCLCT[bx] = p;
0368     }
0369   }
0370 
0371   for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
0372     if (bestCLCT[bx].isValid()) {
0373       bestCLCT[bx].setTrknmb(1);
0374 
0375       // check if the LCT is valid
0376       qualityControl_->checkValid(bestCLCT[bx]);
0377 
0378       if (infoV > 0)
0379         LogDebug("CSCCathodeLCTProcessor")
0380             << bestCLCT[bx] << " found in " << CSCDetId::chamberName(theEndcap, theStation, theRing, theChamber)
0381             << " (sector " << theSector << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
0382             << "\n";
0383     }
0384     if (secondCLCT[bx].isValid()) {
0385       secondCLCT[bx].setTrknmb(2);
0386 
0387       // check if the LCT is valid
0388       qualityControl_->checkValid(secondCLCT[bx]);
0389 
0390       if (infoV > 0)
0391         LogDebug("CSCCathodeLCTProcessor")
0392             << secondCLCT[bx] << " found in " << CSCDetId::chamberName(theEndcap, theStation, theRing, theChamber)
0393             << " (sector " << theSector << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
0394             << "\n";
0395     }
0396   }
0397   checkLocalShower(localShowerZone, halfstrip);
0398   // Now that we have our best CLCTs, they get correlated with the best
0399   // ALCTs and then get sent to the MotherBoard.  -JM
0400 }
0401 
0402 void CSCCathodeLCTProcessor::checkLocalShower(
0403     int zone,
0404     const std::vector<int> halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]) {
0405   // Fire half-strip one-shots for hit_persist bx's (4 bx's by default).
0406   //check local shower after pulse extension
0407   pulseExtension(halfstrip);
0408 
0409   for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
0410     if (not bestCLCT[bx].isValid())
0411       continue;
0412 
0413     //only check the region around best CLCT
0414     int keyHS = bestCLCT[bx].getKeyStrip();
0415     int minHS = (keyHS - zone) >= stagger[CSCConstants::KEY_CLCT_LAYER - 1] ? keyHS - zone
0416                                                                             : stagger[CSCConstants::KEY_CLCT_LAYER - 1];
0417     int maxHS = (keyHS + zone) >= numHalfStrips_ ? numHalfStrips_ : keyHS + zone;
0418     int totalHits = 0;
0419     for (int hstrip = minHS; hstrip < maxHS; hstrip++) {
0420       for (int this_layer = 0; this_layer < CSCConstants::NUM_LAYERS; this_layer++)
0421         if (pulse_.isOneShotHighAtBX(this_layer, hstrip, bx + drift_delay))
0422           totalHits++;
0423     }
0424 
0425     localShowerFlag[bx] = totalHits >= localShowerThresh;
0426     if (infoV > 1)
0427       LogDebug("CSCCathodeLCTProcessor") << " bx " << bx << " bestCLCT key HS " << keyHS
0428                                          << " localshower zone: " << minHS << ", " << maxHS << " totalHits "
0429                                          << totalHits
0430                                          << (localShowerFlag[bx] ? " Validlocalshower " : " NolocalShower ");
0431   }
0432 }
0433 
0434 bool CSCCathodeLCTProcessor::getDigis(const CSCComparatorDigiCollection* compdc) {
0435   bool hasDigis = false;
0436 
0437   // Loop over layers and save comparator digis on each one into digiV[layer].
0438   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0439     digiV[i_layer].clear();
0440 
0441     CSCDetId detid(theEndcap, theStation, theRing, theChamber, i_layer + 1);
0442     getDigis(compdc, detid);
0443 
0444     if (isME11_ && !disableME1a_) {
0445       CSCDetId detid_me1a(theEndcap, theStation, 4, theChamber, i_layer + 1);
0446       getDigis(compdc, detid_me1a);
0447     }
0448 
0449     if (!digiV[i_layer].empty()) {
0450       hasDigis = true;
0451       if (infoV > 1) {
0452         LogTrace("CSCCathodeLCTProcessor") << "found " << digiV[i_layer].size() << " comparator digi(s) in layer "
0453                                            << i_layer << " of " << detid.chamberName() << " (trig. sector " << theSector
0454                                            << " subsector " << theSubsector << " id " << theTrigChamber << ")";
0455       }
0456     }
0457   }
0458 
0459   return hasDigis;
0460 }
0461 
0462 void CSCCathodeLCTProcessor::getDigis(const CSCComparatorDigiCollection* compdc, const CSCDetId& id) {
0463   const bool me1a = (id.station() == 1) && (id.ring() == 4);
0464   const CSCComparatorDigiCollection::Range rcompd = compdc->get(id);
0465   for (CSCComparatorDigiCollection::const_iterator digiIt = rcompd.first; digiIt != rcompd.second; ++digiIt) {
0466     const unsigned int origStrip = digiIt->getStrip();
0467     const unsigned int maxStripsME1a =
0468         gangedME1a_ ? CSCConstants::NUM_STRIPS_ME1A_GANGED : CSCConstants::NUM_STRIPS_ME1A_UNGANGED;
0469     // this special case can only be reached in MC
0470     // in real data, the comparator digis have always ring==1
0471     if (me1a && origStrip <= maxStripsME1a && !disableME1a_) {
0472       // Move ME1/A comparators from CFEB=0 to CFEB=4 if this has not
0473       // been done already.
0474       CSCComparatorDigi digi_corr(
0475           origStrip + CSCConstants::NUM_STRIPS_ME1B, digiIt->getComparator(), digiIt->getTimeBinWord());
0476       digiV[id.layer() - 1].push_back(digi_corr);
0477     } else {
0478       digiV[id.layer() - 1].push_back(*digiIt);
0479     }
0480   }
0481 }
0482 
0483 void CSCCathodeLCTProcessor::readComparatorDigis(
0484     std::vector<int> halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]) {
0485   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0486     int i_digi = 0;  // digi counter, for dumps.
0487     for (std::vector<CSCComparatorDigi>::iterator pld = digiV[i_layer].begin(); pld != digiV[i_layer].end();
0488          pld++, i_digi++) {
0489       // Dump raw digi info.
0490       if (infoV > 1) {
0491         std::ostringstream strstrm;
0492         strstrm << "Comparator digi: comparator = " << pld->getComparator() << " strip #" << pld->getStrip()
0493                 << " time bins on:";
0494         std::vector<int> bx_times = pld->getTimeBinsOn();
0495         for (unsigned int tbin = 0; tbin < bx_times.size(); tbin++)
0496           strstrm << " " << bx_times[tbin];
0497         LogTrace("CSCCathodeLCTProcessor") << strstrm.str();
0498       }
0499 
0500       // Get comparator: 0/1 for left/right halfstrip for each comparator
0501       // that fired.
0502       int thisComparator = pld->getComparator();
0503       if (thisComparator != 0 && thisComparator != 1) {
0504         if (infoV >= 0)
0505           edm::LogWarning("L1CSCTPEmulatorWrongInput")
0506               << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
0507               << " Found comparator digi with wrong comparator value = " << thisComparator << "; skipping it... +++\n";
0508         continue;
0509       }
0510 
0511       // Get strip number.
0512       int thisStrip = pld->getStrip() - 1;  // count from 0
0513       if (thisStrip < 0 || thisStrip >= numStrips_) {
0514         if (infoV >= 0)
0515           edm::LogWarning("L1CSCTPEmulatorWrongInput")
0516               << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
0517               << " Found comparator digi with wrong strip number = " << thisStrip << " (max strips = " << numStrips_
0518               << "); skipping it... +++\n";
0519         continue;
0520       }
0521       // 2*strip: convert strip to 1/2 strip
0522       // comp   : comparator output
0523       // stagger: stagger for this layer
0524       int thisHalfstrip = 2 * thisStrip + thisComparator + stagger[i_layer];
0525       if (thisHalfstrip >= numHalfStrips_) {
0526         if (infoV >= 0)
0527           edm::LogWarning("L1CSCTPEmulatorWrongInput")
0528               << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
0529               << " Found wrong halfstrip number = " << thisHalfstrip << "; skipping this digi... +++\n";
0530         continue;
0531       }
0532 
0533       // Get bx times on this digi and check that they are within the bounds.
0534       std::vector<int> bx_times = pld->getTimeBinsOn();
0535       for (unsigned int i = 0; i < bx_times.size(); i++) {
0536         // Total number of time bins in DAQ readout is given by fifo_tbins,
0537         // which thus determines the maximum length of time interval.
0538         //
0539         // In data, only the CLCT in the time bin that was matched with L1A are read out
0540         // while comparator digi is read out by 12 time bin, which includes 12 time bin info
0541         // in other word, CLCTs emulated from comparator digis usually showed the OTMB behavior in 12 time bin
0542         // while CLCT from data only showed 1 time bin OTMB behavior
0543         // the CLCT emulated from comparator digis usually is centering at time bin 7 (BX7) and
0544         // it is definitly safe to ignore any CLCTs in bx 0 or 1 and those CLCTs will never impacts on any triggers
0545         if (bx_times[i] > 1 && bx_times[i] < static_cast<int>(fifo_tbins)) {
0546           if (i == 0 || (i > 0 && bx_times[i] - bx_times[i - 1] >= static_cast<int>(hit_persist))) {
0547             // A later hit on the same strip is ignored during the
0548             // number of clocks defined by the "hit_persist" parameter
0549             // (i.e., 6 bx's by default).
0550             if (infoV > 1)
0551               LogTrace("CSCCathodeLCTProcessor")
0552                   << "Comp digi: layer " << i_layer + 1 << " digi #" << i_digi + 1 << " strip " << thisStrip
0553                   << " halfstrip " << thisHalfstrip << " time " << bx_times[i] << " comparator " << thisComparator
0554                   << " stagger " << stagger[i_layer];
0555             halfstrip[i_layer][thisHalfstrip].push_back(bx_times[i]);
0556           } else if (i > 0) {
0557             if (infoV > 1)
0558               LogTrace("CSCCathodeLCTProcessor")
0559                   << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
0560                   << " Skipping comparator digi: strip = " << thisStrip << ", layer = " << i_layer + 1
0561                   << ", bx = " << bx_times[i] << ", bx of previous hit = " << bx_times[i - 1];
0562           }
0563         } else {
0564           if (infoV > 1)
0565             LogTrace("CSCCathodeLCTProcessor") << "+++ station " << theStation << " ring " << theRing << " chamber "
0566                                                << theChamber << "+++ Skipping comparator digi: strip = " << thisStrip
0567                                                << ", layer = " << i_layer + 1 << ", bx = " << bx_times[i] << " +++";
0568         }
0569       }
0570     }
0571   }
0572 }
0573 
0574 // TMB-07 version.
0575 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::findLCTs(
0576     const std::vector<int> halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER],
0577     const CSCL1TPLookupTableCCLUT* lookupTable) {
0578   std::vector<CSCCLCTDigi> lctList;
0579 
0580   if (infoV > 1)
0581     dumpDigis(halfstrip);
0582 
0583   // Fire half-strip one-shots for hit_persist bx's (4 bx's by default).
0584   pulseExtension(halfstrip);
0585 
0586   unsigned int start_bx = start_bx_shift;
0587   // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
0588   // not have a full set of hits to start pattern search anyway.
0589   unsigned int stop_bx = fifo_tbins - drift_delay;
0590   // Allow for more than one pass over the hits in the time window.
0591   while (start_bx < stop_bx) {
0592     // temp CLCT objects
0593     CSCCLCTDigi tempBestCLCT;
0594     CSCCLCTDigi tempSecondCLCT;
0595 
0596     // All half-strip pattern envelopes are evaluated simultaneously, on every
0597     // clock cycle.
0598     int first_bx = 999;
0599     bool pre_trig = preTrigger(start_bx, first_bx);
0600 
0601     // If any of half-strip envelopes has enough layers hit in it, TMB
0602     // will pre-trigger.
0603     if (pre_trig) {
0604       thePreTriggerBXs.push_back(first_bx);
0605       if (infoV > 1)
0606         LogTrace("CSCCathodeLCTProcessor") << "..... pretrigger at bx = " << first_bx << "; waiting drift delay .....";
0607 
0608       // TMB latches LCTs drift_delay clocks after pretrigger.
0609       // in the configuration the drift_delay is set to 2bx by default
0610       // this is the time that is required for the electrons to drift to the
0611       // cathode strips. 15ns drift time --> 45 ns is 3 sigma for the delay
0612       // this corresponds to 2bx
0613       int latch_bx = first_bx + drift_delay;
0614 
0615       // define a new pattern map
0616       // for each key half strip, and for each pattern, store the 2D collection of fired comparator digis
0617       std::map<int, std::map<int, CSCCLCTDigi::ComparatorContainer>> hits_in_patterns;
0618       hits_in_patterns.clear();
0619 
0620       // We check if there is at least one key half strip for which at least
0621       // one pattern id has at least the minimum number of hits
0622       bool hits_in_time = patternFinding(latch_bx, hits_in_patterns);
0623       if (infoV > 1) {
0624         if (hits_in_time) {
0625           for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
0626             if (nhits[hstrip] > 0) {
0627               LogTrace("CSCCathodeLCTProcessor")
0628                   << " bx = " << std::setw(2) << latch_bx << " --->"
0629                   << " halfstrip = " << std::setw(3) << hstrip << " best pid = " << std::setw(2) << best_pid[hstrip]
0630                   << " nhits = " << nhits[hstrip];
0631             }
0632           }
0633         }
0634       }
0635       // This trigger emulator does not have an active CFEB flag for DAQ (csc trigger hardware: AFF)
0636       // This is a fundamental difference with the firmware where the TMB prepares the DAQ to
0637       // read out the chamber
0638 
0639       // The pattern finder runs continuously, so another pre-trigger
0640       // could occur already at the next bx.
0641 
0642       // Quality for sorting.
0643       int quality[CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER];
0644       int best_halfstrip[CSCConstants::MAX_CLCTS_PER_PROCESSOR];
0645       int best_quality[CSCConstants::MAX_CLCTS_PER_PROCESSOR];
0646 
0647       for (int ilct = 0; ilct < CSCConstants::MAX_CLCTS_PER_PROCESSOR; ilct++) {
0648         best_halfstrip[ilct] = -1;
0649         best_quality[ilct] = 0;
0650       }
0651 
0652       // Calculate quality from pattern id and number of hits, and
0653       // simultaneously select best-quality LCT.
0654       if (hits_in_time) {
0655         for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
0656           // The bend-direction bit pid[0] is ignored (left and right
0657           // bends have equal quality).
0658           quality[hstrip] = (best_pid[hstrip] & 14) | (nhits[hstrip] << 5);
0659           if (quality[hstrip] > best_quality[0]) {
0660             best_halfstrip[0] = hstrip;
0661             best_quality[0] = quality[hstrip];
0662           }
0663           // temporary alias
0664           const int best_hs(best_halfstrip[0]);
0665           // construct a CLCT if the trigger condition has been met
0666           if (best_hs >= 0 && nhits[best_hs] >= nplanes_hit_pattern) {
0667             // overwrite the current best CLCT
0668             tempBestCLCT = constructCLCT(first_bx, best_hs, hits_in_patterns[best_hs][best_pid[best_hs]], lookupTable);
0669           }
0670         }
0671       }
0672 
0673       // If 1st best CLCT is found, look for the 2nd best.
0674       if (best_halfstrip[0] >= 0) {
0675         // Get the half-strip of the best CLCT in this BX that was put into the list.
0676         // You do need to re-add the any stagger, because the busy keys are based on
0677         // the pulse array which takes into account strip stagger!!!
0678         const unsigned halfStripBestCLCT(tempBestCLCT.getKeyStrip() + stagger[CSCConstants::KEY_CLCT_LAYER - 1]);
0679 
0680         // Mark keys near best CLCT as busy by setting their quality to
0681         // zero, and repeat the search.
0682         markBusyKeys(halfStripBestCLCT, best_pid[halfStripBestCLCT], quality);
0683 
0684         for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
0685           if (quality[hstrip] > best_quality[1]) {
0686             best_halfstrip[1] = hstrip;
0687             best_quality[1] = quality[hstrip];
0688           }
0689           // temporary alias
0690           const int best_hs(best_halfstrip[1]);
0691           // construct a CLCT if the trigger condition has been met
0692           if (best_hs >= 0 && nhits[best_hs] >= nplanes_hit_pattern) {
0693             // overwrite the current second best CLCT
0694             tempSecondCLCT =
0695                 constructCLCT(first_bx, best_hs, hits_in_patterns[best_hs][best_pid[best_hs]], lookupTable);
0696           }
0697         }
0698 
0699         // Sort bestCLCT and secondALCT by quality
0700         // if qualities are the same, sort by run-2 or run-3 pattern
0701         // if qualities and patterns are the same, sort by half strip number
0702         bool changeOrder = false;
0703 
0704         unsigned qualityBest = 0, qualitySecond = 0;
0705         unsigned patternBest = 0, patternSecond = 0;
0706         unsigned halfStripBest = 0, halfStripSecond = 0;
0707 
0708         if (tempBestCLCT.isValid() and tempSecondCLCT.isValid()) {
0709           qualityBest = tempBestCLCT.getQuality();
0710           qualitySecond = tempSecondCLCT.getQuality();
0711           if (!runCCLUT_) {
0712             patternBest = tempBestCLCT.getPattern();
0713             patternSecond = tempSecondCLCT.getPattern();
0714           } else {
0715             patternBest = tempBestCLCT.getRun3Pattern();
0716             patternSecond = tempSecondCLCT.getRun3Pattern();
0717           }
0718           halfStripBest = tempBestCLCT.getKeyStrip();
0719           halfStripSecond = tempSecondCLCT.getKeyStrip();
0720 
0721           if (qualitySecond > qualityBest)
0722             changeOrder = true;
0723           else if ((qualitySecond == qualityBest) and (int(patternSecond / 2) > int(patternBest / 2)))
0724             changeOrder = true;
0725           else if ((qualitySecond == qualityBest) and (int(patternSecond / 2) == int(patternBest / 2)) and
0726                    (halfStripSecond < halfStripBest))
0727             changeOrder = true;
0728         }
0729 
0730         CSCCLCTDigi tempCLCT;
0731         if (changeOrder) {
0732           tempCLCT = tempBestCLCT;
0733           tempBestCLCT = tempSecondCLCT;
0734           tempSecondCLCT = tempCLCT;
0735         }
0736 
0737         // add the CLCTs to the collection
0738         if (tempBestCLCT.isValid()) {
0739           lctList.push_back(tempBestCLCT);
0740         }
0741         if (tempSecondCLCT.isValid()) {
0742           lctList.push_back(tempSecondCLCT);
0743         }
0744       }  //find CLCT, end of best_halfstrip[0] >= 0
0745 
0746       // If there is a trigger, CLCT pre-trigger state machine
0747       // checks the number of hits that lie within a pattern template
0748       // at every bx, and waits for it to drop below threshold.
0749       // The search for CLCTs resumes only when the number of hits
0750       // drops below threshold.
0751       start_bx = fifo_tbins;
0752       // Stop checking drift_delay bx's short of fifo_tbins since
0753       // at later bx's we won't have a full set of hits for a
0754       // pattern search anyway.
0755       unsigned int stop_time = fifo_tbins - drift_delay;
0756       for (unsigned int bx = latch_bx + 1; bx < stop_time; bx++) {
0757         bool return_to_idle = true;
0758         bool hits_in_time = patternFinding(bx, hits_in_patterns);
0759         if (hits_in_time) {
0760           for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
0761             // the dead-time is done at the pre-trigger, not at the trigger
0762             if (nhits[hstrip] >= nplanes_hit_pretrig) {
0763               if (infoV > 1)
0764                 LogTrace("CSCCathodeLCTProcessor") << " State machine busy at bx = " << bx;
0765               return_to_idle = false;
0766               break;
0767             }
0768           }
0769         }
0770         if (return_to_idle) {
0771           if (infoV > 1)
0772             LogTrace("CSCCathodeLCTProcessor") << " State machine returns to idle state at bx = " << bx;
0773           start_bx = bx;
0774           break;
0775         }
0776       }
0777     }  //pre_trig
0778     else {
0779       start_bx = first_bx + 1;  // no dead time
0780     }
0781   }
0782 
0783   return lctList;
0784 }  // findLCTs -- TMB-07 version.
0785 
0786 // Common to all versions.
0787 void CSCCathodeLCTProcessor::pulseExtension(
0788     const std::vector<int> time[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]) {
0789   const unsigned bits_in_pulse = pulse_.bitsInPulse();
0790 
0791   // Clear pulse array.  This array will be used as a bit representation of
0792   // hit times.  For example: if strip[1][2] has a value of 3, then 1 shifted
0793   // left 3 will be bit pattern of pulse[1][2].  This would make the pattern
0794   // look like 0000000000001000.  Then add on additional bits to signify
0795   // the duration of a signal (hit_persist, formerly bx_width) to simulate
0796   // the TMB's drift delay.  So for the same pulse[1][2] with a hit_persist
0797   // of 3 would look like 0000000000111000.  This is similating the digital
0798   // one-shot in the TMB.
0799   pulse_.clear();
0800 
0801   // Loop over all layers and halfstrips.
0802   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0803     for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
0804       // If there is a hit, simulate digital one-shot persistence starting
0805       // in the bx of the initial hit.  Fill this into pulse[][].
0806       if (!time[i_layer][i_strip].empty()) {
0807         std::vector<int> bx_times = time[i_layer][i_strip];
0808         for (unsigned int i = 0; i < bx_times.size(); i++) {
0809           // Check that min and max times are within the allowed range.
0810           if (bx_times[i] < 0 || bx_times[i] + hit_persist >= bits_in_pulse) {
0811             if (infoV > 0)
0812               edm::LogWarning("L1CSCTPEmulatorOutOfTimeDigi")
0813                   << "+++ BX time of comparator digi (halfstrip = " << i_strip << " layer = " << i_layer
0814                   << ") bx = " << bx_times[i] << " is not within the range (0-" << bits_in_pulse
0815                   << "] allowed for pulse extension.  Skip this digi! +++\n";
0816             continue;
0817           }
0818           if (bx_times[i] >= start_bx_shift) {
0819             pulse_.extend(i_layer, i_strip, bx_times[i], hit_persist);
0820           }
0821         }
0822       }
0823     }
0824   }
0825 }  // pulseExtension.
0826 
0827 // TMB-07 version.
0828 bool CSCCathodeLCTProcessor::preTrigger(const int start_bx, int& first_bx) {
0829   if (infoV > 1)
0830     LogTrace("CSCCathodeLCTProcessor") << "....................PreTrigger...........................";
0831 
0832   int nPreTriggers = 0;
0833 
0834   bool pre_trig = false;
0835   // Now do a loop over bx times to see (if/when) track goes over threshold
0836   for (unsigned int bx_time = start_bx; bx_time < fifo_tbins; bx_time++) {
0837     // For any given bunch-crossing, start at the lowest keystrip and look for
0838     // the number of separate layers in the pattern for that keystrip that have
0839     // pulses at that bunch-crossing time.  Do the same for the next keystrip,
0840     // etc.  Then do the entire process again for the next bunch-crossing, etc
0841     // until you find a pre-trigger.
0842 
0843     std::map<int, std::map<int, CSCCLCTDigi::ComparatorContainer>> hits_in_patterns;
0844     hits_in_patterns.clear();
0845 
0846     bool hits_in_time = patternFinding(bx_time, hits_in_patterns);
0847     if (hits_in_time) {
0848       // clear the pretriggers
0849       clearPreTriggers();
0850 
0851       for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
0852         // check the properties of the pattern on this halfstrip
0853         if (infoV > 1) {
0854           if (nhits[hstrip] > 0) {
0855             LogTrace("CSCCathodeLCTProcessor")
0856                 << " bx = " << std::setw(2) << bx_time << " --->"
0857                 << " halfstrip = " << std::setw(3) << hstrip << " best pid = " << std::setw(2) << best_pid[hstrip]
0858                 << " nhits = " << nhits[hstrip];
0859           }
0860         }
0861         // a pretrigger was found
0862         if (nhits[hstrip] >= nplanes_hit_pretrig && best_pid[hstrip] >= pid_thresh_pretrig) {
0863           pre_trig = true;
0864           ispretrig_[hstrip] = true;
0865 
0866           // write each pre-trigger to output
0867           nPreTriggers++;
0868           thePreTriggerDigis.push_back(constructPreCLCT(bx_time, hstrip, nPreTriggers));
0869         }
0870       }
0871 
0872       // upon the first pretrigger, we save first BX and exit
0873       if (pre_trig) {
0874         first_bx = bx_time;  // bx at time of pretrigger
0875         return true;
0876       }
0877     }
0878   }  // end loop over bx times
0879 
0880   if (infoV > 1)
0881     LogTrace("CSCCathodeLCTProcessor") << "no pretrigger, returning \n";
0882   first_bx = fifo_tbins;
0883   return false;
0884 }  // preTrigger -- TMB-07 version.
0885 
0886 // TMB-07 version.
0887 bool CSCCathodeLCTProcessor::patternFinding(
0888     const unsigned int bx_time, std::map<int, std::map<int, CSCCLCTDigi::ComparatorContainer>>& hits_in_patterns) {
0889   if (bx_time >= fifo_tbins)
0890     return false;
0891 
0892   unsigned layers_hit = pulse_.numberOfLayersAtBX(bx_time);
0893   if (layers_hit < nplanes_hit_pretrig)
0894     return false;
0895 
0896   for (int key_hstrip = 0; key_hstrip < numHalfStrips_; key_hstrip++) {
0897     best_pid[key_hstrip] = 0;
0898     nhits[key_hstrip] = 0;
0899   }
0900 
0901   bool hit_layer[CSCConstants::NUM_LAYERS];
0902 
0903   // Loop over candidate key strips.
0904   for (int key_hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; key_hstrip < numHalfStrips_; key_hstrip++) {
0905     // Loop over patterns and look for hits matching each pattern.
0906     for (unsigned int pid = clct_pattern_.size() - 1; pid >= pid_thresh_pretrig and pid < clct_pattern_.size(); pid--) {
0907       layers_hit = 0;
0908       // clear all layers
0909       for (int ilayer = 0; ilayer < CSCConstants::NUM_LAYERS; ilayer++) {
0910         hit_layer[ilayer] = false;
0911       }
0912 
0913       // clear a single pattern!
0914       CSCCLCTDigi::ComparatorContainer hits_single_pattern;
0915       hits_single_pattern.resize(6);
0916       for (auto& p : hits_single_pattern) {
0917         p.resize(CSCConstants::CLCT_PATTERN_WIDTH, CSCConstants::INVALID_HALF_STRIP);
0918       }
0919 
0920       // clear all medians
0921       double num_pattern_hits = 0., times_sum = 0.;
0922       std::multiset<int> mset_for_median;
0923       mset_for_median.clear();
0924 
0925       // Loop over halfstrips in trigger pattern mask and calculate the
0926       // "absolute" halfstrip number for each.
0927       for (int this_layer = 0; this_layer < CSCConstants::NUM_LAYERS; this_layer++) {
0928         for (int strip_num = 0; strip_num < CSCConstants::CLCT_PATTERN_WIDTH; strip_num++) {
0929           // ignore "0" half-strips in the pattern
0930           if (clct_pattern_[pid][this_layer][strip_num] == 0)
0931             continue;
0932 
0933           // the current strip is the key half-strip plus the offset (can be negative or positive)
0934           int this_strip = CSCPatternBank::clct_pattern_offset_[strip_num] + key_hstrip;
0935 
0936           // current strip should be valid of course
0937           if (this_strip >= 0 && this_strip < numHalfStrips_) {
0938             if (infoV > 3) {
0939               LogTrace("CSCCathodeLCTProcessor") << " In patternFinding: key_strip = " << key_hstrip << " pid = " << pid
0940                                                  << " layer = " << this_layer << " strip = " << this_strip << std::endl;
0941             }
0942             // Determine if "one shot" is high at this bx_time
0943             if (pulse_.isOneShotHighAtBX(this_layer, this_strip, bx_time)) {
0944               if (hit_layer[this_layer] == false) {
0945                 hit_layer[this_layer] = true;
0946                 layers_hit++;  // determines number of layers hit
0947                 // add this strip in this layer to the pattern we are currently considering
0948                 hits_single_pattern[this_layer][strip_num] = this_strip - stagger[this_layer];
0949               }
0950 
0951               // find at what bx did pulse on this halsfstrip & layer have started
0952               // use hit_persist constraint on how far back we can go
0953               int first_bx_layer = bx_time;
0954               for (unsigned int dbx = 0; dbx < hit_persist; dbx++) {
0955                 if (pulse_.isOneShotHighAtBX(this_layer, this_strip, first_bx_layer - 1))
0956                   first_bx_layer--;
0957                 else
0958                   break;
0959               }
0960               times_sum += (double)first_bx_layer;
0961               num_pattern_hits += 1.;
0962               mset_for_median.insert(first_bx_layer);
0963               if (infoV > 2)
0964                 LogTrace("CSCCathodeLCTProcessor") << " 1st bx in layer: " << first_bx_layer << " sum bx: " << times_sum
0965                                                    << " #pat. hits: " << num_pattern_hits;
0966             }
0967           }
0968         }  // end loop over strips in pretrigger pattern
0969       }    // end loop over layers
0970 
0971       // save the pattern information when a trigger was formed!
0972       if (layers_hit >= nplanes_hit_pattern) {
0973         hits_in_patterns[key_hstrip][pid] = hits_single_pattern;
0974       }
0975 
0976       // determine the current best pattern!
0977       if (layers_hit > nhits[key_hstrip]) {
0978         best_pid[key_hstrip] = pid;
0979         nhits[key_hstrip] = layers_hit;
0980         // Do not loop over the other (worse) patterns if max. numbers of
0981         // hits is found.
0982         if (nhits[key_hstrip] == CSCConstants::NUM_LAYERS)
0983           break;
0984       }
0985     }  // end loop over pid
0986   }    // end loop over candidate key strips
0987 
0988   // At this point there exists at least one halfstrip for which at least one pattern
0989   // has at least 3 layers --> definition of a pre-trigger
0990   return true;
0991 }  // patternFinding -- TMB-07 version.
0992 
0993 // TMB-07 version.
0994 void CSCCathodeLCTProcessor::markBusyKeys(const int best_hstrip,
0995                                           const int best_patid,
0996                                           int quality[CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]) {
0997   int nspan = min_separation;
0998   int pspan = min_separation;
0999 
1000   for (int hstrip = best_hstrip - nspan; hstrip <= best_hstrip + pspan; hstrip++) {
1001     if (hstrip >= 0 && hstrip < CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER) {
1002       quality[hstrip] = 0;
1003     }
1004   }
1005 }  // markBusyKeys -- TMB-07 version.
1006 
1007 CSCCLCTDigi CSCCathodeLCTProcessor::constructCLCT(const int bx,
1008                                                   const unsigned halfstrip_withstagger,
1009                                                   const CSCCLCTDigi::ComparatorContainer& hits,
1010                                                   const CSCL1TPLookupTableCCLUT* lookupTable) {
1011   // Assign the CLCT properties
1012   const unsigned quality = nhits[halfstrip_withstagger];
1013   const unsigned pattern = best_pid[halfstrip_withstagger];
1014   const unsigned bend = CSCPatternBank::getPatternBend(clct_pattern_[pattern]);
1015   const unsigned keyhalfstrip = halfstrip_withstagger - stagger[CSCConstants::KEY_CLCT_LAYER - 1];
1016   const unsigned cfeb = keyhalfstrip / CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1017   const unsigned halfstrip = keyhalfstrip % CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1018 
1019   // set the Run-2 properties
1020   CSCCLCTDigi clct(1,
1021                    quality,
1022                    pattern,
1023                    // CLCTs are always of type halfstrip (not strip or distrip)
1024                    1,
1025                    bend,
1026                    halfstrip,
1027                    cfeb,
1028                    bx,
1029                    0,
1030                    0,
1031                    -1,
1032                    CSCCLCTDigi::Version::Legacy);
1033 
1034   // set the hit collection
1035   clct.setHits(hits);
1036 
1037   // do the CCLUT procedures for Run-3
1038   if (runCCLUT_) {
1039     cclut_->run(clct, numCFEBs_, lookupTable);
1040   }
1041 
1042   // purge the comparator digi collection from the obsolete "65535" entries...
1043   cleanComparatorContainer(clct);
1044 
1045   if (infoV > 1) {
1046     LogTrace("CSCCathodeLCTProcessor") << "Produce CLCT " << clct << std::endl;
1047   }
1048 
1049   return clct;
1050 }
1051 
1052 CSCCLCTPreTriggerDigi CSCCathodeLCTProcessor::constructPreCLCT(const int bx_time,
1053                                                                const unsigned hstrip,
1054                                                                const unsigned nPreTriggers) const {
1055   const int bend = clct_pattern_[best_pid[hstrip]][CSCConstants::NUM_LAYERS - 1][CSCConstants::CLCT_PATTERN_WIDTH];
1056   const int halfstrip = hstrip % CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1057   const int cfeb = hstrip / CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1058   return CSCCLCTPreTriggerDigi(1, nhits[hstrip], best_pid[hstrip], 1, bend, halfstrip, cfeb, bx_time, nPreTriggers, 0);
1059 }
1060 
1061 void CSCCathodeLCTProcessor::clearPreTriggers() {
1062   for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
1063     ispretrig_[hstrip] = false;
1064   }
1065 }
1066 
1067 void CSCCathodeLCTProcessor::cleanComparatorContainer(CSCCLCTDigi& clct) const {
1068   CSCCLCTDigi::ComparatorContainer newHits = clct.getHits();
1069   for (auto& p : newHits) {
1070     p.erase(
1071         std::remove_if(p.begin(), p.end(), [](unsigned i) -> bool { return i == CSCConstants::INVALID_HALF_STRIP; }),
1072         p.end());
1073   }
1074   clct.setHits(newHits);
1075 }
1076 
1077 // --------------------------------------------------------------------------
1078 // Auxiliary code.
1079 // --------------------------------------------------------------------------
1080 // Dump of configuration parameters.
1081 void CSCCathodeLCTProcessor::dumpConfigParams() const {
1082   std::ostringstream strm;
1083   strm << "\n";
1084   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1085   strm << "+                  CLCT configuration parameters:                  +\n";
1086   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1087   strm << " fifo_tbins   [total number of time bins in DAQ readout] = " << fifo_tbins << "\n";
1088   strm << " fifo_pretrig [start time of cathode raw hits in DAQ readout] = " << fifo_pretrig << "\n";
1089   strm << " hit_persist  [duration of signal pulse, in 25 ns bins] = " << hit_persist << "\n";
1090   strm << " drift_delay  [time after pre-trigger before TMB latches LCTs] = " << drift_delay << "\n";
1091   strm << " nplanes_hit_pretrig [min. number of layers hit for pre-trigger] = " << nplanes_hit_pretrig << "\n";
1092   strm << " nplanes_hit_pattern [min. number of layers hit for trigger] = " << nplanes_hit_pattern << "\n";
1093   strm << " pid_thresh_pretrig [lower threshold on pattern id] = " << pid_thresh_pretrig << "\n";
1094   strm << " min_separation     [region of busy key strips] = " << min_separation << "\n";
1095   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1096   LogDebug("CSCCathodeLCTProcessor") << strm.str();
1097 }
1098 
1099 // Reasonably nice dump of digis on half-strips.
1100 void CSCCathodeLCTProcessor::dumpDigis(
1101     const std::vector<int> strip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]) const {
1102   LogDebug("CSCCathodeLCTProcessor") << theCSCName_ << " strip type: half-strip,  numHalfStrips " << numHalfStrips_;
1103 
1104   std::ostringstream strstrm;
1105   for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
1106     if (i_strip % 10 == 0) {
1107       if (i_strip < 100)
1108         strstrm << i_strip / 10;
1109       else
1110         strstrm << (i_strip - 100) / 10;
1111     } else
1112       strstrm << " ";
1113     if ((i_strip + 1) % CSCConstants::NUM_HALF_STRIPS_PER_CFEB == 0)
1114       strstrm << " ";
1115   }
1116   strstrm << "\n";
1117   for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
1118     strstrm << i_strip % 10;
1119     if ((i_strip + 1) % CSCConstants::NUM_HALF_STRIPS_PER_CFEB == 0)
1120       strstrm << " ";
1121   }
1122   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1123     strstrm << "\n";
1124     for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
1125       if (!strip[i_layer][i_strip].empty()) {
1126         std::vector<int> bx_times = strip[i_layer][i_strip];
1127         // Dump only the first in time.
1128         strstrm << std::hex << bx_times[0] << std::dec;
1129       } else {
1130         strstrm << "-";
1131       }
1132       if ((i_strip + 1) % CSCConstants::NUM_HALF_STRIPS_PER_CFEB == 0)
1133         strstrm << " ";
1134     }
1135   }
1136   LogTrace("CSCCathodeLCTProcessor") << strstrm.str();
1137 }
1138 
1139 // Returns vector of read-out CLCTs, if any.  Starts with the vector
1140 // of all found CLCTs and selects the ones in the read-out time window.
1141 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::readoutCLCTs() const {
1142   // temporary container for further selection
1143   std::vector<CSCCLCTDigi> tmpV;
1144 
1145   /*
1146     CLCTs in the BX window [early_tbin,...,late_tbin] are considered good for physics
1147     The central CLCT BX is time bin 7.
1148     For tmb_l1a_window_size set to 7 (Run-1, Run-2), the window is [4, 5, 6, 7, 8, 9, 10]
1149     For tmb_l1a_window_size set to 5 (Run-3), the window is [5, 6, 7, 8, 9]
1150     For tmb_l1a_window_size set to 3 (Run-4?), the window is [6, 7, 8]
1151   */
1152   const unsigned delta_tbin = tmb_l1a_window_size / 2;
1153   int early_tbin = CSCConstants::CLCT_CENTRAL_BX - delta_tbin;
1154   int late_tbin = CSCConstants::CLCT_CENTRAL_BX + delta_tbin;
1155   /*
1156      Special case for an even-numbered time-window,
1157      For instance tmb_l1a_window_size set to 6: [4, 5, 6, 7, 8, 9]
1158   */
1159   if (tmb_l1a_window_size % 2 == 0)
1160     late_tbin = CSCConstants::CLCT_CENTRAL_BX + delta_tbin - 1;
1161   const int max_late_tbin = CSCConstants::MAX_CLCT_TBINS - 1;
1162 
1163   // debugging messages when early_tbin or late_tbin has a suspicious value
1164   if (early_tbin < 0) {
1165     edm::LogWarning("CSCCathodeLCTProcessor|SuspiciousParameters")
1166         << "Early time bin (early_tbin) smaller than minimum allowed, which is 0. set early_tbin to 0.";
1167     early_tbin = 0;
1168   }
1169   if (late_tbin > max_late_tbin) {
1170     edm::LogWarning("CSCCathodeLCTProcessor|SuspiciousParameters")
1171         << "Late time bin (late_tbin) larger than maximum allowed, which is " << max_late_tbin
1172         << ". set early_tbin to max allowed";
1173     late_tbin = CSCConstants::MAX_CLCT_TBINS - 1;
1174   }
1175 
1176   // get the valid LCTs. No BX selection is done here
1177   const auto& all_clcts = getCLCTs();
1178 
1179   // Start from the vector of all found CLCTs and select those within
1180   // the CLCT*L1A coincidence window.
1181   int bx_readout = -1;
1182   for (const auto& clct : all_clcts) {
1183     // only consider valid CLCTs
1184     if (!clct.isValid())
1185       continue;
1186 
1187     const int bx = clct.getBX();
1188     // Skip CLCTs found too early relative to L1Accept.
1189     if (bx < early_tbin) {
1190       if (infoV > 1)
1191         LogDebug("CSCCathodeLCTProcessor")
1192             << " Do not report correlated CLCT on key halfstrip " << clct.getStrip() << ": found at bx " << bx
1193             << ", whereas the earliest allowed bx is " << early_tbin;
1194       continue;
1195     }
1196 
1197     // Skip CLCTs found too late relative to L1Accept.
1198     if (bx > late_tbin) {
1199       if (infoV > 1)
1200         LogDebug("CSCCathodeLCTProcessor")
1201             << " Do not report correlated CLCT on key halfstrip " << clct.getStrip() << ": found at bx " << bx
1202             << ", whereas the latest allowed bx is " << late_tbin;
1203       continue;
1204     }
1205 
1206     // If (readout_earliest_2) take only CLCTs in the earliest bx in the read-out window:
1207     if (readout_earliest_2) {
1208       // the first CLCT passes
1209       // the second CLCT passes if the BX matches to the first
1210       if (bx_readout == -1 || bx == bx_readout) {
1211         tmpV.push_back(clct);
1212         if (bx_readout == -1)
1213           bx_readout = bx;
1214       }
1215     } else
1216       tmpV.push_back(clct);
1217   }
1218 
1219   // do a final check on the CLCTs in readout
1220   qualityControl_->checkMultiplicityBX(tmpV);
1221   for (const auto& clct : tmpV) {
1222     qualityControl_->checkValid(clct);
1223   }
1224 
1225   return tmpV;
1226 }
1227 
1228 // Returns vector of all found CLCTs, if any.  Used for ALCT-CLCT matching.
1229 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::getCLCTs() const {
1230   std::vector<CSCCLCTDigi> tmpV;
1231   for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
1232     if (bestCLCT[bx].isValid())
1233       tmpV.push_back(bestCLCT[bx]);
1234     if (secondCLCT[bx].isValid())
1235       tmpV.push_back(secondCLCT[bx]);
1236   }
1237   return tmpV;
1238 }
1239 
1240 // shift the BX from 7 to 8
1241 // the unpacked real data CLCTs have central BX at bin 7
1242 // however in simulation the central BX  is bin 8
1243 // to make a proper comparison with ALCTs we need
1244 // CLCT and ALCT to have the central BX in the same bin
1245 CSCCLCTDigi CSCCathodeLCTProcessor::getBestCLCT(int bx) const {
1246   if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1247     return CSCCLCTDigi();
1248   CSCCLCTDigi lct = bestCLCT[bx];
1249   lct.setBX(lct.getBX() + CSCConstants::ALCT_CLCT_OFFSET);
1250   return lct;
1251 }
1252 
1253 CSCCLCTDigi CSCCathodeLCTProcessor::getSecondCLCT(int bx) const {
1254   if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1255     return CSCCLCTDigi();
1256   CSCCLCTDigi lct = secondCLCT[bx];
1257   lct.setBX(lct.getBX() + CSCConstants::ALCT_CLCT_OFFSET);
1258   return lct;
1259 }
1260 
1261 bool CSCCathodeLCTProcessor::getLocalShowerFlag(int bx) const {
1262   if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1263     return false;
1264   return localShowerFlag[bx];
1265 }
1266 
1267 /** return vector of CSCShower digi **/
1268 std::vector<CSCShowerDigi> CSCCathodeLCTProcessor::getAllShower() const {
1269   std::vector<CSCShowerDigi> vshowers(cathode_showers_, cathode_showers_ + CSCConstants::MAX_CLCT_TBINS);
1270   return vshowers;
1271 };
1272 
1273 /** Returns shower bits */
1274 std::vector<CSCShowerDigi> CSCCathodeLCTProcessor::readoutShower() const {
1275   std::vector<CSCShowerDigi> showerOut;
1276   for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++)
1277     if (cathode_showers_[bx].isValid())
1278       showerOut.push_back(cathode_showers_[bx]);
1279   return showerOut;
1280 }
1281 
1282 void CSCCathodeLCTProcessor::encodeHighMultiplicityBits() {
1283   //inTimeHMT_ = 0;
1284 
1285   //numer of layer with hits and number of hits for 0-15 BXs
1286   std::set<unsigned> layersWithHits[CSCConstants::MAX_CLCT_TBINS];
1287   unsigned hitsInTime[CSCConstants::MAX_CLCT_TBINS];
1288   // Calculate layers with hits
1289   for (unsigned bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
1290     hitsInTime[bx] = 0;
1291     for (unsigned i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1292       bool atLeastOneCompHit = false;
1293       for (const auto& compdigi : digiV[i_layer]) {
1294         std::vector<int> bx_times = compdigi.getTimeBinsOn();
1295         // there is at least one comparator digi in this bx
1296         if (std::find(bx_times.begin(), bx_times.end(), bx) != bx_times.end()) {
1297           hitsInTime[bx] += 1;
1298           atLeastOneCompHit = true;
1299         }
1300       }
1301       // add this layer to the number of layers hit
1302       if (atLeastOneCompHit) {
1303         layersWithHits[bx].insert(i_layer);
1304       }
1305     }
1306   }  //end of full bx loop
1307 
1308   // convert station and ring number to index
1309   // index runs from 2 to 10, subtract 2
1310   unsigned csc_idx = CSCDetId::iChamberType(theStation, theRing) - 2;
1311 
1312   // loose, nominal and tight
1313   std::vector<unsigned> station_thresholds = {
1314       thresholds_[csc_idx * 3], thresholds_[csc_idx * 3 + 1], thresholds_[csc_idx * 3 + 2]};
1315 
1316   //hard coded dead time as 2Bx, since showerNumTBins = 3, like firmware
1317   // for example, nhits = 0 at bx7; = 100 at bx8; = 0 at bx9
1318   //cathode HMT must be triggered at bx8, not bx7 and bx9
1319   //meanwhile we forced 2BX dead time after active shower trigger
1320   unsigned int deadtime =
1321       showerNumTBins_ - 1;  // firmware hard coded dead time as 2Bx, since showerNumTBins = 3 in firmware
1322   unsigned int dead_count = 0;
1323 
1324   for (unsigned bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
1325     unsigned minbx = bx >= showerNumTBins_ / 2 ? bx - showerNumTBins_ / 2 : bx;
1326     unsigned maxbx = bx < CSCConstants::MAX_CLCT_TBINS - showerNumTBins_ / 2 ? bx + showerNumTBins_ / 2
1327                                                                              : CSCConstants::MAX_CLCT_TBINS - 1;
1328     unsigned this_hitsInTime = 0;
1329     bool isPeak = true;  //check whether total hits in bx is peak of nhits over time bins
1330     /*following is to count number of hits over [minbx, maxbx], showerNumTBins=3 =>[n-1, n+1]*/
1331     for (unsigned mbx = minbx; mbx <= maxbx; mbx++) {
1332       this_hitsInTime += hitsInTime[mbx];
1333     }
1334 
1335     if (peakCheck_ and bx < CSCConstants::MAX_CLCT_TBINS - showerNumTBins_ / 2 - 1) {
1336       if (hitsInTime[minbx] < hitsInTime[maxbx + 1] or
1337           (hitsInTime[minbx] == hitsInTime[maxbx + 1] and hitsInTime[bx] < hitsInTime[bx + 1]))
1338         isPeak = false;  //next bx would have more hits or in the center
1339     }
1340     bool dead_status = dead_count > 0;
1341     if (dead_status)
1342       dead_count--;
1343 
1344     unsigned this_inTimeHMT = 0;
1345     // require at least nLayersWithHits for the central time bin
1346     // do nothing if there are not enough layers with hits
1347     if (layersWithHits[bx].size() >= minLayersCentralTBin_ and !dead_status and isPeak) {
1348       // assign the bits
1349       if (!station_thresholds.empty()) {
1350         for (int i = station_thresholds.size() - 1; i >= 0; i--) {
1351           if (this_hitsInTime >= station_thresholds[i]) {
1352             this_inTimeHMT = i + 1;
1353             dead_count = deadtime;
1354             break;
1355           }
1356         }
1357       }
1358     }
1359     //CLCTshower constructor with showerType_ = 2, wirehits = 0;
1360     cathode_showers_[bx] = CSCShowerDigi(
1361         this_inTimeHMT, false, theTrigChamber, bx, CSCShowerDigi::ShowerType::kCLCTShower, 0, this_hitsInTime);
1362   }
1363 }