CMS 3D CMS Logo

CSCAnodeLCTProcessor.cc
Go to the documentation of this file.
2 #include <set>
3 
4 // Default values of configuration parameters.
5 const unsigned int CSCAnodeLCTProcessor::def_fifo_tbins = 16;
6 const unsigned int CSCAnodeLCTProcessor::def_fifo_pretrig = 10;
7 const unsigned int CSCAnodeLCTProcessor::def_drift_delay = 2;
12 const unsigned int CSCAnodeLCTProcessor::def_trig_mode = 2; // 3?
13 const unsigned int CSCAnodeLCTProcessor::def_accel_mode = 0; // 1?
14 const unsigned int CSCAnodeLCTProcessor::def_l1a_window_width = 7; // 5?
15 
16 //----------------
17 // Constructors --
18 //----------------
19 
21  unsigned station,
22  unsigned sector,
23  unsigned subsector,
24  unsigned chamber,
27  static std::atomic<bool> config_dumped{false};
28 
29  // ALCT configuration parameters.
30  fifo_tbins = conf.alctParams().getParameter<unsigned int>("alctFifoTbins");
31  fifo_pretrig = conf.alctParams().getParameter<unsigned int>("alctFifoPretrig");
32  drift_delay = conf.alctParams().getParameter<unsigned int>("alctDriftDelay");
33  nplanes_hit_pretrig = conf.alctParams().getParameter<unsigned int>("alctNplanesHitPretrig");
34  nplanes_hit_pattern = conf.alctParams().getParameter<unsigned int>("alctNplanesHitPattern");
35  nplanes_hit_accel_pretrig = conf.alctParams().getParameter<unsigned int>("alctNplanesHitAccelPretrig");
36  nplanes_hit_accel_pattern = conf.alctParams().getParameter<unsigned int>("alctNplanesHitAccelPattern");
37  trig_mode = conf.alctParams().getParameter<unsigned int>("alctTrigMode");
38  accel_mode = conf.alctParams().getParameter<unsigned int>("alctAccelMode");
39  l1a_window_width = conf.alctParams().getParameter<unsigned int>("alctL1aWindowWidth");
40 
41  hit_persist = conf.alctParams().getParameter<unsigned int>("alctHitPersist");
42 
43  // Verbosity level, set to 0 (no print) by default.
44  infoV = conf.alctParams().getParameter<int>("verbosity");
45 
46  // separate handle for early time bins
47  early_tbins = conf.alctParams().getParameter<int>("alctEarlyTbins");
48  if (early_tbins < 0)
50 
51  // delta BX time depth for ghostCancellationLogic
52  ghost_cancellation_bx_depth = conf.alctParams().getParameter<int>("alctGhostCancellationBxDepth");
53 
54  // whether to consider ALCT candidates' qualities while doing ghostCancellationLogic on +-1 wire groups
55  ghost_cancellation_side_quality = conf.alctParams().getParameter<bool>("alctGhostCancellationSideQuality");
56 
57  // deadtime clocks after pretrigger (extra in addition to drift_delay)
58  pretrig_extra_deadtime = conf.alctParams().getParameter<unsigned int>("alctPretrigDeadtime");
59 
60  // whether to use narrow pattern mask for the rings close to the beam
61  narrow_mask_r1 = conf.alctParams().getParameter<bool>("alctNarrowMaskForR1");
62 
63  // Check and print configuration parameters.
65  if ((infoV > 0 || (runPhase2_)) && !config_dumped) {
67  config_dumped = true;
68  }
69 
70  numWireGroups = 0; // Will be set later.
71  MESelection = (theStation < 3) ? 0 : 1;
72 
73  // whether to calculate bx as corrected_bx instead of pretrigger one
74  use_corrected_bx = false;
75  if (runPhase2_) {
76  use_corrected_bx = conf.alctParams().getParameter<bool>("alctUseCorrectedBx");
77  }
78 
79  // Load appropriate pattern mask.
81 
82  // quality control of stubs
83  qualityControl_ = std::make_unique<LCTQualityControl>(endcap, station, sector, subsector, chamber, conf);
84 
85  const auto& shower = conf.showerParams().getParameterSet("anodeShower");
86  thresholds_ = shower.getParameter<std::vector<unsigned>>("showerThresholds");
87  showerNumTBins_ = shower.getParameter<unsigned>("showerNumTBins");
88  minLayersCentralTBin_ = shower.getParameter<unsigned>("minLayersCentralTBin");
92 }
93 
95  // Load appropriate pattern mask.
96  if (narrow_mask_r1 && (theRing == 1 || theRing == 4)) {
98  } else {
100  }
101 }
102 
104  // Set default values for configuration parameters.
117 }
118 
119 // Set configuration parameters obtained via EventSetup mechanism.
121  static std::atomic<bool> config_dumped{false};
122 
123  fifo_tbins = conf->alctFifoTbins();
124  fifo_pretrig = conf->alctFifoPretrig();
125  drift_delay = conf->alctDriftDelay();
130  trig_mode = conf->alctTrigMode();
131  accel_mode = conf->alctAccelMode();
133 
134  // Check and print configuration parameters.
136  if (!config_dumped) {
138  config_dumped = true;
139  }
142 }
143 
145  // Make sure that the parameter values are within the allowed range.
146 
147  // Max expected values.
148  static const unsigned int max_fifo_tbins = 1 << 5;
149  static const unsigned int max_fifo_pretrig = 1 << 5;
150  static const unsigned int max_drift_delay = 1 << 2;
151  static const unsigned int max_nplanes_hit_pretrig = 1 << 3;
152  static const unsigned int max_nplanes_hit_pattern = 1 << 3;
153  static const unsigned int max_nplanes_hit_accel_pretrig = 1 << 3;
154  static const unsigned int max_nplanes_hit_accel_pattern = 1 << 3;
155  static const unsigned int max_trig_mode = 1 << 2;
156  static const unsigned int max_accel_mode = 1 << 2;
157  static const unsigned int max_l1a_window_width = CSCConstants::MAX_ALCT_TBINS; // 4 bits
158 
159  // Checks.
160  CSCBaseboard::checkConfigParameters(fifo_tbins, max_fifo_tbins, def_fifo_tbins, "fifo_tbins");
161  CSCBaseboard::checkConfigParameters(fifo_pretrig, max_fifo_pretrig, def_fifo_pretrig, "fifo_pretrig");
162  CSCBaseboard::checkConfigParameters(drift_delay, max_drift_delay, def_drift_delay, "drift_delay");
164  nplanes_hit_pretrig, max_nplanes_hit_pretrig, def_nplanes_hit_pretrig, "nplanes_hit_pretrig");
166  nplanes_hit_pattern, max_nplanes_hit_pattern, def_nplanes_hit_pattern, "nplanes_hit_pattern");
168  max_nplanes_hit_accel_pretrig,
170  "nplanes_hit_accel_pretrig");
172  max_nplanes_hit_accel_pattern,
174  "nplanes_hit_accel_pattern");
175  CSCBaseboard::checkConfigParameters(trig_mode, max_trig_mode, def_trig_mode, "trig_mode");
176  CSCBaseboard::checkConfigParameters(accel_mode, max_accel_mode, def_accel_mode, "accel_mode");
177  CSCBaseboard::checkConfigParameters(l1a_window_width, max_l1a_window_width, def_l1a_window_width, "l1a_window_width");
178 
180 }
181 
183  for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
184  bestALCT[bx].clear();
185  secondALCT[bx].clear();
186  anode_showers_[bx].clear(); //?
187  }
188  lct_list.clear();
189 }
190 
191 void CSCAnodeLCTProcessor::clear(const int wire, const int pattern) {
192  /* Clear the data off of selected pattern */
195  else {
198  }
199 }
200 
201 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::run(const CSCWireDigiCollection* wiredc, const CSCChamber* cscChamber) {
202  static std::atomic<bool> config_dumped{false};
203  if ((infoV > 0 || (runPhase2_)) && !config_dumped) {
205  config_dumped = true;
206  }
207 
208  // Get the number of wire groups for the given chamber. Do it only once
209  // per chamber.
210  if (numWireGroups <= 0 or numWireGroups > CSCConstants::MAX_NUM_WIREGROUPS) {
211  if (cscChamber) {
214  edm::LogError("CSCAnodeLCTProcessor|SetupError")
215  << "+++ Number of wire groups, " << numWireGroups << " found in " << theCSCName_ << " (sector " << theSector
216  << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
217  << " exceeds max expected, " << CSCConstants::MAX_NUM_WIREGROUPS << " +++\n"
218  << "+++ CSC geometry looks garbled; no emulation possible +++\n";
219  numWireGroups = -1;
220  }
221  } else {
222  edm::LogError("CSCAnodeLCTProcessor|SetupError")
223  << "+++ " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
224  << theTrigChamber << ")"
225  << " is not defined in current geometry! +++\n"
226  << "+++ CSC geometry looks garbled; no emulation possible +++\n";
227  numWireGroups = -1;
228  }
229  }
230 
231  if (numWireGroups <= 0 or (unsigned) numWireGroups > qualityControl_->get_csc_max_wiregroup(theStation, theRing)) {
232  edm::LogError("CSCAnodeLCTProcessor|SetupError")
233  << "+++ " << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector << " trig id. "
234  << theTrigChamber << "):"
235  << " numWireGroups = " << numWireGroups << "; ALCT emulation skipped! +++";
236  std::vector<CSCALCTDigi> emptyV;
237  return emptyV;
238  }
239 
240  // Get wire digis in this chamber from wire digi collection.
241  bool hasDigis = getDigis(wiredc);
242 
243  if (hasDigis) {
244  // First get wiregroup times from the wire digis.
245  std::vector<int> wireGroupTimes[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS];
246  readWireDigis(wireGroupTimes);
247 
248  // Pass an array of wire times on to another run() doing the LCT search.
249  // If the number of layers containing digis is smaller than that
250  // required to trigger, quit right away.
251  const unsigned int min_layers =
255 
256  unsigned int layersHit = 0;
257  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
258  for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
259  if (!wireGroupTimes[i_layer][i_wire].empty()) {
260  layersHit++;
261  break;
262  }
263  }
264  }
265  if (layersHit >= min_layers)
266  run(wireGroupTimes);
267  // Get the high multiplicity bits in this chamber
269  }
270 
271  // Return vector of all found ALCTs.
272  return getALCTs();
273 }
274 
276  bool trigger = false;
277 
278  // initialize the pulse array.
280 
281  // Check if there are any in-time hits and do the pulse extension.
282  bool chamber_empty = pulseExtension(wire);
283 
284  // define a new pattern map
285  // for each key wiregroup, and for each pattern, store the 2D collection of fired wiregroup digis
286  std::map<int, std::map<int, CSCALCTDigi::WireContainer>> hits_in_patterns;
287  hits_in_patterns.clear();
288 
289  // Only do the rest of the processing if chamber is not empty.
290  // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
291  // not have a full set of hits to start pattern search anyway.
292  unsigned int stop_bx = fifo_tbins - drift_delay;
293  if (!chamber_empty) {
294  for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
295  // extra check to make sure only valid wires are processed
296  const unsigned max_wire = qualityControl_->get_csc_max_wiregroup(theStation, theRing);
297  if (unsigned(i_wire) >= max_wire)
298  continue;
299 
300  unsigned int start_bx = 0;
301  // Allow for more than one pass over the hits in the time window.
302  while (start_bx < stop_bx) {
303  if (preTrigger(i_wire, start_bx)) {
304  if (infoV > 2)
305  showPatterns(i_wire);
306  if (patternDetection(i_wire, hits_in_patterns)) {
307  trigger = true;
308  int ghost_cleared[2] = {0, 0};
309  /*
310  In older versions of the ALCT emulation, the ghost cancellation was performed after
311  the ALCTs were found. In December 2018, it became clear that during the study of data
312  and emulation comparison on 2018 data, a small disagreement between data and emulation
313  was found. The changes we implemented then allow re-triggering on one wiregroup after
314  some dead time once an earlier ALCT was constructed built on this wiregroup. Before this
315  commit the ALCT processor would prohibit the wiregroup from triggering in one event after
316  an ALCT was found on that wiregroup. In the firwmare, the wiregroup with ALCT is only dead
317  for a few BX before it can be triggered by next muon. The implementation of ghost cancellation
318  logic was changed to accommodate the re-triggering change while the idea of ghost cancellation
319  logic is kept the same.
320  */
321  ghostCancellationLogicOneWire(i_wire, ghost_cleared);
322 
323  int bx = (use_corrected_bx) ? first_bx_corrected[i_wire] : first_bx[i_wire];
325  edm::LogError("CSCAnodeLCTProcessor")
326  << " bx of valid trigger : " << bx << " > max allowed value " << CSCConstants::MAX_ALCT_TBINS;
327 
328  //acceleration mode
329  if (quality[i_wire][0] > 0 and bx < CSCConstants::MAX_ALCT_TBINS) {
330  int valid = (ghost_cleared[0] == 0) ? 1 : 0; //cancelled, valid=0, otherwise it is 1
331  CSCALCTDigi newALCT(valid, quality[i_wire][0], 1, 0, i_wire, bx);
332 
333  // set the wire digis for this pattern
334  setWireContainer(newALCT, hits_in_patterns[i_wire][0]);
335 
336  lct_list.emplace_back(newALCT);
337  if (infoV > 1)
338  LogTrace("CSCAnodeLCTProcessor") << "Add one ALCT to list " << lct_list.back();
339  }
340 
341  //collision mode
343  int valid = (ghost_cleared[CSCConstants::ALCT_COLLISIONA_PATTERN] == 0)
344  ? 1
345  : 0; //cancelled, valid=0, otherwise it is 1
346 
347  CSCALCTDigi newALCT(valid,
349  0,
351  i_wire,
352  bx);
353 
354  // set the wire digis for this pattern
355  setWireContainer(newALCT, hits_in_patterns[i_wire][CSCConstants::ALCT_COLLISIONA_PATTERN]);
356 
357  lct_list.emplace_back(newALCT);
358  if (infoV > 1)
359  LogTrace("CSCAnodeLCTProcessor") << "Add one ALCT to list " << lct_list.back();
360  }
361 
362  //break;
363  // Assume that the earliest time when another pre-trigger can
364  // occur in case pattern detection failed is bx_pretrigger+4:
365  // this seems to match the data.
366  start_bx = first_bx[i_wire] + drift_delay + pretrig_extra_deadtime;
367  } else {
368  //only pretrigger, no trigger ==> no dead time, continue to find next pretrigger
369  start_bx = first_bx[i_wire] + 1;
370  }
371  } else { //no pretrigger, skip this wiregroup
372  break;
373  }
374  } // end of while
375  }
376  }
377 
378  // Do the rest only if there is at least one trigger candidate.
379  if (trigger) {
380  /* In Run-1 and Run-2, the ghost cancellation was done after the trigger.
381  In the firmware however, the ghost cancellation is done during the trigger
382  on each wiregroup in parallel. For Run-3 and beyond, the ghost cancellation is
383  implemented per wiregroup earlier in the code. See function
384  "ghostCancellationLogicOneWire". There used to be a function ghostCancellationLogic
385  call here.
386  */
387  lctSearch();
388  }
389 }
390 
392  // Routine for getting digis and filling digiV vector.
393  bool hasDigis = false;
394 
395  // Loop over layers and save wire digis on each one into digiV[layer].
396  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
397  digiV[i_layer].clear();
398 
399  CSCDetId detid(theEndcap, theStation, theRing, theChamber, i_layer + 1);
400  getDigis(wiredc, detid);
401 
402  // If this is ME1/1, fetch digis in corresponding ME1/A (ring=4) as well.
403  if (isME11_ && !disableME1a_) {
404  CSCDetId detid_me1a(theEndcap, theStation, 4, theChamber, i_layer + 1);
405  getDigis(wiredc, detid_me1a);
406  }
407 
408  if (!digiV[i_layer].empty()) {
409  hasDigis = true;
410  if (infoV > 1) {
411  LogTrace("CSCAnodeLCTProcessor") << "found " << digiV[i_layer].size() << " wire digi(s) in layer " << i_layer
412  << " of " << theCSCName_ << " (trig. sector " << theSector << " subsector "
413  << theSubsector << " id " << theTrigChamber << ")";
414  for (const auto& wd : digiV[i_layer]) {
415  LogTrace("CSCAnodeLCTProcessor") << " " << wd;
416  }
417  }
418  }
419  }
420 
421  return hasDigis;
422 }
423 
425  CSCWireDigiCollection::Range rwired = wiredc->get(id);
426  for (CSCWireDigiCollection::const_iterator digiIt = rwired.first; digiIt != rwired.second; ++digiIt) {
427  digiV[id.layer() - 1].push_back(*digiIt);
428  }
429 }
430 
433  // Loop over all 6 layers.
434  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
435  // Loop over all digis in the layer and find the wireGroup and bx
436  // time for each.
437  for (const auto& wd : digiV[i_layer]) {
438  int i_wire = wd.getWireGroup() - 1;
439  std::vector<int> bx_times = wd.getTimeBinsOn();
440 
441  // Check that the wires and times are appropriate.
442  if (i_wire < 0 || i_wire >= numWireGroups) {
443  if (infoV >= 0)
444  edm::LogWarning("CSCAnodeLCTProcessor|WrongInput")
445  << "+++ Found wire digi with wrong wire number = " << i_wire << " (max wires = " << numWireGroups
446  << "); skipping it... +++\n";
447  continue;
448  }
449  // Accept digis in expected time window. Total number of time
450  // bins in DAQ readout is given by fifo_tbins, which thus
451  // determines the maximum length of time interval. Anode raw
452  // hits in DAQ readout start (fifo_pretrig - 6) clocks before
453  // L1Accept. If times earlier than L1Accept were recorded, we
454  // use them since they can modify the ALCTs found later, via
455  // ghost-cancellation logic.
456  int last_time = -999;
457  if (bx_times.size() == fifo_tbins) {
458  wire[i_layer][i_wire].push_back(0);
459  wire[i_layer][i_wire].push_back(6);
460  } else {
461  for (unsigned int i = 0; i < bx_times.size(); i++) {
462  // Find rising edge change
463  if (i > 0 && bx_times[i] == (bx_times[i - 1] + 1))
464  continue;
465  if (bx_times[i] < static_cast<int>(fifo_tbins)) {
466  if (infoV > 2)
467  LogTrace("CSCAnodeLCTProcessor")
468  << "Digi on layer " << i_layer << " wire " << i_wire << " at time " << bx_times[i];
469 
470  // Finally save times of hit wires. One shot module will
471  // not restart if a new pulse comes before the expiration
472  // of the 6-bx period.
473  if (last_time < 0 || ((bx_times[i] - last_time) >= 6)) {
474  wire[i_layer][i_wire].push_back(bx_times[i]);
475  last_time = bx_times[i];
476  }
477  } else {
478  if (infoV > 1)
479  LogTrace("CSCAnodeLCTProcessor") << "+++ Skipping wire digi: wire = " << i_wire << " layer = " << i_layer
480  << ", bx = " << bx_times[i] << " +++";
481  }
482  }
483  }
484  }
485  }
486 }
487 
490  bool chamber_empty = true;
491  int i_wire, i_layer, digi_num;
492 
493  const unsigned bits_in_pulse = pulse_.bitsInPulse();
494 
495  // Clear pulse array. This array will be used as a bit representation of
496  // hit times. For example: if strip[1][2] has a value of 3, then 1 shifted
497  // left 3 will be bit pattern of pulse[1][2]. This would make the pattern
498  // look like 0000000000001000. Then add on additional bits to signify
499  // the duration of a signal (hit_persist, formerly bx_width) to simulate
500  // the TMB's drift delay. So for the same pulse[1][2] with a hit_persist
501  // of 3 would look like 0000000000111000. This is similating the digital
502  // one-shot in the TMB.
503  pulse_.clear();
504 
505  for (i_wire = 0; i_wire < numWireGroups; i_wire++) {
506  first_bx[i_wire] = -999;
507  first_bx_corrected[i_wire] = -999;
508  for (int j = 0; j < 3; j++)
509  quality[i_wire][j] = -999;
510  }
511 
512  for (i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
513  digi_num = 0;
514  for (i_wire = 0; i_wire < numWireGroups; i_wire++) {
515  if (!wire[i_layer][i_wire].empty()) {
516  std::vector<int> bx_times = wire[i_layer][i_wire];
517  for (unsigned int i = 0; i < bx_times.size(); i++) {
518  // Check that min and max times are within the allowed range.
519  if (bx_times[i] < 0 || bx_times[i] + hit_persist >= bits_in_pulse) {
520  if (infoV > 0)
521  edm::LogWarning("CSCAnodeLCTProcessor|OutOfTimeDigi")
522  << "+++ BX time of wire digi (wire = " << i_wire << " layer = " << i_layer << ") bx = " << bx_times[i]
523  << " is not within the range (0-" << bits_in_pulse
524  << "] allowed for pulse extension. Skip this digi! +++\n";
525  continue;
526  }
527 
528  // Found at least one in-time digi; set chamber_empty to false
529  if (chamber_empty)
530  chamber_empty = false;
531 
532  // make the pulse
533  pulse_.extend(i_layer, i_wire, bx_times[i], hit_persist);
534 
535  // Debug information.
536  if (infoV > 1) {
537  LogTrace("CSCAnodeLCTProcessor") << "Wire digi: layer " << i_layer << " digi #" << ++digi_num
538  << " wire group " << i_wire << " time " << bx_times[i];
539  if (infoV > 2) {
540  std::ostringstream strstrm;
541  for (int i = 1; i <= 32; i++) {
542  strstrm << pulse_.oneShotAtBX(i_layer, i_wire, 32 - i);
543  }
544  LogTrace("CSCAnodeLCTProcessor") << " Pulse: " << strstrm.str();
545  }
546  }
547  }
548  }
549  }
550  }
551 
552  if (infoV > 1 && !chamber_empty) {
553  dumpDigis(wire);
554  }
555 
556  return chamber_empty;
557 }
558 
559 bool CSCAnodeLCTProcessor::preTrigger(const int key_wire, const int start_bx) {
560  int nPreTriggers = 0;
561 
562  unsigned int layers_hit;
563  bool hit_layer[CSCConstants::NUM_LAYERS];
564  int this_wire;
565  // If nplanes_hit_accel_pretrig is 0, the firmware uses the value
566  // of nplanes_hit_pretrig instead.
567  const unsigned int nplanes_hit_pretrig_acc =
569  const unsigned int pretrig_thresh[CSCConstants::NUM_ALCT_PATTERNS] = {
570  nplanes_hit_pretrig_acc, nplanes_hit_pretrig, nplanes_hit_pretrig};
571 
572  // Loop over bx times, accelerator and collision patterns to
573  // look for pretrigger.
574  // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
575  // not have a full set of hits to start pattern search anyway.
576  unsigned int stop_bx = fifo_tbins - drift_delay;
577  for (unsigned int bx_time = start_bx; bx_time < stop_bx; bx_time++) {
578  for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
579  // initialize the hit layers
580  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++)
581  hit_layer[i_layer] = false;
582  layers_hit = 0;
583 
584  // now run over all layers and wires
585  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
586  for (int i_wire = 0; i_wire < CSCConstants::ALCT_PATTERN_WIDTH; i_wire++) {
587  // check if the hit is valid
588  if (alct_pattern_[i_pattern][i_layer][i_wire]) {
589  this_wire = CSCPatternBank::alct_keywire_offset_[MESelection][i_wire] + key_wire;
590  if ((this_wire >= 0) && (this_wire < numWireGroups)) {
591  // Perform bit operation to see if pulse is 1 at a certain bx_time.
592  if (pulse_.isOneShotHighAtBX(i_layer, this_wire, bx_time)) {
593  // Store number of layers hit.
594  if (!hit_layer[i_layer]) {
595  hit_layer[i_layer] = true;
596  layers_hit++;
597  }
598 
599  // See if number of layers hit is greater than or equal to
600  // pretrig_thresh.
601  if (layers_hit >= pretrig_thresh[i_pattern]) {
602  first_bx[key_wire] = bx_time;
603  if (infoV > 1) {
604  LogTrace("CSCAnodeLCTProcessor") << "Pretrigger was satisfied for wire: " << key_wire
605  << " pattern: " << i_pattern << " bx_time: " << bx_time;
606  }
607  // make a new pre-trigger
608  nPreTriggers++;
609  // make a new pre-trigger digi
610  // useful for calculating DAQ rates
611  thePreTriggerDigis.emplace_back(
612  CSCALCTPreTriggerDigi(1, layers_hit - 3, 0, 0, this_wire, bx_time, nPreTriggers));
613  return true;
614  }
615  }
616  }
617  }
618  }
619  }
620  }
621  }
622  // If the pretrigger was never satisfied, then return false.
623  return false;
624 }
625 
627  const int key_wire, std::map<int, std::map<int, CSCALCTDigi::WireContainer>>& hits_in_patterns) {
628  bool trigger = false;
629  bool hit_layer[CSCConstants::NUM_LAYERS];
630  unsigned int temp_quality;
631  int this_wire, delta_wire;
632  // If nplanes_hit_accel_pattern is 0, the firmware uses the value
633  // of nplanes_hit_pattern instead.
634  const unsigned int nplanes_hit_pattern_acc =
636  const unsigned int pattern_thresh[CSCConstants::NUM_ALCT_PATTERNS] = {
637  nplanes_hit_pattern_acc, nplanes_hit_pattern, nplanes_hit_pattern};
638  const std::string ptn_label[] = {"Accelerator", "CollisionA", "CollisionB"};
639 
640  for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
641  temp_quality = 0;
642 
643  // initialize the hit layers
644  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++)
645  hit_layer[i_layer] = false;
646 
647  // clear a single pattern!
648  CSCALCTDigi::WireContainer hits_single_pattern;
649  hits_single_pattern.clear();
650  hits_single_pattern.resize(CSCConstants::NUM_LAYERS);
651  for (auto& p : hits_single_pattern) {
653  }
654 
655  double num_pattern_hits = 0., times_sum = 0.;
656  std::multiset<int> mset_for_median;
657  mset_for_median.clear();
658 
659  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
660  for (int i_wire = 0; i_wire < CSCConstants::ALCT_PATTERN_WIDTH; i_wire++) {
661  // check if the hit is valid
662  if (alct_pattern_[i_pattern][i_layer][i_wire]) {
664  this_wire = delta_wire + key_wire;
665  if ((this_wire >= 0) && (this_wire < numWireGroups)) {
666  // Wait a drift_delay time later and look for layers hit in
667  // the pattern.
668  if (pulse_.isOneShotHighAtBX(i_layer, this_wire, first_bx[key_wire] + drift_delay)) {
669  // store hits in the temporary pattern vector
670  hits_single_pattern[i_layer][i_wire] = this_wire;
671 
672  // If layer has never had a hit before, then increment number
673  // of layer hits.
674  if (!hit_layer[i_layer]) {
675  temp_quality++;
676  // keep track of which layers already had hits.
677  hit_layer[i_layer] = true;
678  if (infoV > 1)
679  LogTrace("CSCAnodeLCTProcessor")
680  << "bx_time: " << first_bx[key_wire] << " pattern: " << i_pattern << " keywire: " << key_wire
681  << " layer: " << i_layer << " quality: " << temp_quality;
682  }
683 
684  // for averaged time use only the closest WGs around the key WG
685  if (abs(delta_wire) < 2) {
686  // find at what bx did pulse on this wire&layer start
687  // use hit_pesrist constraint on how far back we can go
688  int first_bx_layer = first_bx[key_wire] + drift_delay;
689  for (unsigned int dbx = 0; dbx < hit_persist; dbx++) {
690  if (pulse_.isOneShotHighAtBX(i_layer, this_wire, first_bx_layer - 1)) {
691  first_bx_layer--;
692  } else
693  break;
694  }
695  times_sum += (double)first_bx_layer;
696  num_pattern_hits += 1.;
697  mset_for_median.insert(first_bx_layer);
698  if (infoV > 2)
699  LogTrace("CSCAnodeLCTProcessor") << " 1st bx in layer: " << first_bx_layer << " sum bx: " << times_sum
700  << " #pat. hits: " << num_pattern_hits;
701  }
702  }
703  }
704  }
705  }
706  }
707 
708  // calculate median
709  const int sz = mset_for_median.size();
710  if (sz > 0) {
711  std::multiset<int>::iterator im = mset_for_median.begin();
712  if (sz > 1)
713  std::advance(im, sz / 2 - 1);
714  if (sz == 1)
715  first_bx_corrected[key_wire] = *im;
716  else if ((sz % 2) == 1)
717  first_bx_corrected[key_wire] = *(++im);
718  else
719  first_bx_corrected[key_wire] = ((*im) + (*(++im))) / 2;
720 
721 #if defined(EDM_ML_DEBUG)
722  if (infoV > 1) {
723  auto lt = LogTrace("CSCAnodeLCTProcessor")
724  << "bx=" << first_bx[key_wire] << " bx_cor=" << first_bx_corrected[key_wire] << " bxset=";
725  for (im = mset_for_median.begin(); im != mset_for_median.end(); im++) {
726  lt << " " << *im;
727  }
728  }
729 #endif
730  }
731 
732  // save the pattern information when a trigger was formed!
733  if (temp_quality >= pattern_thresh[i_pattern]) {
734  trigger = true;
735  hits_in_patterns[key_wire][i_pattern] = hits_single_pattern;
736 
737  // Quality definition changed on 22 June 2007: it no longer depends
738  // on pattern_thresh.
739  temp_quality = getTempALCTQuality(temp_quality);
740 
741  if (i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) {
742  // Accelerator pattern
743  quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] = temp_quality;
744  } else {
745  // Only one collision pattern (of the best quality) is reported
746  if (static_cast<int>(temp_quality) > quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN]) {
747  quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] = temp_quality; //real quality
748  quality[key_wire][CSCConstants::ALCT_COLLISIONB_PATTERN] = i_pattern - 1; // pattern, left or right
749  }
750  }
751  if (infoV > 1) {
752  LogTrace("CSCAnodeLCTProcessor") << "Pattern found; keywire: " << key_wire << " type: " << ptn_label[i_pattern]
753  << " quality: " << temp_quality << "\n";
754  }
755  }
756  }
757  if (infoV > 1 && quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
759  LogTrace("CSCAnodeLCTProcessor") << "Collision Pattern A is chosen"
760  << "\n";
761  else if (quality[key_wire][CSCConstants::ALCT_COLLISIONB_PATTERN] == 1)
762  LogTrace("CSCAnodeLCTProcessor") << "Collision Pattern B is chosen"
763  << "\n";
764  }
765 
766  trigMode(key_wire);
767 
768  return trigger;
769 }
770 
771 void CSCAnodeLCTProcessor::ghostCancellationLogicOneWire(const int key_wire, int* ghost_cleared) {
772  for (int i_pattern = 0; i_pattern < 2; i_pattern++) {
773  ghost_cleared[i_pattern] = 0;
774  if (key_wire == 0)
775  continue; //ignore
776 
777  // Non-empty wire group.
778  int qual_this = quality[key_wire][i_pattern];
779  if (qual_this > 0) {
780  // Previous wire.
781  //int qual_prev = (key_wire > 0) ? quality[key_wire-1][i_pattern] : 0;
782  //previous ALCTs were pushed to lct_list, stop use the array quality[key_wire-1][i_pattern]
783  for (auto& p : lct_list) {
784  //ignore whether ALCT is valid or not in ghost cancellation
785  //if wiregroup 10, 11, 12 all have trigger and same quality, only wiregroup 10 can keep the trigger
786  //this met with firmware
787  if (not(p.getKeyWG() == key_wire - 1 and 1 - p.getAccelerator() == i_pattern))
788  continue;
789 
790  bool ghost_cleared_prev = false;
791  int qual_prev = p.getQuality();
792  int first_bx_prev = p.getBX();
793  if (infoV > 1)
794  LogTrace("CSCAnodeLCTProcessor")
795  << "ghost concellation logic "
796  << ((i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) ? "Accelerator" : "Collision") << " key_wire "
797  << key_wire << " quality " << qual_this << " bx " << first_bx[key_wire] << " previous key_wire "
798  << key_wire - 1 << " quality " << qual_prev << " bx " << first_bx[key_wire - 1];
799 
800  //int dt = first_bx[key_wire] - first_bx[key_wire-1];
801  int dt = first_bx[key_wire] - first_bx_prev;
802  // Cancel this wire
803  // 1) If the candidate at the previous wire is at the same bx
804  // clock and has better quality (or equal quality - this has
805  // been implemented only in 2004).
806  // 2) If the candidate at the previous wire is up to 4 clocks
807  // earlier, regardless of quality.
808  if (dt == 0) {
809  if (qual_prev >= qual_this)
810  ghost_cleared[i_pattern] = 1;
811  else if (qual_prev < qual_this)
812  ghost_cleared_prev = true;
813  } else if (dt > 0 && dt <= ghost_cancellation_bx_depth) {
814  if ((!ghost_cancellation_side_quality) || (qual_prev > qual_this))
815  ghost_cleared[i_pattern] = 1;
816  } else if (dt < 0 && dt * (-1) <= ghost_cancellation_bx_depth) {
817  if ((!ghost_cancellation_side_quality) || (qual_prev < qual_this))
818  ghost_cleared_prev = true;
819  }
820 
821  if (ghost_cleared[i_pattern] == 1) {
822  if (infoV > 1)
823  LogTrace("CSCAnodeLCTProcessor")
824  << ((i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) ? "Accelerator" : "Collision")
825  << " pattern ghost cancelled on key_wire " << key_wire << " q=" << qual_this << " by wire "
826  << key_wire - 1 << " q=" << qual_prev;
827  //cancellation for key_wire is done when ALCT is created and pushed to lct_list
828  }
829 
830  if (ghost_cleared_prev) {
831  if (infoV > 1)
832  LogTrace("CSCAnodeLCTProcessor")
833  << ((i_pattern == CSCConstants::ALCT_ACCELERATOR_PATTERN) ? "Accelerator" : "Collision")
834  << " pattern ghost cancelled on key_wire " << key_wire - 1 << " q=" << qual_prev << " by wire "
835  << key_wire << " q=" << qual_this;
836  p.setValid(0); //clean prev ALCT
837  }
838  }
839 
840  } // if qual_this > 0
841  } //i_pattern
842 }
843 
845  // Best track selector selects two collision and two accelerator ALCTs
846  // with the best quality per time bin.
847  const std::vector<CSCALCTDigi>& fourBest = bestTrackSelector(lct_list);
848 
849  if (infoV > 0) {
850  int n_alct_all = 0, n_alct = 0;
851  for (const auto& p : lct_list) {
852  if (p.isValid() && p.getBX() == CSCConstants::LCT_CENTRAL_BX)
853  n_alct_all++;
854  }
855  for (const auto& p : fourBest) {
856  if (p.isValid() && p.getBX() == CSCConstants::LCT_CENTRAL_BX)
857  n_alct++;
858  }
859 
860  LogTrace("CSCAnodeLCTProcessor") << "alct_count E:" << theEndcap << "S:" << theStation << "R:" << theRing
861  << "C:" << theChamber << " all " << n_alct_all << " found " << n_alct;
862  }
863 
864  // Select two best of four per time bin, based on quality and
865  // accel_mode parameter.
866  for (const auto& p : fourBest) {
867  const int bx = p.getBX();
869  if (infoV > 0)
870  edm::LogWarning("CSCAnodeLCTProcessor|OutOfTimeALCT")
871  << "+++ Bx of ALCT candidate, " << bx << ", exceeds max allowed, " << CSCConstants::MAX_ALCT_TBINS - 1
872  << "; skipping it... +++\n";
873  continue;
874  }
875 
876  if (isBetterALCT(p, bestALCT[bx])) {
878  secondALCT[bx] = bestALCT[bx];
879  }
880  bestALCT[bx] = p;
881  } else if (isBetterALCT(p, secondALCT[bx])) {
882  secondALCT[bx] = p;
883  }
884  }
885 
886  for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
887  if (bestALCT[bx].isValid()) {
888  bestALCT[bx].setTrknmb(1);
889 
890  // check if the best ALCT is valid
891  qualityControl_->checkValidReadout(bestALCT[bx]);
892 
893  if (infoV > 0) {
894  LogDebug("CSCAnodeLCTProcessor") << bestALCT[bx] << " fullBX = " << bestALCT[bx].getFullBX() << " found in "
895  << theCSCName_ << " (sector " << theSector << " subsector " << theSubsector
896  << " trig id. " << theTrigChamber << ")"
897  << "\n";
898  }
899  if (secondALCT[bx].isValid()) {
900  secondALCT[bx].setTrknmb(2);
901 
902  // check if the second best ALCT is valid
903  qualityControl_->checkValidReadout(secondALCT[bx]);
904 
905  if (infoV > 0) {
906  LogDebug("CSCAnodeLCTProcessor")
907  << secondALCT[bx] << " fullBX = " << secondALCT[bx].getFullBX() << " found in " << theCSCName_
908  << " (sector " << theSector << " subsector " << theSubsector << " trig id. " << theTrigChamber << ")"
909  << "\n";
910  }
911  }
912  }
913  }
914 }
915 
916 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::bestTrackSelector(const std::vector<CSCALCTDigi>& all_alcts) {
919 
920  if (infoV > 1) {
921  LogTrace("CSCAnodeLCTProcessor") << all_alcts.size() << " ALCTs at the input of best-track selector: ";
922  for (const auto& p : all_alcts) {
923  if (!p.isValid())
924  continue;
925  LogTrace("CSCAnodeLCTProcessor") << p;
926  }
927  }
928 
931  for (const auto& p : all_alcts) {
932  if (!p.isValid())
933  continue;
934 
935  // Select two collision and two accelerator ALCTs with the highest
936  // quality at every bx. The search for best ALCTs is done in parallel
937  // for collision and accelerator patterns, and simultaneously for
938  // two ALCTs, tA and tB. If two or more ALCTs have equal qualities,
939  // the priority is given to the ALCT with larger wiregroup number
940  // in the search for tA (collision and accelerator), and to the ALCT
941  // with smaller wiregroup number in the search for tB.
942  int bx = p.getBX();
943  int accel = p.getAccelerator();
944  int qual = p.getQuality();
945  int wire = p.getKeyWG();
946  bool vA = tA[bx][accel].isValid();
947  bool vB = tB[bx][accel].isValid();
948  int qA = tA[bx][accel].getQuality();
949  int qB = tB[bx][accel].getQuality();
950  int wA = tA[bx][accel].getKeyWG();
951  int wB = tB[bx][accel].getKeyWG();
952  if (!vA || qual > qA || (qual == qA && wire > wA)) {
953  tA[bx][accel] = p;
954  }
955  if (!vB || qual > qB || (qual == qB && wire < wB)) {
956  tB[bx][accel] = p;
957  }
958  }
959 
960  for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
961  for (int accel = 0; accel <= 1; accel++) {
962  // Best ALCT is always tA.
963  if (tA[bx][accel].isValid()) {
964  if (infoV > 2) {
965  LogTrace("CSCAnodeLCTProcessor") << "tA: " << tA[bx][accel];
966  LogTrace("CSCAnodeLCTProcessor") << "tB: " << tB[bx][accel];
967  }
968  bestALCTs[bx][accel] = tA[bx][accel];
969 
970  // If tA exists, tB exists too.
971  if (tA[bx][accel] != tB[bx][accel] && tA[bx][accel].getQuality() == tB[bx][accel].getQuality()) {
972  secondALCTs[bx][accel] = tB[bx][accel];
973  } else {
974  // Funny part: if tA and tB are the same, or the quality of tB
975  // is inferior to the quality of tA, the second best ALCT is
976  // not tB. Instead it is the largest-wiregroup ALCT among those
977  // ALCT whose qualities are lower than the quality of the best one.
978  for (const auto& p : all_alcts) {
979  if (p.isValid() && p.getAccelerator() == accel && p.getBX() == bx &&
980  p.getQuality() < bestALCTs[bx][accel].getQuality() &&
981  p.getQuality() >= secondALCTs[bx][accel].getQuality() &&
982  p.getKeyWG() >= secondALCTs[bx][accel].getKeyWG()) {
983  secondALCTs[bx][accel] = p;
984  }
985  }
986  }
987  }
988  }
989  }
990 
991  // Fill the vector with up to four best ALCTs per bx and return it.
992  std::vector<CSCALCTDigi> fourBest;
993  for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
994  for (int i = 0; i < CSCConstants::MAX_ALCTS_PER_PROCESSOR; i++) {
995  if (bestALCTs[bx][i].isValid()) {
996  fourBest.push_back(bestALCTs[bx][i]);
997  }
998  }
999  for (int i = 0; i < CSCConstants::MAX_ALCTS_PER_PROCESSOR; i++) {
1000  if (secondALCTs[bx][i].isValid()) {
1001  fourBest.push_back(secondALCTs[bx][i]);
1002  }
1003  }
1004  }
1005 
1006  if (infoV > 1) {
1007  LogTrace("CSCAnodeLCTProcessor") << fourBest.size() << " ALCTs selected: ";
1008  for (const auto& p : fourBest) {
1009  LogTrace("CSCAnodeLCTProcessor") << p;
1010  }
1011  }
1012 
1013  return fourBest;
1014 }
1015 
1016 bool CSCAnodeLCTProcessor::isBetterALCT(const CSCALCTDigi& lhsALCT, const CSCALCTDigi& rhsALCT) const {
1017  bool returnValue = false;
1018 
1019  if (lhsALCT.isValid() && !rhsALCT.isValid()) {
1020  return true;
1021  }
1022 
1023  // ALCTs found at earlier bx times are ranked higher than ALCTs found at
1024  // later bx times regardless of the quality.
1025  if (lhsALCT.getBX() < rhsALCT.getBX()) {
1026  returnValue = true;
1027  }
1028  if (lhsALCT.getBX() != rhsALCT.getBX()) {
1029  return returnValue;
1030  }
1031 
1032  // First check the quality of ALCTs.
1033  const int qual1 = lhsALCT.getQuality();
1034  const int qual2 = rhsALCT.getQuality();
1035  if (qual1 > qual2) {
1036  returnValue = true;
1037  }
1038  // If qualities are the same, check accelerator bits of both ALCTs.
1039  // If they are not the same, rank according to accel_mode value.
1040  // If they are the same, keep the track selector assignment.
1041  //else if (qual1 == qual2 &&
1042  // lhsALCT.getAccelerator() != rhsALCT.getAccelerator() &&
1043  // quality[lhsALCT.getKeyWG()][1-lhsALCT.getAccelerator()] >
1044  // quality[rhsALCT.getKeyWG()][1-rhsALCT.getAccelerator()])
1045  // {returnValue = true;}
1046  else if (qual1 == qual2 && lhsALCT.getAccelerator() != rhsALCT.getAccelerator()) {
1047  if ((accel_mode == 0 || accel_mode == 1) && rhsALCT.getAccelerator() == 0)
1048  returnValue = true;
1049  if ((accel_mode == 2 || accel_mode == 3) && lhsALCT.getAccelerator() == 0)
1050  returnValue = true;
1051  }
1052 
1053  return returnValue;
1054 }
1055 
1056 void CSCAnodeLCTProcessor::trigMode(const int key_wire) {
1057  switch (trig_mode) {
1058  default:
1059  case 0:
1060  // Enables both collision and accelerator tracks
1061  break;
1062  case 1:
1063  // Disables collision tracks
1064  if (quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1066  if (infoV > 1)
1067  LogTrace("CSCAnodeLCTProcessor") << "trigMode(): collision track " << key_wire << " disabled"
1068  << "\n";
1069  }
1070  break;
1071  case 2:
1072  // Disables accelerator tracks
1073  if (quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] > 0) {
1075  if (infoV > 1)
1076  LogTrace("CSCAnodeLCTProcessor") << "trigMode(): accelerator track " << key_wire << " disabled"
1077  << "\n";
1078  }
1079  break;
1080  case 3:
1081  // Disables collision track if there is an accelerator track found
1082  // in the same wire group at the same time
1083  if (quality[key_wire][0] > 0 && quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1085  if (infoV > 1)
1086  LogTrace("CSCAnodeLCTProcessor") << "trigMode(): collision track " << key_wire << " disabled"
1087  << "\n";
1088  }
1089  break;
1090  }
1091 }
1092 
1093 void CSCAnodeLCTProcessor::accelMode(const int key_wire) {
1094  int promotionBit = 1 << 2;
1095 
1096  switch (accel_mode) {
1097  default:
1098  case 0:
1099  // Ignore accelerator muons.
1100  if (quality[key_wire][0] > 0) {
1101  quality[key_wire][0] = 0;
1102  if (infoV > 1)
1103  LogTrace("CSCAnodeLCTProcessor") << "alctMode(): accelerator track " << key_wire << " ignored"
1104  << "\n";
1105  }
1106  break;
1107  case 1:
1108  // Prefer collision muons by adding promotion bit.
1109  if (quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1110  quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] += promotionBit;
1111  if (infoV > 1)
1112  LogTrace("CSCAnodeLCTProcessor") << "alctMode(): collision track " << key_wire << " promoted"
1113  << "\n";
1114  }
1115  break;
1116  case 2:
1117  // Prefer accelerator muons by adding promotion bit.
1118  if (quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] > 0) {
1119  quality[key_wire][CSCConstants::ALCT_ACCELERATOR_PATTERN] += promotionBit;
1120  if (infoV > 1)
1121  LogTrace("CSCAnodeLCTProcessor") << "alctMode(): accelerator track " << key_wire << " promoted"
1122  << "\n";
1123  }
1124  break;
1125  case 3:
1126  // Ignore collision muons.
1127  if (quality[key_wire][CSCConstants::ALCT_COLLISIONA_PATTERN] > 0) {
1129  if (infoV > 1)
1130  LogTrace("CSCAnodeLCTProcessor") << "alctMode(): collision track " << key_wire << " ignored"
1131  << "\n";
1132  }
1133  break;
1134  }
1135 }
1136 
1137 // Dump of configuration parameters.
1139  std::ostringstream strm;
1140  strm << "\n";
1141  strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1142  strm << "+ ALCT configuration parameters: +\n";
1143  strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1144  strm << " fifo_tbins [total number of time bins in DAQ readout] = " << fifo_tbins << "\n";
1145  strm << " fifo_pretrig [start time of anode raw hits in DAQ readout] = " << fifo_pretrig << "\n";
1146  strm << " drift_delay [drift delay after pre-trigger, in 25 ns bins] = " << drift_delay << "\n";
1147  strm << " nplanes_hit_pretrig [min. number of layers hit for pre-trigger] = " << nplanes_hit_pretrig << "\n";
1148  strm << " nplanes_hit_pattern [min. number of layers hit for trigger] = " << nplanes_hit_pattern << "\n";
1149  strm << " nplanes_hit_accel_pretrig [min. number of layers hit for accel."
1150  << " pre-trig.] = " << nplanes_hit_accel_pretrig << "\n";
1151  strm << " nplanes_hit_accel_pattern [min. number of layers hit for accel."
1152  << " trigger] = " << nplanes_hit_accel_pattern << "\n";
1153  strm << " trig_mode [enabling/disabling collision/accelerator tracks] = " << trig_mode << "\n";
1154  strm << " accel_mode [preference to collision/accelerator tracks] = " << accel_mode << "\n";
1155  strm << " l1a_window_width [L1Accept window width, in 25 ns bins] = " << l1a_window_width << "\n";
1156  strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
1157  LogDebug("CSCAnodeLCTProcessor") << strm.str();
1158 }
1159 
1160 // Dump of digis on wire groups.
1162  const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS]) const {
1163  LogDebug("CSCAnodeLCTProcessor") << theCSCName_ << " nWiregroups " << numWireGroups;
1164 
1165  std::ostringstream strstrm;
1166  for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
1167  if (i_wire % 10 == 0) {
1168  if (i_wire < 100)
1169  strstrm << i_wire / 10;
1170  else
1171  strstrm << (i_wire - 100) / 10;
1172  } else
1173  strstrm << " ";
1174  }
1175  strstrm << "\n";
1176  for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
1177  strstrm << i_wire % 10;
1178  }
1179  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1180  strstrm << "\n";
1181  for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
1182  if (!wire[i_layer][i_wire].empty()) {
1183  std::vector<int> bx_times = wire[i_layer][i_wire];
1184  strstrm << std::hex << bx_times[0] << std::dec;
1185  } else {
1186  strstrm << ".";
1187  }
1188  }
1189  }
1190  LogTrace("CSCAnodeLCTProcessor") << strstrm.str();
1191 }
1192 
1193 // Returns vector of read-out ALCTs, if any. Starts with the vector of
1194 // all found ALCTs and selects the ones in the read-out time window.
1195 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::readoutALCTs() const {
1196  std::vector<CSCALCTDigi> tmpV;
1197 
1198  // The number of LCT bins in the read-out is given by the
1199  // l1a_window_width parameter, but made even by setting the LSB of
1200  // l1a_window_width to 0.
1201  const int lct_bins = l1a_window_width;
1202  static std::atomic<int> late_tbins{early_tbins + lct_bins};
1203 
1204  static std::atomic<int> ifois{0};
1205  if (ifois == 0) {
1206  if (infoV >= 0 && early_tbins < 0) {
1207  edm::LogWarning("CSCAnodeLCTProcessor|SuspiciousParameters")
1208  << "+++ fifo_pretrig = " << fifo_pretrig << "; in-time ALCTs are not getting read-out!!! +++"
1209  << "\n";
1210  }
1211 
1212  if (late_tbins > CSCConstants::MAX_ALCT_TBINS - 1) {
1213  if (infoV >= 0)
1214  edm::LogWarning("CSCAnodeLCTProcessor|SuspiciousParameters")
1215  << "+++ Allowed range of time bins, [0-" << late_tbins << "] exceeds max allowed, "
1216  << CSCConstants::MAX_ALCT_TBINS - 1 << " +++\n"
1217  << "+++ Set late_tbins to max allowed +++\n";
1218  late_tbins = CSCConstants::MAX_ALCT_TBINS - 1;
1219  }
1220  ifois = 1;
1221  }
1222 
1223  // Start from the vector of all found ALCTs and select those within
1224  // the ALCT*L1A coincidence window.
1225  const std::vector<CSCALCTDigi>& all_alcts = getALCTs();
1226  for (const auto& p : all_alcts) {
1227  if (!p.isValid())
1228  continue;
1229 
1230  int bx = p.getBX();
1231  // Skip ALCTs found too early relative to L1Accept.
1232  if (bx <= early_tbins) {
1233  if (infoV > 1)
1234  LogDebug("CSCAnodeLCTProcessor") << " Do not report ALCT on keywire " << p.getKeyWG() << ": found at bx " << bx
1235  << ", whereas the earliest allowed bx is " << early_tbins + 1;
1236  continue;
1237  }
1238 
1239  // Skip ALCTs found too late relative to L1Accept.
1240  if (bx > late_tbins) {
1241  if (infoV > 1)
1242  LogDebug("CSCAnodeLCTProcessor") << " Do not report ALCT on keywire " << p.getKeyWG() << ": found at bx " << bx
1243  << ", whereas the latest allowed bx is " << late_tbins;
1244  continue;
1245  }
1246 
1247  tmpV.push_back(p);
1248  }
1249 
1250  // shift the BX from 8 to 3
1251  // ALCTs in real data have the central BX in bin 3
1252  // which is the middle of the 7BX wide L1A window
1253  // ALCTs used in the TMB emulator have central BX at bin 8
1254  // but right before we put emulated ALCTs in the event, we shift the BX
1255  // by -5 to make sure they are compatible with real data ALCTs!
1256  for (auto& p : tmpV) {
1257  p.setBX(p.getBX() - (CSCConstants::LCT_CENTRAL_BX - l1a_window_width / 2));
1258  }
1259 
1260  // do a final check on the ALCTs in readout
1261  qualityControl_->checkMultiplicityBX(tmpV);
1262  for (const auto& alct : tmpV) {
1263  qualityControl_->checkValid(alct);
1264  }
1265 
1266  return tmpV;
1267 }
1268 
1269 // Returns vector of all found ALCTs, if any. Used in ALCT-CLCT matching.
1270 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::getALCTs() const {
1271  std::vector<CSCALCTDigi> tmpV;
1272  for (int bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
1273  if (bestALCT[bx].isValid())
1274  tmpV.push_back(bestALCT[bx]);
1275  if (secondALCT[bx].isValid())
1276  tmpV.push_back(secondALCT[bx]);
1277  }
1278  return tmpV;
1279 }
1280 
1282  if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1283  return CSCALCTDigi();
1284  return bestALCT[bx];
1285 }
1286 
1288  if (bx >= CSCConstants::MAX_CLCT_TBINS or bx < 0)
1289  return CSCALCTDigi();
1290  return secondALCT[bx];
1291 }
1292 
1294 std::vector<CSCShowerDigi> CSCAnodeLCTProcessor::getAllShower() const {
1295  std::vector<CSCShowerDigi> vshowers(anode_showers_, anode_showers_ + CSCConstants::MAX_ALCT_TBINS);
1296  return vshowers;
1297 };
1298 
1300 std::vector<CSCShowerDigi> CSCAnodeLCTProcessor::readoutShower() const {
1301  unsigned minBXdiff = 2 * l1a_window_width; //impossible value
1302  unsigned minBX = 0;
1303  std::vector<CSCShowerDigi> showerOut;
1304  for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++) {
1307  if (anode_showers_[bx].isValid() and bx_diff < minBXdiff) {
1308  minBXdiff = bx_diff;
1309  minBX = bx;
1310  }
1311  }
1312 
1313  for (unsigned bx = minbx_readout_; bx < maxbx_readout_; bx++)
1314  if (bx == minBX)
1315  showerOut.push_back(anode_showers_[bx]);
1316  return showerOut;
1317 }
1318 
1321 
1322 void CSCAnodeLCTProcessor::showPatterns(const int key_wire) {
1323  /* Method to test the pretrigger */
1324  for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
1325  std::ostringstream strstrm_header;
1326  LogTrace("CSCAnodeLCTProcessor") << "\n"
1327  << "Pattern: " << i_pattern << " Key wire: " << key_wire;
1328  for (int i = 1; i <= 32; i++) {
1329  strstrm_header << ((32 - i) % 10);
1330  }
1331  LogTrace("CSCAnodeLCTProcessor") << strstrm_header.str();
1332  for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1333  for (int i_wire = 0; i_wire < CSCConstants::ALCT_PATTERN_WIDTH; i_wire++) {
1334  // check if the hit is valid
1335  if (alct_pattern_[i_pattern][i_layer][i_wire]) {
1336  std::ostringstream strstrm_pulse;
1337  int this_wire = CSCPatternBank::alct_keywire_offset_[MESelection][i_wire] + key_wire;
1338  if (this_wire >= 0 && this_wire < numWireGroups) {
1339  for (int i = 1; i <= 32; i++) {
1340  strstrm_pulse << pulse_.oneShotAtBX(i_layer, this_wire, 32 - i);
1341  }
1342  LogTrace("CSCAnodeLCTProcessor") << strstrm_pulse.str() << " on layer " << i_layer << " wire " << this_wire;
1343  }
1344  }
1345  }
1346  }
1347  LogTrace("CSCAnodeLCTProcessor") << "-------------------------------------------";
1348  }
1349 }
1350 
1351 int CSCAnodeLCTProcessor::getTempALCTQuality(int temp_quality) const {
1352  int Q;
1353  if (temp_quality > 3)
1354  Q = temp_quality - 3;
1355  else
1356  Q = 0; // quality code 0 is valid!
1357 
1358  return Q;
1359 }
1360 
1362  for (auto& p : wireHits) {
1363  p.erase(std::remove_if(p.begin(), p.end(), [](unsigned i) -> bool { return i == CSCConstants::INVALID_WIREGROUP; }),
1364  p.end());
1365  }
1366 }
1367 
1369  // clean the wire digi container
1370  cleanWireContainer(wireHits);
1371 
1372  // set the hit container
1373  alct.setHits(wireHits);
1374 }
1375 
1377  //numer of layer with hits and number of hits for 0-15 BXs
1378  std::set<unsigned> layersWithHits[CSCConstants::MAX_ALCT_TBINS];
1379  unsigned hitsInTime[CSCConstants::MAX_ALCT_TBINS];
1380  // Calculate layers with hits
1381  for (unsigned bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
1382  hitsInTime[bx] = 0;
1383  for (unsigned i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
1384  bool atLeastOneWGHit = false;
1385  for (const auto& wd : digiV[i_layer]) {
1386  std::vector<int> bx_times = wd.getTimeBinsOn();
1387  // there is at least one wiregroup in this bx
1388  if (std::find(bx_times.begin(), bx_times.end(), bx) != bx_times.end()) {
1389  hitsInTime[bx] += 1;
1390  atLeastOneWGHit = true;
1391  }
1392  }
1393  // add this layer to the number of layers hit
1394  if (atLeastOneWGHit) {
1395  layersWithHits[bx].insert(i_layer);
1396  }
1397  }
1398  } //end of full bx loop
1399 
1400  // convert station and ring number to index
1401  // index runs from 2 to 10, subtract 2
1402  unsigned csc_idx = CSCDetId::iChamberType(theStation, theRing) - 2;
1403 
1404  // loose, nominal and tight
1405  std::vector<unsigned> station_thresholds = {
1406  thresholds_[csc_idx * 3], thresholds_[csc_idx * 3 + 1], thresholds_[csc_idx * 3 + 2]};
1407 
1408  for (unsigned bx = 0; bx < CSCConstants::MAX_ALCT_TBINS; bx++) {
1409  unsigned minbx = bx >= showerNumTBins_ / 2 ? bx - showerNumTBins_ / 2 : bx;
1410  unsigned maxbx = bx < CSCConstants::MAX_ALCT_TBINS - showerNumTBins_ / 2 ? bx + showerNumTBins_ / 2
1412  unsigned this_hitsInTime = 0;
1413  for (unsigned mbx = minbx; mbx <= maxbx; mbx++) {
1414  this_hitsInTime += hitsInTime[mbx];
1415  }
1416 
1417  unsigned this_inTimeHMT = 0;
1418  // require at least nLayersWithHits for the central time bin
1419  // do nothing if there are not enough layers with hits
1420  if (layersWithHits[bx].size() >= minLayersCentralTBin_) {
1421  // assign the bits
1422  if (!station_thresholds.empty()) {
1423  for (int i = station_thresholds.size() - 1; i >= 0; i--) {
1424  if (this_hitsInTime >= station_thresholds[i]) {
1425  this_inTimeHMT = i + 1;
1426  break;
1427  }
1428  }
1429  }
1430  }
1431  //ALCT shower construction with showerType_=1, comparatorhits_= 0;
1433  this_inTimeHMT, false, theTrigChamber, bx, CSCShowerDigi::ShowerType::kALCTShower, this_hitsInTime, 0);
1434  }
1435 }
size
Write out results.
bool isValid() const
check ALCT validity (1 - valid ALCT)
Definition: CSCALCTDigi.h:40
void setHits(const WireContainer &hits)
Definition: CSCALCTDigi.h:120
float dt
Definition: AMPTWrapper.h:136
CSCShowerDigi anode_showers_[CSCConstants::MAX_ALCT_TBINS]
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
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 int alct_keywire_offset_[2][CSCConstants::ALCT_PATTERN_WIDTH]
uint16_t getBX() const
return BX - five low bits of BXN counter tagged by the ALCT
Definition: CSCALCTDigi.h:73
void showPatterns(const int key_wire)
bool isOneShotHighAtBX(const unsigned layer, const unsigned channel, const unsigned bx) const
Definition: PulseArray.cc:37
unsigned int alctAccelMode() const
std::unique_ptr< LCTQualityControl > qualityControl_
const bool isValid(const Frame &aFrame, const FrameQuality &aQuality, const uint16_t aExpectedPos)
unsigned int alctFifoTbins() const
static const unsigned int def_drift_delay
static const unsigned int def_fifo_tbins
const unsigned theEndcap
Definition: CSCBaseboard.h:74
bool getDigis(const CSCWireDigiCollection *wiredc)
void checkConfigParameters(unsigned int &var, const unsigned int var_max, const unsigned int var_def, const std::string &var_str)
bool pulseExtension(const std::vector< int > wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS])
int first_bx_corrected[CSCConstants::MAX_NUM_WIREGROUPS]
ParameterSet const & getParameterSet(std::string const &) const
std::vector< CSCALCTPreTriggerDigi > thePreTriggerDigis
const unsigned theSector
Definition: CSCBaseboard.h:76
void clear()
clear this ALCT
Definition: CSCALCTDigi.cc:60
Log< level::Error, false > LogError
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:104
void setConfigParameters(const CSCDBL1TPParameters *conf)
void trigMode(const int key_wire)
unsigned int alctTrigMode() const
uint16_t getQuality() const
return quality of a pattern
Definition: CSCALCTDigi.h:46
#define LogTrace(id)
const CSCLayerGeometry * geometry() const
Definition: CSCLayer.h:44
static const unsigned int def_accel_mode
std::vector< CSCALCTDigi > lct_list
CSCAnodeLCTProcessor(unsigned endcap, unsigned station, unsigned sector, unsigned subsector, unsigned chamber, CSCBaseboard::Parameters &conf)
static const unsigned int def_nplanes_hit_accel_pretrig
const unsigned theTrigChamber
Definition: CSCBaseboard.h:78
static const unsigned int def_fifo_pretrig
unsigned int alctNplanesHitPattern() const
std::vector< CSCShowerDigi > readoutShower() const
int numberOfWireGroups() const
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
uint16_t getKeyWG() const
return key wire group
Definition: CSCALCTDigi.h:67
void accelMode(const int key_wire)
const CSCChamber * cscChamber(CSCGeometry const &) const
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
unsigned int alctNplanesHitPretrig() const
unsigned theChamber
Definition: CSCBaseboard.h:81
unsigned int alctL1aWindowWidth() const
unsigned int alctNplanesHitAccelPretrig() const
static const unsigned int def_nplanes_hit_pattern
bool oneShotAtBX(const unsigned layer, const unsigned channel, const unsigned bx) const
Definition: PulseArray.cc:33
static const LCTPatterns alct_pattern_r1_
std::vector< CSCALCTDigi > run(const CSCWireDigiCollection *wiredc, CSCChamber const *chamber)
bool preTrigger(const int key_wire, const int start_bx)
edm::ParameterSet const & alctParams() const
Definition: CSCBaseboard.h:23
CSCALCTDigi secondALCT[CSCConstants::MAX_ALCT_TBINS]
static const unsigned int def_l1a_window_width
uint16_t getFullBX() const
return 12-bit full BX.
Definition: CSCALCTDigi.h:85
CSCPatternBank::LCTPatterns alct_pattern_
CSCALCTDigi getSecondALCT(int bx) const
unsigned int alctDriftDelay() const
static const unsigned int def_trig_mode
std::vector< std::vector< uint16_t > > WireContainer
Definition: CSCALCTDigi.h:21
bool patternDetection(const int key_wire, std::map< int, std::map< int, CSCALCTDigi::WireContainer > > &hits_in_patterns)
std::vector< CSCShowerDigi > getAllShower() const
unsigned int alctNplanesHitAccelPattern() const
static const unsigned int def_nplanes_hit_accel_pattern
bool isBetterALCT(const CSCALCTDigi &lhsALCT, const CSCALCTDigi &rhsALCT) const
std::pair< const_iterator, const_iterator > Range
uint16_t getAccelerator() const
Definition: CSCALCTDigi.h:53
const unsigned theStation
Definition: CSCBaseboard.h:75
std::vector< DigiType >::const_iterator const_iterator
void cleanWireContainer(CSCALCTDigi::WireContainer &wireHits) const
unsigned int alctFifoPretrig() const
std::vector< CSCALCTDigi > bestTrackSelector(const std::vector< CSCALCTDigi > &all_alcts)
void initialize(unsigned numberOfChannels)
Definition: PulseArray.cc:5
CSCALCTDigi getBestALCT(int bx) const
CSCALCTDigi bestALCT[CSCConstants::MAX_ALCT_TBINS]
virtual void ghostCancellationLogicOneWire(const int key_wire, int *ghost_cleared)
std::vector< CSCALCTDigi > getALCTs() const
void setWireContainer(CSCALCTDigi &, CSCALCTDigi::WireContainer &wireHits) const
static const LCTPatterns alct_pattern_legacy_
virtual int getTempALCTQuality(int temp_quality) const
unsigned bitsInPulse() const
Definition: PulseArray.cc:25
void clear()
clear this Shower
void setTrknmb(const uint16_t number)
Set track number (1,2) after sorting ALCTs.
Definition: CSCALCTDigi.h:82
unsigned theRing
Definition: CSCBaseboard.h:80
void dumpDigis(const std::vector< int > wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS]) const
Log< level::Warning, false > LogWarning
int first_bx[CSCConstants::MAX_NUM_WIREGROUPS]
unsigned int nplanes_hit_accel_pattern
int quality[CSCConstants::MAX_NUM_WIREGROUPS][CSCConstants::NUM_ALCT_PATTERNS]
std::vector< CSCALCTDigi > readoutALCTs() const
std::vector< unsigned > thresholds_
void readWireDigis(std::vector< int > wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIREGROUPS])
unsigned int pretrig_extra_deadtime
std::vector< CSCWireDigi > digiV[CSCConstants::NUM_LAYERS]
void extend(const unsigned layer, const unsigned channel, const unsigned bx, const unsigned hit_persist)
Definition: PulseArray.cc:27
static const unsigned int def_nplanes_hit_pretrig
const unsigned theSubsector
Definition: CSCBaseboard.h:77
unsigned int nplanes_hit_accel_pretrig
#define LogDebug(id)