CMS 3D CMS Logo

CSCCathodeLCTProcessor.cc
Go to the documentation of this file.
2 
3 #include <iomanip>
4 #include <memory>
5 
6 // Default values of configuration parameters.
7 const unsigned int CSCCathodeLCTProcessor::def_fifo_tbins = 12;
8 const unsigned int CSCCathodeLCTProcessor::def_fifo_pretrig = 7;
9 const unsigned int CSCCathodeLCTProcessor::def_hit_persist = 6;
10 const unsigned int CSCCathodeLCTProcessor::def_drift_delay = 2;
14 const unsigned int CSCCathodeLCTProcessor::def_min_separation = 10;
16 
17 //----------------
18 // Constructors --
19 //----------------
20 
22  unsigned station,
23  unsigned sector,
24  unsigned subsector,
25  unsigned chamber,
27  : CSCBaseboard(endcap, station, sector, subsector, chamber, conf) {
28  static std::atomic<bool> config_dumped{false};
29 
30  // CLCT configuration parameters.
31  fifo_tbins = conf.clctParams().getParameter<unsigned int>("clctFifoTbins");
32  hit_persist = conf.clctParams().getParameter<unsigned int>("clctHitPersist");
33  drift_delay = conf.clctParams().getParameter<unsigned int>("clctDriftDelay");
34  nplanes_hit_pretrig = conf.clctParams().getParameter<unsigned int>("clctNplanesHitPretrig");
35  nplanes_hit_pattern = conf.clctParams().getParameter<unsigned int>("clctNplanesHitPattern");
36 
37  // Not used yet.
38  fifo_pretrig = conf.clctParams().getParameter<unsigned int>("clctFifoPretrig");
39 
40  pid_thresh_pretrig = conf.clctParams().getParameter<unsigned int>("clctPidThreshPretrig");
41  min_separation = conf.clctParams().getParameter<unsigned int>("clctMinSeparation");
42 
43  start_bx_shift = conf.clctParams().getParameter<int>("clctStartBxShift");
44 
45  localShowerZone = conf.clctParams().getParameter<int>("clctLocalShowerZone");
46 
47  localShowerThresh = conf.clctParams().getParameter<int>("clctLocalShowerThresh");
48 
49  // Motherboard parameters: common for all configurations.
50  tmb_l1a_window_size = // Common to CLCT and TMB
51  conf.tmbParams().getParameter<unsigned int>("tmbL1aWindowSize");
52 
53  /*
54  In Summer 2021 the CLCT readout function was updated so that the
55  window is based on a number of time bins around the central CLCT
56  time BX7. In the past the window was based on early_tbins and late_tbins.
57  The parameter is kept, but is not used.
58  */
59  early_tbins = conf.tmbParams().getParameter<int>("tmbEarlyTbins");
60  if (early_tbins < 0)
62 
63  // wether to readout only the earliest two LCTs in readout window
64  readout_earliest_2 = conf.tmbParams().getParameter<bool>("tmbReadoutEarliest2");
65 
66  // Verbosity level, set to 0 (no print) by default.
67  infoV = conf.clctParams().getParameter<int>("verbosity");
68 
69  // Do not exclude pattern 0 and 1 when the Run-3 patterns are enabled!!
70  // Valid Run-3 patterns are 0,1,2,3,4
71  if (runCCLUT_) {
73  }
74 
75  // Check and print configuration parameters.
77  if ((infoV > 0) && !config_dumped) {
79  config_dumped = true;
80  }
81 
82  numStrips_ = 0; // Will be set later.
83  // Provisional, but should be OK for all stations except ME1.
84  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
85  if ((i_layer + 1) % 2 == 0)
86  stagger[i_layer] = 0;
87  else
88  stagger[i_layer] = 1;
89  }
90 
92  ispretrig_[i] = false;
93  }
94 
95  // which patterns should we use?
96  if (runCCLUT_) {
98  // comparator code lookup table algorithm for Phase-2
99  cclut_ = std::make_unique<ComparatorCodeLUT>(conf.conf());
100  } else {
102  }
103 
104  const auto& shower = conf.showerParams().getParameterSet("cathodeShower");
105  thresholds_ = shower.getParameter<std::vector<unsigned>>("showerThresholds");
106  showerNumTBins_ = shower.getParameter<unsigned>("showerNumTBins");
107  minLayersCentralTBin_ = shower.getParameter<unsigned>("minLayersCentralTBin");
108  peakCheck_ = shower.getParameter<bool>("peakCheck");
112 
113  thePreTriggerDigis.clear();
114 
115  // quality control of stubs
116  qualityControl_ = std::make_unique<LCTQualityControl>(endcap, station, sector, subsector, chamber, conf);
117 }
118 
120  // Set default values for configuration parameters.
132 }
133 
134 // Set configuration parameters obtained via EventSetup mechanism.
136  static std::atomic<bool> config_dumped{false};
137 
138  fifo_tbins = conf->clctFifoTbins();
139  fifo_pretrig = conf->clctFifoPretrig();
140  hit_persist = conf->clctHitPersist();
141  drift_delay = conf->clctDriftDelay();
146 
147  // Check and print configuration parameters.
149  if (!config_dumped) {
151  config_dumped = true;
152  }
155 }
156 
157 void CSCCathodeLCTProcessor::setESLookupTables(const CSCL1TPLookupTableCCLUT* conf) { cclut_->setESLookupTables(conf); }
158 
160  // Make sure that the parameter values are within the allowed range.
161 
162  // Max expected values.
163  static const unsigned int max_fifo_tbins = 1 << 5;
164  static const unsigned int max_fifo_pretrig = 1 << 5;
165  static const unsigned int max_hit_persist = 1 << 4;
166  static const unsigned int max_drift_delay = 1 << 2;
167  static const unsigned int max_nplanes_hit_pretrig = 1 << 3;
168  static const unsigned int max_nplanes_hit_pattern = 1 << 3;
169  static const unsigned int max_pid_thresh_pretrig = 1 << 4;
170  static const unsigned int max_min_separation = CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER;
171  static const unsigned int max_tmb_l1a_window_size = 1 << 4;
172 
173  // Checks.
174  CSCBaseboard::checkConfigParameters(fifo_tbins, max_fifo_tbins, def_fifo_tbins, "fifo_tbins");
175  CSCBaseboard::checkConfigParameters(fifo_pretrig, max_fifo_pretrig, def_fifo_pretrig, "fifo_pretrig");
176  CSCBaseboard::checkConfigParameters(hit_persist, max_hit_persist, def_hit_persist, "hit_persist");
177  CSCBaseboard::checkConfigParameters(drift_delay, max_drift_delay, def_drift_delay, "drift_delay");
179  nplanes_hit_pretrig, max_nplanes_hit_pretrig, def_nplanes_hit_pretrig, "nplanes_hit_pretrig");
181  nplanes_hit_pattern, max_nplanes_hit_pattern, def_nplanes_hit_pattern, "nplanes_hit_pattern");
183  pid_thresh_pretrig, max_pid_thresh_pretrig, def_pid_thresh_pretrig, "pid_thresh_pretrig");
184  CSCBaseboard::checkConfigParameters(min_separation, max_min_separation, def_min_separation, "min_separation");
186  tmb_l1a_window_size, max_tmb_l1a_window_size, def_tmb_l1a_window_size, "tmb_l1a_window_size");
188 }
189 
191  thePreTriggerDigis.clear();
192  thePreTriggerBXs.clear();
193  for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
194  bestCLCT[bx].clear();
195  secondCLCT[bx].clear();
197  localShowerFlag[bx] = false; //init with no shower around CLCT
198  }
199 }
200 
201 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::run(const CSCComparatorDigiCollection* compdc) {
202  // This is the version of the run() function that is called when running
203  // over the entire detector. It gets the comparator & timing info from the
204  // comparator digis and then passes them on to another run() function.
205 
206  static std::atomic<bool> config_dumped{false};
207  if ((infoV > 0) && !config_dumped) {
209  config_dumped = true;
210  }
211 
212  // Get the number of strips and stagger of layers for the given chamber.
213  // Do it only once per chamber.
214  if (numStrips_ <= 0 or numStrips_ > CSCConstants::MAX_NUM_STRIPS_RUN2) {
215  if (cscChamber_) {
217 
218  // ME1/a is known to the readout hardware as strips 65-80 of ME1/1.
219  // Still need to decide whether we do any special adjustments to
220  // reconstruct LCTs in this region (3:1 ganged strips); for now, we
221  // simply allow for hits in ME1/a and apply standard reconstruction
222  // to them.
223  // For Phase2 ME1/1 is set to have 4 CFEBs in ME1/b and 3 CFEBs in ME1/a
224  if (isME11_) {
225  if (theRing == 4) {
226  edm::LogError("CSCCathodeLCTProcessor|SetupError")
227  << "+++ Invalid ring number for this processor " << theRing << " was set in the config."
228  << " +++\n"
229  << "+++ CSC geometry looks garbled; no emulation possible +++\n";
230  }
231  if (!disableME1a_ && theRing == 1 && !gangedME1a_)
233  if (!disableME1a_ && theRing == 1 && gangedME1a_)
235  if (disableME1a_ && theRing == 1)
237  }
238 
239  numHalfStrips_ = 2 * numStrips_ + 1;
241 
243  edm::LogError("CSCCathodeLCTProcessor|SetupError")
244  << "+++ Number of strips, " << numStrips_ << " found in " << theCSCName_ << " (sector " << theSector
245  << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
246  << " exceeds max expected, " << CSCConstants::MAX_NUM_STRIPS_RUN2 << " +++\n"
247  << "+++ CSC geometry looks garbled; no emulation possible +++\n";
248  numStrips_ = -1;
249  numHalfStrips_ = -1;
250  numCFEBs_ = -1;
251  }
252  // The strips for a given layer may be offset from the adjacent layers.
253  // This was done in order to improve resolution. We need to find the
254  // 'staggering' for each layer and make necessary conversions in our
255  // arrays. -JM
256  // In the TMB-07 firmware, half-strips in odd layers (layers are
257  // counted as ly0-ly5) are shifted by -1 half-strip, whereas in
258  // the previous firmware versions half-strips in even layers
259  // were shifted by +1 half-strip. This difference is due to a
260  // change from ly3 to ly2 in the choice of the key layer, and
261  // the intention to keep half-strips in the key layer unchanged.
262  // In the emulator, we use the old way for both cases, to avoid
263  // negative half-strip numbers. This will necessitate a
264  // subtraction of 1 half-strip for TMB-07 later on. -SV.
265  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
266  stagger[i_layer] = (cscChamber_->layer(i_layer + 1)->geometry()->stagger() + 1) / 2;
267  }
268  } else {
269  edm::LogError("CSCCathodeLCTProcessor|ConfigError")
270  << " " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
271  << theTrigChamber << ")"
272  << " is not defined in current geometry! +++\n"
273  << "+++ CSC geometry looks garbled; no emulation possible +++\n";
274  numStrips_ = -1;
275  numHalfStrips_ = -1;
276  numCFEBs_ = -1;
277  }
278  }
279 
280  if (numStrips_ <= 0 or 2 * (unsigned)numStrips_ > qualityControl_->get_csc_max_halfstrip(theStation, theRing)) {
281  edm::LogError("CSCCathodeLCTProcessor|ConfigError")
282  << " " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
283  << theTrigChamber << "):"
284  << " numStrips_ = " << numStrips_ << "; CLCT emulation skipped! +++";
285  std::vector<CSCCLCTDigi> emptyV;
286  return emptyV;
287  }
288 
289  // Get comparator digis in this chamber.
290  bool hasDigis = getDigis(compdc);
291 
292  if (hasDigis) {
293  // Get halfstrip times from comparator digis.
295  readComparatorDigis(halfStripTimes);
296 
297  // Pass arrays of halfstrips on to another run() doing the
298  // LCT search.
299  // If the number of layers containing digis is smaller than that
300  // required to trigger, quit right away. (If LCT-based digi suppression
301  // is implemented one day, this condition will have to be changed
302  // to the number of planes required to pre-trigger.)
303  unsigned int layersHit = 0;
304  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
305  for (int i_hstrip = 0; i_hstrip < CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER; i_hstrip++) {
306  if (!halfStripTimes[i_layer][i_hstrip].empty()) {
307  layersHit++;
308  break;
309  }
310  }
311  }
312  // Run the algorithm only if the probability for the pre-trigger
313  // to fire is not null. (Pre-trigger decisions are used for the
314  // strip read-out conditions in DigiToRaw.)
315  if (layersHit >= nplanes_hit_pretrig)
316  run(halfStripTimes);
317 
318  // Get the high multiplicity bits in this chamber
320  }
321 
322  // Return vector of CLCTs.
323  std::vector<CSCCLCTDigi> tmpV = getCLCTs();
324 
325  // shift the BX from 7 to 8
326  // the unpacked real data CLCTs have central BX at bin 7
327  // however in simulation the central BX is bin 8
328  // to make a proper comparison with ALCTs we need
329  // CLCT and ALCT to have the central BX in the same bin
330  // this shift does not affect the readout of the CLCTs
331  // emulated CLCTs put in the event should be centered at bin 7 (as in data)
332  for (auto& p : tmpV) {
333  p.setBX(p.getBX() + CSCConstants::ALCT_CLCT_OFFSET);
334  }
335 
336  return tmpV;
337 }
338 
341  // This version of the run() function can either be called in a standalone
342  // test, being passed the halfstrip times, or called by the
343  // run() function above. It uses the findLCTs() method to find vectors
344  // of LCT candidates. These candidates are already sorted and the best two per bx
345  // are returned.
346 
347  // initialize the pulse array.
348  // add 1 for possible stagger
350 
351  std::vector<CSCCLCTDigi> CLCTlist = findLCTs(halfstrip);
352 
353  for (const auto& p : CLCTlist) {
354  const int bx = p.getBX();
356  if (infoV > 0)
357  edm::LogWarning("L1CSCTPEmulatorOutOfTimeCLCT")
358  << "+++ Bx of CLCT candidate, " << bx << ", exceeds max allowed, " << CSCConstants::MAX_CLCT_TBINS - 1
359  << "; skipping it... +++\n";
360  continue;
361  }
362 
363  if (!bestCLCT[bx].isValid()) {
364  bestCLCT[bx] = p;
365  } else if (!secondCLCT[bx].isValid()) {
366  secondCLCT[bx] = p;
367  }
368  }
369 
370  for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
371  if (bestCLCT[bx].isValid()) {
372  bestCLCT[bx].setTrknmb(1);
373 
374  // check if the LCT is valid
375  qualityControl_->checkValid(bestCLCT[bx]);
376 
377  if (infoV > 0)
378  LogDebug("CSCCathodeLCTProcessor")
380  << " (sector " << theSector << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
381  << "\n";
382  }
383  if (secondCLCT[bx].isValid()) {
384  secondCLCT[bx].setTrknmb(2);
385 
386  // check if the LCT is valid
387  qualityControl_->checkValid(secondCLCT[bx]);
388 
389  if (infoV > 0)
390  LogDebug("CSCCathodeLCTProcessor")
392  << " (sector " << theSector << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
393  << "\n";
394  }
395  }
396  checkLocalShower(localShowerZone, halfstrip);
397  // Now that we have our best CLCTs, they get correlated with the best
398  // ALCTs and then get sent to the MotherBoard. -JM
399 }
400 
402  int zone,
404  // Fire half-strip one-shots for hit_persist bx's (4 bx's by default).
405  //check local shower after pulse extension
406  pulseExtension(halfstrip);
407 
408  for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
409  if (not bestCLCT[bx].isValid())
410  continue;
411 
412  //only check the region around best CLCT
413  int keyHS = bestCLCT[bx].getKeyStrip();
414  int minHS = (keyHS - zone) >= stagger[CSCConstants::KEY_CLCT_LAYER - 1] ? keyHS - zone
416  int maxHS = (keyHS + zone) >= numHalfStrips_ ? numHalfStrips_ : keyHS + zone;
417  int totalHits = 0;
418  for (int hstrip = minHS; hstrip < maxHS; hstrip++) {
419  for (int this_layer = 0; this_layer < CSCConstants::NUM_LAYERS; this_layer++)
420  if (pulse_.isOneShotHighAtBX(this_layer, hstrip, bx + drift_delay))
421  totalHits++;
422  }
423 
424  localShowerFlag[bx] = totalHits >= localShowerThresh;
425  if (infoV > 1)
426  LogDebug("CSCCathodeLCTProcessor") << " bx " << bx << " bestCLCT key HS " << keyHS
427  << " localshower zone: " << minHS << ", " << maxHS << " totalHits "
428  << totalHits
429  << (localShowerFlag[bx] ? " Validlocalshower " : " NolocalShower ");
430  }
431 }
432 
434  bool hasDigis = false;
435 
436  // Loop over layers and save comparator digis on each one into digiV[layer].
437  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
438  digiV[i_layer].clear();
439 
440  CSCDetId detid(theEndcap, theStation, theRing, theChamber, i_layer + 1);
441  getDigis(compdc, detid);
442 
443  if (isME11_ && !disableME1a_) {
444  CSCDetId detid_me1a(theEndcap, theStation, 4, theChamber, i_layer + 1);
445  getDigis(compdc, detid_me1a);
446  }
447 
448  if (!digiV[i_layer].empty()) {
449  hasDigis = true;
450  if (infoV > 1) {
451  LogTrace("CSCCathodeLCTProcessor") << "found " << digiV[i_layer].size() << " comparator digi(s) in layer "
452  << i_layer << " of " << detid.chamberName() << " (trig. sector " << theSector
453  << " subsector " << theSubsector << " id " << theTrigChamber << ")";
454  }
455  }
456  }
457 
458  return hasDigis;
459 }
460 
462  const bool me1a = (id.station() == 1) && (id.ring() == 4);
463  const CSCComparatorDigiCollection::Range rcompd = compdc->get(id);
464  for (CSCComparatorDigiCollection::const_iterator digiIt = rcompd.first; digiIt != rcompd.second; ++digiIt) {
465  const unsigned int origStrip = digiIt->getStrip();
466  const unsigned int maxStripsME1a =
468  // this special case can only be reached in MC
469  // in real data, the comparator digis have always ring==1
470  if (me1a && origStrip <= maxStripsME1a && !disableME1a_) {
471  // Move ME1/A comparators from CFEB=0 to CFEB=4 if this has not
472  // been done already.
473  CSCComparatorDigi digi_corr(
474  origStrip + CSCConstants::NUM_STRIPS_ME1B, digiIt->getComparator(), digiIt->getTimeBinWord());
475  digiV[id.layer() - 1].push_back(digi_corr);
476  } else {
477  digiV[id.layer() - 1].push_back(*digiIt);
478  }
479  }
480 }
481 
484  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
485  int i_digi = 0; // digi counter, for dumps.
486  for (std::vector<CSCComparatorDigi>::iterator pld = digiV[i_layer].begin(); pld != digiV[i_layer].end();
487  pld++, i_digi++) {
488  // Dump raw digi info.
489  if (infoV > 1) {
490  std::ostringstream strstrm;
491  strstrm << "Comparator digi: comparator = " << pld->getComparator() << " strip #" << pld->getStrip()
492  << " time bins on:";
493  std::vector<int> bx_times = pld->getTimeBinsOn();
494  for (unsigned int tbin = 0; tbin < bx_times.size(); tbin++)
495  strstrm << " " << bx_times[tbin];
496  LogTrace("CSCCathodeLCTProcessor") << strstrm.str();
497  }
498 
499  // Get comparator: 0/1 for left/right halfstrip for each comparator
500  // that fired.
501  int thisComparator = pld->getComparator();
502  if (thisComparator != 0 && thisComparator != 1) {
503  if (infoV >= 0)
504  edm::LogWarning("L1CSCTPEmulatorWrongInput")
505  << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
506  << " Found comparator digi with wrong comparator value = " << thisComparator << "; skipping it... +++\n";
507  continue;
508  }
509 
510  // Get strip number.
511  int thisStrip = pld->getStrip() - 1; // count from 0
512  if (thisStrip < 0 || thisStrip >= numStrips_) {
513  if (infoV >= 0)
514  edm::LogWarning("L1CSCTPEmulatorWrongInput")
515  << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
516  << " Found comparator digi with wrong strip number = " << thisStrip << " (max strips = " << numStrips_
517  << "); skipping it... +++\n";
518  continue;
519  }
520  // 2*strip: convert strip to 1/2 strip
521  // comp : comparator output
522  // stagger: stagger for this layer
523  int thisHalfstrip = 2 * thisStrip + thisComparator + stagger[i_layer];
524  if (thisHalfstrip >= numHalfStrips_) {
525  if (infoV >= 0)
526  edm::LogWarning("L1CSCTPEmulatorWrongInput")
527  << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
528  << " Found wrong halfstrip number = " << thisHalfstrip << "; skipping this digi... +++\n";
529  continue;
530  }
531 
532  // Get bx times on this digi and check that they are within the bounds.
533  std::vector<int> bx_times = pld->getTimeBinsOn();
534  for (unsigned int i = 0; i < bx_times.size(); i++) {
535  // Total number of time bins in DAQ readout is given by fifo_tbins,
536  // which thus determines the maximum length of time interval.
537  //
538  // In data, only the CLCT in the time bin that was matched with L1A are read out
539  // while comparator digi is read out by 12 time bin, which includes 12 time bin info
540  // in other word, CLCTs emulated from comparator digis usually showed the OTMB behavior in 12 time bin
541  // while CLCT from data only showed 1 time bin OTMB behavior
542  // the CLCT emulated from comparator digis usually is centering at time bin 7 (BX7) and
543  // it is definitly safe to ignore any CLCTs in bx 0 or 1 and those CLCTs will never impacts on any triggers
544  if (bx_times[i] > 1 && bx_times[i] < static_cast<int>(fifo_tbins)) {
545  if (i == 0 || (i > 0 && bx_times[i] - bx_times[i - 1] >= static_cast<int>(hit_persist))) {
546  // A later hit on the same strip is ignored during the
547  // number of clocks defined by the "hit_persist" parameter
548  // (i.e., 6 bx's by default).
549  if (infoV > 1)
550  LogTrace("CSCCathodeLCTProcessor")
551  << "Comp digi: layer " << i_layer + 1 << " digi #" << i_digi + 1 << " strip " << thisStrip
552  << " halfstrip " << thisHalfstrip << " time " << bx_times[i] << " comparator " << thisComparator
553  << " stagger " << stagger[i_layer];
554  halfstrip[i_layer][thisHalfstrip].push_back(bx_times[i]);
555  } else if (i > 0) {
556  if (infoV > 1)
557  LogTrace("CSCCathodeLCTProcessor")
558  << "+++ station " << theStation << " ring " << theRing << " chamber " << theChamber
559  << " Skipping comparator digi: strip = " << thisStrip << ", layer = " << i_layer + 1
560  << ", bx = " << bx_times[i] << ", bx of previous hit = " << bx_times[i - 1];
561  }
562  } else {
563  if (infoV > 1)
564  LogTrace("CSCCathodeLCTProcessor") << "+++ station " << theStation << " ring " << theRing << " chamber "
565  << theChamber << "+++ Skipping comparator digi: strip = " << thisStrip
566  << ", layer = " << i_layer + 1 << ", bx = " << bx_times[i] << " +++";
567  }
568  }
569  }
570  }
571 }
572 
573 // TMB-07 version.
574 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::findLCTs(
576  std::vector<CSCCLCTDigi> lctList;
577 
578  if (infoV > 1)
579  dumpDigis(halfstrip);
580 
581  // Fire half-strip one-shots for hit_persist bx's (4 bx's by default).
582  pulseExtension(halfstrip);
583 
584  unsigned int start_bx = start_bx_shift;
585  // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
586  // not have a full set of hits to start pattern search anyway.
587  unsigned int stop_bx = fifo_tbins - drift_delay;
588  // Allow for more than one pass over the hits in the time window.
589  while (start_bx < stop_bx) {
590  // temp CLCT objects
591  CSCCLCTDigi tempBestCLCT;
592  CSCCLCTDigi tempSecondCLCT;
593 
594  // All half-strip pattern envelopes are evaluated simultaneously, on every
595  // clock cycle.
596  int first_bx = 999;
597  bool pre_trig = preTrigger(start_bx, first_bx);
598 
599  // If any of half-strip envelopes has enough layers hit in it, TMB
600  // will pre-trigger.
601  if (pre_trig) {
602  thePreTriggerBXs.push_back(first_bx);
603  if (infoV > 1)
604  LogTrace("CSCCathodeLCTProcessor") << "..... pretrigger at bx = " << first_bx << "; waiting drift delay .....";
605 
606  // TMB latches LCTs drift_delay clocks after pretrigger.
607  // in the configuration the drift_delay is set to 2bx by default
608  // this is the time that is required for the electrons to drift to the
609  // cathode strips. 15ns drift time --> 45 ns is 3 sigma for the delay
610  // this corresponds to 2bx
611  int latch_bx = first_bx + drift_delay;
612 
613  // define a new pattern map
614  // for each key half strip, and for each pattern, store the 2D collection of fired comparator digis
615  std::map<int, std::map<int, CSCCLCTDigi::ComparatorContainer>> hits_in_patterns;
616  hits_in_patterns.clear();
617 
618  // We check if there is at least one key half strip for which at least
619  // one pattern id has at least the minimum number of hits
620  bool hits_in_time = patternFinding(latch_bx, hits_in_patterns);
621  if (infoV > 1) {
622  if (hits_in_time) {
623  for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
624  if (nhits[hstrip] > 0) {
625  LogTrace("CSCCathodeLCTProcessor")
626  << " bx = " << std::setw(2) << latch_bx << " --->"
627  << " halfstrip = " << std::setw(3) << hstrip << " best pid = " << std::setw(2) << best_pid[hstrip]
628  << " nhits = " << nhits[hstrip];
629  }
630  }
631  }
632  }
633  // This trigger emulator does not have an active CFEB flag for DAQ (csc trigger hardware: AFF)
634  // This is a fundamental difference with the firmware where the TMB prepares the DAQ to
635  // read out the chamber
636 
637  // The pattern finder runs continuously, so another pre-trigger
638  // could occur already at the next bx.
639 
640  // Quality for sorting.
642  int best_halfstrip[CSCConstants::MAX_CLCTS_PER_PROCESSOR];
643  int best_quality[CSCConstants::MAX_CLCTS_PER_PROCESSOR];
644 
645  for (int ilct = 0; ilct < CSCConstants::MAX_CLCTS_PER_PROCESSOR; ilct++) {
646  best_halfstrip[ilct] = -1;
647  best_quality[ilct] = 0;
648  }
649 
650  // Calculate quality from pattern id and number of hits, and
651  // simultaneously select best-quality LCT.
652  if (hits_in_time) {
653  for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
654  // The bend-direction bit pid[0] is ignored (left and right
655  // bends have equal quality).
656  quality[hstrip] = (best_pid[hstrip] & 14) | (nhits[hstrip] << 5);
657  if (quality[hstrip] > best_quality[0]) {
658  best_halfstrip[0] = hstrip;
659  best_quality[0] = quality[hstrip];
660  }
661  // temporary alias
662  const int best_hs(best_halfstrip[0]);
663  // construct a CLCT if the trigger condition has been met
664  if (best_hs >= 0 && nhits[best_hs] >= nplanes_hit_pattern) {
665  // overwrite the current best CLCT
666  tempBestCLCT = constructCLCT(first_bx, best_hs, hits_in_patterns[best_hs][best_pid[best_hs]]);
667  }
668  }
669  }
670 
671  // If 1st best CLCT is found, look for the 2nd best.
672  if (best_halfstrip[0] >= 0) {
673  // Get the half-strip of the best CLCT in this BX that was put into the list.
674  // You do need to re-add the any stagger, because the busy keys are based on
675  // the pulse array which takes into account strip stagger!!!
676  const unsigned halfStripBestCLCT(tempBestCLCT.getKeyStrip() + stagger[CSCConstants::KEY_CLCT_LAYER - 1]);
677 
678  // Mark keys near best CLCT as busy by setting their quality to
679  // zero, and repeat the search.
680  markBusyKeys(halfStripBestCLCT, best_pid[halfStripBestCLCT], quality);
681 
682  for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
683  if (quality[hstrip] > best_quality[1]) {
684  best_halfstrip[1] = hstrip;
685  best_quality[1] = quality[hstrip];
686  }
687  // temporary alias
688  const int best_hs(best_halfstrip[1]);
689  // construct a CLCT if the trigger condition has been met
690  if (best_hs >= 0 && nhits[best_hs] >= nplanes_hit_pattern) {
691  // overwrite the current second best CLCT
692  tempSecondCLCT = constructCLCT(first_bx, best_hs, hits_in_patterns[best_hs][best_pid[best_hs]]);
693  }
694  }
695 
696  // Sort bestCLCT and secondALCT by quality
697  // if qualities are the same, sort by run-2 or run-3 pattern
698  // if qualities and patterns are the same, sort by half strip number
699  bool changeOrder = false;
700 
701  unsigned qualityBest = 0, qualitySecond = 0;
702  unsigned patternBest = 0, patternSecond = 0;
703  unsigned halfStripBest = 0, halfStripSecond = 0;
704 
705  if (tempBestCLCT.isValid() and tempSecondCLCT.isValid()) {
706  qualityBest = tempBestCLCT.getQuality();
707  qualitySecond = tempSecondCLCT.getQuality();
708  if (!runCCLUT_) {
709  patternBest = tempBestCLCT.getPattern();
710  patternSecond = tempSecondCLCT.getPattern();
711  } else {
712  patternBest = tempBestCLCT.getRun3Pattern();
713  patternSecond = tempSecondCLCT.getRun3Pattern();
714  }
715  halfStripBest = tempBestCLCT.getKeyStrip();
716  halfStripSecond = tempSecondCLCT.getKeyStrip();
717 
718  if (qualitySecond > qualityBest)
719  changeOrder = true;
720  else if ((qualitySecond == qualityBest) and (int(patternSecond / 2) > int(patternBest / 2)))
721  changeOrder = true;
722  else if ((qualitySecond == qualityBest) and (int(patternSecond / 2) == int(patternBest / 2)) and
723  (halfStripSecond < halfStripBest))
724  changeOrder = true;
725  }
726 
727  CSCCLCTDigi tempCLCT;
728  if (changeOrder) {
729  tempCLCT = tempBestCLCT;
730  tempBestCLCT = tempSecondCLCT;
731  tempSecondCLCT = tempCLCT;
732  }
733 
734  // add the CLCTs to the collection
735  if (tempBestCLCT.isValid()) {
736  lctList.push_back(tempBestCLCT);
737  }
738  if (tempSecondCLCT.isValid()) {
739  lctList.push_back(tempSecondCLCT);
740  }
741  } //find CLCT, end of best_halfstrip[0] >= 0
742 
743  // If there is a trigger, CLCT pre-trigger state machine
744  // checks the number of hits that lie within a pattern template
745  // at every bx, and waits for it to drop below threshold.
746  // The search for CLCTs resumes only when the number of hits
747  // drops below threshold.
748  start_bx = fifo_tbins;
749  // Stop checking drift_delay bx's short of fifo_tbins since
750  // at later bx's we won't have a full set of hits for a
751  // pattern search anyway.
752  unsigned int stop_time = fifo_tbins - drift_delay;
753  for (unsigned int bx = latch_bx + 1; bx < stop_time; bx++) {
754  bool return_to_idle = true;
755  bool hits_in_time = patternFinding(bx, hits_in_patterns);
756  if (hits_in_time) {
757  for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
758  // the dead-time is done at the pre-trigger, not at the trigger
759  if (nhits[hstrip] >= nplanes_hit_pretrig) {
760  if (infoV > 1)
761  LogTrace("CSCCathodeLCTProcessor") << " State machine busy at bx = " << bx;
762  return_to_idle = false;
763  break;
764  }
765  }
766  }
767  if (return_to_idle) {
768  if (infoV > 1)
769  LogTrace("CSCCathodeLCTProcessor") << " State machine returns to idle state at bx = " << bx;
770  start_bx = bx;
771  break;
772  }
773  }
774  } //pre_trig
775  else {
776  start_bx = first_bx + 1; // no dead time
777  }
778  }
779 
780  return lctList;
781 } // findLCTs -- TMB-07 version.
782 
783 // Common to all versions.
786  const unsigned bits_in_pulse = pulse_.bitsInPulse();
787 
788  // Clear pulse array. This array will be used as a bit representation of
789  // hit times. For example: if strip[1][2] has a value of 3, then 1 shifted
790  // left 3 will be bit pattern of pulse[1][2]. This would make the pattern
791  // look like 0000000000001000. Then add on additional bits to signify
792  // the duration of a signal (hit_persist, formerly bx_width) to simulate
793  // the TMB's drift delay. So for the same pulse[1][2] with a hit_persist
794  // of 3 would look like 0000000000111000. This is similating the digital
795  // one-shot in the TMB.
796  pulse_.clear();
797 
798  // Loop over all layers and halfstrips.
799  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
800  for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
801  // If there is a hit, simulate digital one-shot persistence starting
802  // in the bx of the initial hit. Fill this into pulse[][].
803  if (!time[i_layer][i_strip].empty()) {
804  std::vector<int> bx_times = time[i_layer][i_strip];
805  for (unsigned int i = 0; i < bx_times.size(); i++) {
806  // Check that min and max times are within the allowed range.
807  if (bx_times[i] < 0 || bx_times[i] + hit_persist >= bits_in_pulse) {
808  if (infoV > 0)
809  edm::LogWarning("L1CSCTPEmulatorOutOfTimeDigi")
810  << "+++ BX time of comparator digi (halfstrip = " << i_strip << " layer = " << i_layer
811  << ") bx = " << bx_times[i] << " is not within the range (0-" << bits_in_pulse
812  << "] allowed for pulse extension. Skip this digi! +++\n";
813  continue;
814  }
815  if (bx_times[i] >= start_bx_shift) {
816  pulse_.extend(i_layer, i_strip, bx_times[i], hit_persist);
817  }
818  }
819  }
820  }
821  }
822 } // pulseExtension.
823 
824 // TMB-07 version.
825 bool CSCCathodeLCTProcessor::preTrigger(const int start_bx, int& first_bx) {
826  if (infoV > 1)
827  LogTrace("CSCCathodeLCTProcessor") << "....................PreTrigger...........................";
828 
829  int nPreTriggers = 0;
830 
831  bool pre_trig = false;
832  // Now do a loop over bx times to see (if/when) track goes over threshold
833  for (unsigned int bx_time = start_bx; bx_time < fifo_tbins; bx_time++) {
834  // For any given bunch-crossing, start at the lowest keystrip and look for
835  // the number of separate layers in the pattern for that keystrip that have
836  // pulses at that bunch-crossing time. Do the same for the next keystrip,
837  // etc. Then do the entire process again for the next bunch-crossing, etc
838  // until you find a pre-trigger.
839 
840  std::map<int, std::map<int, CSCCLCTDigi::ComparatorContainer>> hits_in_patterns;
841  hits_in_patterns.clear();
842 
843  bool hits_in_time = patternFinding(bx_time, hits_in_patterns);
844  if (hits_in_time) {
845  // clear the pretriggers
847 
848  for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
849  // check the properties of the pattern on this halfstrip
850  if (infoV > 1) {
851  if (nhits[hstrip] > 0) {
852  LogTrace("CSCCathodeLCTProcessor")
853  << " bx = " << std::setw(2) << bx_time << " --->"
854  << " halfstrip = " << std::setw(3) << hstrip << " best pid = " << std::setw(2) << best_pid[hstrip]
855  << " nhits = " << nhits[hstrip];
856  }
857  }
858  // a pretrigger was found
859  if (nhits[hstrip] >= nplanes_hit_pretrig && best_pid[hstrip] >= pid_thresh_pretrig) {
860  pre_trig = true;
861  ispretrig_[hstrip] = true;
862 
863  // write each pre-trigger to output
864  nPreTriggers++;
865  thePreTriggerDigis.push_back(constructPreCLCT(bx_time, hstrip, nPreTriggers));
866  }
867  }
868 
869  // upon the first pretrigger, we save first BX and exit
870  if (pre_trig) {
871  first_bx = bx_time; // bx at time of pretrigger
872  return true;
873  }
874  }
875  } // end loop over bx times
876 
877  if (infoV > 1)
878  LogTrace("CSCCathodeLCTProcessor") << "no pretrigger, returning \n";
879  first_bx = fifo_tbins;
880  return false;
881 } // preTrigger -- TMB-07 version.
882 
883 // TMB-07 version.
885  const unsigned int bx_time, std::map<int, std::map<int, CSCCLCTDigi::ComparatorContainer>>& hits_in_patterns) {
886  if (bx_time >= fifo_tbins)
887  return false;
888 
889  unsigned layers_hit = pulse_.numberOfLayersAtBX(bx_time);
890  if (layers_hit < nplanes_hit_pretrig)
891  return false;
892 
893  for (int key_hstrip = 0; key_hstrip < numHalfStrips_; key_hstrip++) {
894  best_pid[key_hstrip] = 0;
895  nhits[key_hstrip] = 0;
896  }
897 
898  bool hit_layer[CSCConstants::NUM_LAYERS];
899 
900  // Loop over candidate key strips.
901  for (int key_hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; key_hstrip < numHalfStrips_; key_hstrip++) {
902  // Loop over patterns and look for hits matching each pattern.
903  for (unsigned int pid = clct_pattern_.size() - 1; pid >= pid_thresh_pretrig and pid < clct_pattern_.size(); pid--) {
904  layers_hit = 0;
905  // clear all layers
906  for (int ilayer = 0; ilayer < CSCConstants::NUM_LAYERS; ilayer++) {
907  hit_layer[ilayer] = false;
908  }
909 
910  // clear a single pattern!
911  CSCCLCTDigi::ComparatorContainer hits_single_pattern;
912  hits_single_pattern.resize(6);
913  for (auto& p : hits_single_pattern) {
915  }
916 
917  // clear all medians
918  double num_pattern_hits = 0., times_sum = 0.;
919  std::multiset<int> mset_for_median;
920  mset_for_median.clear();
921 
922  // Loop over halfstrips in trigger pattern mask and calculate the
923  // "absolute" halfstrip number for each.
924  for (int this_layer = 0; this_layer < CSCConstants::NUM_LAYERS; this_layer++) {
925  for (int strip_num = 0; strip_num < CSCConstants::CLCT_PATTERN_WIDTH; strip_num++) {
926  // ignore "0" half-strips in the pattern
927  if (clct_pattern_[pid][this_layer][strip_num] == 0)
928  continue;
929 
930  // the current strip is the key half-strip plus the offset (can be negative or positive)
931  int this_strip = CSCPatternBank::clct_pattern_offset_[strip_num] + key_hstrip;
932 
933  // current strip should be valid of course
934  if (this_strip >= 0 && this_strip < numHalfStrips_) {
935  if (infoV > 3) {
936  LogTrace("CSCCathodeLCTProcessor") << " In patternFinding: key_strip = " << key_hstrip << " pid = " << pid
937  << " layer = " << this_layer << " strip = " << this_strip << std::endl;
938  }
939  // Determine if "one shot" is high at this bx_time
940  if (pulse_.isOneShotHighAtBX(this_layer, this_strip, bx_time)) {
941  if (hit_layer[this_layer] == false) {
942  hit_layer[this_layer] = true;
943  layers_hit++; // determines number of layers hit
944  // add this strip in this layer to the pattern we are currently considering
945  hits_single_pattern[this_layer][strip_num] = this_strip - stagger[this_layer];
946  }
947 
948  // find at what bx did pulse on this halsfstrip & layer have started
949  // use hit_persist constraint on how far back we can go
950  int first_bx_layer = bx_time;
951  for (unsigned int dbx = 0; dbx < hit_persist; dbx++) {
952  if (pulse_.isOneShotHighAtBX(this_layer, this_strip, first_bx_layer - 1))
953  first_bx_layer--;
954  else
955  break;
956  }
957  times_sum += (double)first_bx_layer;
958  num_pattern_hits += 1.;
959  mset_for_median.insert(first_bx_layer);
960  if (infoV > 2)
961  LogTrace("CSCCathodeLCTProcessor") << " 1st bx in layer: " << first_bx_layer << " sum bx: " << times_sum
962  << " #pat. hits: " << num_pattern_hits;
963  }
964  }
965  } // end loop over strips in pretrigger pattern
966  } // end loop over layers
967 
968  // save the pattern information when a trigger was formed!
969  if (layers_hit >= nplanes_hit_pattern) {
970  hits_in_patterns[key_hstrip][pid] = hits_single_pattern;
971  }
972 
973  // determine the current best pattern!
974  if (layers_hit > nhits[key_hstrip]) {
975  best_pid[key_hstrip] = pid;
976  nhits[key_hstrip] = layers_hit;
977  // Do not loop over the other (worse) patterns if max. numbers of
978  // hits is found.
979  if (nhits[key_hstrip] == CSCConstants::NUM_LAYERS)
980  break;
981  }
982  } // end loop over pid
983  } // end loop over candidate key strips
984 
985  // At this point there exists at least one halfstrip for which at least one pattern
986  // has at least 3 layers --> definition of a pre-trigger
987  return true;
988 } // patternFinding -- TMB-07 version.
989 
990 // TMB-07 version.
991 void CSCCathodeLCTProcessor::markBusyKeys(const int best_hstrip,
992  const int best_patid,
994  int nspan = min_separation;
995  int pspan = min_separation;
996 
997  for (int hstrip = best_hstrip - nspan; hstrip <= best_hstrip + pspan; hstrip++) {
998  if (hstrip >= 0 && hstrip < CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER) {
999  quality[hstrip] = 0;
1000  }
1001  }
1002 } // markBusyKeys -- TMB-07 version.
1003 
1005  const unsigned halfstrip_withstagger,
1007  // Assign the CLCT properties
1008  const unsigned quality = nhits[halfstrip_withstagger];
1009  const unsigned pattern = best_pid[halfstrip_withstagger];
1010  const unsigned bend = CSCPatternBank::getPatternBend(clct_pattern_[pattern]);
1011  const unsigned keyhalfstrip = halfstrip_withstagger - stagger[CSCConstants::KEY_CLCT_LAYER - 1];
1012  const unsigned cfeb = keyhalfstrip / CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1013  const unsigned halfstrip = keyhalfstrip % CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1014 
1015  // set the Run-2 properties
1016  CSCCLCTDigi clct(1,
1017  quality,
1018  pattern,
1019  // CLCTs are always of type halfstrip (not strip or distrip)
1020  1,
1021  bend,
1022  halfstrip,
1023  cfeb,
1024  bx,
1025  0,
1026  0,
1027  -1,
1029 
1030  // set the hit collection
1031  clct.setHits(hits);
1032 
1033  // do the CCLUT procedures for Run-3
1034  if (runCCLUT_) {
1035  cclut_->run(clct, numCFEBs_);
1036  }
1037 
1038  // purge the comparator digi collection from the obsolete "65535" entries...
1040 
1041  if (infoV > 1) {
1042  LogTrace("CSCCathodeLCTProcessor") << "Produce CLCT " << clct << std::endl;
1043  }
1044 
1045  return clct;
1046 }
1047 
1049  const unsigned hstrip,
1050  const unsigned nPreTriggers) const {
1052  const int halfstrip = hstrip % CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1053  const int cfeb = hstrip / CSCConstants::NUM_HALF_STRIPS_PER_CFEB;
1054  return CSCCLCTPreTriggerDigi(1, nhits[hstrip], best_pid[hstrip], 1, bend, halfstrip, cfeb, bx_time, nPreTriggers, 0);
1055 }
1056 
1058  for (int hstrip = stagger[CSCConstants::KEY_CLCT_LAYER - 1]; hstrip < numHalfStrips_; hstrip++) {
1059  ispretrig_[hstrip] = false;
1060  }
1061 }
1062 
1064  CSCCLCTDigi::ComparatorContainer newHits = clct.getHits();
1065  for (auto& p : newHits) {
1066  p.erase(
1067  std::remove_if(p.begin(), p.end(), [](unsigned i) -> bool { return i == CSCConstants::INVALID_HALF_STRIP; }),
1068  p.end());
1069  }
1070  clct.setHits(newHits);
1071 }
1072 
1073 // --------------------------------------------------------------------------
1074 // Auxiliary code.
1075 // --------------------------------------------------------------------------
1076 // Dump of configuration parameters.
1078  std::ostringstream strm;
1079  strm << "\n";
1080  strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1081  strm << "+ CLCT configuration parameters: +\n";
1082  strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1083  strm << " fifo_tbins [total number of time bins in DAQ readout] = " << fifo_tbins << "\n";
1084  strm << " fifo_pretrig [start time of cathode raw hits in DAQ readout] = " << fifo_pretrig << "\n";
1085  strm << " hit_persist [duration of signal pulse, in 25 ns bins] = " << hit_persist << "\n";
1086  strm << " drift_delay [time after pre-trigger before TMB latches LCTs] = " << drift_delay << "\n";
1087  strm << " nplanes_hit_pretrig [min. number of layers hit for pre-trigger] = " << nplanes_hit_pretrig << "\n";
1088  strm << " nplanes_hit_pattern [min. number of layers hit for trigger] = " << nplanes_hit_pattern << "\n";
1089  strm << " pid_thresh_pretrig [lower threshold on pattern id] = " << pid_thresh_pretrig << "\n";
1090  strm << " min_separation [region of busy key strips] = " << min_separation << "\n";
1091  strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1092  LogDebug("CSCCathodeLCTProcessor") << strm.str();
1093 }
1094 
1095 // Reasonably nice dump of digis on half-strips.
1098  LogDebug("CSCCathodeLCTProcessor") << theCSCName_ << " strip type: half-strip, numHalfStrips " << numHalfStrips_;
1099 
1100  std::ostringstream strstrm;
1101  for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
1102  if (i_strip % 10 == 0) {
1103  if (i_strip < 100)
1104  strstrm << i_strip / 10;
1105  else
1106  strstrm << (i_strip - 100) / 10;
1107  } else
1108  strstrm << " ";
1109  if ((i_strip + 1) % CSCConstants::NUM_HALF_STRIPS_PER_CFEB == 0)
1110  strstrm << " ";
1111  }
1112  strstrm << "\n";
1113  for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
1114  strstrm << i_strip % 10;
1115  if ((i_strip + 1) % CSCConstants::NUM_HALF_STRIPS_PER_CFEB == 0)
1116  strstrm << " ";
1117  }
1118  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1119  strstrm << "\n";
1120  for (int i_strip = 0; i_strip < numHalfStrips_; i_strip++) {
1121  if (!strip[i_layer][i_strip].empty()) {
1122  std::vector<int> bx_times = strip[i_layer][i_strip];
1123  // Dump only the first in time.
1124  strstrm << std::hex << bx_times[0] << std::dec;
1125  } else {
1126  strstrm << "-";
1127  }
1128  if ((i_strip + 1) % CSCConstants::NUM_HALF_STRIPS_PER_CFEB == 0)
1129  strstrm << " ";
1130  }
1131  }
1132  LogTrace("CSCCathodeLCTProcessor") << strstrm.str();
1133 }
1134 
1135 // Returns vector of read-out CLCTs, if any. Starts with the vector
1136 // of all found CLCTs and selects the ones in the read-out time window.
1137 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::readoutCLCTs() const {
1138  // temporary container for further selection
1139  std::vector<CSCCLCTDigi> tmpV;
1140 
1141  /*
1142  CLCTs in the BX window [early_tbin,...,late_tbin] are considered good for physics
1143  The central CLCT BX is time bin 7.
1144  For tmb_l1a_window_size set to 7 (Run-1, Run-2), the window is [4, 5, 6, 7, 8, 9, 10]
1145  For tmb_l1a_window_size set to 5 (Run-3), the window is [5, 6, 7, 8, 9]
1146  For tmb_l1a_window_size set to 3 (Run-4?), the window is [6, 7, 8]
1147  */
1148  const unsigned delta_tbin = tmb_l1a_window_size / 2;
1149  int early_tbin = CSCConstants::CLCT_CENTRAL_BX - delta_tbin;
1150  int late_tbin = CSCConstants::CLCT_CENTRAL_BX + delta_tbin;
1151  /*
1152  Special case for an even-numbered time-window,
1153  For instance tmb_l1a_window_size set to 6: [4, 5, 6, 7, 8, 9]
1154  */
1155  if (tmb_l1a_window_size % 2 == 0)
1156  late_tbin = CSCConstants::CLCT_CENTRAL_BX + delta_tbin - 1;
1157  const int max_late_tbin = CSCConstants::MAX_CLCT_TBINS - 1;
1158 
1159  // debugging messages when early_tbin or late_tbin has a suspicious value
1160  if (early_tbin < 0) {
1161  edm::LogWarning("CSCCathodeLCTProcessor|SuspiciousParameters")
1162  << "Early time bin (early_tbin) smaller than minimum allowed, which is 0. set early_tbin to 0.";
1163  early_tbin = 0;
1164  }
1165  if (late_tbin > max_late_tbin) {
1166  edm::LogWarning("CSCCathodeLCTProcessor|SuspiciousParameters")
1167  << "Late time bin (late_tbin) larger than maximum allowed, which is " << max_late_tbin
1168  << ". set early_tbin to max allowed";
1169  late_tbin = CSCConstants::MAX_CLCT_TBINS - 1;
1170  }
1171 
1172  // get the valid LCTs. No BX selection is done here
1173  const auto& all_clcts = getCLCTs();
1174 
1175  // Start from the vector of all found CLCTs and select those within
1176  // the CLCT*L1A coincidence window.
1177  int bx_readout = -1;
1178  for (const auto& clct : all_clcts) {
1179  // only consider valid CLCTs
1180  if (!clct.isValid())
1181  continue;
1182 
1183  const int bx = clct.getBX();
1184  // Skip CLCTs found too early relative to L1Accept.
1185  if (bx < early_tbin) {
1186  if (infoV > 1)
1187  LogDebug("CSCCathodeLCTProcessor")
1188  << " Do not report correlated CLCT on key halfstrip " << clct.getStrip() << ": found at bx " << bx
1189  << ", whereas the earliest allowed bx is " << early_tbin;
1190  continue;
1191  }
1192 
1193  // Skip CLCTs found too late relative to L1Accept.
1194  if (bx > late_tbin) {
1195  if (infoV > 1)
1196  LogDebug("CSCCathodeLCTProcessor")
1197  << " Do not report correlated CLCT on key halfstrip " << clct.getStrip() << ": found at bx " << bx
1198  << ", whereas the latest allowed bx is " << late_tbin;
1199  continue;
1200  }
1201 
1202  // If (readout_earliest_2) take only CLCTs in the earliest bx in the read-out window:
1203  if (readout_earliest_2) {
1204  // the first CLCT passes
1205  // the second CLCT passes if the BX matches to the first
1206  if (bx_readout == -1 || bx == bx_readout) {
1207  tmpV.push_back(clct);
1208  if (bx_readout == -1)
1209  bx_readout = bx;
1210  }
1211  } else
1212  tmpV.push_back(clct);
1213  }
1214 
1215  // do a final check on the CLCTs in readout
1216  qualityControl_->checkMultiplicityBX(tmpV);
1217  for (const auto& clct : tmpV) {
1218  qualityControl_->checkValid(clct);
1219  }
1220 
1221  return tmpV;
1222 }
1223 
1224 // Returns vector of all found CLCTs, if any. Used for ALCT-CLCT matching.
1225 std::vector<CSCCLCTDigi> CSCCathodeLCTProcessor::getCLCTs() const {
1226  std::vector<CSCCLCTDigi> tmpV;
1227  for (int bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
1228  if (bestCLCT[bx].isValid())
1229  tmpV.push_back(bestCLCT[bx]);
1230  if (secondCLCT[bx].isValid())
1231  tmpV.push_back(secondCLCT[bx]);
1232  }
1233  return tmpV;
1234 }
1235 
1236 // shift the BX from 7 to 8
1237 // the unpacked real data CLCTs have central BX at bin 7
1238 // however in simulation the central BX is bin 8
1239 // to make a proper comparison with ALCTs we need
1240 // CLCT and ALCT to have the central BX in the same bin
1242  if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1243  return CSCCLCTDigi();
1244  CSCCLCTDigi lct = bestCLCT[bx];
1246  return lct;
1247 }
1248 
1250  if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1251  return CSCCLCTDigi();
1252  CSCCLCTDigi lct = secondCLCT[bx];
1254  return lct;
1255 }
1256 
1258  if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1259  return false;
1260  return localShowerFlag[bx];
1261 }
1262 
1264 std::vector<CSCShowerDigi> CSCCathodeLCTProcessor::getAllShower() const {
1265  std::vector<CSCShowerDigi> vshowers(cathode_showers_, cathode_showers_ + CSCConstants::MAX_CLCT_TBINS);
1266  return vshowers;
1267 };
1268 
1270 std::vector<CSCShowerDigi> CSCCathodeLCTProcessor::readoutShower() const {
1271  std::vector<CSCShowerDigi> showerOut;
1272  for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++)
1273  if (cathode_showers_[bx].isValid())
1274  showerOut.push_back(cathode_showers_[bx]);
1275  return showerOut;
1276 }
1277 
1279  //inTimeHMT_ = 0;
1280 
1281  //numer of layer with hits and number of hits for 0-15 BXs
1282  std::set<unsigned> layersWithHits[CSCConstants::MAX_CLCT_TBINS];
1283  unsigned hitsInTime[CSCConstants::MAX_CLCT_TBINS];
1284  // Calculate layers with hits
1285  for (unsigned bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
1286  hitsInTime[bx] = 0;
1287  for (unsigned i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1288  bool atLeastOneCompHit = false;
1289  for (const auto& compdigi : digiV[i_layer]) {
1290  std::vector<int> bx_times = compdigi.getTimeBinsOn();
1291  // there is at least one comparator digi in this bx
1292  if (std::find(bx_times.begin(), bx_times.end(), bx) != bx_times.end()) {
1293  hitsInTime[bx] += 1;
1294  atLeastOneCompHit = true;
1295  }
1296  }
1297  // add this layer to the number of layers hit
1298  if (atLeastOneCompHit) {
1299  layersWithHits[bx].insert(i_layer);
1300  }
1301  }
1302  } //end of full bx loop
1303 
1304  // convert station and ring number to index
1305  // index runs from 2 to 10, subtract 2
1306  unsigned csc_idx = CSCDetId::iChamberType(theStation, theRing) - 2;
1307 
1308  // loose, nominal and tight
1309  std::vector<unsigned> station_thresholds = {
1310  thresholds_[csc_idx * 3], thresholds_[csc_idx * 3 + 1], thresholds_[csc_idx * 3 + 2]};
1311 
1312  //hard coded dead time as 2Bx, since showerNumTBins = 3, like firmware
1313  // for example, nhits = 0 at bx7; = 100 at bx8; = 0 at bx9
1314  //cathode HMT must be triggered at bx8, not bx7 and bx9
1315  //meanwhile we forced 2BX dead time after active shower trigger
1316  unsigned int deadtime =
1317  showerNumTBins_ - 1; // firmware hard coded dead time as 2Bx, since showerNumTBins = 3 in firmware
1318  unsigned int dead_count = 0;
1319 
1320  for (unsigned bx = 0; bx < CSCConstants::MAX_CLCT_TBINS; bx++) {
1321  unsigned minbx = bx >= showerNumTBins_ / 2 ? bx - showerNumTBins_ / 2 : bx;
1322  unsigned maxbx = bx < CSCConstants::MAX_CLCT_TBINS - showerNumTBins_ / 2 ? bx + showerNumTBins_ / 2
1324  unsigned this_hitsInTime = 0;
1325  bool isPeak = true; //check whether total hits in bx is peak of nhits over time bins
1326  /*following is to count number of hits over [minbx, maxbx], showerNumTBins=3 =>[n-1, n+1]*/
1327  for (unsigned mbx = minbx; mbx <= maxbx; mbx++) {
1328  this_hitsInTime += hitsInTime[mbx];
1329  }
1330 
1332  if (hitsInTime[minbx] < hitsInTime[maxbx + 1] or
1333  (hitsInTime[minbx] == hitsInTime[maxbx + 1] and hitsInTime[bx] < hitsInTime[bx + 1]))
1334  isPeak = false; //next bx would have more hits or in the center
1335  }
1336  bool dead_status = dead_count > 0;
1337  if (dead_status)
1338  dead_count--;
1339 
1340  unsigned this_inTimeHMT = 0;
1341  // require at least nLayersWithHits for the central time bin
1342  // do nothing if there are not enough layers with hits
1343  if (layersWithHits[bx].size() >= minLayersCentralTBin_ and !dead_status and isPeak) {
1344  // assign the bits
1345  if (!station_thresholds.empty()) {
1346  for (int i = station_thresholds.size() - 1; i >= 0; i--) {
1347  if (this_hitsInTime >= station_thresholds[i]) {
1348  this_inTimeHMT = i + 1;
1349  dead_count = deadtime;
1350  break;
1351  }
1352  }
1353  }
1354  }
1355  //CLCTshower constructor with showerType_ = 2, wirehits = 0;
1357  this_inTimeHMT, false, theTrigChamber, bx, CSCShowerDigi::ShowerType::kCLCTShower, 0, this_hitsInTime);
1358  }
1359 }
std::unique_ptr< ComparatorCodeLUT > cclut_
void setESLookupTables(const CSCL1TPLookupTableCCLUT *conf)
size
Write out results.
unsigned int clctNplanesHitPattern() const
static const unsigned int def_drift_delay
std::vector< CSCCLCTDigi > readoutCLCTs() const
CSCCLCTDigi bestCLCT[CSCConstants::MAX_CLCT_TBINS]
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
void clear()
Definition: PulseArray.cc:14
const CSCLayer * layer(CSCDetId id) const
Return the layer corresponding to the given id.
Definition: CSCChamber.cc:30
static const unsigned int def_fifo_tbins
bool isOneShotHighAtBX(const unsigned layer, const unsigned channel, const unsigned bx) const
Definition: PulseArray.cc:37
unsigned int clctMinSeparation() const
const bool isValid(const Frame &aFrame, const FrameQuality &aQuality, const uint16_t aExpectedPos)
const unsigned theEndcap
Definition: CSCBaseboard.h:74
static std::string chamberName(int endcap, int station, int ring, int chamber)
Definition: CSCDetId.cc:74
const CSCChamber * cscChamber_
Definition: CSCBaseboard.h:104
void checkConfigParameters(unsigned int &var, const unsigned int var_max, const unsigned int var_def, const std::string &var_str)
unsigned int clctFifoTbins() const
uint16_t getQuality() const
return quality of a pattern (number of layers hit!)
Definition: CSCCLCTDigi.h:56
ParameterSet const & getParameterSet(std::string const &) const
void pulseExtension(const std::vector< int > time[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER])
uint16_t getKeyStrip(const uint16_t n=2) const
Definition: CSCCLCTDigi.cc:107
unsigned int clctNplanesHitPretrig() const
const unsigned theSector
Definition: CSCBaseboard.h:76
static const unsigned int def_min_separation
CSCPatternBank::LCTPatterns clct_pattern_
bool patternFinding(const unsigned int bx_time, std::map< int, std::map< int, CSCCLCTDigi::ComparatorContainer > > &hits_in_patterns)
bool getLocalShowerFlag(int bx) const
Log< level::Error, false > LogError
std::unique_ptr< LCTQualityControl > qualityControl_
edm::ParameterSet const & showerParams() const
Definition: CSCBaseboard.h:21
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
unsigned short iChamberType() const
Definition: CSCDetId.h:96
assert(be >=bs)
std::string theCSCName_
Definition: CSCBaseboard.h:107
static const unsigned int def_nplanes_hit_pretrig
CSCShowerDigi cathode_showers_[CSCConstants::MAX_CLCT_TBINS]
std::vector< CSCShowerDigi > readoutShower() const
void cleanComparatorContainer(CSCCLCTDigi &lct) const
#define LogTrace(id)
edm::ParameterSet const & clctParams() const
Definition: CSCBaseboard.h:24
const CSCLayerGeometry * geometry() const
Definition: CSCLayer.h:44
static const unsigned int def_pid_thresh_pretrig
string quality
std::vector< std::vector< uint16_t > > ComparatorContainer
Definition: CSCCLCTDigi.h:19
CSCCathodeLCTProcessor(unsigned endcap, unsigned station, unsigned sector, unsigned subsector, unsigned chamber, CSCBaseboard::Parameters &conf)
unsigned int nhits[CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]
const unsigned theTrigChamber
Definition: CSCBaseboard.h:78
CSCCLCTPreTriggerDigi constructPreCLCT(const int bx, const unsigned halfstrip, const unsigned index) const
static const LCTPatterns clct_pattern_run3_
CSCCLCTDigi getSecondCLCT(int bx) const
std::string chamberName() const
Definition: CSCDetId.cc:92
std::vector< CSCCLCTDigi > getCLCTs() const
int numberOfStrips() const
static const unsigned int def_tmb_l1a_window_size
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
unsigned int clctFifoPretrig() const
edm::ParameterSet const & tmbParams() const
Definition: CSCBaseboard.h:22
bool getDigis(const CSCComparatorDigiCollection *compdc)
static const unsigned int def_nplanes_hit_pattern
void setHits(const ComparatorContainer &hits)
Definition: CSCCLCTDigi.h:178
unsigned int clctPidThreshPretrig() const
static const int clct_pattern_offset_[CSCConstants::CLCT_PATTERN_WIDTH]
unsigned theChamber
Definition: CSCBaseboard.h:81
bool isValid() const
check CLCT validity (1 - valid CLCT)
Definition: CSCCLCTDigi.h:50
static int getPatternBend(const LCTPattern &pattern)
unsigned int clctHitPersist() const
std::vector< CSCCLCTPreTriggerDigi > thePreTriggerDigis
unsigned numberOfLayersAtBX(const unsigned bx) const
Definition: PulseArray.cc:41
static const LCTPatterns clct_pattern_legacy_
virtual std::vector< CSCCLCTDigi > findLCTs(const std::vector< int > halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER])
void markBusyKeys(const int best_hstrip, const int best_patid, int quality[CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER])
static const unsigned int def_fifo_pretrig
bool localShowerFlag[CSCConstants::MAX_CLCT_TBINS]
std::vector< int > thePreTriggerBXs
std::pair< const_iterator, const_iterator > Range
static const unsigned int def_hit_persist
void dumpDigis(const std::vector< int > halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]) const
const unsigned theStation
Definition: CSCBaseboard.h:75
CSCCLCTDigi getBestCLCT(int bx) const
int stagger[CSCConstants::NUM_LAYERS]
std::vector< DigiType >::const_iterator const_iterator
uint16_t getBX() const
return BX
Definition: CSCCLCTDigi.h:123
uint16_t getPattern() const
return pattern
Definition: CSCCLCTDigi.h:62
std::vector< CSCCLCTDigi > run(const CSCComparatorDigiCollection *compdc)
edm::ParameterSet const & conf() const
Definition: CSCBaseboard.h:18
void initialize(unsigned numberOfChannels)
Definition: PulseArray.cc:5
void setBX(const uint16_t bx)
set bx
Definition: CSCCLCTDigi.h:129
const ComparatorContainer & getHits() const
Definition: CSCCLCTDigi.h:176
virtual bool preTrigger(const int start_bx, int &first_bx)
uint16_t getRun3Pattern() const
return pattern
Definition: CSCCLCTDigi.h:68
CSCCLCTDigi secondCLCT[CSCConstants::MAX_CLCT_TBINS]
void clear()
clear this CLCT
Definition: CSCCLCTDigi.cc:73
std::vector< CSCComparatorDigi > digiV[CSCConstants::NUM_LAYERS]
unsigned bitsInPulse() const
Definition: PulseArray.cc:25
void clear()
clear this Shower
unsigned theRing
Definition: CSCBaseboard.h:80
Log< level::Warning, false > LogWarning
void readComparatorDigis(std::vector< int > halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER])
CSCCLCTDigi constructCLCT(const int bx, const unsigned halfstrip_withstagger, const CSCCLCTDigi::ComparatorContainer &hits)
std::vector< CSCShowerDigi > getAllShower() const
void extend(const unsigned layer, const unsigned channel, const unsigned bx, const unsigned hit_persist)
Definition: PulseArray.cc:27
bool ispretrig_[CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]
void setConfigParameters(const CSCDBL1TPParameters *conf)
const unsigned theSubsector
Definition: CSCBaseboard.h:77
void setTrknmb(const uint16_t number)
Set track number (1,2) after sorting CLCTs.
Definition: CSCCLCTDigi.h:162
void checkLocalShower(int zone, const std::vector< int > halfstrip[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER])
unsigned int clctDriftDelay() const
#define LogDebug(id)
unsigned int best_pid[CSCConstants::MAX_NUM_HALF_STRIPS_RUN2_TRIGGER]
std::vector< unsigned > thresholds_