CMS 3D CMS Logo

HTrphi.cc
Go to the documentation of this file.
8 
11 
12 #include <vector>
13 #include <limits>
14 #include <atomic>
15 #include <sstream>
16 #include <mutex>
17 
18 using namespace std;
19 
20 namespace tmtt {
21 
22  //=== The r-phi Hough Transform array for a single (eta,phi) sector.
23  //===
24  //=== Its axes are (q/Pt, phiTrk), where phiTrk is the phi at which the track crosses a
25  //=== user-configurable radius from the beam-line.
26 
27  //=== Initialise
28 
29  HTrphi::HTrphi(const Settings* settings,
30  unsigned int iPhiSec,
31  unsigned int iEtaReg,
32  float etaMinSector,
33  float etaMaxSector,
34  float phiCentreSector,
35  HTrphi::ErrorMonitor* errMon)
36  : HTbase(settings, iPhiSec, iEtaReg, settings->houghNbinsPt(), settings->houghNbinsPhi()),
37  invPtToDphi_((settings->invPtToDphi())),
38  shape_(static_cast<HTshape>(settings->shape())), // shape of HT cells
39 
40  //--- Specification of HT q/Pt axis.
41  maxAbsQoverPtAxis_(1. / settings->houghMinPt()), // Max. |q/Pt| covered by HT array.
42  nBinsQoverPtAxis_(settings->houghNbinsPt()), // No. of bins in HT array in q/Pt.
43  binSizeQoverPtAxis_(2 * maxAbsQoverPtAxis_ / nBinsQoverPtAxis_),
44 
45  //--- Specification of HT phiTrk axis
46  // (phiTrk corresponds to phi where track crosses radius = chosenRofPhi_).
47  chosenRofPhi_(settings->chosenRofPhi()),
48  phiCentreSector_(phiCentreSector), // Centre of phiTrk sector.
49  maxAbsPhiTrkAxis_(M_PI / float(settings->numPhiSectors())), // Half-width of phiTrk axis in HT array.
50  nBinsPhiTrkAxis_(settings->houghNbinsPhi()), // No. of bins in HT array phiTrk
51  binSizePhiTrkAxis_(2 * maxAbsPhiTrkAxis_ / nBinsPhiTrkAxis_),
52  errMon_(errMon) {
53  // Deal with unusually shaped HT cells.
54  if (shape_ != HTshape::square)
56  if (shape_ == HTshape::hexagon)
58  else if (shape_ == HTshape::diamond)
60 
61  // Optionally merge 2x2 neighbouring cells into a single cell at low Pt, to reduce efficiency loss due to
62  // scattering. (Do this if either of options EnableMerge2x2 or MiniHTstage are enabled.
63  // N.B These two options are never both enabled).
64  enableMerge2x2_ = (settings->enableMerge2x2() || settings->miniHTstage());
65  if (settings->miniHTstage()) {
66  // Mini-HT stage cfg: Merge all bins, irrespective of Pt.
68  } else {
69  // Merged cells cfg: Merge bins below specified Pt threshold.
70  minInvPtToMerge2x2_ = 1. / (settings->maxPtToMerge2x2());
72  enableMerge2x2_ = false;
73  }
74 
75  // Merging 2x2 cells into 1 merged cell is only allowed if HT array dimensions are even.
76  // (This restriction could be removed along q/Pt axis, since there are also unmerged cells there. But this
77  // would require correcting the code after each called to mergedCell() below, since
78  // "if (i%2 == 1) iStore = i - 1" not correct in this case).
79  if (enableMerge2x2_ && (nBinsQoverPtAxis_ % 2 != 0 || nBinsPhiTrkAxis_ % 2 != 0))
80  throw cms::Exception("BadConfig") << "HTrphi: You are not allowed to set EnableMerge2x2 or MiniHTstage = True if "
81  "you have an odd number of bins "
82  "in r-phi HT array "
84 
85  //--- Other options used when filling the HT.
86 
87  // Don't fill all HT cells nominally crossed by line corresponding to stub.
89 
90  // Used to kill excess stubs or tracks that can't be transmitted within time-multiplexed period.
91  nReceivedStubs_ = 0;
92  busyInputSectorKill_ = settings_->busyInputSectorKill(); // Kill excess stubs going fron GP to HT?
93  busySectorKill_ = settings_->busySectorKill(); // Kill excess tracks flowing out of HT?
94  // Max. num. of stubs that can be sent from GP to HT within TM period
96  // Max. num. of stubs that can be sent out of HT within TM period
98  // or individual m bin (=q/Pt) ranges to be output to optical links.
100  // Specifies which m bins should be grouped together by BusySectorMbinRanges. If empty, then they are grouped in order 0,1,2,3,4,5 ...
102  // m bin ranges option disabled if vector empty
105 
106  bool rescaleMbins = false;
108  // Check if the total number of bins specified in cfg option BusySectorMbinRanges corresponds
109  // to the number of m bins (q/Pt) in the HT. If not, determine how much the ranges must be scaled
110  // to make this true.
111  unsigned int nTotalBins = 0;
112  for (unsigned int j = 0; j < busySectorMbinRanges_.size(); j++) {
113  nTotalBins += busySectorMbinRanges_[j];
114  }
115  rescaleMbins = (nTotalBins != nBinsQoverPtAxis_);
116  // No rescaling allowed with MBinOrder option.
117  if (rescaleMbins && busySectorUseMbinOrder_)
118  throw cms::Exception("BadConfig") << "HTrphi: BusySectorUserMbin error";
119  float rescaleFactor = rescaleMbins ? float(nBinsQoverPtAxis_) / float(nTotalBins) : 1.;
120  // Find lower and upper inclusive limits of each m bin range to be sent to a separate optical link.
123  float mBinSum = 0.;
124  for (unsigned int i = 0; i < busySectorMbinRanges_.size(); i++) {
125  busySectorMbinLow_[i] = std::round(mBinSum);
126  busySectorMbinHigh_[i] = std::round(mBinSum + rescaleFactor * busySectorMbinRanges_[i]) - 1;
127  mBinSum += rescaleFactor * busySectorMbinRanges_[i];
128  }
129  }
130  //
131  for (unsigned int i = 0; i < nBinsQoverPtAxis_; i++) {
132  for (unsigned int j = 0; j < nBinsPhiTrkAxis_; j++) {
133  pair<float, float> helix = this->helix2Dconventional(i, j); // Get track params at centre of cell.
134  float qOverPt = helix.first;
135  // Check if this cell is merged with its neighbours (as in low Pt region).
136  bool mergedCell = false;
137  if (enableMerge2x2_ && this->mergedCell(i, j))
138  mergedCell = true;
139  // Initialize each cell in HT array.
140  HTbase::htArray_(i, j) =
141  std::make_unique<HTcell>(settings, iPhiSec, iEtaReg, etaMinSector, etaMaxSector, qOverPt, i, mergedCell);
142  }
143  }
144 
145  std::stringstream text;
146  text << "\n";
147  text << "=== R-PHI HOUGH TRANSFORM AXES RANGES: abs(q/Pt) < " << maxAbsQoverPtAxis_ << " & abs(track-phi) < "
148  << maxAbsPhiTrkAxis_ << " ===\n";
149  text << "=== R-PHI HOUGH TRANSFORM ARRAY SIZE: q/Pt bins = " << nBinsQoverPtAxis_
150  << " & track-phi bins = " << nBinsPhiTrkAxis_ << " ===\n";
151  text << "=== R-PHI HOUGH TRANSFORM BIN SIZE: BIN(q/Pt) = " << binSizeQoverPtAxis_
152  << " & BIN(track-phi) = " << binSizePhiTrkAxis_ << " ===\n\n";
153  if (busySectorKill_ && busySectorUseMbinRanges_ && rescaleMbins) {
154  text << "=== R-PHI HOUGH TRANSFORM WARNING: Rescaled m bin ranges specified by cfg parameter "
155  "BusySectorMbinRanges, as they were inconsistent with total number of m bins in HT.\n";
156  text << "=== Rescaled values for BusySectorMbinRanges =";
157  for (unsigned int i = 0; i < busySectorMbinRanges_.size(); i++) {
158  text << " " << (busySectorMbinHigh_[i] - busySectorMbinLow_[i] + 1);
159  }
160  }
161  text << "\n";
162  static std::once_flag printOnce;
163  std::call_once(printOnce, [](string t) { PrintL1trk() << t; }, text.str());
164 
165  // Note helix parameters at the centre of each HT cell.
166  cellCenters_.clear();
167  for (unsigned int m = 0; m < nBinsQoverPtAxis_; m++) {
168  std::vector<std::pair<float, float> > binCenters;
169  for (unsigned int c = 0; c < nBinsPhiTrkAxis_; c++)
170  binCenters.push_back(this->helix2Dhough(m, c));
171  cellCenters_.push_back(binCenters);
172  }
173  }
174 
175  //=== Add stub to HT array.
176  //=== If eta subsectors are being used within each sector, specify which ones the stub is compatible with.
177 
178  void HTrphi::store(Stub* stub, const vector<bool>& inEtaSubSecs) {
179  // Optionally, only store stubs that can be sent from GP to HT within TM period.
181  nReceivedStubs_++;
182 
183  unsigned int jPhiTrkBinMinLast = 0; // Used for error checking
184  unsigned int jPhiTrkBinMaxLast = 99999;
185 
186  // Loop over q/Pt related bins in HT array.
187  for (unsigned int i = 0; i < nBinsQoverPtAxis_; i++) {
188  if (shape_ == HTshape::square) {
189  //--- This is a traditional HT with square cells.
190 
191  // In this q/Pt bin, find the range of phi bins that this stub is consistent with.
192  pair<unsigned int, unsigned int> jRange = this->iPhiRange(stub, i);
193  unsigned int jPhiTrkBinMin = jRange.first;
194  unsigned int jPhiTrkBinMax = jRange.second;
195 
196  // Store stubs in these cells.
197  for (unsigned int j = jPhiTrkBinMin; j <= jPhiTrkBinMax; j++) {
198  bool canStoreStub = true;
199  unsigned int iStore = i;
200  unsigned int jStore = j;
201 
202  // Optionally merge 2x2 neighbouring cells into a single cell at low Pt, to reduce efficiency loss
203  // due to scattering.
204  if (enableMerge2x2_) {
205  // Check if this cell is merged with its neighbours (as in low Pt region).
206  if (this->mergedCell(i, j)) {
207  // Get location of cell that this cell is merged into (iStore, jStore).
208  // Calculation assumes HT array has even number of bins in both dimensions.
209  if (i % 2 == 1)
210  iStore = i - 1;
211  if (j % 2 == 1)
212  jStore = j - 1;
213  // If this stub was already stored in this merged 2x2 cell, then don't store it again.
214  if (HTbase::htArray_(iStore, jStore)->stubStoredInCell(stub))
215  canStoreStub = false;
216  }
217  }
218 
219  if (canStoreStub)
220  HTbase::htArray_(iStore, jStore)->store(stub, inEtaSubSecs); // Calls HTcell::store()
221  }
222 
223  // Check that limitations of firmware would not prevent stub being stored correctly in this HT column.
224  if (errMon_ != nullptr) {
225  this->countFirmwareErrors(i, jPhiTrkBinMin, jPhiTrkBinMax, jPhiTrkBinMinLast, jPhiTrkBinMaxLast);
226  jPhiTrkBinMinLast = jPhiTrkBinMin;
227  jPhiTrkBinMaxLast = jPhiTrkBinMax;
228  }
229 
230  } else {
231  //--- This is are novel HT with unusual shaped cells.
232 
233  if (shape_ == HTshape::diamond) {
234  //--- This HT has diamond shaped cells.
235 
236  float qOverPtBin = -maxAbsQoverPtAxis_ + i * binSizeQoverPtAxis_;
237  float phiTrk = reco::deltaPhi(stub->phi(), phiCentreSector_) +
238  invPtToDphi_ * qOverPtBin * (stub->r() - chosenRofPhi_) + maxAbsPhiTrkAxis_;
239  if (i % 2 == 0)
240  phiTrk += binSizePhiTrkAxis_ / 2.;
241  unsigned int binCenter = std::floor(phiTrk / binSizePhiTrkAxis_);
242  if (binCenter < nBinsPhiTrkAxis_)
243  HTbase::htArray_(i, binCenter)->store(stub, inEtaSubSecs);
244 
245  } else if (shape_ == HTshape::hexagon) {
246  //--- This HT has hexagonal cells (with two of its sides parallel to the phi axis).
247 
248  float qOverPtBin = -maxAbsQoverPtAxis_ + i * binSizeQoverPtAxis_;
249  float qOverPtBinVar = binSizeQoverPtAxis_;
250  float phiTrk = reco::deltaPhi(stub->phi(), phiCentreSector_) +
251  invPtToDphi_ * qOverPtBin * (stub->r() - chosenRofPhi_) + maxAbsPhiTrkAxis_;
252  float phiTrkVar = invPtToDphi_ * qOverPtBinVar * std::abs(stub->r() - chosenRofPhi_);
253  float phiTrkMin = phiTrk - phiTrkVar;
254  float phiTrkMax = phiTrk + phiTrkVar;
255  if (i % 2 == 0)
256  phiTrk += binSizePhiTrkAxis_ / 6.;
257  else {
258  phiTrk -= binSizePhiTrkAxis_ / 3.;
259  phiTrkMin -= binSizePhiTrkAxis_ / 2.;
260  phiTrkMax -= binSizePhiTrkAxis_ / 2.;
261  }
262  unsigned int iCenter = std::floor(phiTrk / binSizePhiTrkAxis_ * 3.);
263  unsigned int iMin = std::floor(phiTrkMin / binSizePhiTrkAxis_ * 3.);
264  unsigned int iMax = std::floor(phiTrkMax / binSizePhiTrkAxis_ * 3.);
265  std::pair<bool, unsigned int> binCenter;
266  std::pair<bool, unsigned int> binMin;
267  std::pair<bool, unsigned int> binMax;
268  binCenter.second = iCenter / 3;
269  binMin.second = iMin / 3;
270  binMax.second = iMax / 3;
271  binCenter.first = !(iCenter % 3 == 2);
272  binMin.first = (iMin % 3 == 0);
273  binMax.first = (iMax % 3 == 0);
274  if (binCenter.first && binCenter.second < nBinsPhiTrkAxis_)
275  HTbase::htArray_(i, binCenter.second)->store(stub, inEtaSubSecs);
276  else if (binMin.first && binMin.second < nBinsPhiTrkAxis_)
277  HTbase::htArray_(i, binMin.second)->store(stub, inEtaSubSecs);
278  else if (binMax.first && binMax.second < nBinsPhiTrkAxis_)
279  HTbase::htArray_(i, binMax.second)->store(stub, inEtaSubSecs);
280 
281  } else if (shape_ == HTshape::brick) {
282  //--- This HT has square cells with alternate rows shifted horizontally by 0.5*cell_width.
283 
284  float qOverPtBin = -maxAbsQoverPtAxis_ + i * binSizeQoverPtAxis_;
285  float qOverPtBinVar = binSizeQoverPtAxis_;
286  float phiTrk = reco::deltaPhi(stub->phi(), phiCentreSector_) +
287  invPtToDphi_ * qOverPtBin * (stub->r() - chosenRofPhi_) + maxAbsPhiTrkAxis_;
288  float phiTrkVar = invPtToDphi_ * qOverPtBinVar * std::abs(stub->r() - chosenRofPhi_);
289  float phiTrkMin = phiTrk - phiTrkVar;
290  float phiTrkMax = phiTrk + phiTrkVar;
291  unsigned int iMin = std::floor(phiTrkMin / binSizePhiTrkAxis_ * 2.);
292  unsigned int iMax = std::floor(phiTrkMax / binSizePhiTrkAxis_ * 2.);
293  std::pair<bool, unsigned int> binMin;
294  std::pair<bool, unsigned int> binMax;
295  binMin.second = iMin / 2;
296  binMax.second = iMax / 2;
297  binMin.first = (iMin % 2 == i % 2);
298  binMax.first = (iMax % 2 == i % 2);
299  if (binMin.first && binMin.second < nBinsPhiTrkAxis_)
300  HTbase::htArray_(i, binMin.second)->store(stub, inEtaSubSecs);
301  else if (binMax.first && binMax.second < nBinsPhiTrkAxis_)
302  HTbase::htArray_(i, binMax.second)->store(stub, inEtaSubSecs);
303  }
304  }
305  }
306  // Note max. |gradient| that the line corresponding to any stub in any of the r-phi HT arrays could have.
307  // Firmware assumes this should not exceed 1.0;
308  if (errMon_ != nullptr) {
310  }
311  }
312  }
313 
314  //=== Determine the m-bin (q/pt) range the specified track is in. (Used if outputting each m bin range on a different opto-link).
315 
316  unsigned int HTrphi::getMbinRange(const L1track2D& trk) const {
318  unsigned int mBin = trk.cellLocationHT().first;
319  unsigned int mBinOrder;
321  // User wants to group bins in a wierd order.
322  mBinOrder = 99999;
323  for (unsigned int k = 0; k < busySectorMbinOrder_.size(); k++) {
324  if (mBin == busySectorMbinOrder_[k])
325  mBinOrder = k;
326  }
327  if (mBinOrder == 99999)
328  throw cms::Exception("LogicError") << "HTrphi::getMbinRange() mBinOrder calculation wrong.";
329  } else {
330  // User grouping bins in numerical order 0,1,2,3,4,5...
331  mBinOrder = mBin;
332  }
333  for (unsigned int i = 0; i < busySectorMbinRanges_.size(); i++) {
334  if (mBinOrder >= busySectorMbinLow_[i] && mBinOrder <= busySectorMbinHigh_[i])
335  return i;
336  }
337  throw cms::Exception("LogicError") << "HTrphi::getMbinRange() messed up";
338  } else {
339  return 0;
340  }
341  }
342 
343  //=== For a given Q/Pt bin, find the range of phi bins that a given stub is consistent with.
344  //=== Return as a pair (min bin, max bin)
345  //=== If it range lies outside the HT array, then the min bin will be set larger than the max bin.
346 
347  pair<unsigned int, unsigned int> HTrphi::iPhiRange(const Stub* stub, unsigned int iQoverPtBin, bool debug) const {
348  // Note q/Pt value corresponding to centre of this bin.
349  float qOverPtBin = -maxAbsQoverPtAxis_ + (iQoverPtBin + 0.5) * binSizeQoverPtAxis_;
350  // Note change in this q/Pt value needed to reach either edge of the bin.
351  float qOverPtBinVar = 0.5 * binSizeQoverPtAxis_;
352 
353  // Reducing effective bin width can reduce fake rate.
354  //qOverPtVar = 0.4*binSizeQoverPtAxis_;
355 
356  // Calculate range of track-phi that would allow a track in this q/Pt range to pass through the stub.
357  float phiTrk = stub->phi() + invPtToDphi_ * qOverPtBin * (stub->r() - chosenRofPhi_);
358  // The next line does the phiTrk calculation without the usual approximation, but it doesn't
359  // improve performance.
360  //float phiTrk = stub->phi() + asin(invPtToDphi_ * qOverPtBin * stub->r()) - asin(invPtToDphi_ * qOverPtBin * chosenRofPhi_);
361  float phiTrkVar = invPtToDphi_ * qOverPtBinVar * std::abs(stub->r() - chosenRofPhi_);
362  float phiTrkMin = phiTrk - phiTrkVar;
363  float phiTrkMax = phiTrk + phiTrkVar;
364 
365  float deltaPhiMin = reco::deltaPhi(phiTrkMin, phiCentreSector_); // Offset to centre of sector.
366  float deltaPhiMax = reco::deltaPhi(phiTrkMax, phiCentreSector_);
367  pair<float, float> phiTrkRange(deltaPhiMin, deltaPhiMax);
368 
369  // Determine which HT array cell range in track-phi this range "phiTrkRange" corresponds to.
370  pair<unsigned int, unsigned int> iPhiTrkBinRange = this->HTbase::convertCoordRangeToBinRange(
372 
373  return iPhiTrkBinRange;
374  }
375 
376  //=== Check that limitations of firmware would not prevent stub being stored correctly in this HT column.
377 
378  void HTrphi::countFirmwareErrors(unsigned int iQoverPtBin,
379  unsigned int jPhiTrkBinMin,
380  unsigned int jPhiTrkBinMax,
381  unsigned int jPhiTrkBinMinLast,
382  unsigned int jPhiTrkBinMaxLast) {
383  // Only do check if stub is being stored somewhere in this HT column.
384  if (jPhiTrkBinMax >= jPhiTrkBinMin) {
385  //--- Remaining code below checks that firmware could successfully store this stub in this column.
386  // (a) Does cell lie NE, E or SE of cell filled in previous column?
387  bool OK_a = (jPhiTrkBinMin + 1 >= jPhiTrkBinMinLast) && (jPhiTrkBinMax <= jPhiTrkBinMaxLast + 1);
388  // (b) Are no more than 2 cells filled in this column
389  bool OK_b = (jPhiTrkBinMax - jPhiTrkBinMin + 1 <= 2);
390 
391  if (!OK_a)
393  if (!OK_b)
395  errMon_->numErrorsNorm++; // No. of times a stub is added to an HT column.
396  }
397  }
398 
399  //=== Get the values of the track helix params corresponding to middle of a specified HT cell (i,j).
400  //=== The helix parameters returned will be those corresponding to the two axes of the HT array.
401  //=== So they might be (q/pt, phi0) or (q/pt, phi65) etc. depending on the configuration.
402 
403  pair<float, float> HTrphi::helix2Dhough(unsigned int i, unsigned int j) const {
404  unsigned int qOverPtBin = i;
405  unsigned int phiTrkBin = j;
406 
407  // If using merged 2x2 cells in low Pt parts of array, must correct for this.
408  bool merged = false;
409  if (enableMerge2x2_) {
410  // Check if this cell is merged with its neighbours (as in low Pt region).
411  if (this->mergedCell(i, j)) {
412  merged = true;
413  // Get location of cell that this cell is merged into (iStore, jStore).
414  // Calculation assumes HT array has even number of bins in both dimensions.
415  if (i % 2 == 1)
416  qOverPtBin = i - 1;
417  if (j % 2 == 1)
418  phiTrkBin = j - 1;
419  }
420  }
421 
422  float qOverPtBinCenter = .5;
423  float phiTrkBinCenter = .5;
424 
425  if (shape_ != HTshape::square) {
426  qOverPtBinCenter = 0.;
427 
428  float evenPhiPos = 0., oddPhiPos = 0.;
429  if (shape_ == HTshape::hexagon) {
430  evenPhiPos = 1. / 6.;
431  oddPhiPos = 2. / 3.;
432  } else if (shape_ == HTshape::diamond) {
433  evenPhiPos = 0.;
434  oddPhiPos = 0.5;
435  } else if (shape_ == HTshape::brick) {
436  evenPhiPos = 0.25;
437  oddPhiPos = 0.75;
438  }
439  phiTrkBinCenter = (qOverPtBin % 2 == 0) ? evenPhiPos : oddPhiPos;
440  }
441 
442  float qOverPt = -maxAbsQoverPtAxis_ + (qOverPtBin + qOverPtBinCenter) * binSizeQoverPtAxis_;
443  float phiTrk = -maxAbsPhiTrkAxis_ + (phiTrkBin + phiTrkBinCenter) * binSizePhiTrkAxis_;
444 
445  if (merged) {
446  qOverPt += 0.5 * binSizeQoverPtAxis_;
447  phiTrk += 0.5 * binSizePhiTrkAxis_;
448  }
449 
450  // Correct phiTrk to centre of sector, taking care of 2*pi wrapping
451  phiTrk = reco::deltaPhi(phiTrk + phiCentreSector_, 0.);
452  return pair<float, float>(qOverPt, phiTrk);
453  }
454 
455  //=== Get the values of the track helix params corresponding to middle of a specified HT cell (i,j).
456  //=== The helix parameters returned will be always be (q/pt, phi0), irrespective of how the axes
457  //=== of the HT array are defined.
458 
459  pair<float, float> HTrphi::helix2Dconventional(unsigned int i, unsigned int j) const {
460  // Get the helix parameters corresponding to the axes definitions of the HT.
461  pair<float, float> helix2Dht = this->helix2Dhough(i, j);
462  // Convert to the conventionally agreed pair of helix parameters, (q/pt, phi0).
463  float qOverPt = helix2Dht.first; // easy
464  // If HT defined track phi other than at r=0, must correct to get phi0. Allow for 2*pi wrapping of phi.
465  float phi0 = reco::deltaPhi(helix2Dht.second + invPtToDphi_ * chosenRofPhi_ * qOverPt, 0.);
466  return pair<float, float>(qOverPt, phi0);
467  }
468 
469  //=== Which cell in HT array should this TP be in, based on its true trajectory?
470  //=== (If TP is outside HT array, it it put in the closest bin inside it).
471 
472  pair<unsigned int, unsigned int> HTrphi::trueCell(const TP* tp) const {
473  // Get HT axis variables corresponding to this TP.
474  float qOverPt = tp->qOverPt();
475  float phiTrk = tp->trkPhiAtR(chosenRofPhi_);
476  // Measure phi relative to centre of sector.
477  float deltaPhi = reco::deltaPhi(phiTrk, phiCentreSector_);
478  // Convert to bin numbers inside HT array.
479  int iQoverPt = floor((qOverPt - (-maxAbsQoverPtAxis_)) / binSizeQoverPtAxis_);
480  int iPhiTrk = floor((deltaPhi - (-maxAbsPhiTrkAxis_)) / binSizePhiTrkAxis_);
481  // Check if this cell was within the HT array.
482  if (iQoverPt >= 0 && iQoverPt < int(nBinsQoverPtAxis_) && iPhiTrk >= 0 && iPhiTrk < int(nBinsPhiTrkAxis_)) {
483  // Check if this cell is merged with its neighbours (as in low Pt region), and if so return merged cell location.
484  // New: because 2nd stage mini HT may recreate tracks from merged cells with finer cell granularity, one can't predict
485  // if a merged cell was used to create a track merely by looking at its cell location.
486  // So instead ask L1track3D, which knows if it was created from a merged HT cell or not.
487  ;
488  } else {
489  // TP is not in this HT array at all. Flag this by setting "outside" bin index to 0 (Nbins) if outside array below (above).
490  if (iQoverPt < 0)
491  iQoverPt = 0;
492  if (iQoverPt >= int(nBinsQoverPtAxis_))
493  iQoverPt = nBinsQoverPtAxis_ - 1;
494  if (iPhiTrk < 0)
495  iPhiTrk = 0;
496  if (iPhiTrk >= int(nBinsPhiTrkAxis_))
497  iPhiTrk = nBinsPhiTrkAxis_ - 1;
498  }
499  return pair<unsigned int, unsigned int>(iQoverPt, iPhiTrk);
500  }
501 
502  //=== Which cell in HT array should this fitted track be in, based on its fitted trajectory?
503  //=== Always uses beam-spot constrained trajectory if available.
504  //=== (If fitted track is outside HT array, it it put in the closest bin inside it).
505 
506  pair<unsigned int, unsigned int> HTrphi::cell(const L1fittedTrack* fitTrk) const {
507  bool beamConstraint = fitTrk->done_bcon(); // Is beam-spot constraint available? (e.g. 5 param helix fit)
508  // Get HT axis variables corresponding to this fitted track.
509  float qOverPt = beamConstraint ? fitTrk->qOverPt_bcon() : fitTrk->qOverPt();
510  // Convert phi0 to phi at chosen radius used in HT.
511  float phiTrk = fitTrk->phiAtChosenR(beamConstraint);
512  // Measure phi relative to centre of sector.
513  float deltaPhi = reco::deltaPhi(phiTrk, phiCentreSector_);
514  // Convert to bin numbers inside HT array.
515  int iQoverPt = 999999;
516  int iPhiTrk = 999999;
517 
518  if (shape_ == HTshape::square) {
519  //--- This is a traditional HT with square cells.
520 
521  iQoverPt = floor((qOverPt - (-maxAbsQoverPtAxis_)) / binSizeQoverPtAxis_);
522  iPhiTrk = floor((deltaPhi - (-maxAbsPhiTrkAxis_)) / binSizePhiTrkAxis_);
523 
524  // Check if this cell was within the HT array.
525  if (iQoverPt >= 0 && iQoverPt < int(nBinsQoverPtAxis_) && iPhiTrk >= 0 && iPhiTrk < int(nBinsPhiTrkAxis_)) {
526  // Check if this cell is merged with its neighbours (as in low Pt region), and if so return merged cell location.
527  // New: because 2nd stage mini HT may recreate tracks from merged cells with finer cell granularity, one can't predict
528  // if a merged cell was used to create a track merely by looking at its cell location.
529  // So instead ask L1track3D, which knows if it was created from a merged HT cell or not.
530  ;
531  } else {
532  // Fitted track is not in this HT array at all. Flag this by setting "outside" bin index to 0 (Nbins-1) if outside array below (above).
533  if (iQoverPt < 0)
534  iQoverPt = 0;
535  if (iQoverPt >= int(nBinsQoverPtAxis_))
536  iQoverPt = nBinsQoverPtAxis_ - 1;
537  if (iPhiTrk < 0)
538  iPhiTrk = 0;
539  if (iPhiTrk >= int(nBinsPhiTrkAxis_))
540  iPhiTrk = nBinsPhiTrkAxis_ - 1;
541  }
542 
543  } else {
544  //--- This is are novel HT with unusual shaped cells.
545 
547  float d(0);
548  unsigned int m(0);
549  for (const auto& binCenters : cellCenters_) {
550  unsigned int c(0);
551  for (auto cellCenter : binCenters) {
552  d = std::pow((cellCenter.first - qOverPt) / (float)binSizeQoverPtAxis_, 2) +
553  std::pow((cellCenter.second - phiTrk) / (float)binSizePhiTrkAxis_, 2);
554  if (d < minD) {
555  minD = d;
556  iQoverPt = m;
557  iPhiTrk = c;
558  }
559  c++;
560  }
561  m++;
562  }
563  // Fitted track is not in this HT array at all. Flag this by setting "outside" bin index to 0 (Nbins-1) if outside array below (above).
564  if (iQoverPt < 0)
565  iQoverPt = 0;
566  if (iQoverPt >= int(nBinsQoverPtAxis_))
567  iQoverPt = nBinsQoverPtAxis_ - 1;
568  if (iPhiTrk < 0)
569  iPhiTrk = 0;
570  if (iPhiTrk >= int(nBinsPhiTrkAxis_))
571  iPhiTrk = nBinsPhiTrkAxis_ - 1;
572  }
573 
574  return pair<unsigned int, unsigned int>(iQoverPt, iPhiTrk);
575  }
576 
577  //=== Check if specified cell is merged with its 2x2 neighbours into a single cell,
578  //=== as it is in low Pt region.
579 
580  bool HTrphi::mergedCell(unsigned int iQoverPtBin, unsigned int jPhiTrkBin) const {
581  bool merge = false;
582 
583  if (enableMerge2x2_) {
584  unsigned int i = iQoverPtBin;
585  //unsigned int j = jPhiTrkBin;
586 
587  // Calculate number of merged bins on each q/Pt side of array.
588  float fMergeBins = (maxAbsQoverPtAxis_ - minInvPtToMerge2x2_) / (2. * binSizeQoverPtAxis_);
589  // Number of unmerged bins this corresponds to, which must be even, since each merged bin comprises two normal q/pt bins.
590  unsigned int numQoverPtBinsToMerge = 2 * min((unsigned int)(std::round(fMergeBins)), (nBinsQoverPtAxis_ / 4));
591  const float small = 0.001;
592  if (minInvPtToMerge2x2_ < small && (unsigned int)(std::round(2. * fMergeBins)) % 2 == 1)
593  numQoverPtBinsToMerge++;
594  unsigned int iB = (nBinsQoverPtAxis_ - 1) - i; // Count backwards across array.
595  if (min(i, iB) < numQoverPtBinsToMerge)
596  merge = true;
597  }
598 
599  return merge;
600  }
601 
602  //=== Calculate line |gradient| of stubs in HT array, so can check it doesn't exceed 1.
603 
604  float HTrphi::calcLineGradArray(float r) const {
605  float grad = std::abs(invPtToDphi_ * (r - chosenRofPhi_));
606  // Convert it to units of bin width.
608  if (shape_ == HTshape::hexagon)
609  grad *= 3.;
610  else if (shape_ == HTshape::diamond)
611  grad *= 2.;
612  else if (shape_ == HTshape::brick)
613  grad *= 4.;
614  return grad;
615  }
616 
617  //=== If requested, kill those tracks in this sector that can't be read out during the time-multiplexed period, because
618  //=== the HT has associated too many stubs to tracks.
619 
620  list<L1track2D> HTrphi::killTracksBusySec(const list<L1track2D>& tracks) const {
621  list<L1track2D> outTracks;
622 
623  if (busySectorKill_) {
624  unsigned int nStubsOut = 0; // #stubs assigned to tracks in this sector.
625  // #stubs assigned to each m bin range in this sector.
626  vector<unsigned int> nStubsOutInRange(busySectorMbinRanges_.size(), 0);
627 
628  for (const L1track2D& trk : tracks) {
629  bool keep = true;
630  unsigned int nStubs = trk.numStubs(); // #stubs on this track.
631  if (busySectorUseMbinRanges_) { // Are tracks from different m bin ranges output seperately to increase bandwidth?
632  unsigned int mBinRange = this->getMbinRange(trk); // Which m bin range is this track in?
633  nStubsOutInRange[mBinRange] += nStubs;
634  if (nStubsOutInRange[mBinRange] > busySectorNumStubs_)
635  keep = false;
636  } else {
637  nStubsOut += nStubs;
638  if (nStubsOut > busySectorNumStubs_)
639  keep = false;
640  }
641 
642  if (keep)
643  outTracks.push_back(trk);
644  }
645 
646  } else {
647  outTracks = tracks;
648  }
649 
650  return outTracks;
651  }
652 
653  //=== Define the order in which the hardware processes rows of the HT array when it outputs track candidates.
654  //=== Currently corresponds to highest Pt tracks first.
655  //=== If two tracks have the same Pt, the -ve charge one is output before the +ve charge one.
656 
657  vector<unsigned int> HTrphi::rowOrder(unsigned int numRows) const {
658  vector<unsigned int> iOrder;
659 
660  // Logic slightly different depending on whether HT array has even or odd number of rows.
661  const bool oddNumRows = (numRows % 2 == 1);
662 
663  // This selects middle rows first before moving to exterior ones.
664  if (oddNumRows) {
665  unsigned int middleRow = (numRows - 1) / 2;
666  iOrder.push_back(middleRow);
667  for (unsigned int i = 1; i <= (numRows - 1) / 2; i++) {
668  iOrder.push_back(middleRow - i); // -ve charge
669  iOrder.push_back(middleRow + i); // +ve charge
670  }
671  } else {
672  unsigned int startRowPos = numRows / 2;
673  unsigned int startRowNeg = startRowPos - 1;
674  for (unsigned int i = 0; i < numRows / 2; i++) {
675  iOrder.push_back(startRowNeg - i); // -ve charge
676  iOrder.push_back(startRowPos + i); // +ve charge
677  }
678  }
679 
680  return iOrder;
681  }
682 
683 } // namespace tmtt
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
std::vector< unsigned int > busySectorMbinRanges_
Definition: HTrphi.h:149
Definition: merge.py:1
bool miniHTstage() const
Definition: Settings.h:149
float maxAbsPhiTrkAxis_
Definition: HTrphi.h:133
unsigned int killSomeHTCellsRphi() const
Definition: Settings.h:166
float maxAbsQoverPtAxis_
Definition: HTrphi.h:127
bool done_bcon() const
bool enableMerge2x2_
Definition: HTrphi.h:137
float r() const
Definition: Stub.h:108
bool mergedCell(unsigned int iQoverPtBin, unsigned int jPhiTrkBin) const
Definition: HTrphi.cc:580
int merge(int argc, char *argv[])
Definition: DiMuonVmerge.cc:28
float chosenRofPhi_
Definition: HTrphi.h:131
float binSizeQoverPtAxis_
Definition: HTrphi.h:129
void store(Stub *stub, const std::vector< bool > &inEtaSubSecs)
Definition: HTrphi.cc:178
virtual std::pair< unsigned int, unsigned int > convertCoordRangeToBinRange(std::pair< float, float > coordRange, unsigned int nBinsAxis, float coordAxisMin, float coordAxisBinSize, unsigned int killSomeHTcells) const
Definition: HTbase.cc:122
std::vector< unsigned int > busySectorMbinLow_
Definition: HTrphi.h:153
std::vector< unsigned int > busySectorMbinOrder_
Definition: HTrphi.h:150
const std::vector< unsigned int > & busySectorMbinRanges() const
Definition: Settings.h:178
unsigned int killSomeHTCellsRphi_
Definition: HTrphi.h:143
unsigned int nBinsPhiTrkAxis_
Definition: HTrphi.h:134
unsigned int busyInputSectorNumStubs_
Definition: HTrphi.h:147
float qOverPt_bcon() const
std::pair< unsigned int, unsigned int > iPhiRange(const Stub *stub, unsigned int iQoverPtBin, bool debug=false) const
Definition: HTrphi.cc:347
std::pair< unsigned int, unsigned int > cellLocationHT() const override
Definition: L1track2D.h:63
std::atomic< float > maxLineGradient
Definition: HTrphi.h:31
float invPtToDphi_
Definition: HTrphi.h:120
Array2D< std::unique_ptr< HTcell > > htArray_
Definition: HTbase.h:132
std::atomic< unsigned int > numErrorsNorm
Definition: HTrphi.h:37
ErrorMonitor * errMon_
Definition: HTrphi.h:161
bool busySectorUseMbinOrder_
Definition: HTrphi.h:152
unsigned int busySectorNumStubs() const
Definition: Settings.h:176
std::atomic< unsigned int > numErrorsTypeA
Definition: HTrphi.h:33
Definition: TP.h:23
std::vector< unsigned int > rowOrder(unsigned int numRows) const override
Definition: HTrphi.cc:657
std::pair< unsigned int, unsigned int > trueCell(const TP *tp) const override
Definition: HTrphi.cc:472
const std::vector< unsigned int > & busySectorMbinOrder() const
Definition: Settings.h:181
std::pair< unsigned int, unsigned int > cell(const L1fittedTrack *fitTrk) const override
Definition: HTrphi.cc:506
double maxPtToMerge2x2() const
Definition: Settings.h:143
std::pair< float, float > helix2Dhough(unsigned int i, unsigned int j) const override
Definition: HTrphi.cc:403
float qOverPt() const override
const double infinity
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::pair< float, float > helix2Dconventional(unsigned int i, unsigned int j) const override
Definition: HTrphi.cc:459
bool busySectorUseMbinRanges_
Definition: HTrphi.h:151
d
Definition: ztail.py:151
unsigned int busyInputSectorNumStubs() const
Definition: Settings.h:185
const Settings * settings_
Definition: HTbase.h:122
void countFirmwareErrors(unsigned int iQoverPtBin, unsigned int iPhiTrkBinMin, unsigned int iPhiTrkBinMax, unsigned int jPhiTrkBinMinLast, unsigned int jPhiTrkBinMaxLast)
Definition: HTrphi.cc:378
#define M_PI
float minInvPtToMerge2x2_
Definition: HTrphi.h:138
float phi() const
Definition: Stub.h:107
bool busySectorKill_
Definition: HTrphi.h:146
unsigned int busySectorNumStubs_
Definition: HTrphi.h:148
#define debug
Definition: HDRShower.cc:19
=== This is the base class for the linearised chi-squared track fit algorithms.
Definition: Array2D.h:16
bool enableMerge2x2() const
Definition: Settings.h:141
unsigned int nReceivedStubs_
Definition: HTrphi.h:158
float phiAtChosenR(bool beamConstraint) const
float binSizePhiTrkAxis_
Definition: HTrphi.h:135
unsigned int getMbinRange(const L1track2D &trk) const
Definition: HTrphi.cc:316
const float binMin[32]
std::atomic< unsigned int > numErrorsTypeB
Definition: HTrphi.h:35
bool busyInputSectorKill_
Definition: HTrphi.h:145
std::vector< std::vector< std::pair< float, float > > > cellCenters_
Definition: HTrphi.h:123
bool busySectorKill() const
Definition: Settings.h:175
float phiCentreSector_
Definition: HTrphi.h:132
float calcLineGradArray(float r) const
Definition: HTrphi.cc:604
std::list< L1track2D > killTracksBusySec(const std::list< L1track2D > &tracks) const override
Definition: HTrphi.cc:620
bool busyInputSectorKill() const
Definition: Settings.h:184
HTshape shape_
Definition: HTrphi.h:122
unsigned int nBinsQoverPtAxis_
Definition: HTrphi.h:128
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
std::vector< unsigned int > busySectorMbinHigh_
Definition: HTrphi.h:154