Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-11-04 03:24:52

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