Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SeedFinderFTF.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SeedFinderFTF.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2021 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 // SeedFinderFTF.ipp
10 // TODO: update to C++17 style
11 
12 #include "Acts/Definitions/Algebra.hpp" //for M_PI
13 #include "Acts/Geometry/Extent.hpp"
19 
20 #include <cmath>
21 #include <fstream>
22 #include <functional>
23 #include <iostream>
24 #include <list>
25 #include <numeric>
26 #include <type_traits>
27 #include <vector>
28 
29 // core so in ACTS namespace
30 
31 namespace Acts {
32 
33 template <typename external_spacepoint_t>
37  : m_config(config) {
38  m_storage = new TrigFTF_GNN_DataStorage(GNNgeo);
39 }
40 
41 template <typename external_spacepoint_t>
43  delete m_storage;
44 
45  m_storage = nullptr;
46 }
47 
48 // define loadspace points function
49 template <typename external_spacepoint_t>
51  const std::vector<FTF_SP<external_spacepoint_t>>& FTF_SP_vect) {
52  for (const auto& FTF_sp : FTF_SP_vect) {
53  bool is_Pixel = FTF_sp.isPixel();
54  if (!is_Pixel) {
55  continue;
56  }
57  m_storage->addSpacePoint(FTF_sp, (m_config.m_useClusterWidth > 0));
58  }
59 
60  m_config.m_nMaxPhiSlice = 1;
61  m_config.m_phiSliceWidth = 2 * M_PI / m_config.m_nMaxPhiSlice;
62 
63  m_storage->sortByPhi();
64 
65  m_storage->generatePhiIndexing(1.5 * m_config.m_phiSliceWidth);
66 }
67 
68 template <typename external_spacepoint_t>
70  std::vector<GNN_TrigTracklet<external_spacepoint_t>>& vTracks,
71  const Acts::RoiDescriptor& roi,
73  // long term move these to ftf finder config, then m_config. to access them
74  const int MaxEdges = 2000000;
75 
76  const float cut_dphi_max = 0.012;
77  const float cut_dcurv_max = 0.001;
78  const float cut_tau_ratio_max = 0.007;
79  const float min_z0 = -2800; // roiDescriptor->zedMinus(); //blank for now,
80  // get from config eventually
81  const float max_z0 = 2800; // roiDescriptor->zedPlus();
82 
83  const float maxOuterRadius = 550.0;
84  const float cut_zMinU =
85  min_z0 +
86  maxOuterRadius * roi.dzdrMinus(); // dzdr can only find =0 in athena
87  const float cut_zMaxU = max_z0 + maxOuterRadius * roi.dzdrPlus();
88 
89  float m_minR_squ = 1; // set earlier
90  float m_maxCurv = 1;
91 
92  const float maxKappa_high_eta = 0.8 / m_minR_squ;
93  const float maxKappa_low_eta = 0.6 / m_minR_squ;
94 
95  // 1. loop over stages
96 
97  int currentStage = 0;
98 
99  const Acts::FasTrackConnector& fastrack = *(gnngeo.fastrack());
100 
101  std::vector<Acts::TrigFTF_GNN_Edge<external_spacepoint_t>> edgeStorage;
102 
103  edgeStorage.reserve(MaxEdges);
104 
105  int nEdges = 0;
106 
107  for (std::map<int, std::vector<FasTrackConnector::LayerGroup>>::const_iterator
108  it = fastrack.m_layerGroups.begin();
109  it != fastrack.m_layerGroups.end(); ++it, currentStage++) {
110  // loop over L1 layers for the current stage
111 
112  for (const auto& layerGroup : (*it).second) {
113  unsigned int dst = layerGroup.m_dst; // n1 : inner nodes
114 
116  gnngeo.getTrigFTF_GNN_LayerByKey(dst);
117 
118  if (pL1 == nullptr) {
119  continue;
120  }
121 
122  for (const auto& conn :
123  layerGroup.m_sources) { // loop over L2(L1) for the current stage
124 
125  unsigned int src = conn->m_src; // n2 : the new connectors
126 
128  gnngeo.getTrigFTF_GNN_LayerByKey(src);
129 
130  if (pL2 == nullptr) {
131  continue;
132  }
133  int nDstBins = pL1->m_bins.size();
134  int nSrcBins = pL2->m_bins.size();
135 
136  for (int b1 = 0; b1 < nDstBins; b1++) { // loop over bins in Layer 1
137 
139  m_storage->getEtaBin(pL1->m_bins.at(b1));
140 
141  if (B1.empty()) {
142  continue;
143  }
144 
145  float rb1 = pL1->getMinBinRadius(b1);
146 
147  // 3. loops over source eta-bins
148 
149  for (int b2 = 0; b2 < nSrcBins; b2++) { // loop over bins in Layer 2
150 
151  if (m_config.m_useEtaBinning && (nSrcBins + nDstBins > 2)) {
152  if (conn->m_binTable[b1 + b2 * nDstBins] != 1) {
153  continue; // using precomputed LUT
154  }
155  }
156 
158  m_storage->getEtaBin(pL2->m_bins.at(b2));
159 
160  if (B2.empty()) {
161  continue;
162  }
163 
164  float rb2 = pL2->getMaxBinRadius(b2);
165 
166  // calculated delta Phi for rb1 ---> rb2 extrapolation
167 
168  float deltaPhi =
169  0.5f *
170  m_config
171  .m_phiSliceWidth; // the default sliding window along phi
172 
173  if (m_config.m_useEtaBinning) {
174  deltaPhi = 0.001f + m_maxCurv * std::fabs(rb2 - rb1);
175  }
176 
177  unsigned int first_it = 0;
178  for (typename std::vector<
180  n1It = B1.m_vn.begin();
181  n1It != B1.m_vn.end(); ++n1It) { // loop over nodes in Layer 1
182 
184 
185  if (n1->m_in.size() >= MAX_SEG_PER_NODE) {
186  continue;
187  }
188 
189  float r1 = n1->m_sp_FTF.SP->r();
190  float x1 = n1->m_sp_FTF.SP->x();
191  float y1 = n1->m_sp_FTF.SP->y();
192  float z1 = n1->m_sp_FTF.SP->z();
193  float phi1 = std::atan(x1 / y1);
194 
195  float minPhi = phi1 - deltaPhi;
196  float maxPhi = phi1 + deltaPhi;
197 
198  for (unsigned int n2PhiIdx = first_it;
199  n2PhiIdx < B2.m_vPhiNodes.size();
200  n2PhiIdx++) { // sliding window over nodes in Layer 2
201 
202  float phi2 = B2.m_vPhiNodes.at(n2PhiIdx).first;
203 
204  if (phi2 < minPhi) {
205  first_it = n2PhiIdx;
206  continue;
207  }
208  if (phi2 > maxPhi) {
209  break;
210  }
211 
213  B2.m_vn.at(B2.m_vPhiNodes.at(n2PhiIdx).second);
214 
215  if (n2->m_out.size() >= MAX_SEG_PER_NODE) {
216  continue;
217  }
218  if (n2->isFull()) {
219  continue;
220  }
221 
222  float r2 = n2->m_sp_FTF.SP->r();
223 
224  float dr = r2 - r1;
225 
226  if (dr < m_config.m_minDeltaRadius) {
227  continue;
228  }
229 
230  float z2 = n2->m_sp_FTF.SP->z();
231 
232  float dz = z2 - z1;
233  float tau = dz / dr;
234  float ftau = std::fabs(tau);
235  if (ftau > 36.0) {
236  continue;
237  }
238 
239  if (ftau < n1->m_minCutOnTau) {
240  continue;
241  }
242  if (ftau < n2->m_minCutOnTau) {
243  continue;
244  }
245  if (ftau > n1->m_maxCutOnTau) {
246  continue;
247  }
248  if (ftau > n2->m_maxCutOnTau) {
249  continue;
250  }
251 
252  if (m_config.m_doubletFilterRZ) {
253  float z0 = z1 - r1 * tau;
254 
255  if (z0 < min_z0 || z0 > max_z0) {
256  continue;
257  }
258 
259  float zouter = z0 + maxOuterRadius * tau;
260 
261  if (zouter < cut_zMinU || zouter > cut_zMaxU) {
262  continue;
263  }
264  }
265 
266  float dx = n2->m_sp_FTF.SP->x() - x1;
267  float dy = n2->m_sp_FTF.SP->y() - y1;
268 
269  float L2 = 1 / (dx * dx + dy * dy);
270 
271  float D =
272  (n2->m_sp_FTF.SP->y() * x1 - y1 * n2->m_sp_FTF.SP->x()) /
273  (r1 * r2);
274 
275  float kappa = D * D * L2;
276 
277  if (ftau < 4.0) { // eta = 2.1
278  if (kappa > maxKappa_low_eta) {
279  continue;
280  }
281 
282  } else {
283  if (kappa > maxKappa_high_eta) {
284  continue;
285  }
286  }
287 
288  // match edge candidate against edges incoming to n2
289 
290  float exp_eta = std::sqrt(1 + tau * tau) - tau;
291 
292  bool isGood =
293  n2->m_in.size() <=
294  2; // we must have enough incoming edges to decide
295 
296  if (!isGood) {
297  float uat_1 = 1.0f / exp_eta;
298 
299  for (const auto& n2_in_idx : n2->m_in) {
300  float tau2 = edgeStorage.at(n2_in_idx).m_p[0];
301  float tau_ratio = tau2 * uat_1 - 1.0f;
302 
303  if (std::fabs(tau_ratio) > cut_tau_ratio_max) { // bad
304  // match
305  continue;
306  }
307  isGood = true; // good match found
308  break;
309  }
310  }
311  if (!isGood) {
312  continue; // no moatch found, skip creating [n1 <- n2] edge
313  }
314 
315  float curv = D * std::sqrt(L2); // signed curvature
316  float dPhi2 = std::asin(curv * r2);
317  float dPhi1 = std::asin(curv * r1);
318 
319  if (nEdges < MaxEdges) {
320  edgeStorage.emplace_back(n1, n2, exp_eta, curv, phi1 + dPhi1,
321  phi2 + dPhi2);
322 
323  n1->addIn(nEdges);
324  n2->addOut(nEdges);
325 
326  nEdges++;
327  }
328  } // loop over n2 (outer) nodes
329  } // loop over n1 (inner) nodes
330  } // loop over source eta bins
331  } // loop over dst eta bins
332  } // loop over L2(L1) layers
333  } // loop over dst layers
334  } // loop over the stages of doublet making
335 
336  std::vector<const TrigFTF_GNN_Node<external_spacepoint_t>*> vNodes;
337 
338  m_storage->getConnectingNodes(vNodes);
339 
340  if (vNodes.empty()) {
341  return;
342  }
343 
344  int nNodes = vNodes.size();
345 
346  for (int nodeIdx = 0; nodeIdx < nNodes; nodeIdx++) {
347  const TrigFTF_GNN_Node<external_spacepoint_t>* pN = vNodes.at(nodeIdx);
348 
349  std::vector<std::pair<float, int>> in_sort, out_sort;
350  in_sort.resize(pN->m_in.size());
351  out_sort.resize(pN->m_out.size());
352 
353  for (int inIdx = 0; inIdx < static_cast<int>(pN->m_in.size()); inIdx++) {
354  int inEdgeIdx = pN->m_in.at(inIdx);
356  &(edgeStorage.at(inEdgeIdx));
357  in_sort[inIdx].second = inEdgeIdx;
358  in_sort[inIdx].first = pS->m_p[0];
359  }
360  for (int outIdx = 0; outIdx < static_cast<int>(pN->m_out.size());
361  outIdx++) {
362  int outEdgeIdx = pN->m_out.at(outIdx);
364  &(edgeStorage.at(outEdgeIdx));
365  out_sort[outIdx].second = outEdgeIdx;
366  out_sort[outIdx].first = pS->m_p[0];
367  }
368 
369  std::sort(in_sort.begin(), in_sort.end());
370  std::sort(out_sort.begin(), out_sort.end());
371 
372  unsigned int last_out = 0;
373 
374  for (unsigned int in_idx = 0; in_idx < in_sort.size();
375  in_idx++) { // loop over incoming edges
376 
377  int inEdgeIdx = in_sort[in_idx].second;
378 
380  &(edgeStorage.at(inEdgeIdx));
381 
382  pS->m_nNei = 0;
383  float tau1 = pS->m_p[0];
384  float uat_1 = 1.0f / tau1;
385  float curv1 = pS->m_p[1];
386  float Phi1 = pS->m_p[2];
387 
388  for (unsigned int out_idx = last_out; out_idx < out_sort.size();
389  out_idx++) {
390  int outEdgeIdx = out_sort[out_idx].second;
391 
393  &(edgeStorage.at(outEdgeIdx));
394 
395  float tau2 = pNS->m_p[0];
396  float tau_ratio = tau2 * uat_1 - 1.0f;
397 
398  if (tau_ratio < -cut_tau_ratio_max) {
399  last_out = out_idx;
400  continue;
401  }
402  if (tau_ratio > cut_tau_ratio_max) {
403  break;
404  }
405 
406  float dPhi = pNS->m_p[3] - Phi1;
407 
408  if (dPhi < -M_PI) {
409  dPhi += 2 * M_PI;
410  } else if (dPhi > M_PI) {
411  dPhi -= 2 * M_PI;
412  }
413 
414  if (dPhi < -cut_dphi_max || dPhi > cut_dphi_max) {
415  continue;
416  }
417 
418  float curv2 = pNS->m_p[1];
419  float dcurv = curv2 - curv1;
420 
421  if (dcurv < -cut_dcurv_max || dcurv > cut_dcurv_max) {
422  continue;
423  }
424 
425  pS->m_vNei[pS->m_nNei++] = outEdgeIdx;
426  if (pS->m_nNei >= N_SEG_CONNS) {
427  break;
428  }
429  }
430  }
431  }
432 
433  const int maxIter = 15;
434 
435  int maxLevel = 0;
436 
437  int iter = 0;
438 
439  std::vector<Acts::TrigFTF_GNN_Edge<external_spacepoint_t>*> v_old;
440 
441  for (int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
443  &(edgeStorage.at(edgeIndex));
444  if (pS->m_nNei == 0) {
445  continue;
446  }
447  v_old.push_back(pS); // TO-DO: increment level for segments as they already
448  // have at least one neighbour
449  }
450 
451  for (; iter < maxIter; iter++) {
452  // generate proposals
453  std::vector<Acts::TrigFTF_GNN_Edge<external_spacepoint_t>*> v_new;
454  v_new.clear();
455 
456  for (auto pS : v_old) {
457  int next_level = pS->m_level;
458 
459  for (int nIdx = 0; nIdx < pS->m_nNei; nIdx++) {
460  unsigned int nextEdgeIdx = pS->m_vNei[nIdx];
461 
463  &(edgeStorage.at(nextEdgeIdx));
464 
465  if (pS->m_level == pN->m_level) {
466  next_level = pS->m_level + 1;
467  v_new.push_back(pS);
468  break;
469  }
470  }
471 
472  pS->m_next = next_level; // proposal
473  }
474  // update
475 
476  int nChanges = 0;
477 
478  for (auto pS : v_new) {
479  if (pS->m_next != pS->m_level) {
480  nChanges++;
481  pS->m_level = pS->m_next;
482  if (maxLevel < pS->m_level) {
483  maxLevel = pS->m_level;
484  }
485  }
486  }
487 
488  if (nChanges == 0) {
489  break;
490  }
491 
492  v_old = std::move(v_new);
493  v_new.clear();
494  }
495 
496  int minLevel = 3; // a triplet + 2 confirmation
497 
498  std::vector<Acts::TrigFTF_GNN_Edge<external_spacepoint_t>*> vSeeds;
499 
500  vSeeds.reserve(MaxEdges / 2);
501 
502  for (int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
504  &(edgeStorage.at(edgeIndex));
505 
506  if (pS->m_level < minLevel) {
507  continue;
508  }
509 
510  vSeeds.push_back(pS);
511  }
512 
513  m_triplets.clear();
514 
515  std::sort(
516  vSeeds.begin(), vSeeds.end(),
518 
519  if (vSeeds.empty()) {
520  return;
521  }
522 
523  // backtracking
524 
526  m_config.m_layerGeometry, edgeStorage);
527 
528  for (auto pS : vSeeds) {
529  if (pS->m_level == -1) {
530  continue;
531  }
532 
534 
535  tFilter.followTrack(pS, rs);
536 
537  if (!rs.m_initialized) {
538  continue;
539  }
540 
541  if (static_cast<int>(rs.m_vs.size()) < minLevel) {
542  continue;
543  }
544 
545  std::vector<const FTF_SP<external_spacepoint_t>*> vSP;
546 
547  for (typename std::vector<Acts::TrigFTF_GNN_Edge<external_spacepoint_t>*>::
548  reverse_iterator sIt = rs.m_vs.rbegin();
549  sIt != rs.m_vs.rend(); ++sIt) {
550  (*sIt)->m_level = -1; // mark as collected
551 
552  if (sIt == rs.m_vs.rbegin()) {
553  vSP.push_back(&(*sIt)->m_n1->m_sp_FTF);
554  }
555  vSP.push_back(&(*sIt)->m_n2->m_sp_FTF);
556  }
557 
558  if (vSP.size() < 3) {
559  continue;
560  }
561 
562  // making triplets
563 
564  unsigned int nTriplets = 0;
565 
566  std::vector<TrigInDetTriplet<external_spacepoint_t>> output;
567 
568  for (unsigned int idx_m = 1; idx_m < vSP.size() - 1; idx_m++) {
569  const FTF_SP<external_spacepoint_t>& spM = *vSP.at(idx_m);
570  const double pS_r = spM.SP->r();
571  const double pS_x = spM.SP->x();
572  const double pS_y = spM.SP->y();
573  const double cosA = pS_x / pS_r;
574  const double sinA = pS_y / pS_r;
575 
576  for (unsigned int idx_o = idx_m + 1; idx_o < vSP.size(); idx_o++) {
577  const FTF_SP<external_spacepoint_t>& spO = *vSP.at(idx_o);
578 
579  double dx = spO.SP->x() - pS_x;
580  double dy = spO.SP->y() - pS_y;
581  double R2inv = 1.0 / (dx * dx + dy * dy);
582  double xn = dx * cosA + dy * sinA;
583  double yn = -dx * sinA + dy * cosA;
584 
585  const double uo = xn * R2inv;
586  const double vo = yn * R2inv;
587 
588  for (unsigned int idx_i = 0; idx_i < idx_m; idx_i++) {
589  const FTF_SP<external_spacepoint_t>& spI = *vSP.at(idx_i);
590 
591  dx = spI.SP->x() - pS_x;
592  dy = spI.SP->y() - pS_y;
593  R2inv = 1.0 / (dx * dx + dy * dy);
594 
595  xn = dx * cosA + dy * sinA;
596  yn = -dx * sinA + dy * cosA;
597 
598  const double ui = xn * R2inv;
599  const double vi = yn * R2inv;
600 
601  // 1. pT estimate
602 
603  const double du = uo - ui;
604  if (du == 0.0) {
605  continue;
606  }
607  const double A = (vo - vi) / du;
608  const double B = vi - A * ui;
609  const double R_squ = (1 + A * A) / (B * B);
610 
611  if (R_squ < m_minR_squ) {
612  continue;
613  }
614 
615  // 2. d0 cut
616 
617  const double fabs_d0 = std::abs(pS_r * (B * pS_r - A));
618 
619  if (fabs_d0 > m_config.m_tripletD0Max) {
620  continue;
621  }
622 
623  // 3. phi0 cut
624 
625  // if (!roi.isFullscan()) {
626  // const double uc = 2 * B * pS_r - A;
627  // // const double phi0 = std::atan2(sinA - uc * cosA, cosA + uc *
628  // sinA);
629  // // if ( !RoiUtil::containsPhi( *roiDescriptor, phi0 ) )
630  // {
631  // // continue;
632  // // }
633  // }
634 
635  // 4. add new triplet
636 
637  const double Q = fabs_d0 * fabs_d0;
638 
639  output.emplace_back(spI, spM, spO, Q);
640 
641  nTriplets++;
642 
643  if (nTriplets >= m_config.m_maxTripletBufferLength) {
644  break;
645  }
646  }
647  if (nTriplets >= m_config.m_maxTripletBufferLength) {
648  break;
649  }
650  }
651  if (nTriplets >= m_config.m_maxTripletBufferLength) {
652  break;
653  }
654  }
655 
656  if (output.empty()) {
657  continue;
658  }
659 
660  vTracks.emplace_back(vSP, output);
661  }
662 }
663 
664 template <typename external_spacepoint_t>
666  const Acts::RoiDescriptor& roi,
668  std::vector<GNN_TrigTracklet<external_spacepoint_t>>
669  vTracks; // make empty vector
670 
671  vTracks.reserve(5000);
672 
673  runGNN_TrackFinder(vTracks, roi, gnngeo); // returns filled vector
674 
675  if (vTracks.empty()) {
676  return;
677  }
678 
679  m_triplets.clear(); // member of class , saying not declared, maybe public?
680 
681  for (auto& track : vTracks) {
682  for (auto& seed : track.m_seeds) { // access mmeber of GNN_TrigTracklet
683 
684  float newQ = seed.Q(); // function of TrigInDetTriplet
685  if (m_config.m_LRTmode) {
686  // In LRT mode penalize pixels in Triplets
687  if (seed.s1().isPixel()) {
688  newQ += 1000; // functions of TrigSiSpacePointBase
689  }
690  if (seed.s2().isPixel()) {
691  newQ += 1000;
692  }
693  if (seed.s3().isPixel()) {
694  newQ += 1000;
695  }
696  } else {
697  // In normal (non LRT) mode penalise SSS by 1000, PSS (if enabled) and
698  // PPS by 10000
699  if (seed.s3().isSCT()) {
700  newQ += seed.s1().isSCT() ? 1000.0 : 10000.0;
701  }
702  }
703  seed.Q(newQ);
704  m_triplets.emplace_back(seed);
705  }
706  }
707  vTracks.clear();
708 }
709 
710 // // still to be developed
711 template <typename external_spacepoint_t>
712 template <typename input_container_t, typename output_container_t,
713  typename callable_t>
715  const Acts::SeedFinderOptions& /*options*/,
716  const input_container_t& /*spacePoints*/, output_container_t& /*out_cont*/,
717  callable_t&& /*extract_coordinates*/) const {}
718 
719 template <typename external_spacepoint_t>
720 template <typename input_container_t, typename callable_t>
721 std::vector<Seed<external_spacepoint_t>>
724  const input_container_t& spacePoints,
725  callable_t&& extract_coordinates) const {
726  std::vector<seed_t> r;
727  createSeeds_old(options, spacePoints, r,
728  std::forward<callable_t>(extract_coordinates));
729  return r;
730 }
731 
732 } // namespace Acts