Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-12-03 23:52:10

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