CMS 3D CMS Logo

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