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