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