CMS 3D CMS Logo

MkFinder.cc
Go to the documentation of this file.
1 #include "MkFinder.h"
2 
5 #include "CandCloner.h"
6 #include "FindingFoos.h"
7 #include "KalmanUtilsMPlex.h"
8 #include "MatriplexPackers.h"
9 
10 //#define DEBUG
11 #include "Debug.h"
12 
13 #if (defined(DUMPHITWINDOW) || defined(DEBUG_BACKWARD_FIT)) && defined(MKFIT_STANDALONE)
15 #endif
16 
17 #include <algorithm>
18 
19 namespace mkfit {
20 
22  const IterationParams &ip,
23  const IterationLayerConfig &ilc,
24  const SteeringParams &sp,
25  const std::vector<bool> *ihm,
26  bool infwd) {
27  m_prop_config = &pc;
28  m_iteration_params = &ip;
30  m_steering_params = &sp;
32  m_in_fwd = infwd;
33  }
34 
36  m_prop_config = &pc;
37  m_steering_params = &sp;
38  }
39 
41  m_prop_config = nullptr;
42  m_iteration_params = nullptr;
43  m_iteration_layer_config = nullptr;
44  m_steering_params = nullptr;
45  m_iteration_hit_mask = nullptr;
46  m_in_fwd = true;
47  }
48 
49  //==============================================================================
50  // Input / Output TracksAndHitIdx
51  //==============================================================================
52 
53  void MkFinder::inputTracksAndHitIdx(const std::vector<Track> &tracks, int beg, int end, bool inputProp) {
54  // Assign track parameters to initial state and copy hit values in.
55 
56  // This might not be true for the last chunk!
57  // assert(end - beg == NN);
58 
59  const int iI = inputProp ? iP : iC;
60 
61  for (int i = beg, imp = 0; i < end; ++i, ++imp) {
62  copy_in(tracks[i], imp, iI);
63  }
64  }
65 
67  const std::vector<Track> &tracks, const std::vector<int> &idxs, int beg, int end, bool inputProp, int mp_offset) {
68  // Assign track parameters to initial state and copy hit values in.
69 
70  // This might not be true for the last chunk!
71  // assert(end - beg == NN);
72 
73  const int iI = inputProp ? iP : iC;
74 
75  for (int i = beg, imp = mp_offset; i < end; ++i, ++imp) {
76  copy_in(tracks[idxs[i]], imp, iI);
77  }
78  }
79 
80  void MkFinder::inputTracksAndHitIdx(const std::vector<CombCandidate> &tracks,
81  const std::vector<std::pair<int, int>> &idxs,
82  int beg,
83  int end,
84  bool inputProp) {
85  // Assign track parameters to initial state and copy hit values in.
86 
87  // This might not be true for the last chunk!
88  // assert(end - beg == NN);
89 
90  const int iI = inputProp ? iP : iC;
91 
92  for (int i = beg, imp = 0; i < end; ++i, ++imp) {
93  const TrackCand &trk = tracks[idxs[i].first][idxs[i].second];
94 
95  copy_in(trk, imp, iI);
96 
97 #ifdef DUMPHITWINDOW
98  m_SeedAlgo(imp, 0, 0) = tracks[idxs[i].first].seed_algo();
99  m_SeedLabel(imp, 0, 0) = tracks[idxs[i].first].seed_label();
100 #endif
101 
102  m_SeedIdx(imp, 0, 0) = idxs[i].first;
103  m_CandIdx(imp, 0, 0) = idxs[i].second;
104  }
105  }
106 
107  void MkFinder::inputTracksAndHits(const std::vector<CombCandidate> &tracks,
108  const LayerOfHits &layer_of_hits,
109  const std::vector<UpdateIndices> &idxs,
110  int beg,
111  int end,
112  bool inputProp) {
113  // Assign track parameters to initial state and copy hit values in.
114 
115  // This might not be true for the last chunk!
116  // assert(end - beg == NN);
117 
118  const int iI = inputProp ? iP : iC;
119 
120  for (int i = beg, imp = 0; i < end; ++i, ++imp) {
121  const TrackCand &trk = tracks[idxs[i].seed_idx][idxs[i].cand_idx];
122 
123  copy_in(trk, imp, iI);
124 
125 #ifdef DUMPHITWINDOW
126  m_SeedAlgo(imp, 0, 0) = tracks[idxs[i].seed_idx].seed_algo();
127  m_SeedLabel(imp, 0, 0) = tracks[idxs[i].seed_idx.seed_label();
128 #endif
129 
130  m_SeedIdx(imp, 0, 0) = idxs[i].seed_idx;
131  m_CandIdx(imp, 0, 0) = idxs[i].cand_idx;
132 
133  const Hit &hit = layer_of_hits.refHit(idxs[i].hit_idx);
134  m_msErr.copyIn(imp, hit.errArray());
135  m_msPar.copyIn(imp, hit.posArray());
136  }
137  }
138 
139  void MkFinder::inputTracksAndHitIdx(const std::vector<CombCandidate> &tracks,
140  const std::vector<std::pair<int, IdxChi2List>> &idxs,
141  int beg,
142  int end,
143  bool inputProp) {
144  // Assign track parameters to initial state and copy hit values in.
145 
146  // This might not be true for the last chunk!
147  // assert(end - beg == NN);
148 
149  const int iI = inputProp ? iP : iC;
150 
151  for (int i = beg, imp = 0; i < end; ++i, ++imp) {
152  const TrackCand &trk = tracks[idxs[i].first][idxs[i].second.trkIdx];
153 
154  copy_in(trk, imp, iI);
155 
156 #ifdef DUMPHITWINDOW
157  m_SeedAlgo(imp, 0, 0) = tracks[idxs[i].first].seed_algo();
158  m_SeedLabel(imp, 0, 0) = tracks[idxs[i].first].seed_label();
159 #endif
160 
161  m_SeedIdx(imp, 0, 0) = idxs[i].first;
162  m_CandIdx(imp, 0, 0) = idxs[i].second.trkIdx;
163  }
164  }
165 
166  void MkFinder::outputTracksAndHitIdx(std::vector<Track> &tracks, int beg, int end, bool outputProp) const {
167  // Copies requested track parameters into Track objects.
168  // The tracks vector should be resized to allow direct copying.
169 
170  const int iO = outputProp ? iP : iC;
171 
172  for (int i = beg, imp = 0; i < end; ++i, ++imp) {
173  copy_out(tracks[i], imp, iO);
174  }
175  }
176 
178  std::vector<Track> &tracks, const std::vector<int> &idxs, int beg, int end, bool outputProp) const {
179  // Copies requested track parameters into Track objects.
180  // The tracks vector should be resized to allow direct copying.
181 
182  const int iO = outputProp ? iP : iC;
183 
184  for (int i = beg, imp = 0; i < end; ++i, ++imp) {
185  copy_out(tracks[idxs[i]], imp, iO);
186  }
187  }
188 
189  //==============================================================================
190  // getHitSelDynamicWindows
191  //==============================================================================
192  // From HitSelectionWindows.h: track-related config on hit selection windows
193 
195  const float invpt, const float theta, float &min_dq, float &max_dq, float &min_dphi, float &max_dphi) {
196  float max_invpt = std::min(invpt, 10.0f); // => pT>0.1 GeV
197 
198  enum SelWinParameters_e { dp_sf = 0, dp_0, dp_1, dp_2, dq_sf, dq_0, dq_1, dq_2 };
200 
201  if (!v.empty()) {
202  // dq hit selection window
203  float this_dq = v[dq_sf] * (v[dq_0] * max_invpt + v[dq_1] * theta + v[dq_2]);
204  // In case value is below 0 (bad window derivation or other reasons), leave original limits
205  if (this_dq > 0.f) {
206  min_dq = this_dq;
207  max_dq = 2.0f * min_dq;
208  }
209 
210  // dphi hit selection window
211  float this_dphi = v[dp_sf] * (v[dp_0] * max_invpt + v[dp_1] * theta + v[dp_2]);
212  // In case value is too low (bad window derivation or other reasons), leave original limits
213  if (this_dphi > min_dphi) {
214  min_dphi = this_dphi;
215  max_dphi = 2.0f * min_dphi;
216  }
217  }
218  }
219 
220  //==============================================================================
221  // getHitSelDynamicChi2Cut
222  //==============================================================================
223  // From HitSelectionWindows.h: track-related config on hit selection windows
224 
225  inline float MkFinder::getHitSelDynamicChi2Cut(const int itrk, const int ipar) {
226  const float minChi2Cut = m_iteration_params->chi2Cut_min;
227  const float invpt = m_Par[ipar].At(itrk, 3, 0);
228  const float theta = std::abs(m_Par[ipar].At(itrk, 5, 0) - Const::PIOver2);
229 
230  float max_invpt = std::min(invpt, 10.0f); // => pT>0.1 GeV
231 
232  enum SelWinParameters_e { c2_sf = 8, c2_0, c2_1, c2_2 };
234 
235  if (!v.empty()) {
236  float this_c2 = v[c2_sf] * (v[c2_0] * max_invpt + v[c2_1] * theta + v[c2_2]);
237  // In case value is too low (bad window derivation or other reasons), leave original limits
238  if (this_c2 > minChi2Cut)
239  return this_c2;
240  }
241  return minChi2Cut;
242  }
243 
244  //==============================================================================
245  // SelectHitIndices
246  //==============================================================================
247 
248  void MkFinder::selectHitIndices(const LayerOfHits &layer_of_hits, const int N_proc) {
249  // bool debug = true;
250  using bidx_t = LayerOfHits::bin_index_t;
251  using bcnt_t = LayerOfHits::bin_content_t;
252  const LayerOfHits &L = layer_of_hits;
254 
255  const int iI = iP;
256  const float nSigmaPhi = 3;
257  const float nSigmaZ = 3;
258  const float nSigmaR = 3;
259 
260  dprintf("LayerOfHits::SelectHitIndices %s layer=%d N_proc=%d\n",
261  L.is_barrel() ? "barrel" : "endcap",
262  L.layer_id(),
263  N_proc);
264 
265  float dqv[NN], dphiv[NN], qv[NN], phiv[NN];
266  bidx_t qb1v[NN], qb2v[NN], qbv[NN], pb1v[NN], pb2v[NN];
267 
268  const auto assignbins = [&](int itrack,
269  float q,
270  float dq,
271  float phi,
272  float dphi,
273  float min_dq,
274  float max_dq,
275  float min_dphi,
276  float max_dphi) {
277  dphi = std::clamp(std::abs(dphi), min_dphi, max_dphi);
278  dq = std::clamp(dq, min_dq, max_dq);
279  //
280  qv[itrack] = q;
281  phiv[itrack] = phi;
282  dphiv[itrack] = dphi;
283  dqv[itrack] = dq;
284  //
285  qbv[itrack] = L.qBinChecked(q);
286  qb1v[itrack] = L.qBinChecked(q - dq);
287  qb2v[itrack] = L.qBinChecked(q + dq) + 1;
288  pb1v[itrack] = L.phiBinChecked(phi - dphi);
289  pb2v[itrack] = L.phiMaskApply(L.phiBin(phi + dphi) + 1);
290  };
291 
292  const auto calcdphi2 = [&](int itrack, float dphidx, float dphidy) {
293  return dphidx * dphidx * m_Err[iI].constAt(itrack, 0, 0) + dphidy * dphidy * m_Err[iI].constAt(itrack, 1, 1) +
294  2 * dphidx * dphidy * m_Err[iI].constAt(itrack, 0, 1);
295  };
296 
297  const auto calcdphi = [&](float dphi2, float min_dphi) {
298  return std::max(nSigmaPhi * std::sqrt(std::abs(dphi2)), min_dphi);
299  };
300 
301  if (L.is_barrel()) {
302  // Pull out the part of the loop that vectorizes with icc and gcc
303  // In llvm16 clang issues a warning that it can't vectorize
304  // the loop. Unfortunately, there doesn't seem to be a
305  // pragma to suppress the warning, so we ifdef it out. This
306  // should be rechecked if llvm vectorization improves.
307 #if !defined(__clang__)
308 #pragma omp simd
309 #endif
310  for (int itrack = 0; itrack < NN; ++itrack) {
311  m_XHitSize[itrack] = 0;
312 
313  float min_dq = ILC.min_dq();
314  float max_dq = ILC.max_dq();
315  float min_dphi = ILC.min_dphi();
316  float max_dphi = ILC.max_dphi();
317 
318  const float invpt = m_Par[iI].At(itrack, 3, 0);
319  const float theta = std::fabs(m_Par[iI].At(itrack, 5, 0) - Const::PIOver2);
320  getHitSelDynamicWindows(invpt, theta, min_dq, max_dq, min_dphi, max_dphi);
321 
322  const float x = m_Par[iI].constAt(itrack, 0, 0);
323  const float y = m_Par[iI].constAt(itrack, 1, 0);
324  const float r2 = x * x + y * y;
325  const float dphidx = -y / r2, dphidy = x / r2;
326  const float dphi2 = calcdphi2(itrack, dphidx, dphidy);
327 #ifdef HARD_CHECK
328  assert(dphi2 >= 0);
329 #endif
330 
331  const float phi = getPhi(x, y);
332  float dphi = calcdphi(dphi2, min_dphi);
333 
334  const float z = m_Par[iI].constAt(itrack, 2, 0);
335  const float dz = std::abs(nSigmaZ * std::sqrt(m_Err[iI].constAt(itrack, 2, 2)));
336  const float edgeCorr = std::abs(0.5f * (L.layer_info()->rout() - L.layer_info()->rin()) /
337  std::tan(m_Par[iI].constAt(itrack, 5, 0)));
338  // XXX-NUM-ERR above, m_Err(2,2) gets negative!
339 
340  m_XWsrResult[itrack] = L.is_within_z_sensitive_region(z, std::sqrt(dz * dz + edgeCorr * edgeCorr));
341  assignbins(itrack, z, dz, phi, dphi, min_dq, max_dq, min_dphi, max_dphi);
342  }
343  } else // endcap
344  {
345  //layer half-thikness for dphi spread calculation; only for very restrictive iters
346  const float layerD = std::abs(L.layer_info()->zmax() - L.layer_info()->zmin()) * 0.5f *
348  // Pull out the part of the loop that vectorizes with icc and gcc
349 #if !defined(__clang__)
350 #pragma omp simd
351 #endif
352  for (int itrack = 0; itrack < NN; ++itrack) {
353  m_XHitSize[itrack] = 0;
354 
355  float min_dq = ILC.min_dq();
356  float max_dq = ILC.max_dq();
357  float min_dphi = ILC.min_dphi();
358  float max_dphi = ILC.max_dphi();
359 
360  const float invpt = m_Par[iI].At(itrack, 3, 0);
361  const float theta = std::fabs(m_Par[iI].At(itrack, 5, 0) - Const::PIOver2);
362  getHitSelDynamicWindows(invpt, theta, min_dq, max_dq, min_dphi, max_dphi);
363 
364  const float x = m_Par[iI].constAt(itrack, 0, 0);
365  const float y = m_Par[iI].constAt(itrack, 1, 0);
366  const float r2 = x * x + y * y;
367  const float r2Inv = 1.f / r2;
368  const float dphidx = -y * r2Inv, dphidy = x * r2Inv;
369  const float phi = getPhi(x, y);
370  const float dphi2 =
371  calcdphi2(itrack, dphidx, dphidy)
372  //range from finite layer thickness
373  + std::pow(layerD * std::tan(m_Par[iI].At(itrack, 5, 0)) * std::sin(m_Par[iI].At(itrack, 4, 0) - phi), 2) *
374  r2Inv;
375 #ifdef HARD_CHECK
376  assert(dphi2 >= 0);
377 #endif
378 
379  float dphi = calcdphi(dphi2, min_dphi);
380 
381  const float r = std::sqrt(r2);
382  const float dr = nSigmaR * std::sqrt(std::abs(x * x * m_Err[iI].constAt(itrack, 0, 0) +
383  y * y * m_Err[iI].constAt(itrack, 1, 1) +
384  2 * x * y * m_Err[iI].constAt(itrack, 0, 1)) /
385  r2);
386  const float edgeCorr = std::abs(0.5f * (L.layer_info()->zmax() - L.layer_info()->zmin()) *
387  std::tan(m_Par[iI].constAt(itrack, 5, 0)));
388 
389  m_XWsrResult[itrack] = L.is_within_r_sensitive_region(r, std::sqrt(dr * dr + edgeCorr * edgeCorr));
390  assignbins(itrack, r, dr, phi, dphi, min_dq, max_dq, min_dphi, max_dphi);
391  }
392  }
393 
394  // Vectorizing this makes it run slower!
395  //#pragma omp simd
396  for (int itrack = 0; itrack < N_proc; ++itrack) {
397  // PROP-FAIL-ENABLE The following to be enabled when propagation failure
398  // detection is properly implemented in propagate-to-R/Z.
399  // if (m_FailFlag[itrack]) {
400  // m_XWsrResult[itrack].m_wsr = WSR_Failed;
401  // m_XHitSize[itrack] = -1;
402  // continue;
403  // }
404 
405  if (m_XWsrResult[itrack].m_wsr == WSR_Outside) {
406  m_XHitSize[itrack] = -1;
407  continue;
408  }
409 
410  const bidx_t qb = qbv[itrack];
411  const bidx_t qb1 = qb1v[itrack];
412  const bidx_t qb2 = qb2v[itrack];
413  const bidx_t pb1 = pb1v[itrack];
414  const bidx_t pb2 = pb2v[itrack];
415 
416  // Used only by usePhiQArrays
417  const float q = qv[itrack];
418  const float phi = phiv[itrack];
419  const float dphi = dphiv[itrack];
420  const float dq = dqv[itrack];
421  // clang-format off
422  dprintf(" %2d/%2d: %6.3f %6.3f %6.6f %7.5f %3u %3u %4u %4u\n",
423  L.layer_id(), itrack, q, phi, dq, dphi,
424  qb1, qb2, pb1, pb2);
425  // clang-format on
426  // MT: One could iterate in "spiral" order, to pick hits close to the center.
427  // http://stackoverflow.com/questions/398299/looping-in-a-spiral
428  // This would then work best with relatively small bin sizes.
429  // Or, set them up so I can always take 3x3 array around the intersection.
430 
431 #if defined(DUMPHITWINDOW) && defined(MKFIT_STANDALONE)
432  int thisseedmcid = -999999;
433  {
434  int seedlabel = m_SeedLabel(itrack, 0, 0);
435  TrackVec &seedtracks = m_event->seedTracks_;
436  int thisidx = -999999;
437  for (int i = 0; i < int(seedtracks.size()); ++i) {
438  auto &thisseed = seedtracks[i];
439  if (thisseed.label() == seedlabel) {
440  thisidx = i;
441  break;
442  }
443  }
444  if (thisidx > -999999) {
445  auto &seedtrack = m_event->seedTracks_[thisidx];
446  std::vector<int> thismcHitIDs;
447  seedtrack.mcHitIDsVec(m_event->layerHits_, m_event->simHitsInfo_, thismcHitIDs);
448  if (std::adjacent_find(thismcHitIDs.begin(), thismcHitIDs.end(), std::not_equal_to<>()) ==
449  thismcHitIDs.end()) {
450  thisseedmcid = thismcHitIDs.at(0);
451  }
452  }
453  }
454 #endif
455 
456  for (bidx_t qi = qb1; qi != qb2; ++qi) {
457  for (bidx_t pi = pb1; pi != pb2; pi = L.phiMaskApply(pi + 1)) {
458  // Limit to central Q-bin
459  if (qi == qb && L.isBinDead(pi, qi) == true) {
460  dprint("dead module for track in layer=" << L.layer_id() << " qb=" << qi << " pi=" << pi << " q=" << q
461  << " phi=" << phi);
462  m_XWsrResult[itrack].m_in_gap = true;
463  }
464 
465  // MT: The following line is the biggest hog (4% total run time).
466  // This comes from cache misses, I presume.
467  // It might make sense to make first loop to extract bin indices
468  // and issue prefetches at the same time.
469  // Then enter vectorized loop to actually collect the hits in proper order.
470 
471  //SK: ~20x1024 bin sizes give mostly 1 hit per bin. Commented out for 128 bins or less
472  // #pragma nounroll
473  auto pbi = L.phiQBinContent(pi, qi);
474  for (bcnt_t hi = pbi.begin(); hi < pbi.end(); ++hi) {
475  // MT: Access into m_hit_zs and m_hit_phis is 1% run-time each.
476 
477  unsigned int hi_orig = L.getOriginalHitIndex(hi);
478 
479  if (m_iteration_hit_mask && (*m_iteration_hit_mask)[hi_orig]) {
480  dprintf(
481  "Yay, denying masked hit on layer %u, hi %u, orig idx %u\n", L.layer_info()->layer_id(), hi, hi_orig);
482  continue;
483  }
484 
485  if (Config::usePhiQArrays) {
486  if (m_XHitSize[itrack] >= MPlexHitIdxMax)
487  break;
488 
489  const float ddq = std::abs(q - L.hit_q(hi));
490  const float ddphi = cdist(std::abs(phi - L.hit_phi(hi)));
491 
492 #if defined(DUMPHITWINDOW) && defined(MKFIT_STANDALONE)
493  {
494  const MCHitInfo &mchinfo = m_event->simHitsInfo_[L.refHit(hi).mcHitID()];
495  int mchid = mchinfo.mcTrackID();
496  int st_isfindable = 0;
497  int st_label = -999999;
498  int st_prodtype = 0;
499  int st_nhits = -1;
500  int st_charge = 0;
501  float st_r = -999.;
502  float st_z = -999.;
503  float st_pt = -999.;
504  float st_eta = -999.;
505  float st_phi = -999.;
506  if (mchid >= 0) {
507  Track simtrack = m_event->simTracks_[mchid];
508  st_isfindable = (int)simtrack.isFindable();
509  st_label = simtrack.label();
510  st_prodtype = (int)simtrack.prodType();
511  st_pt = simtrack.pT();
512  st_eta = simtrack.momEta();
513  st_phi = simtrack.momPhi();
514  st_nhits = simtrack.nTotalHits();
515  st_charge = simtrack.charge();
516  st_r = simtrack.posR();
517  st_z = simtrack.z();
518  }
519 
520  const Hit &thishit = L.refHit(hi);
521  m_msErr.copyIn(itrack, thishit.errArray());
522  m_msPar.copyIn(itrack, thishit.posArray());
523 
524  MPlexQF thisOutChi2;
525  MPlexLV tmpPropPar;
526  const FindingFoos &fnd_foos = FindingFoos::get_finding_foos(L.is_barrel());
527  (*fnd_foos.m_compute_chi2_foo)(m_Err[iI],
528  m_Par[iI],
529  m_Chg,
530  m_msErr,
531  m_msPar,
532  thisOutChi2,
533  tmpPropPar,
534  N_proc,
537 
538  float hx = thishit.x();
539  float hy = thishit.y();
540  float hz = thishit.z();
541  float hr = std::hypot(hx, hy);
542  float hphi = std::atan2(hy, hx);
543  float hex = std::sqrt(thishit.exx());
544  if (std::isnan(hex))
545  hex = -999.;
546  float hey = std::sqrt(thishit.eyy());
547  if (std::isnan(hey))
548  hey = -999.;
549  float hez = std::sqrt(thishit.ezz());
550  if (std::isnan(hez))
551  hez = -999.;
552  float her = std::sqrt(
553  (hx * hx * thishit.exx() + hy * hy * thishit.eyy() + 2.0f * hx * hy * m_msErr.At(itrack, 0, 1)) /
554  (hr * hr));
555  if (std::isnan(her))
556  her = -999.;
557  float hephi = std::sqrt(thishit.ephi());
558  if (std::isnan(hephi))
559  hephi = -999.;
560  float hchi2 = thisOutChi2[itrack];
561  if (std::isnan(hchi2))
562  hchi2 = -999.;
563  float tx = m_Par[iI].At(itrack, 0, 0);
564  float ty = m_Par[iI].At(itrack, 1, 0);
565  float tz = m_Par[iI].At(itrack, 2, 0);
566  float tr = std::hypot(tx, ty);
567  float tphi = std::atan2(ty, tx);
568  float tchi2 = m_Chi2(itrack, 0, 0);
569  if (std::isnan(tchi2))
570  tchi2 = -999.;
571  float tex = std::sqrt(m_Err[iI].At(itrack, 0, 0));
572  if (std::isnan(tex))
573  tex = -999.;
574  float tey = std::sqrt(m_Err[iI].At(itrack, 1, 1));
575  if (std::isnan(tey))
576  tey = -999.;
577  float tez = std::sqrt(m_Err[iI].At(itrack, 2, 2));
578  if (std::isnan(tez))
579  tez = -999.;
580  float ter = std::sqrt(
581  (tx * tx * tex * tex + ty * ty * tey * tey + 2.0f * tx * ty * m_Err[iI].At(itrack, 0, 1)) /
582  (tr * tr));
583  if (std::isnan(ter))
584  ter = -999.;
585  float tephi = std::sqrt(
586  (ty * ty * tex * tex + tx * tx * tey * tey - 2.0f * tx * ty * m_Err[iI].At(itrack, 0, 1)) /
587  (tr * tr * tr * tr));
588  if (std::isnan(tephi))
589  tephi = -999.;
590  float ht_dxy = std::hypot(hx - tx, hy - ty);
591  float ht_dz = hz - tz;
592  float ht_dphi = cdist(std::abs(hphi - tphi));
593 
594  static bool first = true;
595  if (first) {
596  printf(
597  "HITWINDOWSEL "
598  "evt_id/I:"
599  "lyr_id/I:lyr_isbrl/I:hit_idx/I:"
600  "trk_cnt/I:trk_idx/I:trk_label/I:"
601  "trk_pt/F:trk_eta/F:trk_mphi/F:trk_chi2/F:"
602  "nhits/I:"
603  "seed_idx/I:seed_label/I:seed_algo/I:seed_mcid/I:"
604  "hit_mcid/I:"
605  "st_isfindable/I:st_prodtype/I:st_label/I:"
606  "st_pt/F:st_eta/F:st_phi/F:"
607  "st_nhits/I:st_charge/I:st_r/F:st_z/F:"
608  "trk_q/F:hit_q/F:dq_trkhit/F:dq_cut/F:trk_phi/F:hit_phi/F:dphi_trkhit/F:dphi_cut/F:"
609  "t_x/F:t_y/F:t_r/F:t_phi/F:t_z/F:"
610  "t_ex/F:t_ey/F:t_er/F:t_ephi/F:t_ez/F:"
611  "h_x/F:h_y/F:h_r/F:h_phi/F:h_z/F:"
612  "h_ex/F:h_ey/F:h_er/F:h_ephi/F:h_ez/F:"
613  "ht_dxy/F:ht_dz/F:ht_dphi/F:"
614  "h_chi2/F"
615  "\n");
616  first = false;
617  }
618 
619  if (!(std::isnan(phi)) && !(std::isnan(getEta(m_Par[iI].At(itrack, 5, 0))))) {
620  //|| std::isnan(ter) || std::isnan(her) || std::isnan(m_Chi2(itrack, 0, 0)) || std::isnan(hchi2)))
621  // clang-format off
622  printf("HITWINDOWSEL "
623  "%d "
624  "%d %d %d "
625  "%d %d %d "
626  "%6.3f %6.3f %6.3f %6.3f "
627  "%d "
628  "%d %d %d %d "
629  "%d "
630  "%d %d %d "
631  "%6.3f %6.3f %6.3f "
632  "%d %d %6.3f %6.3f "
633  "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f "
634  "%6.3f %6.3f %6.3f %6.3f %6.3f "
635  "%6.6f %6.6f %6.6f %6.6f %6.6f "
636  "%6.3f %6.3f %6.3f %6.3f %6.3f "
637  "%6.6f %6.6f %6.6f %6.6f %6.6f "
638  "%6.3f %6.3f %6.3f "
639  "%6.3f"
640  "\n",
641  m_event->evtID(),
642  L.layer_id(), L.is_barrel(), L.getOriginalHitIndex(hi),
643  itrack, m_CandIdx(itrack, 0, 0), m_Label(itrack, 0, 0),
644  1.0f / m_Par[iI].At(itrack, 3, 0), getEta(m_Par[iI].At(itrack, 5, 0)), m_Par[iI].At(itrack, 4, 0), m_Chi2(itrack, 0, 0),
645  m_NFoundHits(itrack, 0, 0),
646  m_SeedIdx(itrack, 0, 0), m_SeedLabel(itrack, 0, 0), m_SeedAlgo(itrack, 0, 0), thisseedmcid,
647  mchid,
648  st_isfindable, st_prodtype, st_label,
649  st_pt, st_eta, st_phi,
650  st_nhits, st_charge, st_r, st_z,
651  q, L.hit_q(hi), ddq, dq, phi, L.hit_phi(hi), ddphi, dphi,
652  tx, ty, tr, tphi, tz,
653  tex, tey, ter, tephi, tez,
654  hx, hy, hr, hphi, hz,
655  hex, hey, her, hephi, hez,
656  ht_dxy, ht_dz, ht_dphi,
657  hchi2);
658  // clang-format on
659  }
660  }
661 #endif
662 
663  if (ddq >= dq)
664  continue;
665  if (ddphi >= dphi)
666  continue;
667  // clang-format off
668  dprintf(" SHI %3u %4u %5u %6.3f %6.3f %6.4f %7.5f %s\n",
669  qi, pi, hi, L.hit_q(hi), L.hit_phi(hi),
670  ddq, ddphi, (ddq < dq && ddphi < dphi) ? "PASS" : "FAIL");
671  // clang-format on
672 
673  // MT: Removing extra check gives full efficiency ...
674  // and means our error estimations are wrong!
675  // Avi says we should have *minimal* search windows per layer.
676  // Also ... if bins are sufficiently small, we do not need the extra
677  // checks, see above.
678  m_XHitArr.At(itrack, m_XHitSize[itrack]++, 0) = hi_orig;
679  } else {
680  // MT: The following check alone makes more sense with spiral traversal,
681  // we'd be taking in closest hits first.
682 
683  // Hmmh -- there used to be some more checks here.
684  // Or, at least, the phi binning was much smaller and no further checks were done.
685  assert(false && "this code has not been used in a while -- see comments in code");
686 
687  if (m_XHitSize[itrack] < MPlexHitIdxMax) {
688  m_XHitArr.At(itrack, m_XHitSize[itrack]++, 0) = hi_orig;
689  }
690  }
691  } //hi
692  } //pi
693  } //qi
694  } //itrack
695  }
696 
697  //==============================================================================
698  // AddBestHit - Best Hit Track Finding
699  //==============================================================================
700 
701  void MkFinder::addBestHit(const LayerOfHits &layer_of_hits, const int N_proc, const FindingFoos &fnd_foos) {
702  // debug = true;
703 
704  MatriplexHitPacker mhp(layer_of_hits.hitArray());
705 
706  float minChi2[NN];
707  int bestHit[NN];
708  int maxSize = 0;
709 
710  // Determine maximum number of hits for tracks in the collection.
711  for (int it = 0; it < NN; ++it) {
712  if (it < N_proc) {
713  if (m_XHitSize[it] > 0) {
715  }
716  }
717 
718  bestHit[it] = -1;
720  }
721 
722  for (int hit_cnt = 0; hit_cnt < maxSize; ++hit_cnt) {
723  //fixme what if size is zero???
724 
725  mhp.reset();
726 
727  //#pragma omp simd doesn't vectorize with current compilers
728  for (int itrack = 0; itrack < N_proc; ++itrack) {
729  if (hit_cnt < m_XHitSize[itrack]) {
730  mhp.addInputAt(itrack, layer_of_hits.refHit(m_XHitArr.At(itrack, hit_cnt, 0)));
731  }
732  }
733 
734  mhp.pack(m_msErr, m_msPar);
735 
736  //now compute the chi2 of track state vs hit
737  MPlexQF outChi2;
738  MPlexLV tmpPropPar;
739  clearFailFlag();
740  (*fnd_foos.m_compute_chi2_foo)(m_Err[iP],
741  m_Par[iP],
742  m_Chg,
743  m_msErr,
744  m_msPar,
745  outChi2,
746  tmpPropPar,
747  m_FailFlag,
748  N_proc,
751 
752  //update best hit in case chi2<minChi2
753 #pragma omp simd
754  for (int itrack = 0; itrack < N_proc; ++itrack) {
755  if (hit_cnt < m_XHitSize[itrack]) {
756  const float chi2 = std::abs(outChi2[itrack]); //fixme negative chi2 sometimes...
757  dprint("chi2=" << chi2 << " minChi2[itrack]=" << minChi2[itrack]);
758  if (chi2 < minChi2[itrack]) {
759  minChi2[itrack] = chi2;
760  bestHit[itrack] = m_XHitArr.At(itrack, hit_cnt, 0);
761  }
762  }
763  }
764  } // end loop over hits
765 
766  //#pragma omp simd
767  for (int itrack = 0; itrack < N_proc; ++itrack) {
768  if (m_XWsrResult[itrack].m_wsr == WSR_Outside) {
769  // Why am I doing this?
770  m_msErr.setDiagonal3x3(itrack, 666);
771  m_msPar(itrack, 0, 0) = m_Par[iP](itrack, 0, 0);
772  m_msPar(itrack, 1, 0) = m_Par[iP](itrack, 1, 0);
773  m_msPar(itrack, 2, 0) = m_Par[iP](itrack, 2, 0);
774 
775  // XXXX If not in gap, should get back the old track params. But they are gone ...
776  // Would actually have to do it right after SelectHitIndices where updated params are still ok.
777  // Here they got screwed during hit matching.
778  // So, I'd store them there (into propagated params) and retrieve them here.
779  // Or we decide not to care ...
780 
781  continue;
782  }
783 
784  //fixme decide what to do in case no hit found
785  if (bestHit[itrack] >= 0) {
786  const Hit &hit = layer_of_hits.refHit(bestHit[itrack]);
787  const float chi2 = minChi2[itrack];
788 
789  dprint("ADD BEST HIT FOR TRACK #"
790  << itrack << std::endl
791  << "prop x=" << m_Par[iP].constAt(itrack, 0, 0) << " y=" << m_Par[iP].constAt(itrack, 1, 0) << std::endl
792  << "copy in hit #" << bestHit[itrack] << " x=" << hit.position()[0] << " y=" << hit.position()[1]);
793 
794  m_msErr.copyIn(itrack, hit.errArray());
795  m_msPar.copyIn(itrack, hit.posArray());
796  m_Chi2(itrack, 0, 0) += chi2;
797 
798  add_hit(itrack, bestHit[itrack], layer_of_hits.layer_id());
799  } else {
800  int fake_hit_idx = Hit::kHitMissIdx;
801 
802  if (m_XWsrResult[itrack].m_wsr == WSR_Edge) {
803  // YYYYYY Config::store_missed_layers
804  fake_hit_idx = Hit::kHitEdgeIdx;
805  } else if (num_all_minus_one_hits(itrack)) {
806  fake_hit_idx = Hit::kHitStopIdx;
807  }
808 
809  dprint("ADD FAKE HIT FOR TRACK #" << itrack << " withinBounds=" << (fake_hit_idx != Hit::kHitEdgeIdx)
810  << " r=" << std::hypot(m_Par[iP](itrack, 0, 0), m_Par[iP](itrack, 1, 0)));
811 
812  m_msErr.setDiagonal3x3(itrack, 666);
813  m_msPar(itrack, 0, 0) = m_Par[iP](itrack, 0, 0);
814  m_msPar(itrack, 1, 0) = m_Par[iP](itrack, 1, 0);
815  m_msPar(itrack, 2, 0) = m_Par[iP](itrack, 2, 0);
816  // Don't update chi2
817 
818  add_hit(itrack, fake_hit_idx, layer_of_hits.layer_id());
819  }
820  }
821 
822  // Update the track parameters with this hit. (Note that some calculations
823  // are already done when computing chi2. Not sure it's worth caching them?)
824 
825  dprint("update parameters");
826  clearFailFlag();
827  (*fnd_foos.m_update_param_foo)(m_Err[iP],
828  m_Par[iP],
829  m_Chg,
830  m_msErr,
831  m_msPar,
832  m_Err[iC],
833  m_Par[iC],
834  m_FailFlag,
835  N_proc,
838 
839  dprint("m_Par[iP](0,0,0)=" << m_Par[iP](0, 0, 0) << " m_Par[iC](0,0,0)=" << m_Par[iC](0, 0, 0));
840  }
841 
842  //=======================================================
843  // isStripQCompatible : check if prop is consistent with the barrel/endcap strip length
844  //=======================================================
846  int itrack, bool isBarrel, const MPlexLS &pErr, const MPlexLV &pPar, const MPlexHS &msErr, const MPlexHV &msPar) {
847  //check module compatibility via long strip side = L/sqrt(12)
848  if (isBarrel) { //check z direction only
849  const float res = std::abs(msPar.constAt(itrack, 2, 0) - pPar.constAt(itrack, 2, 0));
850  const float hitHL = sqrt(msErr.constAt(itrack, 2, 2) * 3.f); //half-length
851  const float qErr = sqrt(pErr.constAt(itrack, 2, 2));
852  dprint("qCompat " << hitHL << " + " << 3.f * qErr << " vs " << res);
853  return hitHL + std::max(3.f * qErr, 0.5f) > res;
854  } else { //project on xy, assuming the strip Length >> Width
855  const float res[2]{msPar.constAt(itrack, 0, 0) - pPar.constAt(itrack, 0, 0),
856  msPar.constAt(itrack, 1, 0) - pPar.constAt(itrack, 1, 0)};
857  const float hitT2 = msErr.constAt(itrack, 0, 0) + msErr.constAt(itrack, 1, 1);
858  const float hitT2inv = 1.f / hitT2;
859  const float proj[3] = {msErr.constAt(itrack, 0, 0) * hitT2inv,
860  msErr.constAt(itrack, 0, 1) * hitT2inv,
861  msErr.constAt(itrack, 1, 1) * hitT2inv};
862  const float qErr =
863  sqrt(std::abs(pErr.constAt(itrack, 0, 0) * proj[0] + 2.f * pErr.constAt(itrack, 0, 1) * proj[1] +
864  pErr.constAt(itrack, 1, 1) * proj[2])); //take abs to avoid non-pos-def cases
865  const float resProj =
866  sqrt(res[0] * proj[0] * res[0] + 2.f * res[1] * proj[1] * res[0] + res[1] * proj[2] * res[1]);
867  dprint("qCompat " << sqrt(hitT2 * 3.f) << " + " << 3.f * qErr << " vs " << resProj);
868  return sqrt(hitT2 * 3.f) + std::max(3.f * qErr, 0.5f) > resProj;
869  }
870  }
871 
872  //=======================================================
873  // passStripChargePCMfromTrack : apply the slope correction to charge per cm and cut using hit err matrix
874  // the raw pcm = charge/L_normal
875  // the corrected qCorr = charge/L_path = charge/(L_normal*p/p_zLocal) = pcm*p_zLocal/p
876  //=======================================================
878  int itrack, bool isBarrel, unsigned int pcm, unsigned int pcmMin, const MPlexLV &pPar, const MPlexHS &msErr) {
879  //skip the overflow case
880  if (pcm >= Hit::maxChargePerCM())
881  return true;
882 
883  float qSF;
884  if (isBarrel) { //project in x,y, assuming zero-error direction is in this plane
885  const float hitT2 = msErr.constAt(itrack, 0, 0) + msErr.constAt(itrack, 1, 1);
886  const float hitT2inv = 1.f / hitT2;
887  const float proj[3] = {msErr.constAt(itrack, 0, 0) * hitT2inv,
888  msErr.constAt(itrack, 0, 1) * hitT2inv,
889  msErr.constAt(itrack, 1, 1) * hitT2inv};
890  const bool detXY_OK =
891  std::abs(proj[0] * proj[2] - proj[1] * proj[1]) < 0.1f; //check that zero-direction is close
892  const float cosP = cos(pPar.constAt(itrack, 4, 0));
893  const float sinP = sin(pPar.constAt(itrack, 4, 0));
894  const float sinT = std::abs(sin(pPar.constAt(itrack, 5, 0)));
895  //qSF = sqrt[(px,py)*(1-proj)*(px,py)]/p = sinT*sqrt[(cosP,sinP)*(1-proj)*(cosP,sinP)].
896  qSF = detXY_OK ? sinT * std::sqrt(std::abs(1.f + cosP * cosP * proj[0] + sinP * sinP * proj[2] -
897  2.f * cosP * sinP * proj[1]))
898  : 1.f;
899  } else { //project on z
900  // p_zLocal/p = p_z/p = cosT
901  qSF = std::abs(cos(pPar.constAt(itrack, 5, 0)));
902  }
903 
904  const float qCorr = pcm * qSF;
905  dprint("pcm " << pcm << " * " << qSF << " = " << qCorr << " vs " << pcmMin);
906  return qCorr > pcmMin;
907  }
908 
909  //==============================================================================
910  // FindCandidates - Standard Track Finding
911  //==============================================================================
912 
913  void MkFinder::findCandidates(const LayerOfHits &layer_of_hits,
914  std::vector<std::vector<TrackCand>> &tmp_candidates,
915  const int offset,
916  const int N_proc,
917  const FindingFoos &fnd_foos) {
918  // bool debug = true;
919 
920  MatriplexHitPacker mhp(layer_of_hits.hitArray());
921 
922  int maxSize = 0;
923 
924  // Determine maximum number of hits for tracks in the collection.
925  for (int it = 0; it < NN; ++it) {
926  if (it < N_proc) {
927  if (m_XHitSize[it] > 0) {
929  }
930  }
931  }
932 
933  dprintf("FindCandidates max hits to process=%d\n", maxSize);
934 
935  int nHitsAdded[NN]{};
936  bool isTooLargeCluster[NN]{false};
937 
938  for (int hit_cnt = 0; hit_cnt < maxSize; ++hit_cnt) {
939  mhp.reset();
940 
941  int charge_pcm[NN];
942 
943  //#pragma omp simd doesn't vectorize with current compilers
944  for (int itrack = 0; itrack < N_proc; ++itrack) {
945  if (hit_cnt < m_XHitSize[itrack]) {
946  const auto &hit = layer_of_hits.refHit(m_XHitArr.At(itrack, hit_cnt, 0));
947  mhp.addInputAt(itrack, hit);
948  charge_pcm[itrack] = hit.chargePerCM();
949  }
950  }
951 
952  mhp.pack(m_msErr, m_msPar);
953 
954  //now compute the chi2 of track state vs hit
955  MPlexQF outChi2;
956  MPlexLV propPar;
957  clearFailFlag();
958  (*fnd_foos.m_compute_chi2_foo)(m_Err[iP],
959  m_Par[iP],
960  m_Chg,
961  m_msErr,
962  m_msPar,
963  outChi2,
964  propPar,
965  m_FailFlag,
966  N_proc,
969 
970  // Now update the track parameters with this hit (note that some
971  // calculations are already done when computing chi2, to be optimized).
972  // 1. This is not needed for candidates the hit is not added to, but it's
973  // vectorized so doing it serially below should take the same time.
974  // 2. Still it's a waste of time in case the hit is not added to any of the
975  // candidates, so check beforehand that at least one cand needs update.
976  bool oneCandPassCut = false;
977  for (int itrack = 0; itrack < N_proc; ++itrack) {
978  float max_c2 = getHitSelDynamicChi2Cut(itrack, iP);
979 
980  if (hit_cnt < m_XHitSize[itrack]) {
981  const float chi2 = std::abs(outChi2[itrack]); //fixme negative chi2 sometimes...
982  dprint("chi2=" << chi2);
983  if (chi2 < max_c2) {
984  bool isCompatible = true;
985  if (!layer_of_hits.is_pixel()) {
986  //check module compatibility via long strip side = L/sqrt(12)
987  isCompatible =
988  isStripQCompatible(itrack, layer_of_hits.is_barrel(), m_Err[iP], propPar, m_msErr, m_msPar);
989 
990  //rescale strip charge to track parameters and reapply the cut
991  isCompatible &= passStripChargePCMfromTrack(
992  itrack, layer_of_hits.is_barrel(), charge_pcm[itrack], Hit::minChargePerCM(), propPar, m_msErr);
993  }
994  // Select only SiStrip hits with cluster size < maxClusterSize
995  if (!layer_of_hits.is_pixel()) {
996  if (layer_of_hits.refHit(m_XHitArr.At(itrack, hit_cnt, 0)).spanRows() >=
998  isTooLargeCluster[itrack] = true;
999  isCompatible = false;
1000  }
1001  }
1002 
1003  if (isCompatible) {
1004  oneCandPassCut = true;
1005  break;
1006  }
1007  }
1008  }
1009  }
1010 
1011  if (oneCandPassCut) {
1012  MPlexQI tmpChg = m_Chg;
1013  clearFailFlag();
1014  (*fnd_foos.m_update_param_foo)(m_Err[iP],
1015  m_Par[iP],
1016  tmpChg,
1017  m_msErr,
1018  m_msPar,
1019  m_Err[iC],
1020  m_Par[iC],
1021  m_FailFlag,
1022  N_proc,
1025 
1026  dprint("update parameters" << std::endl
1027  << "propagated track parameters x=" << m_Par[iP].constAt(0, 0, 0)
1028  << " y=" << m_Par[iP].constAt(0, 1, 0) << std::endl
1029  << " hit position x=" << m_msPar.constAt(0, 0, 0)
1030  << " y=" << m_msPar.constAt(0, 1, 0) << std::endl
1031  << " updated track parameters x=" << m_Par[iC].constAt(0, 0, 0)
1032  << " y=" << m_Par[iC].constAt(0, 1, 0));
1033 
1034  //create candidate with hit in case chi2 < max_c2
1035  //fixme: please vectorize me... (not sure it's possible in this case)
1036  for (int itrack = 0; itrack < N_proc; ++itrack) {
1037  float max_c2 = getHitSelDynamicChi2Cut(itrack, iP);
1038 
1039  if (hit_cnt < m_XHitSize[itrack]) {
1040  const float chi2 = std::abs(outChi2[itrack]); //fixme negative chi2 sometimes...
1041  dprint("chi2=" << chi2);
1042  if (chi2 < max_c2) {
1043  bool isCompatible = true;
1044  if (!layer_of_hits.is_pixel()) {
1045  //check module compatibility via long strip side = L/sqrt(12)
1046  isCompatible =
1047  isStripQCompatible(itrack, layer_of_hits.is_barrel(), m_Err[iP], propPar, m_msErr, m_msPar);
1048 
1049  //rescale strip charge to track parameters and reapply the cut
1050  isCompatible &= passStripChargePCMfromTrack(
1051  itrack, layer_of_hits.is_barrel(), charge_pcm[itrack], Hit::minChargePerCM(), propPar, m_msErr);
1052  }
1053  // Select only SiStrip hits with cluster size < maxClusterSize
1054  if (!layer_of_hits.is_pixel()) {
1055  if (layer_of_hits.refHit(m_XHitArr.At(itrack, hit_cnt, 0)).spanRows() >=
1057  isCompatible = false;
1058  }
1059 
1060  if (isCompatible) {
1061  bool hitExists = false;
1062  int maxHits = m_NFoundHits(itrack, 0, 0);
1063  if (layer_of_hits.is_pixel()) {
1064  for (int i = 0; i <= maxHits; ++i) {
1065  if (i > 2)
1066  break;
1067  if (m_HoTArrs[itrack][i].layer == layer_of_hits.layer_id()) {
1068  hitExists = true;
1069  break;
1070  }
1071  }
1072  }
1073  if (hitExists)
1074  continue;
1075 
1076  nHitsAdded[itrack]++;
1077  dprint("chi2 cut passed, creating new candidate");
1078  // Create a new candidate and fill the tmp_candidates output vector.
1079  // QQQ only instantiate if it will pass, be better than N_best
1080 
1081  const int hit_idx = m_XHitArr.At(itrack, hit_cnt, 0);
1082 
1083  TrackCand newcand;
1084  copy_out(newcand, itrack, iC);
1085  newcand.setCharge(tmpChg(itrack, 0, 0));
1086  newcand.addHitIdx(hit_idx, layer_of_hits.layer_id(), chi2);
1088  newcand,
1089  true /*penalizeTailMissHits*/,
1090  true /*inFindCandidates*/));
1091  newcand.setOriginIndex(m_CandIdx(itrack, 0, 0));
1092 
1093  // To apply a fixed cut instead of dynamic cut for overlap: m_iteration_params->chi2CutOverlap
1094  if (chi2 < max_c2) {
1095  CombCandidate &ccand = *newcand.combCandidate();
1096  ccand[m_CandIdx(itrack, 0, 0)].considerHitForOverlap(
1097  hit_idx, layer_of_hits.refHit(hit_idx).detIDinLayer(), chi2);
1098  }
1099 
1100  dprint("updated track parameters x=" << newcand.parameters()[0] << " y=" << newcand.parameters()[1]
1101  << " z=" << newcand.parameters()[2]
1102  << " pt=" << 1. / newcand.parameters()[3]);
1103 
1104  tmp_candidates[m_SeedIdx(itrack, 0, 0) - offset].emplace_back(newcand);
1105  }
1106  }
1107  }
1108  }
1109  } //end if (oneCandPassCut)
1110 
1111  } //end loop over hits
1112 
1113  //now add invalid hit
1114  //fixme: please vectorize me...
1115  for (int itrack = 0; itrack < N_proc; ++itrack) {
1116  // Cands that miss the layer are stashed away in MkBuilder(), before propagation,
1117  // and then merged back afterwards.
1118  if (m_XWsrResult[itrack].m_wsr == WSR_Outside) {
1119  continue;
1120  }
1121 
1122  int fake_hit_idx = ((num_all_minus_one_hits(itrack) < m_iteration_params->maxHolesPerCand) &&
1125  : Hit::kHitStopIdx;
1126 
1127  if (m_XWsrResult[itrack].m_wsr == WSR_Edge) {
1128  // YYYYYY m_iteration_params->store_missed_layers
1129  fake_hit_idx = Hit::kHitEdgeIdx;
1130  }
1131  //now add fake hit for tracks that passsed through inactive modules
1132  else if (m_XWsrResult[itrack].m_in_gap == true && nHitsAdded[itrack] == 0) {
1133  fake_hit_idx = Hit::kHitInGapIdx;
1134  }
1135  //now add fake hit for cases where hit cluster size is larger than maxClusterSize
1136  else if (isTooLargeCluster[itrack] == true && nHitsAdded[itrack] == 0) {
1137  fake_hit_idx = Hit::kHitMaxClusterIdx;
1138  }
1139 
1140  dprint("ADD FAKE HIT FOR TRACK #" << itrack << " withinBounds=" << (fake_hit_idx != Hit::kHitEdgeIdx)
1141  << " r=" << std::hypot(m_Par[iP](itrack, 0, 0), m_Par[iP](itrack, 1, 0)));
1142 
1143  // QQQ as above, only create and add if score better
1144  TrackCand newcand;
1145  copy_out(newcand, itrack, iP);
1146  newcand.addHitIdx(fake_hit_idx, layer_of_hits.layer_id(), 0.);
1147  newcand.setScore(getScoreCand(
1148  m_steering_params->m_track_scorer, newcand, true /*penalizeTailMissHits*/, true /*inFindCandidates*/));
1149  // Only relevant when we actually add a hit
1150  // newcand.setOriginIndex(m_CandIdx(itrack, 0, 0));
1151  tmp_candidates[m_SeedIdx(itrack, 0, 0) - offset].emplace_back(newcand);
1152  }
1153  }
1154 
1155  //==============================================================================
1156  // FindCandidatesCloneEngine - Clone Engine Track Finding
1157  //==============================================================================
1158 
1160  CandCloner &cloner,
1161  const int offset,
1162  const int N_proc,
1163  const FindingFoos &fnd_foos) {
1164  // bool debug = true;
1165 
1166  MatriplexHitPacker mhp(layer_of_hits.hitArray());
1167 
1168  int maxSize = 0;
1169 
1170  // Determine maximum number of hits for tracks in the collection.
1171 #pragma omp simd
1172  for (int it = 0; it < NN; ++it) {
1173  if (it < N_proc) {
1174  if (m_XHitSize[it] > 0) {
1176  }
1177  }
1178  }
1179 
1180  dprintf("FindCandidatesCloneEngine max hits to process=%d\n", maxSize);
1181 
1182  int nHitsAdded[NN]{};
1183  bool isTooLargeCluster[NN]{false};
1184 
1185  for (int hit_cnt = 0; hit_cnt < maxSize; ++hit_cnt) {
1186  mhp.reset();
1187 
1188  int charge_pcm[NN];
1189 
1190  //#pragma omp simd doesn't vectorize with current compilers
1191  for (int itrack = 0; itrack < N_proc; ++itrack) {
1192  if (hit_cnt < m_XHitSize[itrack]) {
1193  const auto &hit = layer_of_hits.refHit(m_XHitArr.At(itrack, hit_cnt, 0));
1194  mhp.addInputAt(itrack, hit);
1195  charge_pcm[itrack] = hit.chargePerCM();
1196  }
1197  }
1198 
1199  mhp.pack(m_msErr, m_msPar);
1200 
1201  //now compute the chi2 of track state vs hit
1202  MPlexQF outChi2;
1203  MPlexLV propPar;
1204  clearFailFlag();
1205  (*fnd_foos.m_compute_chi2_foo)(m_Err[iP],
1206  m_Par[iP],
1207  m_Chg,
1208  m_msErr,
1209  m_msPar,
1210  outChi2,
1211  propPar,
1212  m_FailFlag,
1213  N_proc,
1216 
1217  //#pragma omp simd // DOES NOT VECTORIZE AS IT IS NOW
1218  for (int itrack = 0; itrack < N_proc; ++itrack) {
1219  // We can be in failed state from the initial propagation before selectHitIndices
1220  // and there hit_count for track is set to -1 and WSR state to Failed, handled below.
1221  // Or we might have hit it here in propagate-to-hit.
1222  // PROP-FAIL-ENABLE FailFlag check to be enabled when propagation failure
1223  // detection is properly implemented in propagate-to-R/Z.
1224  if ( hit_cnt < m_XHitSize[itrack]) {
1225  // make sure the hit was in the compatiblity window for the candidate
1226  const float max_c2 = getHitSelDynamicChi2Cut(itrack, iP);
1227  const float chi2 = std::abs(outChi2[itrack]); //fixme negative chi2 sometimes...
1228  // XXX-NUM-ERR assert(chi2 >= 0);
1229 
1230  dprint("chi2=" << chi2 << " for trkIdx=" << itrack << " hitIdx=" << m_XHitArr.At(itrack, hit_cnt, 0));
1231  if (chi2 < max_c2) {
1232  bool isCompatible = true;
1233  if (!layer_of_hits.is_pixel()) {
1234  //check module compatibility via long strip side = L/sqrt(12)
1235  isCompatible =
1236  isStripQCompatible(itrack, layer_of_hits.is_barrel(), m_Err[iP], propPar, m_msErr, m_msPar);
1237 
1238  //rescale strip charge to track parameters and reapply the cut
1239  isCompatible &= passStripChargePCMfromTrack(
1240  itrack, layer_of_hits.is_barrel(), charge_pcm[itrack], Hit::minChargePerCM(), propPar, m_msErr);
1241  }
1242 
1243  // Select only SiStrip hits with cluster size < maxClusterSize
1244  if (!layer_of_hits.is_pixel()) {
1245  if (layer_of_hits.refHit(m_XHitArr.At(itrack, hit_cnt, 0)).spanRows() >=
1247  isTooLargeCluster[itrack] = true;
1248  isCompatible = false;
1249  }
1250  }
1251 
1252  if (isCompatible) {
1253  CombCandidate &ccand = cloner.combCandWithOriginalIndex(m_SeedIdx(itrack, 0, 0));
1254  bool hitExists = false;
1255  int maxHits = m_NFoundHits(itrack, 0, 0);
1256  if (layer_of_hits.is_pixel()) {
1257  for (int i = 0; i <= maxHits; ++i) {
1258  if (i > 2)
1259  break;
1260  if (ccand.hot(i).layer == layer_of_hits.layer_id()) {
1261  hitExists = true;
1262  break;
1263  }
1264  }
1265  }
1266  if (hitExists)
1267  continue;
1268 
1269  nHitsAdded[itrack]++;
1270  const int hit_idx = m_XHitArr.At(itrack, hit_cnt, 0);
1271 
1272  // Register hit for overlap consideration, if chi2 cut is passed
1273  // To apply a fixed cut instead of dynamic cut for overlap: m_iteration_params->chi2CutOverlap
1274  if (chi2 < max_c2) {
1275  ccand[m_CandIdx(itrack, 0, 0)].considerHitForOverlap(
1276  hit_idx, layer_of_hits.refHit(hit_idx).detIDinLayer(), chi2);
1277  }
1278 
1279  IdxChi2List tmpList;
1280  tmpList.trkIdx = m_CandIdx(itrack, 0, 0);
1281  tmpList.hitIdx = hit_idx;
1282  tmpList.module = layer_of_hits.refHit(hit_idx).detIDinLayer();
1283  tmpList.nhits = m_NFoundHits(itrack, 0, 0) + 1;
1284  tmpList.ntailholes = 0;
1285  tmpList.noverlaps = m_NOverlapHits(itrack, 0, 0);
1286  tmpList.nholes = num_all_minus_one_hits(itrack);
1287  tmpList.pt = std::abs(1.0f / m_Par[iP].At(itrack, 3, 0));
1288  tmpList.chi2 = m_Chi2(itrack, 0, 0) + chi2;
1289  tmpList.chi2_hit = chi2;
1291  cloner.add_cand(m_SeedIdx(itrack, 0, 0) - offset, tmpList);
1292 
1293  dprint(" adding hit with hit_cnt=" << hit_cnt << " for trkIdx=" << tmpList.trkIdx
1294  << " orig Seed=" << m_Label(itrack, 0, 0));
1295  }
1296  }
1297  }
1298  }
1299 
1300  } //end loop over hits
1301 
1302  //now add invalid hit
1303  for (int itrack = 0; itrack < N_proc; ++itrack) {
1304  dprint("num_all_minus_one_hits(" << itrack << ")=" << num_all_minus_one_hits(itrack));
1305 
1306  // Cands that miss the layer are stashed away in MkBuilder(), before propagation,
1307  // and then merged back afterwards.
1308  if (m_XWsrResult[itrack].m_wsr == WSR_Outside) {
1309  continue;
1310  }
1311 
1312  // int fake_hit_idx = num_all_minus_one_hits(itrack) < m_iteration_params->maxHolesPerCand ? -1 : -2;
1313  int fake_hit_idx = ((num_all_minus_one_hits(itrack) < m_iteration_params->maxHolesPerCand) &&
1316  : Hit::kHitStopIdx;
1317 
1318  if (m_XWsrResult[itrack].m_wsr == WSR_Edge) {
1319  fake_hit_idx = Hit::kHitEdgeIdx;
1320  }
1321  //now add fake hit for tracks that passsed through inactive modules
1322  else if (m_XWsrResult[itrack].m_in_gap == true && nHitsAdded[itrack] == 0) {
1323  fake_hit_idx = Hit::kHitInGapIdx;
1324  }
1325  //now add fake hit for cases where hit cluster size is larger than maxClusterSize
1326  else if (isTooLargeCluster[itrack] == true && nHitsAdded[itrack] == 0) {
1327  fake_hit_idx = Hit::kHitMaxClusterIdx;
1328  }
1329 
1330  // PROP-FAIL-ENABLE The following to be enabled when propagation failure
1331  // detection is properly implemented in propagate-to-R/Z.
1332  // // Override for failed propagation, this trumps all other cases.
1333  // if (m_XWsrResult[itrack].m_wsr == WSR_Failed) {
1334  // fake_hit_idx = Hit::kHitStopIdx;
1335  // }
1336 
1337  IdxChi2List tmpList;
1338  tmpList.trkIdx = m_CandIdx(itrack, 0, 0);
1339  tmpList.hitIdx = fake_hit_idx;
1340  tmpList.module = -1;
1341  tmpList.nhits = m_NFoundHits(itrack, 0, 0);
1342  tmpList.ntailholes = (fake_hit_idx == Hit::kHitMissIdx ? m_NTailMinusOneHits(itrack, 0, 0) + 1
1343  : m_NTailMinusOneHits(itrack, 0, 0));
1344  tmpList.noverlaps = m_NOverlapHits(itrack, 0, 0);
1345  tmpList.nholes = num_inside_minus_one_hits(itrack);
1346  tmpList.pt = std::abs(1.0f / m_Par[iP].At(itrack, 3, 0));
1347  tmpList.chi2 = m_Chi2(itrack, 0, 0);
1348  tmpList.chi2_hit = 0;
1350  cloner.add_cand(m_SeedIdx(itrack, 0, 0) - offset, tmpList);
1351  dprint("adding invalid hit " << fake_hit_idx);
1352  }
1353  }
1354 
1355  //==============================================================================
1356  // UpdateWithLoadedHit
1357  //==============================================================================
1358 
1359  void MkFinder::updateWithLoadedHit(int N_proc, const FindingFoos &fnd_foos) {
1360  // See comment in MkBuilder::find_tracks_in_layer() about intra / inter flags used here
1361  // for propagation to the hit.
1362  clearFailFlag();
1363  (*fnd_foos.m_update_param_foo)(m_Err[iP],
1364  m_Par[iP],
1365  m_Chg,
1366  m_msErr,
1367  m_msPar,
1368  m_Err[iC],
1369  m_Par[iC],
1370  m_FailFlag,
1371  N_proc,
1374 
1375  // PROP-FAIL-ENABLE The following to be enabled when propagation failure
1376  // detection is properly implemented in propagate-to-R/Z.
1377  // for (int i = 0; i < N_proc; ++i) {
1378  // if (m_FailFlag[i]) {
1379  // dprintf("MkFinder::updateWithLoadedHit fail in update, recovering.\n");
1380  // m_Err[iC].copySlot(i, m_Err[iP]);
1381  // m_Par[iC].copySlot(i, m_Par[iP]);
1382  // }
1383  // }
1384  }
1385 
1386  //==============================================================================
1387  // CopyOutParErr
1388  //==============================================================================
1389 
1390  void MkFinder::copyOutParErr(std::vector<CombCandidate> &seed_cand_vec, int N_proc, bool outputProp) const {
1391  const int iO = outputProp ? iP : iC;
1392 
1393  for (int i = 0; i < N_proc; ++i) {
1394  TrackCand &cand = seed_cand_vec[m_SeedIdx(i, 0, 0)][m_CandIdx(i, 0, 0)];
1395 
1396  // Set the track state to the updated parameters
1397  m_Err[iO].copyOut(i, cand.errors_nc().Array());
1398  m_Par[iO].copyOut(i, cand.parameters_nc().Array());
1399  cand.setCharge(m_Chg(i, 0, 0));
1400 
1401  dprint((outputProp ? "propagated" : "updated")
1402  << " track parameters x=" << cand.parameters()[0] << " y=" << cand.parameters()[1]
1403  << " z=" << cand.parameters()[2] << " pt=" << 1. / cand.parameters()[3] << " posEta=" << cand.posEta());
1404  }
1405  }
1406 
1407  //==============================================================================
1408  // Backward Fit hack
1409  //==============================================================================
1410 
1411  void MkFinder::bkFitInputTracks(TrackVec &cands, int beg, int end) {
1412  // Uses HitOnTrack vector from Track directly + a local cursor array to current hit.
1413 
1414  MatriplexTrackPacker mtp(&cands[beg]);
1415 
1416  int itrack = 0;
1417 
1418  for (int i = beg; i < end; ++i, ++itrack) {
1419  const Track &trk = cands[i];
1420 
1421  m_Chg(itrack, 0, 0) = trk.charge();
1422  m_CurHit[itrack] = trk.nTotalHits() - 1;
1423  m_HoTArr[itrack] = trk.getHitsOnTrackArray();
1424 
1425  mtp.addInput(trk);
1426  }
1427 
1428  m_Chi2.setVal(0);
1429 
1430  mtp.pack(m_Err[iC], m_Par[iC]);
1431 
1432  m_Err[iC].scale(100.0f);
1433  }
1434 
1435  void MkFinder::bkFitInputTracks(EventOfCombCandidates &eocss, int beg, int end) {
1436  // Could as well use HotArrays from tracks directly + a local cursor array to last hit.
1437 
1438  // XXXX - shall we assume only TrackCand-zero is needed and that we can freely
1439  // bork the HoTNode array?
1440 
1441  MatriplexTrackPacker mtp(&eocss[beg][0]);
1442 
1443  int itrack = 0;
1444 
1445  for (int i = beg; i < end; ++i, ++itrack) {
1446  const TrackCand &trk = eocss[i][0];
1447 
1448  m_Chg(itrack, 0, 0) = trk.charge();
1449  m_CurNode[itrack] = trk.lastCcIndex();
1450  m_HoTNodeArr[itrack] = trk.combCandidate()->hotsData();
1451 
1452  // XXXX Need TrackCand* to update num-hits. Unless I collect info elsewhere
1453  // and fix it in BkFitOutputTracks.
1454  m_TrkCand[itrack] = &eocss[i][0];
1455 
1456  mtp.addInput(trk);
1457  }
1458 
1459  m_Chi2.setVal(0);
1460 
1461  mtp.pack(m_Err[iC], m_Par[iC]);
1462 
1463  m_Err[iC].scale(100.0f);
1464  }
1465 
1466  //------------------------------------------------------------------------------
1467 
1468  void MkFinder::bkFitOutputTracks(TrackVec &cands, int beg, int end, bool outputProp) {
1469  // Only copy out track params / errors / chi2, all the rest is ok.
1470 
1471  const int iO = outputProp ? iP : iC;
1472 
1473  int itrack = 0;
1474  for (int i = beg; i < end; ++i, ++itrack) {
1475  Track &trk = cands[i];
1476 
1477  m_Err[iO].copyOut(itrack, trk.errors_nc().Array());
1478  m_Par[iO].copyOut(itrack, trk.parameters_nc().Array());
1479 
1480  trk.setChi2(m_Chi2(itrack, 0, 0));
1481  if (isFinite(trk.chi2())) {
1483  }
1484  }
1485  }
1486 
1487  void MkFinder::bkFitOutputTracks(EventOfCombCandidates &eocss, int beg, int end, bool outputProp) {
1488  // Only copy out track params / errors / chi2, all the rest is ok.
1489 
1490  // XXXX - where will rejected hits get removed?
1491 
1492  const int iO = outputProp ? iP : iC;
1493 
1494  int itrack = 0;
1495  for (int i = beg; i < end; ++i, ++itrack) {
1496  TrackCand &trk = eocss[i][0];
1497 
1498  m_Err[iO].copyOut(itrack, trk.errors_nc().Array());
1499  m_Par[iO].copyOut(itrack, trk.parameters_nc().Array());
1500 
1501  trk.setChi2(m_Chi2(itrack, 0, 0));
1502  if (isFinite(trk.chi2())) {
1504  }
1505  }
1506  }
1507 
1508  //------------------------------------------------------------------------------
1509 
1510 #if defined(DEBUG_BACKWARD_FIT) || defined(DEBUG_BACKWARD_FIT_BH)
1511  namespace {
1512  float e2s(float x) { return 1e4 * std::sqrt(x); }
1513  } // namespace
1514 #endif
1515 
1516  void MkFinder::bkFitFitTracksBH(const EventOfHits &eventofhits,
1517  const SteeringParams &st_par,
1518  const int N_proc,
1519  bool chiDebug) {
1520  // Prototyping final backward fit.
1521  // This works with track-finding indices, before remapping.
1522  //
1523  // Layers should be collected during track finding and list all layers that have actual hits.
1524  // Then we could avoid checking which layers actually do have hits.
1525 
1526  MPlexQF tmp_chi2;
1527  float tmp_err[6] = {666, 0, 666, 0, 0, 666};
1528  float tmp_pos[3];
1529 
1530  for (auto lp_iter = st_par.m_layer_plan.rbegin(); lp_iter != st_par.m_layer_plan.rend(); ++lp_iter) {
1531  const int layer = lp_iter->m_layer;
1532 
1533  const LayerOfHits &L = eventofhits[layer];
1534  const LayerInfo &LI = *L.layer_info();
1535 
1536  int count = 0;
1537  for (int i = 0; i < N_proc; ++i) {
1538  while (m_CurHit[i] >= 0 && m_HoTArr[i][m_CurHit[i]].index < 0)
1539  --m_CurHit[i];
1540 
1541  if (m_CurHit[i] >= 0 && m_HoTArr[i][m_CurHit[i]].layer == layer) {
1542  // Skip the overlap hits -- if they exist.
1543  // 1. Overlap hit gets placed *after* the original hit in TrackCand::exportTrack()
1544  // which is *before* in the reverse iteration that we are doing here.
1545  // 2. Seed-hit merging can result in more than two hits per layer.
1546  while (m_CurHit[i] > 0 && m_HoTArr[i][m_CurHit[i] - 1].layer == layer)
1547  --m_CurHit[i];
1548 
1549  const Hit &hit = L.refHit(m_HoTArr[i][m_CurHit[i]].index);
1550  m_msErr.copyIn(i, hit.errArray());
1551  m_msPar.copyIn(i, hit.posArray());
1552  ++count;
1553  --m_CurHit[i];
1554  } else {
1555  tmp_pos[0] = m_Par[iC](i, 0, 0);
1556  tmp_pos[1] = m_Par[iC](i, 1, 0);
1557  tmp_pos[2] = m_Par[iC](i, 2, 0);
1558  m_msErr.copyIn(i, tmp_err);
1559  m_msPar.copyIn(i, tmp_pos);
1560  }
1561  }
1562 
1563  if (count == 0)
1564  continue;
1565 
1566  // ZZZ Could add missing hits here, only if there are any actual matches.
1567 
1568  if (LI.is_barrel()) {
1570 
1572  m_Err[iP],
1573  m_Par[iP],
1574  m_msErr,
1575  m_msPar,
1576  m_Err[iC],
1577  m_Par[iC],
1578  tmp_chi2,
1579  N_proc);
1580  } else {
1582 
1584  m_Err[iP],
1585  m_Par[iP],
1586  m_msErr,
1587  m_msPar,
1588  m_Err[iC],
1589  m_Par[iC],
1590  tmp_chi2,
1591  N_proc);
1592  }
1593 
1594  //fixup invpt sign and charge
1595  for (int n = 0; n < N_proc; ++n) {
1596  if (m_Par[iC].At(n, 3, 0) < 0) {
1597  m_Chg.At(n, 0, 0) = -m_Chg.At(n, 0, 0);
1598  m_Par[iC].At(n, 3, 0) = -m_Par[iC].At(n, 3, 0);
1599  }
1600  }
1601 
1602 #ifdef DEBUG_BACKWARD_FIT_BH
1603  // Dump per hit chi2
1604  for (int i = 0; i < N_proc; ++i) {
1605  float r_h = std::hypot(m_msPar.At(i, 0, 0), m_msPar.At(i, 1, 0));
1606  float r_t = std::hypot(m_Par[iC].At(i, 0, 0), m_Par[iC].At(i, 1, 0));
1607 
1608  // if ((std::isnan(tmp_chi2[i]) || std::isnan(r_t)))
1609  // if ( ! std::isnan(tmp_chi2[i]) && tmp_chi2[i] > 0) // && tmp_chi2[i] > 30)
1610  if (chiDebug) {
1611  int ti = iP;
1612  printf(
1613  "CHIHIT %3d %10g %10g %10g %10g %10g %11.5g %11.5g %11.5g %10g %10g %10g %10g %11.5g %11.5g %11.5g %10g "
1614  "%10g %10g %10g %10g %11.5g %11.5g\n",
1615  layer,
1616  tmp_chi2[i],
1617  m_msPar.At(i, 0, 0),
1618  m_msPar.At(i, 1, 0),
1619  m_msPar.At(i, 2, 0),
1620  r_h, // x_h y_h z_h r_h -- hit pos
1621  e2s(m_msErr.At(i, 0, 0)),
1622  e2s(m_msErr.At(i, 1, 1)),
1623  e2s(m_msErr.At(i, 2, 2)), // ex_h ey_h ez_h -- hit errors
1624  m_Par[ti].At(i, 0, 0),
1625  m_Par[ti].At(i, 1, 0),
1626  m_Par[ti].At(i, 2, 0),
1627  r_t, // x_t y_t z_t r_t -- track pos
1628  e2s(m_Err[ti].At(i, 0, 0)),
1629  e2s(m_Err[ti].At(i, 1, 1)),
1630  e2s(m_Err[ti].At(i, 2, 2)), // ex_t ey_t ez_t -- track errors
1631  1.0f / m_Par[ti].At(i, 3, 0),
1632  m_Par[ti].At(i, 4, 0),
1633  m_Par[ti].At(i, 5, 0), // pt, phi, theta
1634  std::atan2(m_msPar.At(i, 1, 0), m_msPar.At(i, 0, 0)), // phi_h
1635  std::atan2(m_Par[ti].At(i, 1, 0), m_Par[ti].At(i, 0, 0)), // phi_t
1636  1e4f * std::hypot(m_msPar.At(i, 0, 0) - m_Par[ti].At(i, 0, 0),
1637  m_msPar.At(i, 1, 0) - m_Par[ti].At(i, 1, 0)), // d_xy
1638  1e4f * (m_msPar.At(i, 2, 0) - m_Par[ti].At(i, 2, 0)) // d_z
1639  // e2s((m_msErr.At(i,0,0) + m_msErr.At(i,1,1)) / (r_h * r_h)), // ephi_h
1640  // e2s((m_Err[ti].At(i,0,0) + m_Err[ti].At(i,1,1)) / (r_t * r_t)) // ephi_t
1641  );
1642  }
1643  }
1644 #endif
1645 
1646  // update chi2
1647  m_Chi2.add(tmp_chi2);
1648  }
1649  }
1650 
1651  //------------------------------------------------------------------------------
1652 
1653  void MkFinder::print_par_err(int corp, int mslot) const {
1654 #ifdef DEBUG
1655  printf("Parameters:\n");
1656  for (int i = 0; i < 6; ++i) {
1657  printf(" %12.4g", m_Par[corp].constAt(mslot, i, 0));
1658  }
1659  printf("\nError matrix\n");
1660  for (int i = 0; i < 6; ++i) {
1661  for (int j = 0; j < 6; ++j) {
1662  printf(" %12.4g", m_Err[corp].constAt(mslot, i, j));
1663  }
1664  printf("\n");
1665  }
1666 #endif
1667  }
1668 
1669  void MkFinder::bkFitFitTracks(const EventOfHits &eventofhits,
1670  const SteeringParams &st_par,
1671  const int N_proc,
1672  bool chiDebug) {
1673  // Prototyping final backward fit.
1674  // This works with track-finding indices, before remapping.
1675  //
1676  // Layers should be collected during track finding and list all layers that have actual hits.
1677  // Then we could avoid checking which layers actually do have hits.
1678 
1679  // bool debug = true;
1680 
1681  MPlexQF tmp_chi2;
1682  MPlexQI no_mat_effs;
1683  float tmp_err[6] = {666, 0, 666, 0, 0, 666};
1684  float tmp_pos[3];
1685 
1686 #if defined(DEBUG_PROP_UPDATE)
1687  const int DSLOT = 0;
1688  printf("bkfit entry, track in slot %d\n", DSLOT);
1689  print_par_err(iC, DSLOT);
1690 #endif
1691 
1692  for (auto lp_iter = st_par.make_iterator(SteeringParams::IT_BkwFit); lp_iter.is_valid(); ++lp_iter) {
1693  const int layer = lp_iter.layer();
1694 
1695  const LayerOfHits &L = eventofhits[layer];
1696  const LayerInfo &LI = *L.layer_info();
1697 
1698 #if defined(DEBUG_BACKWARD_FIT)
1699  const Hit *last_hit_ptr[NN];
1700 #endif
1701 
1702  no_mat_effs.setVal(0);
1703  int done_count = 0;
1704  int here_count = 0;
1705  for (int i = 0; i < N_proc; ++i) {
1706  while (m_CurNode[i] >= 0 && m_HoTNodeArr[i][m_CurNode[i]].m_hot.index < 0) {
1708  }
1709 
1710  if (m_CurNode[i] < 0)
1711  ++done_count;
1712 
1713  if (m_CurNode[i] >= 0 && m_HoTNodeArr[i][m_CurNode[i]].m_hot.layer == layer) {
1714  // Skip the overlap hits -- if they exist.
1715  // 1. Overlap hit gets placed *after* the original hit in TrackCand::exportTrack()
1716  // which is *before* in the reverse iteration that we are doing here.
1717  // 2. Seed-hit merging can result in more than two hits per layer.
1718  // while (m_CurHit[i] > 0 && m_HoTArr[ i ][ m_CurHit[i] - 1 ].layer == layer) --m_CurHit[i];
1719  while (m_HoTNodeArr[i][m_CurNode[i]].m_prev_idx >= 0 &&
1720  m_HoTNodeArr[i][m_HoTNodeArr[i][m_CurNode[i]].m_prev_idx].m_hot.layer == layer)
1722 
1723  const Hit &hit = L.refHit(m_HoTNodeArr[i][m_CurNode[i]].m_hot.index);
1724 
1725 #ifdef DEBUG_BACKWARD_FIT
1726  last_hit_ptr[i] = &hit;
1727 #endif
1728  m_msErr.copyIn(i, hit.errArray());
1729  m_msPar.copyIn(i, hit.posArray());
1730  ++here_count;
1731 
1733  } else {
1734 #ifdef DEBUG_BACKWARD_FIT
1735  last_hit_ptr[i] = nullptr;
1736 #endif
1737  no_mat_effs[i] = 1;
1738  tmp_pos[0] = m_Par[iC](i, 0, 0);
1739  tmp_pos[1] = m_Par[iC](i, 1, 0);
1740  tmp_pos[2] = m_Par[iC](i, 2, 0);
1741  m_msErr.copyIn(i, tmp_err);
1742  m_msPar.copyIn(i, tmp_pos);
1743  }
1744  }
1745 
1746  if (done_count == N_proc)
1747  break;
1748  if (here_count == 0)
1749  continue;
1750 
1751  // ZZZ Could add missing hits here, only if there are any actual matches.
1752 
1753  clearFailFlag();
1754 
1755  // PROP-FAIL-ENABLE Once always "copy input to output on fail" is removed from
1756  // propagateToR one might want to enable this for barrel or endcap or both.
1757  if (LI.is_barrel()) {
1759 
1761  m_Err[iP],
1762  m_Par[iP],
1763  m_msErr,
1764  m_msPar,
1765  m_Err[iC],
1766  m_Par[iC],
1767  tmp_chi2,
1768  N_proc);
1769  } else {
1771 
1773  m_Err[iP],
1774  m_Par[iP],
1775  m_msErr,
1776  m_msPar,
1777  m_Err[iC],
1778  m_Par[iC],
1779  tmp_chi2,
1780  N_proc);
1781  }
1782 
1783 #if defined(DEBUG_PROP_UPDATE)
1784  printf("\nbkfit at layer %d, track in slot %d -- fail=%d, had hit=%d (%g, %g, %g)\n",
1785  LI.layer_id(),
1786  DSLOT,
1787  m_FailFlag[DSLOT],
1788  1 - no_mat_effs[DSLOT],
1789  m_msPar(DSLOT, 0, 0),
1790  m_msPar(DSLOT, 1, 0),
1791  m_msPar(DSLOT, 2, 0));
1792  printf("Propagated:\n");
1793  print_par_err(iP, DSLOT);
1794  printf("Updated:\n");
1795  print_par_err(iC, DSLOT);
1796 #endif
1797 
1798  // Fixup for failed propagation or invpt sign and charge.
1799  for (int i = 0; i < N_proc; ++i) {
1800  // PROP-FAIL-ENABLE The following to be enabled when propagation failure
1801  // detection is properly implemented in propagate-to-R/Z.
1802  // 1. The following code was only expecting barrel state to be restored.
1803  // auto barrel_pf(m_prop_config->backward_fit_pflags);
1804  // barrel_pf.copy_input_state_on_fail = true;
1805  // 2. There is also check on chi2, commented out to keep physics changes minimal.
1806  /*
1807  if (m_FailFlag[i] && LI.is_barrel()) {
1808  // Barrel pflags are set to include PF_copy_input_state_on_fail.
1809  // Endcap errors are immaterial here (relevant for fwd search), with prop error codes
1810  // one could do other things.
1811  // Are there also fail conditions in KalmanUpdate?
1812 #ifdef DEBUG
1813  if (debug && g_debug) {
1814  dprintf("MkFinder::bkFitFitTracks prop fail: chi2=%f, layer=%d, label=%d. Recovering.\n",
1815  tmp_chi2[i], LI.layer_id(), m_Label[i]);
1816  print_par_err(iC, i);
1817  }
1818 #endif
1819  m_Err[iC].copySlot(i, m_Err[iP]);
1820  m_Par[iC].copySlot(i, m_Par[iP]);
1821  } else if (tmp_chi2[i] > 200 || tmp_chi2[i] < 0) {
1822 #ifdef DEBUG
1823  if (debug && g_debug) {
1824  dprintf("MkFinder::bkFitFitTracks chi2 fail: chi2=%f, layer=%d, label=%d. Recovering.\n",
1825  tmp_chi2[i], LI.layer_id(), m_Label[i]);
1826  print_par_err(iC, i);
1827  }
1828 #endif
1829  // Go back to propagated state (at the current hit, the previous one is lost).
1830  m_Err[iC].copySlot(i, m_Err[iP]);
1831  m_Par[iC].copySlot(i, m_Par[iP]);
1832  }
1833  */
1834  // Fixup invpt sign and charge.
1835  if (m_Par[iC].At(i, 3, 0) < 0) {
1836  m_Chg.At(i, 0, 0) = -m_Chg.At(i, 0, 0);
1837  m_Par[iC].At(i, 3, 0) = -m_Par[iC].At(i, 3, 0);
1838  }
1839  }
1840 
1841 #if defined(DEBUG_BACKWARD_FIT)
1842  // clang-format off
1843  bool debug = true;
1844  const char beg_cur_sep = '/'; // set to ' ' root parsable printouts
1845  for (int i = 0; i < N_proc; ++i) {
1846  if (chiDebug && last_hit_ptr[i]) {
1847  TrackCand &bb = *m_TrkCand[i];
1848  int ti = iP;
1849  float chi = tmp_chi2.At(i, 0, 0);
1850  float chi_prnt = std::isfinite(chi) ? chi : -9;
1851 
1852 #if defined(MKFIT_STANDALONE)
1853  const MCHitInfo &mchi = m_event->simHitsInfo_[last_hit_ptr[i]->mcHitID()];
1854 
1855  dprintf("BKF_OVERLAP %d %d %d %d %d %d %d "
1856  "%f%c%f %f %f%c%f %f %f %f %d %d %d %d "
1857  "%f %f %f %f %f\n",
1858  m_event->evtID(),
1859 #else
1860  dprintf("BKF_OVERLAP %d %d %d %d %d %d "
1861  "%f%c%f %f %f%c%f %f %f %f %d %d %d "
1862  "%f %f %f %f %f\n",
1863 #endif
1864  bb.label(), (int)bb.prodType(), bb.isFindable(),
1865  layer, L.is_stereo(), L.is_barrel(),
1866  bb.pT(), beg_cur_sep, 1.0f / m_Par[ti].At(i, 3, 0),
1867  bb.posEta(),
1868  bb.posPhi(), beg_cur_sep, std::atan2(m_Par[ti].At(i, 1, 0), m_Par[ti].At(i, 0, 0)),
1869  std::hypot(m_Par[ti].At(i, 0, 0), m_Par[ti].At(i, 1, 0)),
1870  m_Par[ti].At(i, 2, 0),
1871  chi_prnt,
1872  std::isnan(chi), std::isfinite(chi), chi > 0,
1873 #if defined(MKFIT_STANDALONE)
1874  mchi.mcTrackID(),
1875 #endif
1876  // The following three can get negative / prouce nans in e2s.
1877  // std::abs the args for FPE hunt.
1878  e2s(std::abs(m_Err[ti].At(i, 0, 0))),
1879  e2s(std::abs(m_Err[ti].At(i, 1, 1))),
1880  e2s(std::abs(m_Err[ti].At(i, 2, 2))), // sx_t sy_t sz_t -- track errors
1881  1e4f * std::hypot(m_msPar.At(i, 0, 0) - m_Par[ti].At(i, 0, 0),
1882  m_msPar.At(i, 1, 0) - m_Par[ti].At(i, 1, 0)), // d_xy
1883  1e4f * (m_msPar.At(i, 2, 0) - m_Par[ti].At(i, 2, 0)) // d_z
1884  );
1885  }
1886  }
1887  // clang-format on
1888 #endif
1889 
1890  // update chi2
1891  m_Chi2.add(tmp_chi2);
1892  }
1893  }
1894 
1895  //------------------------------------------------------------------------------
1896 
1897  void MkFinder::bkFitPropTracksToPCA(const int N_proc) {
1899  }
1900 
1901 } // end namespace mkfit
float chi2_hit
Definition: Track.h:44
void(* m_compute_chi2_foo)(const MPlexLS &, const MPlexLV &, const MPlexQI &, const MPlexHS &, const MPlexHV &, MPlexQF &, MPlexLV &, MPlexQI &, const int, const PropagationFlags &, const bool)
Definition: FindingFoos.h:21
void setOriginIndex(int oi)
float getScoreCand(const track_score_func &score_func, const Track &cand1, bool penalizeTailMissHits=false, bool inFindCandidates=false)
Definition: Track.h:608
float x() const
Definition: Hit.h:162
void addHitIdx(int hitIdx, int hitLyr, float chi2)
def isnan(num)
MPlexQI m_Chg
Definition: MkBase.h:102
static constexpr int iC
Definition: MkBase.h:18
void copy_in(const Track &trk, const int mslot, const int tslot)
Definition: MkFinder.h:167
static constexpr int MPlexHitIdxMax
Definition: MkFinder.h:43
const SVector6 & parameters() const
Definition: Track.h:146
int charge() const
Definition: Track.h:185
MPlexQI m_NFoundHits
Definition: MkFinder.h:284
const IterationLayerConfig * m_iteration_layer_config
Definition: MkFinder.h:332
void setDiagonal3x3(idx_t n, T d)
Definition: MatriplexSym.h:201
const HitOnTrack * m_HoTArr[NN]
Definition: MkFinder.h:339
static constexpr int iP
Definition: MkBase.h:19
void kalmanOperationEndcap(const int kfOp, const MPlexLS &psErr, const MPlexLV &psPar, const MPlexHS &msErr, const MPlexHV &msPar, MPlexLS &outErr, MPlexLV &outPar, MPlexQF &outChi2, const int N_proc)
void copy_out(Track &trk, const int mslot, const int tslot) const
Definition: MkFinder.h:184
void copyIn(idx_t n, const T *arr)
Definition: Matriplex.h:70
void outputTracksAndHitIdx(std::vector< Track > &tracks, int beg, int end, bool outputProp) const
Definition: MkFinder.cc:166
float pT() const
Definition: Track.h:171
void propagateTracksToHitZ(const MPlexHV &par, const int N_proc, const PropagationFlags &pf, const MPlexQI *noMatEffPtr=nullptr)
Definition: MkBase.h:67
HitOnTrack m_HoTArrs[NN][Config::nMaxTrkHits]
Definition: MkFinder.h:286
const Hit * hitArray() const
Definition: HitStructures.h:98
void inputTracksAndHitIdx(const std::vector< Track > &tracks, int beg, int end, bool inputProp)
Definition: MkFinder.cc:53
void bkFitInputTracks(TrackVec &cands, int beg, int end)
Definition: MkFinder.cc:1411
void setup_bkfit(const PropagationConfig &pc, const SteeringParams &sp)
Definition: MkFinder.cc:35
void setChi2(float chi2)
Definition: Track.h:191
const T & constAt(idx_t n, idx_t i, idx_t j) const
Definition: Matriplex.h:52
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
float chi2() const
Definition: Track.h:186
MPlexLV m_Par[2]
Definition: MkBase.h:101
PropagationFlags backward_fit_pflags
MPlexQI m_FailFlag
Definition: MkBase.h:103
ProdType prodType() const
Definition: Track.h:263
bool is_pixel() const
T & At(idx_t n, idx_t i, idx_t j)
Definition: MatriplexSym.h:71
void selectHitIndices(const LayerOfHits &layer_of_hits, const int N_proc)
Definition: MkFinder.cc:248
int label() const
Definition: Track.h:188
constexpr int pow(int x)
Definition: conifer.h:24
void bkFitPropTracksToPCA(const int N_proc)
Definition: MkFinder.cc:1897
SMatrixSym66 & errors_nc()
Definition: Track.h:154
int mcTrackID() const
Definition: Hit.h:114
constexpr float PIOver2
Definition: Config.h:9
void inputTracksAndHits(const std::vector< CombCandidate > &tracks, const LayerOfHits &layer_of_hits, const std::vector< UpdateIndices > &idxs, int beg, int end, bool inputProp)
Definition: MkFinder.cc:107
void release()
Definition: MkFinder.cc:40
void add_hit(const int mslot, int index, int layer)
Definition: MkFinder.h:236
float getEta(float r, float z)
Definition: Hit.h:38
assert(be >=bs)
float exx() const
Definition: Hit.h:165
Definition: Electron.h:6
const float * posArray() const
Definition: Hit.h:151
static unsigned int maxChargePerCM()
Definition: Hit.h:234
static constexpr int kHitStopIdx
Definition: Hit.h:194
const IterationParams * m_iteration_params
Definition: MkFinder.h:331
MPlexLS m_Err[2]
Definition: MkBase.h:100
void kalmanOperation(const int kfOp, const MPlexLS &psErr, const MPlexLV &psPar, const MPlexHS &msErr, const MPlexHV &msPar, MPlexLS &outErr, MPlexLV &outPar, MPlexQF &outChi2, const int N_proc)
void findCandidates(const LayerOfHits &layer_of_hits, std::vector< std::vector< TrackCand >> &tmp_candidates, const int offset, const int N_proc, const FindingFoos &fnd_foos)
Definition: MkFinder.cc:913
static constexpr int kHitInGapIdx
Definition: Hit.h:197
const Double_t pi
track_score_func m_track_scorer
float ezz() const
Definition: Hit.h:167
constexpr bool usePhiQArrays
Definition: Config.h:69
float momEta() const
Definition: Track.h:175
const HoTNode * hotsData() const
PropagationFlags finding_inter_layer_pflags
bool isStripQCompatible(int itrack, bool isBarrel, const MPlexLS &pErr, const MPlexLV &pPar, const MPlexHS &msErr, const MPlexHV &msPar)
Definition: MkFinder.cc:845
void setScore(float s)
Definition: Track.h:192
void add(const Matriplex &v)
Definition: Matriplex.h:37
float getScoreStruct(const track_score_func &score_func, const IdxChi2List &cand1)
Definition: Track.h:624
const PropagationConfig * m_prop_config
Definition: MkFinder.h:330
float posR() const
Definition: Track.h:163
iterator make_iterator(IterationType_e type) const
unsigned int module
Definition: Track.h:37
const T & constAt(idx_t n, idx_t i, idx_t j) const
Definition: MatriplexSym.h:69
int num_all_minus_one_hits(const int mslot) const
Definition: MkFinder.h:270
unsigned int detIDinLayer() const
Definition: Hit.h:228
void(* m_update_param_foo)(const MPlexLS &, const MPlexLV &, MPlexQI &, const MPlexHS &, const MPlexHV &, MPlexLS &, MPlexLV &, MPlexQI &, const int, const PropagationFlags &, const bool)
Definition: FindingFoos.h:22
Definition: EPCuts.h:4
tex
Definition: cuy.py:773
T sqrt(T t)
Definition: SSEVec.h:19
const float * errArray() const
Definition: Hit.h:152
constexpr Matriplex::idx_t NN
Definition: Matrix.h:43
unsigned int bin_content_t
Definition: HitStructures.h:27
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
int layer_id() const
Definition: TrackerInfo.h:61
float eyy() const
Definition: Hit.h:166
CombCandidate * combCandidate() const
Tan< T >::type tan(const T &t)
Definition: Tan.h:22
MPlexQI m_XHitSize
Definition: MkFinder.h:316
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
MPlexHV m_msPar
Definition: MkFinder.h:321
void propagateTracksToHitR(const MPlexHV &par, const int N_proc, const PropagationFlags &pf, const MPlexQI *noMatEffPtr=nullptr)
Definition: MkBase.h:41
MPlexQI m_NTailMinusOneHits
Definition: MkFinder.h:306
double f[11][100]
bool isFindable() const
Definition: Track.h:256
void clearFailFlag()
Definition: MkBase.h:95
float ephi() const
Definition: Hit.h:172
void copyOut(idx_t n, T *arr) const
Definition: MatriplexSym.h:195
const HitOnTrack * getHitsOnTrackArray() const
Definition: Track.h:500
int m_CurNode[NN]
Definition: MkFinder.h:340
PropagationFlags pca_prop_pflags
float posEta() const
Definition: Track.h:166
constexpr float nSigmaPhi
float cdist(float a)
Definition: Config.h:32
int lastCcIndex() const
MPlexHS m_msErr
Definition: MkFinder.h:320
void propagateTracksToPCAZ(const int N_proc, const PropagationFlags &pf)
Definition: MkBase.h:81
TrackCand * m_TrkCand[NN]
Definition: MkFinder.h:312
float y() const
Definition: Hit.h:163
std::vector< Track > TrackVec
#define debug
Definition: HDRShower.cc:19
void pack(TMerr &err, TMpar &par)
void bkFitFitTracks(const EventOfHits &eventofhits, const SteeringParams &st_par, const int N_proc, bool chiDebug=false)
Definition: MkFinder.cc:1669
int m_CurHit[NN]
Definition: MkFinder.h:338
const SteeringParams * m_steering_params
Definition: MkFinder.h:333
static const FindingFoos & get_finding_foos(bool is_barrel)
Definition: FindingFoos.cc:18
void updateWithLoadedHit(int N_proc, const FindingFoos &fnd_foos)
Definition: MkFinder.cc:1359
float z() const
Definition: Track.h:162
std::vector< LayerControl > m_layer_plan
MPlexQI m_NOverlapHits
Definition: MkFinder.h:304
bool passStripChargePCMfromTrack(int itrack, bool isBarrel, unsigned int pcm, unsigned int pcmMin, const MPlexLV &pPar, const MPlexHS &msErr)
Definition: MkFinder.cc:877
float getPhi(float x, float y)
Definition: Hit.h:34
int nTotalHits() const
Definition: Track.h:519
MPlexHitIdx m_XHitArr
Definition: MkFinder.h:317
#define dprint(x)
Definition: Debug.h:95
MPlexQF m_Chi2
Definition: MkFinder.h:280
static constexpr int kHitMaxClusterIdx
Definition: Hit.h:196
void bkFitOutputTracks(TrackVec &cands, int beg, int end, bool outputProp)
Definition: MkFinder.cc:1468
void bkFitFitTracksBH(const EventOfHits &eventofhits, const SteeringParams &st_par, const int N_proc, bool chiDebug=false)
Definition: MkFinder.cc:1516
float z() const
Definition: Hit.h:164
void copyIn(idx_t n, const T *arr)
Definition: MatriplexSym.h:87
const std::vector< float > & get_window_params(bool forward, bool fallback_to_other) const
MPlexQI m_CandIdx
Definition: MkFinder.h:295
MPlexQI m_SeedIdx
Definition: MkFinder.h:294
HitOnTrack hot(int i) const
void copyOutParErr(std::vector< CombCandidate > &seed_cand_vec, int N_proc, bool outputProp) const
Definition: MkFinder.cc:1390
int num_inside_minus_one_hits(const int mslot) const
Definition: MkFinder.h:274
void findCandidatesCloneEngine(const LayerOfHits &layer_of_hits, CandCloner &cloner, const int offset, const int N_proc, const FindingFoos &fnd_foos)
Definition: MkFinder.cc:1159
void copyOut(idx_t n, T *arr) const
Definition: Matriplex.h:180
float x
const std::vector< bool > * m_iteration_hit_mask
Definition: MkFinder.h:334
bool is_barrel() const
PropagationFlags finding_intra_layer_pflags
int layer_id() const
void setCharge(int chg)
Definition: Track.h:190
void add_cand(int idx, const IdxChi2List &cand_info)
Definition: CandCloner.h:34
float getHitSelDynamicChi2Cut(const int itrk, const int ipar)
Definition: MkFinder.cc:225
void setVal(T v)
Definition: Matriplex.h:31
static constexpr int kHitMissIdx
Definition: Hit.h:193
const HoTNode * m_HoTNodeArr[NN]
Definition: MkFinder.h:341
unsigned short bin_index_t
Definition: HitStructures.h:26
float momPhi() const
Definition: Track.h:174
WSR_Result m_XWsrResult[NN]
Definition: MkFinder.h:315
float posPhi() const
Definition: Track.h:165
void getHitSelDynamicWindows(const float invpt, const float theta, float &min_dq, float &max_dq, float &min_dphi, float &max_dphi)
Definition: MkFinder.cc:194
Geom::Theta< T > theta() const
static constexpr int kHitEdgeIdx
Definition: Hit.h:195
T & At(idx_t n, idx_t i, idx_t j)
Definition: Matriplex.h:54
CombCandidate & combCandWithOriginalIndex(int idx)
Definition: CandCloner.h:51
static unsigned int minChargePerCM()
Definition: Hit.h:233
SVector6 & parameters_nc()
Definition: Track.h:153
#define dprintf(...)
Definition: Debug.h:98
int mcHitID() const
Definition: Hit.h:187
MPlexQI m_Label
Definition: MkFinder.h:281
bool is_barrel() const
Definition: TrackerInfo.h:73
void setup(const PropagationConfig &pc, const IterationParams &ip, const IterationLayerConfig &ilc, const SteeringParams &sp, const std::vector< bool > *ihm, bool infwd)
Definition: MkFinder.cc:21
const Hit & refHit(int i) const
Definition: HitStructures.h:97
void print_par_err(int corp, int mslot) const
Definition: MkFinder.cc:1653
void addBestHit(const LayerOfHits &layer_of_hits, const int N_proc, const FindingFoos &fnd_foos)
Definition: MkFinder.cc:701
constexpr bool isFinite(float x)