Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #include "L1Trigger/CSCTriggerPrimitives/interface/CSCAnodeLCTProcessor.h"
0002 #include <set>
0003 
0004 // Default values of configuration parameters.
0005 const unsigned int CSCAnodeLCTProcessor::def_fifo_tbins = 16;
0006 const unsigned int CSCAnodeLCTProcessor::def_fifo_pretrig = 10;
0007 const unsigned int CSCAnodeLCTProcessor::def_drift_delay = 2;
0008 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_pretrig = 2;
0009 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_pattern = 4;
0010 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_accel_pretrig = 2;
0011 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_accel_pattern = 4;
0012 const unsigned int CSCAnodeLCTProcessor::def_trig_mode = 2;         // 3?
0013 const unsigned int CSCAnodeLCTProcessor::def_accel_mode = 0;        // 1?
0014 const unsigned int CSCAnodeLCTProcessor::def_l1a_window_width = 7;  // 5?
0015 
0016 //----------------
0017 // Constructors --
0018 //----------------
0019 
0020 CSCAnodeLCTProcessor::CSCAnodeLCTProcessor(unsigned endcap,
0021                                            unsigned station,
0022                                            unsigned sector,
0023                                            unsigned subsector,
0024                                            unsigned chamber,
0025                                            CSCBaseboard::Parameters& conf)
0026     : CSCBaseboard(endcap, station, sector, subsector, chamber, conf) {
0027   static std::atomic<bool> config_dumped{false};
0028 
0029   // ALCT configuration parameters.
0030   fifo_tbins = conf.alctParams().getParameter<unsigned int>("alctFifoTbins");
0031   fifo_pretrig = conf.alctParams().getParameter<unsigned int>("alctFifoPretrig");
0032   drift_delay = conf.alctParams().getParameter<unsigned int>("alctDriftDelay");
0033   nplanes_hit_pretrig = conf.alctParams().getParameter<unsigned int>("alctNplanesHitPretrig");
0034   nplanes_hit_pattern = conf.alctParams().getParameter<unsigned int>("alctNplanesHitPattern");
0035   nplanes_hit_accel_pretrig = conf.alctParams().getParameter<unsigned int>("alctNplanesHitAccelPretrig");
0036   nplanes_hit_accel_pattern = conf.alctParams().getParameter<unsigned int>("alctNplanesHitAccelPattern");
0037   trig_mode = conf.alctParams().getParameter<unsigned int>("alctTrigMode");
0038   accel_mode = conf.alctParams().getParameter<unsigned int>("alctAccelMode");
0039   l1a_window_width = conf.alctParams().getParameter<unsigned int>("alctL1aWindowWidth");
0040 
0041   hit_persist = conf.alctParams().getParameter<unsigned int>("alctHitPersist");
0042 
0043   // Verbosity level, set to 0 (no print) by default.
0044   infoV = conf.alctParams().getParameter<int>("verbosity");
0045 
0046   // separate handle for early time bins
0047   early_tbins = conf.alctParams().getParameter<int>("alctEarlyTbins");
0048   if (early_tbins < 0)
0049     early_tbins = fifo_pretrig - CSCConstants::ALCT_EMUL_TIME_OFFSET;
0050 
0051   // delta BX time depth for ghostCancellationLogic
0052   ghost_cancellation_bx_depth = conf.alctParams().getParameter<int>("alctGhostCancellationBxDepth");
0053 
0054   // whether to consider ALCT candidates' qualities while doing ghostCancellationLogic on +-1 wire groups
0055   ghost_cancellation_side_quality = conf.alctParams().getParameter<bool>("alctGhostCancellationSideQuality");
0056 
0057   // deadtime clocks after pretrigger (extra in addition to drift_delay)
0058   pretrig_extra_deadtime = conf.alctParams().getParameter<unsigned int>("alctPretrigDeadtime");
0059 
0060   // whether to use narrow pattern mask for the rings close to the beam
0061   narrow_mask_r1 = conf.alctParams().getParameter<bool>("alctNarrowMaskForR1");
0062 
0063   // Check and print configuration parameters.
0064   checkConfigParameters();
0065   if ((infoV > 0 || (runPhase2_)) && !config_dumped) {
0066     dumpConfigParams();
0067     config_dumped = true;
0068   }
0069 
0070   numWireGroups = 0;  // Will be set later.
0071   MESelection = (theStation < 3) ? 0 : 1;
0072 
0073   // whether to calculate bx as corrected_bx instead of pretrigger one
0074   use_corrected_bx = false;
0075   if (runPhase2_) {
0076     use_corrected_bx = conf.alctParams().getParameter<bool>("alctUseCorrectedBx");
0077   }
0078 
0079   // Load appropriate pattern mask.
0080   loadPatternMask();
0081 
0082   // quality control of stubs
0083   qualityControl_ = std::make_unique<LCTQualityControl>(endcap, station, sector, subsector, chamber, conf);
0084 
0085   const auto& shower = conf.showerParams().getParameterSet("anodeShower");
0086   thresholds_ = shower.getParameter<std::vector<unsigned>>("showerThresholds");
0087   showerNumTBins_ = shower.getParameter<unsigned>("showerNumTBins");
0088   minLayersCentralTBin_ = shower.getParameter<unsigned>("minLayersCentralTBin");
0089   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - l1a_window_width / 2;
0090   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + l1a_window_width / 2;
0091   assert(l1a_window_width / 2 <= CSCConstants::LCT_CENTRAL_BX);
0092 }
0093 
0094 void CSCAnodeLCTProcessor::loadPatternMask() {
0095   // Load appropriate pattern mask.
0096   if (narrow_mask_r1 && (theRing == 1 || theRing == 4)) {
0097     alct_pattern_ = CSCPatternBank::alct_pattern_r1_;
0098   } else {
0099     alct_pattern_ = CSCPatternBank::alct_pattern_legacy_;
0100   }
0101 }
0102 
0103 void CSCAnodeLCTProcessor::setDefaultConfigParameters() {
0104   // Set default values for configuration parameters.
0105   fifo_tbins = def_fifo_tbins;
0106   fifo_pretrig = def_fifo_pretrig;
0107   drift_delay = def_drift_delay;
0108   nplanes_hit_pretrig = def_nplanes_hit_pretrig;
0109   nplanes_hit_pattern = def_nplanes_hit_pattern;
0110   nplanes_hit_accel_pretrig = def_nplanes_hit_accel_pretrig;
0111   nplanes_hit_accel_pattern = def_nplanes_hit_accel_pattern;
0112   trig_mode = def_trig_mode;
0113   accel_mode = def_accel_mode;
0114   l1a_window_width = def_l1a_window_width;
0115   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - l1a_window_width / 2;
0116   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + l1a_window_width / 2;
0117 }
0118 
0119 // Set configuration parameters obtained via EventSetup mechanism.
0120 void CSCAnodeLCTProcessor::setConfigParameters(const CSCDBL1TPParameters* conf) {
0121   static std::atomic<bool> config_dumped{false};
0122 
0123   fifo_tbins = conf->alctFifoTbins();
0124   fifo_pretrig = conf->alctFifoPretrig();
0125   drift_delay = conf->alctDriftDelay();
0126   nplanes_hit_pretrig = conf->alctNplanesHitPretrig();
0127   nplanes_hit_pattern = conf->alctNplanesHitPattern();
0128   nplanes_hit_accel_pretrig = conf->alctNplanesHitAccelPretrig();
0129   nplanes_hit_accel_pattern = conf->alctNplanesHitAccelPattern();
0130   trig_mode = conf->alctTrigMode();
0131   accel_mode = conf->alctAccelMode();
0132   l1a_window_width = conf->alctL1aWindowWidth();
0133 
0134   // Check and print configuration parameters.
0135   checkConfigParameters();
0136   if (!config_dumped) {
0137     dumpConfigParams();
0138     config_dumped = true;
0139   }
0140   minbx_readout_ = CSCConstants::LCT_CENTRAL_BX - l1a_window_width / 2;
0141   maxbx_readout_ = CSCConstants::LCT_CENTRAL_BX + l1a_window_width / 2;
0142 }
0143 
0144 void CSCAnodeLCTProcessor::checkConfigParameters() {
0145   // Make sure that the parameter values are within the allowed range.
0146 
0147   // Max expected values.
0148   static const unsigned int max_fifo_tbins = 1 << 5;
0149   static const unsigned int max_fifo_pretrig = 1 << 5;
0150   static const unsigned int max_drift_delay = 1 << 2;
0151   static const unsigned int max_nplanes_hit_pretrig = 1 << 3;
0152   static const unsigned int max_nplanes_hit_pattern = 1 << 3;
0153   static const unsigned int max_nplanes_hit_accel_pretrig = 1 << 3;
0154   static const unsigned int max_nplanes_hit_accel_pattern = 1 << 3;
0155   static const unsigned int max_trig_mode = 1 << 2;
0156   static const unsigned int max_accel_mode = 1 << 2;
0157   static const unsigned int max_l1a_window_width = CSCConstants::MAX_ALCT_TBINS;  // 4 bits
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(drift_delay, max_drift_delay, def_drift_delay, "drift_delay");
0163   CSCBaseboard::checkConfigParameters(
0164       nplanes_hit_pretrig, max_nplanes_hit_pretrig, def_nplanes_hit_pretrig, "nplanes_hit_pretrig");
0165   CSCBaseboard::checkConfigParameters(
0166       nplanes_hit_pattern, max_nplanes_hit_pattern, def_nplanes_hit_pattern, "nplanes_hit_pattern");
0167   CSCBaseboard::checkConfigParameters(nplanes_hit_accel_pretrig,
0168                                       max_nplanes_hit_accel_pretrig,
0169                                       def_nplanes_hit_accel_pretrig,
0170                                       "nplanes_hit_accel_pretrig");
0171   CSCBaseboard::checkConfigParameters(nplanes_hit_accel_pattern,
0172                                       max_nplanes_hit_accel_pattern,
0173                                       def_nplanes_hit_accel_pattern,
0174                                       "nplanes_hit_accel_pattern");
0175   CSCBaseboard::checkConfigParameters(trig_mode, max_trig_mode, def_trig_mode, "trig_mode");
0176   CSCBaseboard::checkConfigParameters(accel_mode, max_accel_mode, def_accel_mode, "accel_mode");
0177   CSCBaseboard::checkConfigParameters(l1a_window_width, max_l1a_window_width, def_l1a_window_width, "l1a_window_width");
0178 
0179   assert(l1a_window_width / 2 <= CSCConstants::LCT_CENTRAL_BX);
0180 }
0181 
0182 void CSCAnodeLCTProcessor::clear() {
0183   for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
0184     bestALCT[bx].clear();
0185     secondALCT[bx].clear();
0186     anode_showers_[bx].clear();  //?
0187   }
0188   lct_list.clear();
0189 }
0190 
0191 void CSCAnodeLCTProcessor::clear(const int wire, const int pattern) {
0192   /* Clear the data off of selected pattern */
0193   if (pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN)
0194     quality[wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] = -999;
0195   else {
0196     quality[wire][CSCConstants::ALCT_COLLISIONA_PATTERN] = -999;
0197     quality[wire][CSCConstants::ALCT_COLLISIONB_PATTERN] = -999;
0198   }
0199 }
0200 
0201 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::run(const CSCWireDigiCollection* wiredc, const CSCChamber* cscChamber) {
0202   static std::atomic<bool> config_dumped{false};
0203   if ((infoV > 0 || (runPhase2_)) && !config_dumped) {
0204     dumpConfigParams();
0205     config_dumped = true;
0206   }
0207 
0208   // Get the number of wire groups for the given chamber.  Do it only once
0209   // per chamber.
0210   if (numWireGroups <= 0 or numWireGroups > CSCConstants::MAX_NUM_WIREGROUPS) {
0211     if (cscChamber) {
0212       numWireGroups = cscChamber->layer(1)->geometry()->numberOfWireGroups();
0213       if (numWireGroups > CSCConstants::MAX_NUM_WIREGROUPS) {
0214         edm::LogError("CSCAnodeLCTProcessor|SetupError")
0215             << "+++ Number of wire groups, " << numWireGroups << " found in " << theCSCName_ << " (sector " << theSector
0216             << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
0217             << " exceeds max expected, " << CSCConstants::MAX_NUM_WIREGROUPS << " +++\n"
0218             << "+++ CSC geometry looks garbled; no emulation possible +++\n";
0219         numWireGroups = -1;
0220       }
0221     } else {
0222       edm::LogError("CSCAnodeLCTProcessor|SetupError")
0223           << "+++ " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
0224           << theTrigChamber << ")"
0225           << " is not defined in current geometry! +++\n"
0226           << "+++ CSC geometry looks garbled; no emulation possible +++\n";
0227       numWireGroups = -1;
0228     }
0229   }
0230 
0231   if (numWireGroups <= 0 or (unsigned) numWireGroups > qualityControl_->get_csc_max_wiregroup(theStation, theRing)) {
0232     edm::LogError("CSCAnodeLCTProcessor|SetupError")
0233         << "+++ " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
0234         << theTrigChamber << "):"
0235         << " numWireGroups = " << numWireGroups << "; ALCT emulation skipped! +++";
0236     std::vector<CSCALCTDigi> emptyV;
0237     return emptyV;
0238   }
0239 
0240   // Get wire digis in this chamber from wire digi collection.
0241   bool hasDigis = getDigis(wiredc);
0242 
0243   if (hasDigis) {
0244     // First get wiregroup times from the wire digis.
0245     std::vector<int> wireGroupTimes[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS];
0246     readWireDigis(wireGroupTimes);
0247 
0248     // Pass an array of wire times on to another run() doing the LCT search.
0249     // If the number of layers containing digis is smaller than that
0250     // required to trigger, quit right away.
0251     const unsigned int min_layers =
0252         (nplanes_hit_accel_pattern == 0)
0253             ? nplanes_hit_pattern
0254             : ((nplanes_hit_pattern <= nplanes_hit_accel_pattern) ? nplanes_hit_pattern : nplanes_hit_accel_pattern);
0255 
0256     unsigned int layersHit = 0;
0257     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0258       for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
0259         if (!wireGroupTimes[i_layer][i_wire].empty()) {
0260           layersHit++;
0261           break;
0262         }
0263       }
0264     }
0265     if (layersHit >= min_layers)
0266       run(wireGroupTimes);
0267     // Get the high multiplicity bits in this chamber
0268     encodeHighMultiplicityBits();
0269   }
0270 
0271   // Return vector of all found ALCTs.
0272   return getALCTs();
0273 }
0274 
0275 void CSCAnodeLCTProcessor::run(const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS]) {
0276   bool trigger = false;
0277 
0278   // initialize the pulse array.
0279   pulse_.initialize(numWireGroups);
0280 
0281   // Check if there are any in-time hits and do the pulse extension.
0282   bool chamber_empty = pulseExtension(wire);
0283 
0284   // define a new pattern map
0285   // for each key wiregroup, and for each pattern, store the 2D collection of fired wiregroup digis
0286   std::map<int, std::map<int, CSCALCTDigi::WireContainer>> hits_in_patterns;
0287   hits_in_patterns.clear();
0288 
0289   // Only do the rest of the processing if chamber is not empty.
0290   // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
0291   // not have a full set of hits to start pattern search anyway.
0292   unsigned int stop_bx = fifo_tbins - drift_delay;
0293   if (!chamber_empty) {
0294     for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
0295       // extra check to make sure only valid wires are processed
0296       const unsigned max_wire = qualityControl_->get_csc_max_wiregroup(theStation, theRing);
0297       if (unsigned(i_wire) >= max_wire)
0298         continue;
0299 
0300       unsigned int start_bx = 0;
0301       // Allow for more than one pass over the hits in the time window.
0302       while (start_bx < stop_bx) {
0303         if (preTrigger(i_wire, start_bx)) {
0304           if (infoV > 2)
0305             showPatterns(i_wire);
0306           if (patternDetection(i_wire, hits_in_patterns)) {
0307             trigger = true;
0308             int ghost_cleared[2] = {0, 0};
0309             /*
0310               In older versions of the ALCT emulation, the ghost cancellation was performed after
0311               the ALCTs were found. In December 2018, it became clear that during the study of data
0312               and emulation comparison on 2018 data, a small disagreement between data and emulation
0313               was found. The changes we implemented then allow re-triggering on one wiregroup after
0314               some dead time once an earlier ALCT was constructed built on this wiregroup. Before this
0315               commit the ALCT processor would prohibit the wiregroup from triggering in one event after
0316               an ALCT was found on that wiregroup. In the firwmare, the wiregroup with ALCT is only dead
0317               for a few BX before it can be triggered by next muon. The implementation of ghost cancellation
0318               logic was changed to accommodate the re-triggering change while the idea of ghost cancellation
0319               logic is kept the same.
0320             */
0321             ghostCancellationLogicOneWire(i_wire, ghost_cleared);
0322 
0323             int bx = (use_corrected_bx) ? first_bx_corrected[i_wire] : first_bx[i_wire];
0324             if (bx >= CSCConstants::MAX_ALCT_TBINS)
0325               edm::LogError("CSCAnodeLCTProcessor")
0326                   << " bx of valid trigger : " << bx << " > max allowed value " << CSCConstants::MAX_ALCT_TBINS;
0327 
0328             //acceleration mode
0329             if (quality[i_wire][0] > 0 and bx < CSCConstants::MAX_ALCT_TBINS) {
0330               int valid = (ghost_cleared[0] == 0) ? 1 : 0;  //cancelled, valid=0, otherwise it is 1
0331               CSCALCTDigi newALCT(valid, quality[i_wire][0], 1, 0, i_wire, bx);
0332 
0333               // set the wire digis for this pattern
0334               setWireContainer(newALCT, hits_in_patterns[i_wire][0]);
0335 
0336               lct_list.emplace_back(newALCT);
0337               if (infoV > 1)
0338                 LogTrace("CSCAnodeLCTProcessor") << "Add one ALCT to list " << lct_list.back();
0339             }
0340 
0341             //collision mode
0342             if (quality[i_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0 and bx < CSCConstants::MAX_ALCT_TBINS) {
0343               int valid = (ghost_cleared[CSCConstants::ALCT_COLLISIONA_PATTERN] == 0)
0344                               ? 1
0345                               : 0;  //cancelled, valid=0, otherwise it is 1
0346 
0347               CSCALCTDigi newALCT(valid,
0348                                   quality[i_wire][CSCConstants::ALCT_COLLISIONA_PATTERN],
0349                                   0,
0350                                   quality[i_wire][CSCConstants::ALCT_COLLISIONB_PATTERN],
0351                                   i_wire,
0352                                   bx);
0353 
0354               // set the wire digis for this pattern
0355               setWireContainer(newALCT, hits_in_patterns[i_wire][CSCConstants::ALCT_COLLISIONA_PATTERN]);
0356 
0357               lct_list.emplace_back(newALCT);
0358               if (infoV > 1)
0359                 LogTrace("CSCAnodeLCTProcessor") << "Add one ALCT to list " << lct_list.back();
0360             }
0361 
0362             //break;
0363             // Assume that the earliest time when another pre-trigger can
0364             // occur in case pattern detection failed is bx_pretrigger+4:
0365             // this seems to match the data.
0366             start_bx = first_bx[i_wire] + drift_delay + pretrig_extra_deadtime;
0367           } else {
0368             //only pretrigger, no trigger ==> no dead time, continue to find next pretrigger
0369             start_bx = first_bx[i_wire] + 1;
0370           }
0371         } else {  //no pretrigger, skip this wiregroup
0372           break;
0373         }
0374       }  // end of while
0375     }
0376   }
0377 
0378   // Do the rest only if there is at least one trigger candidate.
0379   if (trigger) {
0380     /* In Run-1 and Run-2, the ghost cancellation was done after the trigger.
0381        In the firmware however, the ghost cancellation is done during the trigger
0382        on each wiregroup in parallel. For Run-3 and beyond, the ghost cancellation is
0383        implemented per wiregroup earlier in the code. See function
0384        "ghostCancellationLogicOneWire". There used to be a function ghostCancellationLogic
0385        call here.
0386     */
0387     lctSearch();
0388   }
0389 }
0390 
0391 bool CSCAnodeLCTProcessor::getDigis(const CSCWireDigiCollection* wiredc) {
0392   // Routine for getting digis and filling digiV vector.
0393   bool hasDigis = false;
0394 
0395   // Loop over layers and save wire digis on each one into digiV[layer].
0396   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0397     digiV[i_layer].clear();
0398 
0399     CSCDetId detid(theEndcap, theStation, theRing, theChamber, i_layer + 1);
0400     getDigis(wiredc, detid);
0401 
0402     // If this is ME1/1, fetch digis in corresponding ME1/A (ring=4) as well.
0403     if (isME11_ && !disableME1a_) {
0404       CSCDetId detid_me1a(theEndcap, theStation, 4, theChamber, i_layer + 1);
0405       getDigis(wiredc, detid_me1a);
0406     }
0407 
0408     if (!digiV[i_layer].empty()) {
0409       hasDigis = true;
0410       if (infoV > 1) {
0411         LogTrace("CSCAnodeLCTProcessor") << "found " << digiV[i_layer].size() << " wire digi(s) in layer " << i_layer
0412                                          << " of " << theCSCName_ << " (trig. sector " << theSector << " subsector "
0413                                          << theSubsector << " id " << theTrigChamber << ")";
0414         for (const auto& wd : digiV[i_layer]) {
0415           LogTrace("CSCAnodeLCTProcessor") << "   " << wd;
0416         }
0417       }
0418     }
0419   }
0420 
0421   return hasDigis;
0422 }
0423 
0424 void CSCAnodeLCTProcessor::getDigis(const CSCWireDigiCollection* wiredc, const CSCDetId& id) {
0425   CSCWireDigiCollection::Range rwired = wiredc->get(id);
0426   for (CSCWireDigiCollection::const_iterator digiIt = rwired.first; digiIt != rwired.second; ++digiIt) {
0427     digiV[id.layer() - 1].push_back(*digiIt);
0428   }
0429 }
0430 
0431 void CSCAnodeLCTProcessor::readWireDigis(
0432     std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS]) {
0433   // Loop over all 6 layers.
0434   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0435     // Loop over all digis in the layer and find the wireGroup and bx
0436     // time for each.
0437     for (const auto& wd : digiV[i_layer]) {
0438       int i_wire = wd.getWireGroup() - 1;
0439       std::vector<int> bx_times = wd.getTimeBinsOn();
0440 
0441       // Check that the wires and times are appropriate.
0442       if (i_wire < 0 || i_wire >= numWireGroups) {
0443         if (infoV >= 0)
0444           edm::LogWarning("CSCAnodeLCTProcessor|WrongInput")
0445               << "+++ Found wire digi with wrong wire number = " << i_wire << " (max wires = " << numWireGroups
0446               << "); skipping it... +++\n";
0447         continue;
0448       }
0449       // Accept digis in expected time window.  Total number of time
0450       // bins in DAQ readout is given by fifo_tbins, which thus
0451       // determines the maximum length of time interval.  Anode raw
0452       // hits in DAQ readout start (fifo_pretrig - 6) clocks before
0453       // L1Accept.  If times earlier than L1Accept were recorded, we
0454       // use them since they can modify the ALCTs found later, via
0455       // ghost-cancellation logic.
0456       int last_time = -999;
0457       if (bx_times.size() == fifo_tbins) {
0458         wire[i_layer][i_wire].push_back(0);
0459         wire[i_layer][i_wire].push_back(6);
0460       } else {
0461         for (unsigned int i = 0; i < bx_times.size(); i++) {
0462           // Find rising edge change
0463           if (i > 0 && bx_times[i] == (bx_times[i - 1] + 1))
0464             continue;
0465           if (bx_times[i] < static_cast<int>(fifo_tbins)) {
0466             if (infoV > 2)
0467               LogTrace("CSCAnodeLCTProcessor")
0468                   << "Digi on layer " << i_layer << " wire " << i_wire << " at time " << bx_times[i];
0469 
0470             // Finally save times of hit wires.  One shot module will
0471             // not restart if a new pulse comes before the expiration
0472             // of the 6-bx period.
0473             if (last_time < 0 || ((bx_times[i] - last_time) >= 6)) {
0474               wire[i_layer][i_wire].push_back(bx_times[i]);
0475               last_time = bx_times[i];
0476             }
0477           } else {
0478             if (infoV > 1)
0479               LogTrace("CSCAnodeLCTProcessor") << "+++ Skipping wire digi: wire = " << i_wire << " layer = " << i_layer
0480                                                << ", bx = " << bx_times[i] << " +++";
0481           }
0482         }
0483       }
0484     }
0485   }
0486 }
0487 
0488 bool CSCAnodeLCTProcessor::pulseExtension(
0489     const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS]) {
0490   bool chamber_empty = true;
0491   int i_wire, i_layer, digi_num;
0492 
0493   const unsigned bits_in_pulse = pulse_.bitsInPulse();
0494 
0495   // Clear pulse array.  This array will be used as a bit representation of
0496   // hit times.  For example: if strip[1][2] has a value of 3, then 1 shifted
0497   // left 3 will be bit pattern of pulse[1][2].  This would make the pattern
0498   // look like 0000000000001000.  Then add on additional bits to signify
0499   // the duration of a signal (hit_persist, formerly bx_width) to simulate
0500   // the TMB's drift delay.  So for the same pulse[1][2] with a hit_persist
0501   // of 3 would look like 0000000000111000.  This is similating the digital
0502   // one-shot in the TMB.
0503   pulse_.clear();
0504 
0505   for (i_wire = 0; i_wire < numWireGroups; i_wire++) {
0506     first_bx[i_wire] = -999;
0507     first_bx_corrected[i_wire] = -999;
0508     for (int j = 0; j < 3; j++)
0509       quality[i_wire][j] = -999;
0510   }
0511 
0512   for (i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0513     digi_num = 0;
0514     for (i_wire = 0; i_wire < numWireGroups; i_wire++) {
0515       if (!wire[i_layer][i_wire].empty()) {
0516         std::vector<int> bx_times = wire[i_layer][i_wire];
0517         for (unsigned int i = 0; i < bx_times.size(); i++) {
0518           // Check that min and max times are within the allowed range.
0519           if (bx_times[i] < 0 || bx_times[i] + hit_persist >= bits_in_pulse) {
0520             if (infoV > 0)
0521               edm::LogWarning("CSCAnodeLCTProcessor|OutOfTimeDigi")
0522                   << "+++ BX time of wire digi (wire = " << i_wire << " layer = " << i_layer << ") bx = " << bx_times[i]
0523                   << " is not within the range (0-" << bits_in_pulse
0524                   << "] allowed for pulse extension.  Skip this digi! +++\n";
0525             continue;
0526           }
0527 
0528           // Found at least one in-time digi; set chamber_empty to false
0529           if (chamber_empty)
0530             chamber_empty = false;
0531 
0532           // make the pulse
0533           pulse_.extend(i_layer, i_wire, bx_times[i], hit_persist);
0534 
0535           // Debug information.
0536           if (infoV > 1) {
0537             LogTrace("CSCAnodeLCTProcessor") << "Wire digi: layer " << i_layer << " digi #" << ++digi_num
0538                                              << " wire group " << i_wire << " time " << bx_times[i];
0539             if (infoV > 2) {
0540               std::ostringstream strstrm;
0541               for (int i = 1; i <= 32; i++) {
0542                 strstrm << pulse_.oneShotAtBX(i_layer, i_wire, 32 - i);
0543               }
0544               LogTrace("CSCAnodeLCTProcessor") << "  Pulse: " << strstrm.str();
0545             }
0546           }
0547         }
0548       }
0549     }
0550   }
0551 
0552   if (infoV > 1 && !chamber_empty) {
0553     dumpDigis(wire);
0554   }
0555 
0556   return chamber_empty;
0557 }
0558 
0559 bool CSCAnodeLCTProcessor::preTrigger(const int key_wire, const int start_bx) {
0560   int nPreTriggers = 0;
0561 
0562   unsigned int layers_hit;
0563   bool hit_layer[CSCConstants::NUM_LAYERS];
0564   int this_wire;
0565   // If nplanes_hit_accel_pretrig is 0, the firmware uses the value
0566   // of nplanes_hit_pretrig instead.
0567   const unsigned int nplanes_hit_pretrig_acc =
0568       (nplanes_hit_accel_pretrig != 0) ? nplanes_hit_accel_pretrig : nplanes_hit_pretrig;
0569   const unsigned int pretrig_thresh[CSCConstants::NUM_ALCT_PATTERNS] = {
0570       nplanes_hit_pretrig_acc, nplanes_hit_pretrig, nplanes_hit_pretrig};
0571 
0572   // Loop over bx times, accelerator and collision patterns to
0573   // look for pretrigger.
0574   // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
0575   // not have a full set of hits to start pattern search anyway.
0576   unsigned int stop_bx = fifo_tbins - drift_delay;
0577   for (unsigned int bx_time = start_bx; bx_time < stop_bx; bx_time++) {
0578     for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
0579       // initialize the hit layers
0580       for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++)
0581         hit_layer[i_layer] = false;
0582       layers_hit = 0;
0583 
0584       // now run over all layers and wires
0585       for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0586         for (int i_wire = 0; i_wire < CSCConstants::ALCT_PATTERN_WIDTH; i_wire++) {
0587           // check if the hit is valid
0588           if (alct_pattern_[i_pattern][i_layer][i_wire]) {
0589             this_wire = CSCPatternBank::alct_keywire_offset_[MESelection][i_wire] + key_wire;
0590             if ((this_wire >= 0) && (this_wire < numWireGroups)) {
0591               // Perform bit operation to see if pulse is 1 at a certain bx_time.
0592               if (pulse_.isOneShotHighAtBX(i_layer, this_wire, bx_time)) {
0593                 // Store number of layers hit.
0594                 if (!hit_layer[i_layer]) {
0595                   hit_layer[i_layer] = true;
0596                   layers_hit++;
0597                 }
0598 
0599                 // See if number of layers hit is greater than or equal to
0600                 // pretrig_thresh.
0601                 if (layers_hit >= pretrig_thresh[i_pattern]) {
0602                   first_bx[key_wire] = bx_time;
0603                   if (infoV > 1) {
0604                     LogTrace("CSCAnodeLCTProcessor") << "Pretrigger was satisfied for wire: " << key_wire
0605                                                      << " pattern: " << i_pattern << " bx_time: " << bx_time;
0606                   }
0607                   // make a new pre-trigger
0608                   nPreTriggers++;
0609                   // make a new pre-trigger digi
0610                   // useful for calculating DAQ rates
0611                   thePreTriggerDigis.emplace_back(
0612                       CSCALCTPreTriggerDigi(1, layers_hit - 3, 0, 0, this_wire, bx_time, nPreTriggers));
0613                   return true;
0614                 }
0615               }
0616             }
0617           }
0618         }
0619       }
0620     }
0621   }
0622   // If the pretrigger was never satisfied, then return false.
0623   return false;
0624 }
0625 
0626 bool CSCAnodeLCTProcessor::patternDetection(
0627     const int key_wire, std::map<int, std::map<int, CSCALCTDigi::WireContainer>>& hits_in_patterns) {
0628   bool trigger = false;
0629   bool hit_layer[CSCConstants::NUM_LAYERS];
0630   unsigned int temp_quality;
0631   int this_wire, delta_wire;
0632   // If nplanes_hit_accel_pattern is 0, the firmware uses the value
0633   // of nplanes_hit_pattern instead.
0634   const unsigned int nplanes_hit_pattern_acc =
0635       (nplanes_hit_accel_pattern != 0) ? nplanes_hit_accel_pattern : nplanes_hit_pattern;
0636   const unsigned int pattern_thresh[CSCConstants::NUM_ALCT_PATTERNS] = {
0637       nplanes_hit_pattern_acc, nplanes_hit_pattern, nplanes_hit_pattern};
0638   const std::string ptn_label[] = {"Accelerator", "CollisionA", "CollisionB"};
0639 
0640   for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
0641     temp_quality = 0;
0642 
0643     // initialize the hit layers
0644     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++)
0645       hit_layer[i_layer] = false;
0646 
0647     // clear a single pattern!
0648     CSCALCTDigi::WireContainer hits_single_pattern;
0649     hits_single_pattern.clear();
0650     hits_single_pattern.resize(CSCConstants::NUM_LAYERS);
0651     for (auto& p : hits_single_pattern) {
0652       p.resize(CSCConstants::ALCT_PATTERN_WIDTH, CSCConstants::INVALID_WIREGROUP);
0653     }
0654 
0655     double num_pattern_hits = 0., times_sum = 0.;
0656     std::multiset<int> mset_for_median;
0657     mset_for_median.clear();
0658 
0659     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
0660       for (int i_wire = 0; i_wire < CSCConstants::ALCT_PATTERN_WIDTH; i_wire++) {
0661         // check if the hit is valid
0662         if (alct_pattern_[i_pattern][i_layer][i_wire]) {
0663           delta_wire = CSCPatternBank::alct_keywire_offset_[MESelection][i_wire];
0664           this_wire = delta_wire + key_wire;
0665           if ((this_wire >= 0) && (this_wire < numWireGroups)) {
0666             // Wait a drift_delay time later and look for layers hit in
0667             // the pattern.
0668             if (pulse_.isOneShotHighAtBX(i_layer, this_wire, first_bx[key_wire] + drift_delay)) {
0669               // store hits in the temporary pattern vector
0670               hits_single_pattern[i_layer][i_wire] = this_wire;
0671 
0672               // If layer has never had a hit before, then increment number
0673               // of layer hits.
0674               if (!hit_layer[i_layer]) {
0675                 temp_quality++;
0676                 // keep track of which layers already had hits.
0677                 hit_layer[i_layer] = true;
0678                 if (infoV > 1)
0679                   LogTrace("CSCAnodeLCTProcessor")
0680                       << "bx_time: " << first_bx[key_wire] << " pattern: " << i_pattern << " keywire: " << key_wire
0681                       << " layer: " << i_layer << " quality: " << temp_quality;
0682               }
0683 
0684               // for averaged time use only the closest WGs around the key WG
0685               if (abs(delta_wire) < 2) {
0686                 // find at what bx did pulse on this wire&layer start
0687                 // use hit_pesrist constraint on how far back we can go
0688                 int first_bx_layer = first_bx[key_wire] + drift_delay;
0689                 for (unsigned int dbx = 0; dbx < hit_persist; dbx++) {
0690                   if (pulse_.isOneShotHighAtBX(i_layer, this_wire, first_bx_layer - 1)) {
0691                     first_bx_layer--;
0692                   } else
0693                     break;
0694                 }
0695                 times_sum += (double)first_bx_layer;
0696                 num_pattern_hits += 1.;
0697                 mset_for_median.insert(first_bx_layer);
0698                 if (infoV > 2)
0699                   LogTrace("CSCAnodeLCTProcessor") << " 1st bx in layer: " << first_bx_layer << " sum bx: " << times_sum
0700                                                    << " #pat. hits: " << num_pattern_hits;
0701               }
0702             }
0703           }
0704         }
0705       }
0706     }
0707 
0708     // calculate median
0709     const int sz = mset_for_median.size();
0710     if (sz > 0) {
0711       std::multiset<int>::iterator im = mset_for_median.begin();
0712       if (sz > 1)
0713         std::advance(im, sz / 2 - 1);
0714       if (sz == 1)
0715         first_bx_corrected[key_wire] = *im;
0716       else if ((sz % 2) == 1)
0717         first_bx_corrected[key_wire] = *(++im);
0718       else
0719         first_bx_corrected[key_wire] = ((*im) + (*(++im))) / 2;
0720 
0721 #if defined(EDM_ML_DEBUG)
0722       if (infoV > 1) {
0723         auto lt = LogTrace("CSCAnodeLCTProcessor")
0724                   << "bx=" << first_bx[key_wire] << " bx_cor=" << first_bx_corrected[key_wire] << "  bxset=";
0725         for (im = mset_for_median.begin(); im != mset_for_median.end(); im++) {
0726           lt << " " << *im;
0727         }
0728       }
0729 #endif
0730     }
0731 
0732     // save the pattern information when a trigger was formed!
0733     if (temp_quality >= pattern_thresh[i_pattern]) {
0734       trigger = true;
0735       hits_in_patterns[key_wire][i_pattern] = hits_single_pattern;
0736 
0737       // Quality definition changed on 22 June 2007: it no longer depends
0738       // on pattern_thresh.
0739       temp_quality = getTempALCTQuality(temp_quality);
0740 
0741       if (i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) {
0742         // Accelerator pattern
0743         quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] = temp_quality;
0744       } else {
0745         // Only one collision pattern (of the best quality) is reported
0746         if (static_cast<int>(temp_quality) > quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN]) {
0747           quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] = temp_quality;   //real quality
0748           quality[key_wire][CSCConstants::ALCT_COLLISIONB_PATTERN] = i_pattern - 1;  // pattern, left or right
0749         }
0750       }
0751       if (infoV > 1) {
0752         LogTrace("CSCAnodeLCTProcessor") << "Pattern found; keywire: " << key_wire << " type: " << ptn_label[i_pattern]
0753                                          << " quality: " << temp_quality << "\n";
0754       }
0755     }
0756   }
0757   if (infoV > 1 && quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
0758     if (quality[key_wire][CSCConstants::ALCT_COLLISIONB_PATTERN] == 0)
0759       LogTrace("CSCAnodeLCTProcessor") << "Collision Pattern A is chosen"
0760                                        << "\n";
0761     else if (quality[key_wire][CSCConstants::ALCT_COLLISIONB_PATTERN] == 1)
0762       LogTrace("CSCAnodeLCTProcessor") << "Collision Pattern B is chosen"
0763                                        << "\n";
0764   }
0765 
0766   trigMode(key_wire);
0767 
0768   return trigger;
0769 }
0770 
0771 void CSCAnodeLCTProcessor::ghostCancellationLogicOneWire(const int key_wire, int* ghost_cleared) {
0772   for (int i_pattern = 0; i_pattern < 2; i_pattern++) {
0773     ghost_cleared[i_pattern] = 0;
0774     if (key_wire == 0)
0775       continue;  //ignore
0776 
0777     // Non-empty wire group.
0778     int qual_this = quality[key_wire][i_pattern];
0779     if (qual_this > 0) {
0780       // Previous wire.
0781       //int qual_prev = (key_wire > 0) ? quality[key_wire-1][i_pattern] : 0;
0782       //previous ALCTs were pushed to lct_list, stop use the array quality[key_wire-1][i_pattern]
0783       for (auto& p : lct_list) {
0784         //ignore whether ALCT is valid or not in ghost cancellation
0785         //if wiregroup 10, 11, 12 all have trigger and same quality, only wiregroup 10 can keep the trigger
0786         //this met with firmware
0787         if (not(p.getKeyWG() == key_wire - 1 and 1 - p.getAccelerator() == i_pattern))
0788           continue;
0789 
0790         bool ghost_cleared_prev = false;
0791         int qual_prev = p.getQuality();
0792         int first_bx_prev = p.getBX();
0793         if (infoV > 1)
0794           LogTrace("CSCAnodeLCTProcessor")
0795               << "ghost concellation logic "
0796               << ((i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) ? "Accelerator" : "Collision") << " key_wire "
0797               << key_wire << " quality " << qual_this << " bx " << first_bx[key_wire] << " previous key_wire "
0798               << key_wire - 1 << " quality " << qual_prev << " bx " << first_bx[key_wire - 1];
0799 
0800         //int dt = first_bx[key_wire] - first_bx[key_wire-1];
0801         int dt = first_bx[key_wire] - first_bx_prev;
0802         // Cancel this wire
0803         //   1) If the candidate at the previous wire is at the same bx
0804         //      clock and has better quality (or equal quality - this has
0805         //      been implemented only in 2004).
0806         //   2) If the candidate at the previous wire is up to 4 clocks
0807         //      earlier, regardless of quality.
0808         if (dt == 0) {
0809           if (qual_prev >= qual_this)
0810             ghost_cleared[i_pattern] = 1;
0811           else if (qual_prev < qual_this)
0812             ghost_cleared_prev = true;
0813         } else if (dt > 0 && dt <= ghost_cancellation_bx_depth) {
0814           if ((!ghost_cancellation_side_quality) || (qual_prev > qual_this))
0815             ghost_cleared[i_pattern] = 1;
0816         } else if (dt < 0 && dt * (-1) <= ghost_cancellation_bx_depth) {
0817           if ((!ghost_cancellation_side_quality) || (qual_prev < qual_this))
0818             ghost_cleared_prev = true;
0819         }
0820 
0821         if (ghost_cleared[i_pattern] == 1) {
0822           if (infoV > 1)
0823             LogTrace("CSCAnodeLCTProcessor")
0824                 << ((i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) ? "Accelerator" : "Collision")
0825                 << " pattern ghost cancelled on key_wire " << key_wire << " q=" << qual_this << "  by wire "
0826                 << key_wire - 1 << " q=" << qual_prev;
0827           //cancellation for key_wire is done when ALCT is created and pushed to lct_list
0828         }
0829 
0830         if (ghost_cleared_prev) {
0831           if (infoV > 1)
0832             LogTrace("CSCAnodeLCTProcessor")
0833                 << ((i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) ? "Accelerator" : "Collision")
0834                 << " pattern ghost cancelled on key_wire " << key_wire - 1 << " q=" << qual_prev << "  by wire "
0835                 << key_wire << " q=" << qual_this;
0836           p.setValid(0);  //clean prev ALCT
0837         }
0838       }
0839 
0840     }  // if qual_this > 0
0841   }    //i_pattern
0842 }
0843 
0844 void CSCAnodeLCTProcessor::lctSearch() {
0845   // Best track selector selects two collision and two accelerator ALCTs
0846   // with the best quality per time bin.
0847   const std::vector<CSCALCTDigi>& fourBest = bestTrackSelector(lct_list);
0848 
0849   if (infoV > 0) {
0850     int n_alct_all = 0, n_alct = 0;
0851     for (const auto& p : lct_list) {
0852       if (p.isValid() && p.getBX() == CSCConstants::LCT_CENTRAL_BX)
0853         n_alct_all++;
0854     }
0855     for (const auto& p : fourBest) {
0856       if (p.isValid() && p.getBX() == CSCConstants::LCT_CENTRAL_BX)
0857         n_alct++;
0858     }
0859 
0860     LogTrace("CSCAnodeLCTProcessor") << "alct_count E:" << theEndcap << "S:" << theStation << "R:" << theRing
0861                                      << "C:" << theChamber << "  all " << n_alct_all << "  found " << n_alct;
0862   }
0863 
0864   // Select two best of four per time bin, based on quality and
0865   // accel_mode parameter.
0866   for (const auto& p : fourBest) {
0867     const int bx = p.getBX();
0868     if (bx >= CSCConstants::MAX_ALCT_TBINS) {
0869       if (infoV > 0)
0870         edm::LogWarning("CSCAnodeLCTProcessor|OutOfTimeALCT")
0871             << "+++ Bx of ALCT candidate, " << bx << ", exceeds max allowed, " << CSCConstants::MAX_ALCT_TBINS - 1
0872             << "; skipping it... +++\n";
0873       continue;
0874     }
0875 
0876     if (isBetterALCT(p, bestALCT[bx])) {
0877       if (isBetterALCT(bestALCT[bx], secondALCT[bx])) {
0878         secondALCT[bx] = bestALCT[bx];
0879       }
0880       bestALCT[bx] = p;
0881     } else if (isBetterALCT(p, secondALCT[bx])) {
0882       secondALCT[bx] = p;
0883     }
0884   }
0885 
0886   for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
0887     if (bestALCT[bx].isValid()) {
0888       bestALCT[bx].setTrknmb(1);
0889 
0890       // check if the best ALCT is valid
0891       qualityControl_->checkValidReadout(bestALCT[bx]);
0892 
0893       if (infoV > 0) {
0894         LogDebug("CSCAnodeLCTProcessor") << bestALCT[bx] << " fullBX = " << bestALCT[bx].getFullBX() << " found in "
0895                                          << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector
0896                                          << " trig id. " << theTrigChamber << ")"
0897                                          << "\n";
0898       }
0899       if (secondALCT[bx].isValid()) {
0900         secondALCT[bx].setTrknmb(2);
0901 
0902         // check if the second best ALCT is valid
0903         qualityControl_->checkValidReadout(secondALCT[bx]);
0904 
0905         if (infoV > 0) {
0906           LogDebug("CSCAnodeLCTProcessor")
0907               << secondALCT[bx] << " fullBX = " << secondALCT[bx].getFullBX() << " found in " << theCSCName_
0908               << " (sector " << theSector << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
0909               << "\n";
0910         }
0911       }
0912     }
0913   }
0914 }
0915 
0916 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::bestTrackSelector(const std::vector<CSCALCTDigi>& all_alcts) {
0917   CSCALCTDigi bestALCTs[CSCConstants::MAX_ALCT_TBINS][CSCConstants::MAX_ALCTS_PER_PROCESSOR];
0918   CSCALCTDigi secondALCTs[CSCConstants::MAX_ALCT_TBINS][CSCConstants::MAX_ALCTS_PER_PROCESSOR];
0919 
0920   if (infoV > 1) {
0921     LogTrace("CSCAnodeLCTProcessor") << all_alcts.size() << " ALCTs at the input of best-track selector: ";
0922     for (const auto& p : all_alcts) {
0923       if (!p.isValid())
0924         continue;
0925       LogTrace("CSCAnodeLCTProcessor") << p;
0926     }
0927   }
0928 
0929   CSCALCTDigi tA[CSCConstants::MAX_ALCT_TBINS][CSCConstants::MAX_ALCTS_PER_PROCESSOR];
0930   CSCALCTDigi tB[CSCConstants::MAX_ALCT_TBINS][CSCConstants::MAX_ALCTS_PER_PROCESSOR];
0931   for (const auto& p : all_alcts) {
0932     if (!p.isValid())
0933       continue;
0934 
0935     // Select two collision and two accelerator ALCTs with the highest
0936     // quality at every bx.  The search for best ALCTs is done in parallel
0937     // for collision and accelerator patterns, and simultaneously for
0938     // two ALCTs, tA and tB.  If two or more ALCTs have equal qualities,
0939     // the priority is given to the ALCT with larger wiregroup number
0940     // in the search for tA (collision and accelerator), and to the ALCT
0941     // with smaller wiregroup number in the search for tB.
0942     int bx = p.getBX();
0943     int accel = p.getAccelerator();
0944     int qual = p.getQuality();
0945     int wire = p.getKeyWG();
0946     bool vA = tA[bx][accel].isValid();
0947     bool vB = tB[bx][accel].isValid();
0948     int qA = tA[bx][accel].getQuality();
0949     int qB = tB[bx][accel].getQuality();
0950     int wA = tA[bx][accel].getKeyWG();
0951     int wB = tB[bx][accel].getKeyWG();
0952     if (!vA || qual > qA || (qual == qA && wire > wA)) {
0953       tA[bx][accel] = p;
0954     }
0955     if (!vB || qual > qB || (qual == qB && wire < wB)) {
0956       tB[bx][accel] = p;
0957     }
0958   }
0959 
0960   for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
0961     for (int accel = 0; accel <= 1; accel++) {
0962       // Best ALCT is always tA.
0963       if (tA[bx][accel].isValid()) {
0964         if (infoV > 2) {
0965           LogTrace("CSCAnodeLCTProcessor") << "tA: " << tA[bx][accel];
0966           LogTrace("CSCAnodeLCTProcessor") << "tB: " << tB[bx][accel];
0967         }
0968         bestALCTs[bx][accel] = tA[bx][accel];
0969 
0970         // If tA exists, tB exists too.
0971         if (tA[bx][accel] != tB[bx][accel] && tA[bx][accel].getQuality() == tB[bx][accel].getQuality()) {
0972           secondALCTs[bx][accel] = tB[bx][accel];
0973         } else {
0974           // Funny part: if tA and tB are the same, or the quality of tB
0975           // is inferior to the quality of tA, the second best ALCT is
0976           // not tB.  Instead it is the largest-wiregroup ALCT among those
0977           // ALCT whose qualities are lower than the quality of the best one.
0978           for (const auto& p : all_alcts) {
0979             if (p.isValid() && p.getAccelerator() == accel && p.getBX() == bx &&
0980                 p.getQuality() < bestALCTs[bx][accel].getQuality() &&
0981                 p.getQuality() >= secondALCTs[bx][accel].getQuality() &&
0982                 p.getKeyWG() >= secondALCTs[bx][accel].getKeyWG()) {
0983               secondALCTs[bx][accel] = p;
0984             }
0985           }
0986         }
0987       }
0988     }
0989   }
0990 
0991   // Fill the vector with up to four best ALCTs per bx and return it.
0992   std::vector<CSCALCTDigi> fourBest;
0993   for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
0994     for (int i = 0; i < CSCConstants::MAX_ALCTS_PER_PROCESSOR; i++) {
0995       if (bestALCTs[bx][i].isValid()) {
0996         fourBest.push_back(bestALCTs[bx][i]);
0997       }
0998     }
0999     for (int i = 0; i < CSCConstants::MAX_ALCTS_PER_PROCESSOR; i++) {
1000       if (secondALCTs[bx][i].isValid()) {
1001         fourBest.push_back(secondALCTs[bx][i]);
1002       }
1003     }
1004   }
1005 
1006   if (infoV > 1) {
1007     LogTrace("CSCAnodeLCTProcessor") << fourBest.size() << " ALCTs selected: ";
1008     for (const auto& p : fourBest) {
1009       LogTrace("CSCAnodeLCTProcessor") << p;
1010     }
1011   }
1012 
1013   return fourBest;
1014 }
1015 
1016 bool CSCAnodeLCTProcessor::isBetterALCT(const CSCALCTDigi& lhsALCT, const CSCALCTDigi& rhsALCT) const {
1017   bool returnValue = false;
1018 
1019   if (lhsALCT.isValid() && !rhsALCT.isValid()) {
1020     return true;
1021   }
1022 
1023   // ALCTs found at earlier bx times are ranked higher than ALCTs found at
1024   // later bx times regardless of the quality.
1025   if (lhsALCT.getBX() < rhsALCT.getBX()) {
1026     returnValue = true;
1027   }
1028   if (lhsALCT.getBX() != rhsALCT.getBX()) {
1029     return returnValue;
1030   }
1031 
1032   // First check the quality of ALCTs.
1033   const int qual1 = lhsALCT.getQuality();
1034   const int qual2 = rhsALCT.getQuality();
1035   if (qual1 > qual2) {
1036     returnValue = true;
1037   }
1038   // If qualities are the same, check accelerator bits of both ALCTs.
1039   // If they are not the same, rank according to accel_mode value.
1040   // If they are the same, keep the track selector assignment.
1041   //else if (qual1 == qual2 &&
1042   //         lhsALCT.getAccelerator() != rhsALCT.getAccelerator() &&
1043   //         quality[lhsALCT.getKeyWG()][1-lhsALCT.getAccelerator()] >
1044   //         quality[rhsALCT.getKeyWG()][1-rhsALCT.getAccelerator()])
1045   //  {returnValue = true;}
1046   else if (qual1 == qual2 && lhsALCT.getAccelerator() != rhsALCT.getAccelerator()) {
1047     if ((accel_mode == 0 || accel_mode == 1) && rhsALCT.getAccelerator() == 0)
1048       returnValue = true;
1049     if ((accel_mode == 2 || accel_mode == 3) && lhsALCT.getAccelerator() == 0)
1050       returnValue = true;
1051   }
1052 
1053   return returnValue;
1054 }
1055 
1056 void CSCAnodeLCTProcessor::trigMode(const int key_wire) {
1057   switch (trig_mode) {
1058     default:
1059     case 0:
1060       // Enables both collision and accelerator tracks
1061       break;
1062     case 1:
1063       // Disables collision tracks
1064       if (quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1065         quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] = 0;
1066         if (infoV > 1)
1067           LogTrace("CSCAnodeLCTProcessor") << "trigMode(): collision track " << key_wire << " disabled"
1068                                            << "\n";
1069       }
1070       break;
1071     case 2:
1072       // Disables accelerator tracks
1073       if (quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] > 0) {
1074         quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] = 0;
1075         if (infoV > 1)
1076           LogTrace("CSCAnodeLCTProcessor") << "trigMode(): accelerator track " << key_wire << " disabled"
1077                                            << "\n";
1078       }
1079       break;
1080     case 3:
1081       // Disables collision track if there is an accelerator track found
1082       // in the same wire group at the same time
1083       if (quality[key_wire][0] > 0 && quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1084         quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] = 0;
1085         if (infoV > 1)
1086           LogTrace("CSCAnodeLCTProcessor") << "trigMode(): collision track " << key_wire << " disabled"
1087                                            << "\n";
1088       }
1089       break;
1090   }
1091 }
1092 
1093 void CSCAnodeLCTProcessor::accelMode(const int key_wire) {
1094   int promotionBit = 1 << 2;
1095 
1096   switch (accel_mode) {
1097     default:
1098     case 0:
1099       // Ignore accelerator muons.
1100       if (quality[key_wire][0] > 0) {
1101         quality[key_wire][0] = 0;
1102         if (infoV > 1)
1103           LogTrace("CSCAnodeLCTProcessor") << "alctMode(): accelerator track " << key_wire << " ignored"
1104                                            << "\n";
1105       }
1106       break;
1107     case 1:
1108       // Prefer collision muons by adding promotion bit.
1109       if (quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1110         quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] += promotionBit;
1111         if (infoV > 1)
1112           LogTrace("CSCAnodeLCTProcessor") << "alctMode(): collision track " << key_wire << " promoted"
1113                                            << "\n";
1114       }
1115       break;
1116     case 2:
1117       // Prefer accelerator muons by adding promotion bit.
1118       if (quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] > 0) {
1119         quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] += promotionBit;
1120         if (infoV > 1)
1121           LogTrace("CSCAnodeLCTProcessor") << "alctMode(): accelerator track " << key_wire << " promoted"
1122                                            << "\n";
1123       }
1124       break;
1125     case 3:
1126       // Ignore collision muons.
1127       if (quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1128         quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] = 0;
1129         if (infoV > 1)
1130           LogTrace("CSCAnodeLCTProcessor") << "alctMode(): collision track " << key_wire << " ignored"
1131                                            << "\n";
1132       }
1133       break;
1134   }
1135 }
1136 
1137 // Dump of configuration parameters.
1138 void CSCAnodeLCTProcessor::dumpConfigParams() const {
1139   std::ostringstream strm;
1140   strm << "\n";
1141   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1142   strm << "+                  ALCT configuration parameters:                  +\n";
1143   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1144   strm << " fifo_tbins   [total number of time bins in DAQ readout] = " << fifo_tbins << "\n";
1145   strm << " fifo_pretrig [start time of anode raw hits in DAQ readout] = " << fifo_pretrig << "\n";
1146   strm << " drift_delay  [drift delay after pre-trigger, in 25 ns bins] = " << drift_delay << "\n";
1147   strm << " nplanes_hit_pretrig [min. number of layers hit for pre-trigger] = " << nplanes_hit_pretrig << "\n";
1148   strm << " nplanes_hit_pattern [min. number of layers hit for trigger] = " << nplanes_hit_pattern << "\n";
1149   strm << " nplanes_hit_accel_pretrig [min. number of layers hit for accel."
1150        << " pre-trig.] = " << nplanes_hit_accel_pretrig << "\n";
1151   strm << " nplanes_hit_accel_pattern [min. number of layers hit for accel."
1152        << " trigger] = " << nplanes_hit_accel_pattern << "\n";
1153   strm << " trig_mode  [enabling/disabling collision/accelerator tracks] = " << trig_mode << "\n";
1154   strm << " accel_mode [preference to collision/accelerator tracks] = " << accel_mode << "\n";
1155   strm << " l1a_window_width [L1Accept window width, in 25 ns bins] = " << l1a_window_width << "\n";
1156   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1157   LogDebug("CSCAnodeLCTProcessor") << strm.str();
1158 }
1159 
1160 // Dump of digis on wire groups.
1161 void CSCAnodeLCTProcessor::dumpDigis(
1162     const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS]) const {
1163   LogDebug("CSCAnodeLCTProcessor") << theCSCName_ << " nWiregroups " << numWireGroups;
1164 
1165   std::ostringstream strstrm;
1166   for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
1167     if (i_wire % 10 == 0) {
1168       if (i_wire < 100)
1169         strstrm << i_wire / 10;
1170       else
1171         strstrm << (i_wire - 100) / 10;
1172     } else
1173       strstrm << " ";
1174   }
1175   strstrm << "\n";
1176   for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
1177     strstrm << i_wire % 10;
1178   }
1179   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1180     strstrm << "\n";
1181     for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
1182       if (!wire[i_layer][i_wire].empty()) {
1183         std::vector<int> bx_times = wire[i_layer][i_wire];
1184         strstrm << std::hex << bx_times[0] << std::dec;
1185       } else {
1186         strstrm << ".";
1187       }
1188     }
1189   }
1190   LogTrace("CSCAnodeLCTProcessor") << strstrm.str();
1191 }
1192 
1193 // Returns vector of read-out ALCTs, if any.  Starts with the vector of
1194 // all found ALCTs and selects the ones in the read-out time window.
1195 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::readoutALCTs() const {
1196   std::vector<CSCALCTDigi> tmpV;
1197 
1198   // The number of LCT bins in the read-out is given by the
1199   // l1a_window_width parameter, but made even by setting the LSB of
1200   // l1a_window_width to 0.
1201   const int lct_bins = l1a_window_width;
1202   static std::atomic<int> late_tbins{early_tbins + lct_bins};
1203 
1204   static std::atomic<int> ifois{0};
1205   if (ifois == 0) {
1206     if (infoV >= 0 && early_tbins < 0) {
1207       edm::LogWarning("CSCAnodeLCTProcessor|SuspiciousParameters")
1208           << "+++ fifo_pretrig = " << fifo_pretrig << "; in-time ALCTs are not getting read-out!!! +++"
1209           << "\n";
1210     }
1211 
1212     if (late_tbins > CSCConstants::MAX_ALCT_TBINS - 1) {
1213       if (infoV >= 0)
1214         edm::LogWarning("CSCAnodeLCTProcessor|SuspiciousParameters")
1215             << "+++ Allowed range of time bins, [0-" << late_tbins << "] exceeds max allowed, "
1216             << CSCConstants::MAX_ALCT_TBINS - 1 << " +++\n"
1217             << "+++ Set late_tbins to max allowed +++\n";
1218       late_tbins = CSCConstants::MAX_ALCT_TBINS - 1;
1219     }
1220     ifois = 1;
1221   }
1222 
1223   // Start from the vector of all found ALCTs and select those within
1224   // the ALCT*L1A coincidence window.
1225   const std::vector<CSCALCTDigi>& all_alcts = getALCTs();
1226   for (const auto& p : all_alcts) {
1227     if (!p.isValid())
1228       continue;
1229 
1230     int bx = p.getBX();
1231     // Skip ALCTs found too early relative to L1Accept.
1232     if (bx <= early_tbins) {
1233       if (infoV > 1)
1234         LogDebug("CSCAnodeLCTProcessor") << " Do not report ALCT on keywire " << p.getKeyWG() << ": found at bx " << bx
1235                                          << ", whereas the earliest allowed bx is " << early_tbins + 1;
1236       continue;
1237     }
1238 
1239     // Skip ALCTs found too late relative to L1Accept.
1240     if (bx > late_tbins) {
1241       if (infoV > 1)
1242         LogDebug("CSCAnodeLCTProcessor") << " Do not report ALCT on keywire " << p.getKeyWG() << ": found at bx " << bx
1243                                          << ", whereas the latest allowed bx is " << late_tbins;
1244       continue;
1245     }
1246 
1247     tmpV.push_back(p);
1248   }
1249 
1250   // shift the BX from 8 to 3
1251   // ALCTs in real data have the central BX in bin 3
1252   // which is the middle of the 7BX wide L1A window
1253   // ALCTs used in the TMB emulator have central BX at bin 8
1254   // but right before we put emulated ALCTs in the event, we shift the BX
1255   // by -5 to make sure they are compatible with real data ALCTs!
1256   for (auto& p : tmpV) {
1257     p.setBX(p.getBX() - (CSCConstants::LCT_CENTRAL_BX - l1a_window_width / 2));
1258   }
1259 
1260   // do a final check on the ALCTs in readout
1261   qualityControl_->checkMultiplicityBX(tmpV);
1262   for (const auto& alct : tmpV) {
1263     qualityControl_->checkValid(alct);
1264   }
1265 
1266   return tmpV;
1267 }
1268 
1269 // Returns vector of all found ALCTs, if any.  Used in ALCT-CLCT matching.
1270 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::getALCTs() const {
1271   std::vector<CSCALCTDigi> tmpV;
1272   for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
1273     if (bestALCT[bx].isValid())
1274       tmpV.push_back(bestALCT[bx]);
1275     if (secondALCT[bx].isValid())
1276       tmpV.push_back(secondALCT[bx]);
1277   }
1278   return tmpV;
1279 }
1280 
1281 CSCALCTDigi CSCAnodeLCTProcessor::getBestALCT(int bx) const {
1282   if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1283     return CSCALCTDigi();
1284   return bestALCT[bx];
1285 }
1286 
1287 CSCALCTDigi CSCAnodeLCTProcessor::getSecondALCT(int bx) const {
1288   if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1289     return CSCALCTDigi();
1290   return secondALCT[bx];
1291 }
1292 
1293 /** return vector of CSCShower digi **/
1294 std::vector<CSCShowerDigi> CSCAnodeLCTProcessor::getAllShower() const {
1295   std::vector<CSCShowerDigi> vshowers(anode_showers_, anode_showers_ + CSCConstants::MAX_ALCT_TBINS);
1296   return vshowers;
1297 };
1298 
1299 /** Returns shower bits */
1300 std::vector<CSCShowerDigi> CSCAnodeLCTProcessor::readoutShower() const {
1301   unsigned minBXdiff = 2 * l1a_window_width;  //impossible value
1302   unsigned minBX = 0;
1303   std::vector<CSCShowerDigi> showerOut;
1304   for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++) {
1305     unsigned bx_diff = (bx > bx - CSCConstants::LCT_CENTRAL_BX) ? bx - CSCConstants::LCT_CENTRAL_BX
1306                                                                 : CSCConstants::LCT_CENTRAL_BX - bx;
1307     if (anode_showers_[bx].isValid() and bx_diff < minBXdiff) {
1308       minBXdiff = bx_diff;
1309       minBX = bx;
1310     }
1311   }
1312 
1313   for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++)
1314     if (bx == minBX)
1315       showerOut.push_back(anode_showers_[bx]);
1316   return showerOut;
1317 }
1318 
1319 ////////////////////////////////////////////////////////////////////////
1320 ////////////////////////////Test Routines///////////////////////////////
1321 
1322 void CSCAnodeLCTProcessor::showPatterns(const int key_wire) {
1323   /* Method to test the pretrigger */
1324   for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
1325     std::ostringstream strstrm_header;
1326     LogTrace("CSCAnodeLCTProcessor") << "\n"
1327                                      << "Pattern: " << i_pattern << " Key wire: " << key_wire;
1328     for (int i = 1; i <= 32; i++) {
1329       strstrm_header << ((32 - i) % 10);
1330     }
1331     LogTrace("CSCAnodeLCTProcessor") << strstrm_header.str();
1332     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1333       for (int i_wire = 0; i_wire < CSCConstants::ALCT_PATTERN_WIDTH; i_wire++) {
1334         // check if the hit is valid
1335         if (alct_pattern_[i_pattern][i_layer][i_wire]) {
1336           std::ostringstream strstrm_pulse;
1337           int this_wire = CSCPatternBank::alct_keywire_offset_[MESelection][i_wire] + key_wire;
1338           if (this_wire >= 0 && this_wire < numWireGroups) {
1339             for (int i = 1; i <= 32; i++) {
1340               strstrm_pulse << pulse_.oneShotAtBX(i_layer, this_wire, 32 - i);
1341             }
1342             LogTrace("CSCAnodeLCTProcessor") << strstrm_pulse.str() << " on layer " << i_layer << " wire " << this_wire;
1343           }
1344         }
1345       }
1346     }
1347     LogTrace("CSCAnodeLCTProcessor") << "-------------------------------------------";
1348   }
1349 }
1350 
1351 int CSCAnodeLCTProcessor::getTempALCTQuality(int temp_quality) const {
1352   int Q;
1353   if (temp_quality > 3)
1354     Q = temp_quality - 3;
1355   else
1356     Q = 0;  // quality code 0 is valid!
1357 
1358   return Q;
1359 }
1360 
1361 void CSCAnodeLCTProcessor::cleanWireContainer(CSCALCTDigi::WireContainer& wireHits) const {
1362   for (auto& p : wireHits) {
1363     p.erase(std::remove_if(p.begin(), p.end(), [](unsigned i) -> bool { return i == CSCConstants::INVALID_WIREGROUP; }),
1364             p.end());
1365   }
1366 }
1367 
1368 void CSCAnodeLCTProcessor::setWireContainer(CSCALCTDigi& alct, CSCALCTDigi::WireContainer& wireHits) const {
1369   // clean the wire digi container
1370   cleanWireContainer(wireHits);
1371 
1372   // set the hit container
1373   alct.setHits(wireHits);
1374 }
1375 
1376 void CSCAnodeLCTProcessor::encodeHighMultiplicityBits() {
1377   //numer of layer with hits and number of hits for 0-15 BXs
1378   std::set<unsigned> layersWithHits[CSCConstants::MAX_ALCT_TBINS];
1379   unsigned hitsInTime[CSCConstants::MAX_ALCT_TBINS];
1380   // Calculate layers with hits
1381   for (unsigned bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
1382     hitsInTime[bx] = 0;
1383     for (unsigned i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1384       bool atLeastOneWGHit = false;
1385       for (const auto& wd : digiV[i_layer]) {
1386         std::vector<int> bx_times = wd.getTimeBinsOn();
1387         // there is at least one wiregroup in this bx
1388         if (std::find(bx_times.begin(), bx_times.end(), bx) != bx_times.end()) {
1389           hitsInTime[bx] += 1;
1390           atLeastOneWGHit = true;
1391         }
1392       }
1393       // add this layer to the number of layers hit
1394       if (atLeastOneWGHit) {
1395         layersWithHits[bx].insert(i_layer);
1396       }
1397     }
1398   }  //end of full bx loop
1399 
1400   // convert station and ring number to index
1401   // index runs from 2 to 10, subtract 2
1402   unsigned csc_idx = CSCDetId::iChamberType(theStation, theRing) - 2;
1403 
1404   // loose, nominal and tight
1405   std::vector<unsigned> station_thresholds = {
1406       thresholds_[csc_idx * 3], thresholds_[csc_idx * 3 + 1], thresholds_[csc_idx * 3 + 2]};
1407 
1408   for (unsigned bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
1409     unsigned minbx = bx >= showerNumTBins_ / 2 ? bx - showerNumTBins_ / 2 : bx;
1410     unsigned maxbx = bx < CSCConstants::MAX_ALCT_TBINS - showerNumTBins_ / 2 ? bx + showerNumTBins_ / 2
1411                                                                              : CSCConstants::MAX_ALCT_TBINS - 1;
1412     unsigned this_hitsInTime = 0;
1413     for (unsigned mbx = minbx; mbx <= maxbx; mbx++) {
1414       this_hitsInTime += hitsInTime[mbx];
1415     }
1416 
1417     unsigned this_inTimeHMT = 0;
1418     // require at least nLayersWithHits for the central time bin
1419     // do nothing if there are not enough layers with hits
1420     if (layersWithHits[bx].size() >= minLayersCentralTBin_) {
1421       // assign the bits
1422       if (!station_thresholds.empty()) {
1423         for (int i = station_thresholds.size() - 1; i >= 0; i--) {
1424           if (this_hitsInTime >= station_thresholds[i]) {
1425             this_inTimeHMT = i + 1;
1426             break;
1427           }
1428         }
1429       }
1430     }
1431     //ALCT shower construction with showerType_=1, comparatorhits_= 0;
1432     anode_showers_[bx] = CSCShowerDigi(
1433         this_inTimeHMT, false, theTrigChamber, bx, CSCShowerDigi::ShowerType::kALCTShower, this_hitsInTime, 0);
1434   }
1435 }