ATLAS Offline Software
Loading...
Searching...
No Matches
TrigInDetPattRecoTools/src/SeedingToolBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
7
9
11
12#include "GNN_TrackingFilter.h"
13
15
16#include "SeedingToolBase.h"
17
18#include "GNN_TrackingFilter.h"
19
20#include <cmath>
21
22#include <algorithm> //for std::sort
23
25 ATH_CHECK(AthAlgTool::initialize());
26
27 ATH_CHECK(m_layerNumberTool.retrieve());
28
29
30 ATH_CHECK(detStore()->retrieve(m_atlasId, "AtlasID"));
31
32 ATH_CHECK(detStore()->retrieve(m_pixelId, "PixelID"));
33
34 ATH_CHECK(detStore()->retrieve(m_sctId, "SCT_ID"));
35
36 std::string conn_fileName = PathResolver::find_file(m_connectionFile, "DATAPATH");
37 if (conn_fileName.empty()) {
38 ATH_MSG_FATAL("Cannot find layer connections file " << conn_fileName);
39 return StatusCode::FAILURE;
40 }
41 else {
42
43 std::ifstream ifs(conn_fileName.c_str());
44
45 m_connector = std::make_unique<GNN_FASTRACK_CONNECTOR>(ifs, m_LRTmode);
46 if (m_etaBinOverride != 0.0f) {
47 m_connector->m_etaBin = m_etaBinOverride;
48 }
49
50 ATH_MSG_INFO("Layer connections are initialized from file " << conn_fileName);
51 }
52
53 const std::vector<TrigInDetSiLayer>* pVL = m_layerNumberTool->layerGeometry();
54
55 std::copy(pVL->begin(),pVL->end(), std::back_inserter(m_layerGeometry));
56
57 m_geo = std::make_unique<TrigFTF_GNN_Geometry>(m_layerGeometry, m_connector);
58
59
60 if (m_useML) {
61 std::string lut_fileName = PathResolver::find_file(m_lutFile, "DATAPATH");
62 if (lut_fileName.empty()) {
63 ATH_MSG_FATAL("Cannot find ML predictor LUT file " << lut_fileName);
64 return StatusCode::FAILURE;
65 }
66 else {
67 m_mlLUT.reserve(100);
68 std::ifstream ifs(lut_fileName.c_str());
69 while (!ifs.eof()) {
70 float cl_width, min1, max1, min2, max2;
71 ifs >> cl_width >> min1 >> max1 >> min2 >> max2;
72 if (ifs.eof()) break;
73 std::array<float, 5> lut_line = {cl_width, min1, max1, min2, max2};
74 m_mlLUT.emplace_back(lut_line);
75 }
76 ifs.close();
77 ATH_MSG_INFO("ML predictor is initialized from file " << lut_fileName<<" LUT has "<<m_mlLUT.size()<<" entries");
78 }
79 }
80
82
83 ATH_MSG_INFO("SeedingToolBase initialized ");
84
85 ATH_MSG_DEBUG("Property useML "<< m_useML);
86 ATH_MSG_DEBUG("Property DoPhiFiltering "<<m_filter_phi);
87 ATH_MSG_DEBUG("Property pTmin "<<m_minPt);
88 ATH_MSG_DEBUG("Property LRTmode "<<m_LRTmode);
89
90 return StatusCode::SUCCESS;
91}
92
94 StatusCode sc = AthAlgTool::finalize();
95 return sc;
96}
97
98std::pair<int, int> SeedingToolBase::buildTheGraph(const IRoiDescriptor& roi, const std::unique_ptr<TrigFTF_GNN_DataStorage>& storage, std::vector<TrigFTF_GNN_Edge>& edgeStorage) const {
99
100
101 struct GBTS_SlidingWindow {
102
103 GBTS_SlidingWindow() : m_first_it(0), m_deltaPhi(0.0), m_has_nodes(false), m_bin(nullptr) {};
104
105 unsigned int m_first_it;// sliding window position
106 float m_deltaPhi; // window half-width;
107 bool m_has_nodes; // active or not
108
109 const TrigFTF_GNN_EtaBin* m_bin;//associated eta bin
110 };
111
112 constexpr float M_2PI = 2.0*M_PI;
113
114 const float cut_dphi_max = m_LRTmode ? 0.07f : 0.012f;
115 const float cut_dcurv_max = m_LRTmode ? 0.015f : 0.001f;
116 const float cut_tau_ratio_max = m_LRTmode ? 0.015f : static_cast<float>(m_tau_ratio_cut);
117 const float min_z0 = m_LRTmode ? -600.0 : roi.zedMinus();
118 const float max_z0 = m_LRTmode ? 600.0 : roi.zedPlus();
119 const float min_deltaPhi = m_LRTmode ? 0.01f : 0.001f;
120 const float tau_ratio_precut = 0.009f;
121
122 const float maxOuterRadius = m_LRTmode ? 1050.0 : 550.0;
123
124 const float cut_zMinU = min_z0 + maxOuterRadius*roi.dzdrMinus();
125 const float cut_zMaxU = max_z0 + maxOuterRadius*roi.dzdrPlus();
126
127 constexpr float ptCoeff = 0.29997*1.9972/2.0;// ~0.3*B/2 - assuming nominal field of 2*T
128
129 float tripletPtMin = 0.8f*m_minPt;//correction due to limited pT resolution
130 const float pt_scale = 900.0f/m_minPt;//to re-scale original tunings done for the 900 MeV pT cut
131
132 float maxCurv = ptCoeff/tripletPtMin;
133
134 float maxKappa_high_eta = m_LRTmode ? 1.0f*maxCurv : std::sqrt(0.8f)*maxCurv;
135 float maxKappa_low_eta = m_LRTmode ? 1.0f*maxCurv : std::sqrt(0.6f)*maxCurv;
136
137 if(!m_useOldTunings && !m_LRTmode) {//new settings for curvature cuts
138 maxKappa_high_eta = 4.75e-4f*pt_scale;
139 maxKappa_low_eta = 3.75e-4f*pt_scale;
140 }
141
142 const float dphi_coeff = m_LRTmode ? 1.0f*maxCurv : 0.68f*maxCurv;
143
144 const float minDeltaRadius = 2.0;
145
146 float deltaPhi0 = 0.5f*m_phiSliceWidth;//the default sliding window along phi
147
148 unsigned int nConnections = 0;
149
150 edgeStorage.reserve(m_nMaxEdges);
151
152 int nEdges = 0;
153
154 float z0_histo_coeff = 16/(max_z0 - min_z0 + 1e-6);//assuming 16-bit z0 bitmask
155
156 for(const auto& bg : m_geo->bin_groups()) {//loop over bin groups
157
158 TrigFTF_GNN_EtaBin& B1 = storage->getEtaBin(bg.first);
159
160 if(B1.empty()) continue;
161
162 float rb1 = B1.getMinBinRadius();
163
164 const unsigned int lk1 = B1.m_layerKey;
165
166 const bool isBarrel1 = (lk1 / 10000) == 8;
167
168 //prepare a sliding window for each bin2 in the group
169
170 std::vector<GBTS_SlidingWindow> vSLW;
171
172 vSLW.resize(bg.second.size());//initialization using default ctor
173
174 int win_idx = 0;
175
176 for(const auto& b2_idx : bg.second) { //loop over n2 eta-bins in L2 layers
177
178 const TrigFTF_GNN_EtaBin& B2 = storage->getEtaBin(b2_idx);
179
180 if(B2.empty()) {
181 win_idx++;
182 continue;
183 }
184
185 float rb2 = B2.getMaxBinRadius();
186
187 float deltaPhi = deltaPhi0;//the default
188
189 if(m_useEtaBinning) { //override the default window width
190 float abs_dr = std::fabs(rb2-rb1);
191 if (m_useOldTunings) {
192 deltaPhi = min_deltaPhi + dphi_coeff*abs_dr;
193 }
194 else {
195 if(abs_dr < 60.0) {
196 deltaPhi = 0.002f + 4.33e-4f*pt_scale*abs_dr;
197 } else {
198 deltaPhi = 0.015f + 2.2e-4f*pt_scale*abs_dr;
199 }
200 }
201 }
202
203 vSLW[win_idx].m_bin = &B2;
204 vSLW[win_idx].m_has_nodes = true;
205 vSLW[win_idx].m_deltaPhi = deltaPhi;
206 win_idx++;
207 }
208
209 for(unsigned int n1Idx = 0;n1Idx<B1.m_vn.size();n1Idx++) {//in GBTSv3 the outer loop goes over n1 nodes in the Layer 1 bin
210
211 B1.m_vFirstEdge[n1Idx] = nEdges;//initialization using the top watermark of the edge storage
212
213 unsigned short num_created_edges = 0;//the counter for the incoming graph edges created for n1
214
215 bool is_connected = false;
216
217 std::array<unsigned char, 16> z0_histo = {};
218
219 const std::array<float, 5>& n1pars = B1.m_params[n1Idx];
220
221 float phi1 = n1pars[2];
222 float r1 = n1pars[3];
223 float z1 = n1pars[4];
224
225 for(unsigned int winIdx = 0; winIdx < vSLW.size(); winIdx++) {//the intermediate loop over sliding windows
226
227 GBTS_SlidingWindow& slw = vSLW[winIdx];
228
229 if (!slw.m_has_nodes) continue;
230
231 const TrigFTF_GNN_EtaBin& B2 = *slw.m_bin;
232
233 const unsigned int lk2 = B2.m_layerKey;
234
235 const bool isBarrel2 = (lk2 / 10000) == 8;
236
237 float deltaPhi = slw.m_deltaPhi;
238
239 //sliding window phi1 +/- deltaPhi
240
241 float minPhi = phi1 - deltaPhi;
242 float maxPhi = phi1 + deltaPhi;
243
244 for(unsigned int n2PhiIdx = slw.m_first_it; n2PhiIdx<B2.m_vPhiNodes.size();n2PhiIdx++) {//the inner loop over n2 nodes using sliding window
245
246 float phi2 = B2.m_vPhiNodes[n2PhiIdx].first;
247
248 if(phi2 < minPhi) {
249 slw.m_first_it = n2PhiIdx; //update the window position
250 continue;
251 }
252 if(phi2 > maxPhi) break; //break and go to the next window
253
254 unsigned int n2Idx = B2.m_vPhiNodes[n2PhiIdx].second;
255
256 unsigned short node_info = B2.m_vIsConnected[n2Idx];
257
258 if ((lk1 == 80000) && (node_info == 0) ) continue;//skip isolated nodes as their incoming edges lead to nowhere
259
260 unsigned int n2_first_edge = B2.m_vFirstEdge[n2Idx];
261 unsigned short n2_num_edges = B2.m_vNumEdges[n2Idx];
262 unsigned int n2_last_edge = n2_first_edge + n2_num_edges;
263
264 const std::array<float, 5>& n2pars = B2.m_params[n2Idx];
265
266 float r2 = n2pars[3];
267
268 float dr = r2 - r1;
269
270 if(dr < minDeltaRadius) {
271 continue;
272 }
273
274 float z2 = n2pars[4];
275
276 float dz = z2 - z1;
277 float tau = dz/dr;
278 float ftau = std::fabs(tau);
279 if (ftau > 36.0) {
280 continue;
281 }
282
283 if(ftau < n1pars[0]) continue;
284 if(ftau > n1pars[1]) continue;
285
286 if(ftau < n2pars[0]) continue;
287 if(ftau > n2pars[1]) continue;
288
289 float z0 = z1 - r1*tau;
290
291 if (lk1 == 80000) {//check against non-empty z0 histogram
292
293 if ( !check_z0_bitmask(node_info, z0, min_z0, z0_histo_coeff) ) {
294 continue;
295 }
296 }
297
298 if (m_doubletFilterRZ) {
299
300 if(z0 < min_z0 || z0 > max_z0) continue;
301
302 float zouter = z0 + maxOuterRadius*tau;
303
304 if(zouter < cut_zMinU || zouter > cut_zMaxU) continue;
305 }
306
307 float curv = (phi2-phi1)/dr;
308 float abs_curv = std::abs(curv);
309
310 if(ftau < 4.0) {//eta = 2.1
311 if(abs_curv > maxKappa_low_eta) {
312 continue;
313 }
314 }
315 else {
316 if(abs_curv > maxKappa_high_eta) {
317 continue;
318 }
319 }
320
321 float exp_eta = std::sqrt(1.f+tau*tau) - tau;
322
323 if (m_matchBeforeCreate && (lk1 == 80000 || lk1 == 81000) ) {//match edge candidate against edges incoming to n2
324
325 bool isGood = n2_num_edges <= 2;//we must have enough incoming edges to decide
326
327 if(!isGood) {
328
329 float uat_1 = 1.0f/exp_eta;
330
331 for(unsigned int n2_in_idx = n2_first_edge; n2_in_idx < n2_last_edge; n2_in_idx++) {
332
333 float tau2 = edgeStorage.at(n2_in_idx).m_p[0];
334 float tau_ratio = tau2*uat_1 - 1.0f;
335
336 if(std::fabs(tau_ratio) > tau_ratio_precut){//bad match
337 continue;
338 }
339 isGood = true;//good match found
340 break;
341 }
342 }
343
344 if(!isGood) {//no match found, skip creating [n1 <- n2] edge
345 continue;
346 }
347 }
348
349 float dPhi2 = curv*r2;
350 float dPhi1 = curv*r1;
351
352 if(nEdges < m_nMaxEdges) {
353
354 edgeStorage.emplace_back(B1.m_vn[n1Idx], B2.m_vn[n2Idx], exp_eta, curv, phi1 + dPhi1);
355
356 num_created_edges++;
357
358 int outEdgeIdx = nEdges;
359
360 float uat_2 = 1.f/exp_eta;
361 float Phi2 = phi2 + dPhi2;
362 float curv2 = curv;
363
364 for(unsigned int inEdgeIdx = n2_first_edge; inEdgeIdx < n2_last_edge; inEdgeIdx++) {//looking for neighbours of the new edge
365
366 TrigFTF_GNN_Edge* pS = &(edgeStorage.at(inEdgeIdx));
367
368 if(pS->m_nNei >= N_SEG_CONNS) continue;
369
370 const unsigned int lk3 = m_geo->getTrigFTF_GNN_LayerKeyByIndex(pS->m_n2->m_layer);
371
372 const bool isBarrel3 = (lk3 / 10000) == 8;
373
374 float abs_tau_ratio = std::abs(pS->m_p[0]*uat_2 - 1.0f);
375 float add_tau_ratio_corr = 0;
376
377 if (m_useAdaptiveCuts) {
378
379 if (isBarrel1 && isBarrel2 && isBarrel3) {
380 bool no_gap = ((lk3-lk2) == 1000) && ((lk2-lk1) == 1000);
381 if(!no_gap) {
382 add_tau_ratio_corr = m_tau_ratio_corr;//assume more scattering due to the layer in between
383 }
384 }
385 else {
386 bool mixed_triplet = isBarrel1 && isBarrel2 && !isBarrel3;
387 if (mixed_triplet) {
388 add_tau_ratio_corr = m_tau_ratio_corr;
389 }
390 }
391 }
392
393 if(abs_tau_ratio > cut_tau_ratio_max + add_tau_ratio_corr){//bad match
394 continue;
395 }
396
397 float dPhi = Phi2 - pS->m_p[2];
398
399 if(dPhi<-M_PI) dPhi += M_2PI;
400 else if(dPhi>M_PI) dPhi -= M_2PI;
401
402 if(std::abs(dPhi) > cut_dphi_max) {
403 continue;
404 }
405
406 float dcurv = curv2 - pS->m_p[1];
407
408 if(dcurv < -cut_dcurv_max || dcurv > cut_dcurv_max) {
409 continue;
410 }
411
412 //final check: cuts on pT and d0
413
414 if (isBarrel1 && isBarrel2 && isBarrel3) {//Pixel barrel
415
416 std::array<const GNN_Node*, 3> sps = {B1.m_vn[n1Idx], B2.m_vn[n2Idx], pS->m_n2};
417
418 if (!validate_triplet(sps, tripletPtMin, abs_tau_ratio, cut_tau_ratio_max) ) continue;
419
420 }
421
422 pS->m_vNei[pS->m_nNei++] = outEdgeIdx;
423
424 is_connected = true;//there is at least one good match
425
426 //edge confirmed - update z0 histogram
427
428 int z0_bin_index = z0_histo_coeff*(z0 - min_z0);
429
430 ++z0_histo[z0_bin_index];
431
432 nConnections++;
433
434 }
435 nEdges++;
436 }
437 } //loop over n2 (outer) nodes inside a sliding window on n2 bin
438 } //loop over sliding windows associated with n2 bins
439
440 //updating the n1 node attributes
441
442 B1.m_vNumEdges[n1Idx] = num_created_edges;
443
444 if (is_connected) {
445
446 unsigned short z0_bitmask = 0x0;
447
448 for(unsigned int bIdx = 0; bIdx < 16; bIdx++) {
449
450 if (z0_histo[bIdx] == 0) continue;
451
452 z0_bitmask |= (1 << bIdx);
453 }
454
455 B1.m_vIsConnected[n1Idx] = z0_bitmask;//non-zero mask indicates that there is at least one connected edge
456 }
457
458 } //loop over n1 (inner) nodes
459 } //loop over bin groups: a single n1 bin and multiple n2 bins
460
461 if(nEdges >= m_nMaxEdges) {
462 ATH_MSG_WARNING("Maximum number of graph edges exceeded - possible efficiency loss "<< nEdges);
463 }
464
465 return std::make_pair(nEdges, nConnections);
466}
467
468int SeedingToolBase::runCCA(int nEdges, std::vector<TrigFTF_GNN_Edge>& edgeStorage) const {
469
470 constexpr int maxIter = 15;
471
472 int maxLevel = 0;
473
474 int iter = 0;
475
476 std::vector<TrigFTF_GNN_Edge*> v_old;
477
478 for(int edgeIndex=0;edgeIndex<nEdges;edgeIndex++) {
479
480 TrigFTF_GNN_Edge* pS = &(edgeStorage[edgeIndex]);
481 if(pS->m_nNei == 0) continue;
482
483 v_old.push_back(pS);//TO-DO: increment level for segments as they already have at least one neighbour
484 }
485
486 std::vector<TrigFTF_GNN_Edge*> v_new;
487 v_new.reserve(v_old.size());
488
489 for(;iter<maxIter;iter++) {
490
491 //generate proposals
492 v_new.clear();
493
494 for(auto pS : v_old) {
495
496 int next_level = pS->m_level;
497
498 for(int nIdx=0;nIdx<pS->m_nNei;nIdx++) {
499
500 unsigned int nextEdgeIdx = pS->m_vNei[nIdx];
501
502 TrigFTF_GNN_Edge* pN = &(edgeStorage[nextEdgeIdx]);
503
504 if(pS->m_level == pN->m_level) {
505 next_level = pS->m_level + 1;
506 v_new.push_back(pS);
507 break;
508 }
509 }
510
511 pS->m_next = next_level;//proposal
512 }
513
514 //update
515
516 int nChanges = 0;
517
518 for(auto pS : v_new) {
519 if(pS->m_next != pS->m_level) {
520 nChanges++;
521 pS->m_level = pS->m_next;
522 if(maxLevel < pS->m_level) maxLevel = pS->m_level;
523 }
524 }
525
526 if(nChanges == 0) break;
527
528
529 v_old.swap(v_new);
530 v_new.clear();
531 }
532
533 return maxLevel;
534}
535
536void SeedingToolBase::extractSeedsFromTheGraph(int maxLevel, int nEdges, int nHits, std::vector<GNN_Edge>& edgeStorage, std::vector<std::pair<float, std::vector<unsigned int> > >& vOutputSeeds) const {
537
538 const float edge_mask_min_eta = 1.5;
539 const float hit_share_threshold = 0.49;
540 const float max_eta_for_seed_split = 0.6;
541 const float max_inv_rad_diff = 0.7e-2;//in inverse meters
542
543 int minLevel = 3;//a triplet + 2 confirmation
544
545 if(m_LRTmode) {
546 minLevel = 2;//a triplet + 1 confirmation
547 }
548
549 if(maxLevel < minLevel) return;
550
551 std::vector<GNN_Edge*> vSeeds;
552
553 vSeeds.reserve(nEdges/2);
554
555 for(int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
556
557 GNN_Edge* pS = &(edgeStorage.at(edgeIndex));
558
559 if(pS->m_level < minLevel) continue;
560
561 vSeeds.push_back(pS);
562 }
563
564 if(vSeeds.empty()) return;
565
566 std::sort(vSeeds.begin(), vSeeds.end(), GNN_Edge::CompareLevel());
567
568 //backtracking
569
570 std::vector<std::tuple<float, int, std::vector<const GNN_Node*>, int > > vSeedCandidates;
571
572 vSeedCandidates.reserve(vSeeds.size());
573
574 std::vector<std::pair<float, unsigned int> > vArgSort;
575
576 vArgSort.reserve(vSeeds.size());
577
578 unsigned int seed_counter = 0;
579
580 auto tFilter = std::make_unique<TrigFTF_GNN_TrackingFilter>(m_layerGeometry, edgeStorage);
581
582 for(auto pS : vSeeds) {
583
584 if(pS->m_level == -1) continue;
585
587
588 tFilter->followTrack(pS, rs);
589
590 if(!rs.m_initialized) {
591 continue;
592 }
593
594 if(static_cast<int>(rs.m_vs.size()) < minLevel) continue;
595
596 float seed_eta = std::abs(-std::log(pS->m_p[0]));
597
598 std::vector<const GNN_Node*> vN;
599
600 for(std::vector<GNN_Edge*>::reverse_iterator sIt=rs.m_vs.rbegin();sIt!=rs.m_vs.rend();++sIt) {
601
602 if (seed_eta > edge_mask_min_eta) {
603 (*sIt)->m_level = -1;//mark as collected
604 }
605
606 if(sIt == rs.m_vs.rbegin()) {
607 vN.push_back((*sIt)->m_n1);
608 }
609
610 vN.push_back((*sIt)->m_n2);
611
612 }
613
614 if(vN.size()<3) continue;
615
616 unsigned int orig_seed_size = vN.size();
617
618 float orig_seed_quality = -rs.m_J/orig_seed_size;
619
620 int seed_split_flag = (seed_eta < max_eta_for_seed_split) && (orig_seed_size > 3) && (orig_seed_size <= 5) ? 1 : 0;
621
622 if (seed_split_flag) {//split the seed by dropping spacepoints
623
624 std::array< std::array<const GNN_Node*, 3>, 3> triplets;//2 "drop-outs" and the original seed candidate
625
626 std::array<float, 3> inv_rads;//triplet parameter estimate
627
628 triplets[0] = {vN[0], vN[orig_seed_size/2], vN[orig_seed_size-1]};
629
630 std::vector<const GNN_Node*> drop_out1 = {vN.begin()+1, vN.end()}; //all but the first one
631
632 triplets[1] = {drop_out1[0], drop_out1[(orig_seed_size-1)/2], drop_out1[orig_seed_size-2]};
633
634 std::vector<const GNN_Node*> drop_out2;
635
636 drop_out2.reserve(orig_seed_size-1);
637
638 for(unsigned int k = 0; k < orig_seed_size; k++) {
639
640 if (k == orig_seed_size/2) continue;//drop the middle SP in the original seed
641
642 drop_out2.emplace_back(vN[k]);
643 }
644
645 triplets[2] = {drop_out2[0], drop_out2[(orig_seed_size-1)/2], drop_out2[orig_seed_size-2]};
646
647 for (unsigned int k = 0; k < inv_rads.size(); k++) {
648
649 inv_rads[k] = estimate_curvature(triplets[k]);
650
651 }
652
653 float diffs[3] = {std::abs(inv_rads[1] - inv_rads[0]), std::abs(inv_rads[2] - inv_rads[0]), std::abs(inv_rads[2] - inv_rads[1])};
654
655 bool confirmed = diffs[0] < max_inv_rad_diff && diffs[1] < max_inv_rad_diff && diffs[2] < max_inv_rad_diff;
656
657 if (confirmed) {
658 seed_split_flag = 0;//reset the flag
659 }
660
661 }
662
663 vSeedCandidates.emplace_back(orig_seed_quality, 0, vN, seed_split_flag);
664
665 vArgSort.emplace_back(orig_seed_quality, seed_counter);
666
667 ++seed_counter;
668
669 }
670
671 //clone removal code goes below ...
672
673 std::sort(vArgSort.begin(), vArgSort.end());
674
675 std::vector<int> H2T(nHits + 1, 0);//hit to track associations
676
677 int trackId = 0;
678
679
680 for(const auto& ags : vArgSort) {
681
682 const auto& seed = vSeedCandidates[ags.second];
683
684 trackId++;
685
686 for(const auto& h : std::get<2>(seed) ) {//loop over spacepoints indices
687
688 unsigned int hit_id = h->sp_idx() + 1;
689
690 int tid = H2T[hit_id];
691
692 if(tid == 0 || tid > trackId) {//unused hit or used by a lesser track
693
694 H2T[hit_id] = trackId;//overwrite
695
696 }
697 }
698 }
699
700 unsigned int trackIdx = 0;
701
702 for(const auto& ags : vArgSort) {
703
704 const auto& seed = std::get<2>(vSeedCandidates[ags.second]);
705
706 int nTotal = seed.size();
707
708 int nOther = 0;
709
710 int trackId = trackIdx + 1;
711
712 ++trackIdx;
713
714 for(const auto& h : seed ) {
715
716 unsigned int hit_id = h->sp_idx() + 1;
717
718 int tid = H2T[hit_id];
719
720 if(tid != trackId) {//taken by a better candidate
721 nOther++;
722 }
723 }
724
725 if (nOther > hit_share_threshold*nTotal) {
726 std::get<1>(vSeedCandidates[ags.second]) = -1;//reject
727 }
728
729 }
730
731 vOutputSeeds.reserve(vSeedCandidates.size());
732
733 //drop the clones and split seeds if need be
734
735 for(const auto& ags : vArgSort) {
736
737 const auto& seed = vSeedCandidates[ags.second];
738
739 if (std::get<1>(seed) != 0) continue;//identified as a clone of a better candidate
740
741 const auto& vN = std::get<2>(seed);
742
743 if (std::get<3>(seed) == 0) {
744
745 //add seed to output
746
747 std::vector<unsigned int> vSpIdx;
748
749 vSpIdx.resize(vN.size());
750
751 for(unsigned int k = 0; k < vSpIdx.size(); k++) {
752 vSpIdx[k] = vN[k]->sp_idx();
753 }
754
755 vOutputSeeds.emplace_back(std::get<0>(seed), vSpIdx);
756
757 continue;
758
759 }
760
761 //seed split into "drop-out" seeds
762
763 unsigned int seedSize = vN.size();
764
765 std::array<std::size_t, 2> indices2drop = {0, seedSize / 2ul};//the first and the middle
766
767 for(const auto& skipIdx : indices2drop) {
768
769 std::vector<unsigned int> new_seed;
770
771 new_seed.reserve(seedSize-1);
772
773 for (unsigned int k = 0; k < seedSize; k++) {
774
775 if (k == skipIdx) continue;
776
777 new_seed.emplace_back(vN[k]->sp_idx());
778 }
779
780 vOutputSeeds.emplace_back(std::get<0>(seed), new_seed);
781
782 }
783
784 }
785
786}
787
788bool SeedingToolBase::check_z0_bitmask(const unsigned short& z0_bitmask, const float& z0, const float& min_z0, const float& z0_histo_coeff) const {
789
790 if (z0_bitmask == 0) return true;
791
792 float dz = z0 - min_z0;
793 int z0_bin_index = z0_histo_coeff*dz;
794
795 if ((z0_bitmask >> z0_bin_index) & 1) return true;
796
797 //check adjacent bins as well
798
799 const float z0_resolution = 2.5;
800
801 float dzm = dz - z0_resolution;
802
803 int next_bin = z0_histo_coeff*dzm;
804
805 if (next_bin >= 0 && next_bin != z0_bin_index) {
806
807 if ((z0_bitmask >> next_bin) & 1) return true;
808
809 }
810
811 float dzp = dz + z0_resolution;
812
813 next_bin = z0_histo_coeff*dzp;
814
815 if (next_bin < 16 && next_bin != z0_bin_index) {
816
817 if ((z0_bitmask >> next_bin) & 1) return true;
818
819 }
820
821 return false;
822}
823
824
825float SeedingToolBase::estimate_curvature(const std::array<const GNN_Node*, 3>& sps) const {
826
827 //conformal mapping with the center at the last spacepoint
828
829 float u[2], v[2];
830
831 float x0 = sps[2]->x();
832 float y0 = sps[2]->y();
833
834 float r0 = sps[2]->r();
835
836 float cosA = x0/r0;
837
838 float sinA = y0/r0;
839
840
841 for(unsigned int k=0;k<2;k++) {
842
843 float dx = sps[k]->x() - x0;
844
845 float dy = sps[k]->y() - y0;
846
847 float r2_inv = 1.0/(dx*dx+dy*dy);
848
849 float xn = dx*cosA + dy*sinA;
850
851 float yn =-dx*sinA + dy*cosA;
852
853 u[k] = xn*r2_inv;
854 v[k] = yn*r2_inv;
855 }
856
857 float du = u[0] - u[1];
858
859 if(du==0.0) return 0.0;
860
861 float A = (v[0] - v[1])/du;
862
863 float B = v[1] - A*u[1];
864
865 return 1000.0*B/std::sqrt(1 + A*A); //inverse meters
866
867}
868
869bool SeedingToolBase::validate_triplet(std::array<const GNN_Node*, 3>& sps, const float min_pT, const float tau_ratio, const float tau_ratio_cut) const {
870
871 //conformal mapping with the center at the middle spacepoint
872
873 float u[2], v[2];
874
875 const float x0 = sps[1]->x();
876 const float y0 = sps[1]->y();
877
878 const float r0 = sps[1]->r();
879
880 const float cosA = x0/r0;
881
882 const float sinA = y0/r0;
883
884 for(unsigned int k=0;k<2;k++) {
885
886 int sp_idx = (k==1) ? 2 : k;
887
888 const float dx = sps[sp_idx]->x() - x0;
889
890 const float dy = sps[sp_idx]->y() - y0;
891
892 const float r2_inv = 1.0/(dx*dx+dy*dy);
893
894 const float xn = dx*cosA + dy*sinA;
895
896 const float yn =-dx*sinA + dy*cosA;
897
898 u[k] = xn*r2_inv;
899 v[k] = yn*r2_inv;
900 }
901
902 const float du = u[0] - u[1];
903
904 if ( du == 0.0 ) return false;
905
906 const float A = (v[0] - v[1])/du;
907
908 const float B = v[1] - A*u[1];
909
910 const float d0 = r0*(B*r0 - A);
911
912 if (std::abs(d0) > m_d0_max) return false;
913
914 if (B != 0.0) {//straight-line track is OK
915
916 const float R = std::sqrt(1 + A*A)/B; //signed radius in mm
917
918 const float pT = std::abs(0.3*R); //asssuming uniform 2T field
919
920 if (pT < min_pT) return false;
921
922 if (pT > 5*min_pT) {//relatively high-pT track
923
924 if (tau_ratio > 0.9*tau_ratio_cut) return false;
925
926 }
927
928 }
929
930 return true;
931
932}
#define M_PI
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This class provides an interface to generate or decode an identifier for the upper levels of the dete...
#define M_2PI
#define N_SEG_CONNS
static Double_t rs
static Double_t sc
static const uint32_t nHits
This is an Identifier helper class for the Pixel subdetector.
This is an Identifier helper class for the SCT subdetector.
const ServiceHandle< StoreGateSvc > & detStore() const
Header file for AthHistogramAlgorithm.
Describes the API of the Region of Ineterest geometry.
virtual double zedPlus() const =0
the zed and eta values at the most forward and most rear ends of the RoI
virtual double dzdrMinus() const =0
return the gradients
virtual double zedMinus() const =0
virtual double dzdrPlus() const =0
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
int runCCA(int, std::vector< GNN_Edge > &) const
ToolHandle< ITrigL2LayerNumberTool > m_layerNumberTool
std::vector< std::array< float, 5 > > m_mlLUT
std::vector< TrigInDetSiLayer > m_layerGeometry
void extractSeedsFromTheGraph(int, int, int, std::vector< GNN_Edge > &, std::vector< std::pair< float, std::vector< unsigned int > > > &) const
std::pair< int, int > buildTheGraph(const IRoiDescriptor &, const std::unique_ptr< GNN_DataStorage > &, std::vector< GNN_Edge > &) const
std::unique_ptr< GNN_FasTrackConnector > m_connector
bool check_z0_bitmask(const unsigned short &, const float &, const float &, const float &) const
float estimate_curvature(const std::array< const GNN_Node *, 3 > &) const
std::unique_ptr< const TrigFTF_GNN_Geometry > m_geo
bool validate_triplet(std::array< const GNN_Node *, 3 > &, const float min_pt, const float tau_ratio, const float tau_ratio_cut) const
unsigned int m_vNei[N_SEG_CONNS]
unsigned char m_nNei
const TrigFTF_GNN_Node * m_n2
std::vector< const TrigFTF_GNN_Node * > m_vn
float getMinBinRadius() const
std::vector< unsigned short > m_vIsConnected
float getMaxBinRadius() const
std::vector< unsigned int > m_vFirstEdge
std::vector< std::pair< float, unsigned int > > m_vPhiNodes
std::vector< std::array< float, 5 > > m_params
unsigned int m_layerKey
std::vector< unsigned short > m_vNumEdges
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
hold the test vectors and ease the comparison
unsigned short m_layer