ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimNNTrackTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
13
19
21FPGATrackSimNNTrackTool::FPGATrackSimNNTrackTool(const std::string &algname, const std::string &name, const IInterface *ifc) : FPGATrackSimTrackingToolBase(algname, name, ifc), OnnxRuntimeBase() {}
22
23
24// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27 ATH_CHECK(m_tHistSvc.retrieve());
28 if (m_useSpacePoints) ATH_CHECK(m_spRoadFilterTool.retrieve(EnableTool{m_spRoadFilterTool}));
29
30 if (m_FPGATrackSimMapping->getFakeNNMapString() != "") {
31 m_fakeNN_1st.initialize(m_FPGATrackSimMapping->getFakeNNMapString());
32 }
33 else {
34 ATH_MSG_ERROR("Path to 1st stage NN-based fake track removal ONNX file is empty! If you want to run this pipeline, you need to provide an input file.");
35 return StatusCode::FAILURE;
36 }
37
38 if (m_FPGATrackSimMapping->getParamNNMapString() != "") {
39 m_paramNN_1st.initialize(m_FPGATrackSimMapping->getParamNNMapString());
40 }
41 else {
42 ATH_MSG_INFO("Path 1st stage to NN-based track parameter estimation ONNX file is empty! Estimation is not run...");
43 m_useParamNN_1st = false;
44 }
45
46 if (m_FPGATrackSimMapping->getFakeNNMap2ndString() != "") {
47 m_fakeNN_2nd.initialize(m_FPGATrackSimMapping->getFakeNNMap2ndString());
48 }
49 else {
50 ATH_MSG_ERROR("Path to 2nd stage NN-based fake track 1st stage removal ONNX file is empty! If you want to run this pipeline, you need to provide an input file.");
51 return StatusCode::FAILURE;
52 }
53
54 if (m_FPGATrackSimMapping->getParamNNMap2ndString() != "") {
55 m_paramNN_2nd.initialize(m_FPGATrackSimMapping->getParamNNMap2ndString());
56 }
57 else {
58 ATH_MSG_INFO("Path to 2nd stage NN-based track parameter estimation 2nd ONNX file is empty! Estimation is not run...");
59 m_useParamNN_2nd = false;
60 }
61
62 return StatusCode::SUCCESS;
63}
64
65
66StatusCode FPGATrackSimNNTrackTool::setTrackParameters(std::vector<FPGATrackSimTrack> &tracks, bool isFirst, const FPGATrackSimTrackPars& min, const FPGATrackSimTrackPars& max) {
67
68 ATH_MSG_DEBUG("Running NN-based track parameter estimation!");
69 std::vector<float> paramNNoutputs;
70 if (!m_useParamNN_1st && isFirst) return StatusCode::SUCCESS;
71 if (!m_useParamNN_2nd && !isFirst) return StatusCode::SUCCESS;
72
73 for (auto &track : tracks) {
74 if (!track.passedOR()) continue;
75 std::vector<float> inputTensorValues;
76 const auto& hits = track.getFPGATrackSimHitPtrs();
77 bool gotSecondSP = false;
78 float tmp_xf;
79 float tmp_yf;
80 float tmp_zf;
81 float tmp_rf;
82 float tmp_phif;
83
84 for (const auto& hit_ptr : hits) {
85 if (!hit_ptr) {
86 ATH_MSG_ERROR("Null hit pointer in track");
87 return StatusCode::FAILURE;
88 }
89 if (!hit_ptr->isReal()) continue;
90 const auto& hit = *hit_ptr;
91
92 // Need to rotate hits
93 float xf = hit.getX();
94 float yf = hit.getY();
95 float zf = hit.getZ();
96 float rf = std::sqrt(xf*xf+yf*yf);
97 float phif = hit.getGPhi();
98
99 // Get average of values for strip hit pairs
100 // TODO: this needs to be fixed in the future, for this to work for other cases
101 if (hit.isStrip()) {
102 if (hit.getHitType() != HitType::spacepoint) { // this is a strip but not a SP!
103 if (m_useCartesian) {
104 float xf_scaled = (xf) / (getXScale());
105 float yf_scaled = (yf) / (getYScale());
106 float zf_scaled = (zf) / (getZScale());
107
108 // Get average of two hits for strip hits
109 inputTensorValues.push_back(xf_scaled);
110 inputTensorValues.push_back(yf_scaled);
111 inputTensorValues.push_back(zf_scaled);
112
113 }
114 else {
115 float rf_scaled = (rf) / (getRScale());
116 float phif_scaled = (phif) / (getPhiScale());
117 float zf_scaled = (zf) / (getZScale());
118 // Get average of two hits for strip hits
119 inputTensorValues.push_back(rf_scaled);
120 inputTensorValues.push_back(phif_scaled);
121 inputTensorValues.push_back(zf_scaled);
122 }
123 }
124 else if (!gotSecondSP) {
125 tmp_xf = xf;
126 tmp_yf = yf;
127 tmp_zf = zf;
128 tmp_rf = rf;
129 tmp_phif = phif;
130 gotSecondSP = true;
131 }
132 else {
133 gotSecondSP = false;
134
135 if (m_useCartesian) {
136 float xf_scaled = (xf + tmp_xf) / (2.*getXScale());
137 float yf_scaled = (yf + tmp_yf) / (2.*getYScale());
138 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
139
140 // Get average of two hits for strip hits
141 inputTensorValues.push_back(xf_scaled);
142 inputTensorValues.push_back(yf_scaled);
143 inputTensorValues.push_back(zf_scaled);
144
145 }
146 else {
147 float rf_scaled = (rf+tmp_rf) / (2.*getRScale());
148 float phif_scaled = (phif+tmp_phif) / (2.*getPhiScale());
149 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
150 // Get average of two hits for strip hits
151 inputTensorValues.push_back(rf_scaled);
152 inputTensorValues.push_back(phif_scaled);
153 inputTensorValues.push_back(zf_scaled);
154 }
155 }
156 }
157 else {
158 if (m_useCartesian) {
159 float xf_scaled = (xf) / (getXScale());
160 float yf_scaled = (yf) / (getYScale());
161 float zf_scaled = (zf) / (getZScale());
162 inputTensorValues.push_back(xf_scaled);
163 inputTensorValues.push_back(yf_scaled);
164 inputTensorValues.push_back(zf_scaled);
165 }
166 else {
167 float rf_scaled = (rf) / (getRScale());
168 float phif_scaled = (phif) / (getPhiScale());
169 float zf_scaled = (zf) / (getZScale());
170 // Get average of two hits for strip hits
171 inputTensorValues.push_back(rf_scaled);
172 inputTensorValues.push_back(phif_scaled);
173 inputTensorValues.push_back(zf_scaled);
174 }
175 }
176 }
177
178 if (isFirst){
179 if (inputTensorValues.size() < 15) {
180 inputTensorValues.resize(15, 0.0f); // Resize to 15 and fill with 0.0f
181 }
182
183 if (m_doGNNTracking) {
184 inputTensorValues.resize(m_nInputsGNN * 3);
185 }
186 }
187 else {
188 if (inputTensorValues.size() < 39) {
189 inputTensorValues.resize(39, 0.0f); // Resize to 39 and fill with 0.0f
190 }
191 else if (inputTensorValues.size() > 39) {
192 inputTensorValues.resize(39); // Resize to 39 and keep the first e9 elements
193 }
194 }
195
196 if (m_doGNNTracking) {
197 inputTensorValues.resize(m_nInputsGNN * 3);
198 }
199
200
201 if (isFirst) paramNNoutputs = m_paramNN_1st.runONNXInference(inputTensorValues);
202 else paramNNoutputs = m_paramNN_2nd.runONNXInference(inputTensorValues);
203
204 ATH_MSG_DEBUG("Estimated Track Parameters");
205 for (unsigned int i = 0; i < paramNNoutputs.size(); i++) {
206 ATH_MSG_DEBUG(paramNNoutputs[i]);
207 }
208
209
210 double qopt = paramNNoutputs[0]*getQoverPtScale();
211 double eta = paramNNoutputs[1]*getEtaScale();
212 double phi = paramNNoutputs[2]*getPhiScale();
213 double d0 = paramNNoutputs[3]*getD0Scale();
214 double z0 = paramNNoutputs[4]*getZ0Scale();
215
216
227
228 track.setQOverPt(qopt);
229 track.setEta(eta);
230 track.setPhi(phi);
231 track.setD0(d0);
232 track.setZ0(z0);
233 }
234 return StatusCode::SUCCESS;
235}
236
237
238StatusCode FPGATrackSimNNTrackTool::getTracks_1st(std::vector<FPGATrackSimRoad> &roads, std::vector<FPGATrackSimTrack> &tracks) {
239
240 if(m_doGNNTracking) {
241 ATH_CHECK(getTracks_GNN(roads, tracks));
242 return StatusCode::SUCCESS;
243 }
244
246 int n_track = 0;
247
248 std::vector<std::vector<float> >inputTensorValuesAll;
249
250 // Loop over roads
251 for (auto const &iroad : roads) {
252
253 double y = iroad.getY();
254
255 // Just used to get number of layers considered
256 const FPGATrackSimPlaneMap *planeMap = m_FPGATrackSimMapping->PlaneMap_1st(iroad.getSubRegion());
257
258 // Get info on layers with missing hits
259 int nMissing = 0;
260 layer_bitmask_t missing_mask = iroad.getNWCLayers();
261 for (unsigned ilayer = 0; ilayer < planeMap->getNLogiLayers(); ilayer++) {
262 if ((missing_mask >> ilayer) & 0x1) {
263 nMissing++;
264 if (planeMap->isPixel(ilayer)) nMissing++;
265 }
266 }
267
268
269 // Create a template track with common parameters filled already for
270 // initializing below
273 temp.setNLayers(planeMap->getNLogiLayers());
274 temp.setBankID(-1);
275 temp.setPatternID(iroad.getPID());
276 temp.setFirstSectorID(iroad.getSector());
277 temp.setHitMap(missing_mask);
278 temp.setNMissing(nMissing);
279 temp.setQOverPt(y);
280
281 temp.setSubRegion(iroad.getSubRegion());
282 temp.setHoughX(iroad.getX());
283 temp.setHoughY(iroad.getY());
284 temp.setHoughXBin(iroad.getXBin());
285 temp.setHoughYBin(iroad.getYBin());
286
287 temp.setBinIdx(iroad.getBinIdx());
288
290 // Get a list of indices for all possible combinations given a certain
291 // number of layers
292 std::vector<std::vector<int>> combs;
293
294 combs = getComboIndices(iroad.getNHits_layer());
295
296 // Loop over possible combinations for this road
297 for (size_t icomb = 0; icomb < combs.size(); icomb++) {
298 std::vector<float> inputTensorValues;
299 std::vector<std::shared_ptr<const FPGATrackSimHit>> hit_list;
300
301 // list of indices for this particular combination
302 std::vector<int> const &hit_indices = combs[icomb];
303
304 // Loop over all layers
305 for (unsigned layer = 0; layer < planeMap->getNLogiLayers(); layer++) {
306
307 // Check to see if this is a valid hit
308 if (hit_indices[layer] >= 0) {
309
310 std::shared_ptr<const FPGATrackSimHit> hit = iroad.getHitPtrs(layer)[hit_indices[layer]];
311 // Add this hit to the road
312 if (hit->isReal()){
313 hit_list.push_back(std::move(hit));
314 }
315 }
316 }
317
318 // Sort the list by radial distance
319 std::sort(hit_list.begin(), hit_list.end(),
320 [](std::shared_ptr<const FPGATrackSimHit> &hit1, std::shared_ptr<const FPGATrackSimHit> &hit2) {
321 double rho1 = std::hypot(hit1->getX(), hit1->getY());
322 double rho2 = std::hypot(hit2->getX(), hit2->getY());
323 return rho1 < rho2;
324 });
325
326
327 int index = 1;
328 bool flipZ = false;
329 double rotateAngle = 0;
330 bool gotSecondSP = false;
331 float tmp_xf;
332 float tmp_yf;
333 float tmp_zf;
334 float tmp_rf;
335 float tmp_phif;
336 // Loop over all hits
337 for (const auto &hit : hit_list) {
338 // Need to rotate hits
339 float x0 = hit->getX();
340 float y0 = hit->getY();
341 float z0 = hit->getZ();
342 float r0 = std::sqrt(x0*x0+y0*y0);
343 float phi0 = hit->getGPhi();
344 float xf = x0;
345 float yf = y0;
346 float zf = z0;
347 float rf = r0;
348 float phif = phi0;
349 if (m_useCartesian) {
350 if (index == 1) {
351 if (z0 < 0)
352 flipZ = true;
353 rotateAngle = std::atan(x0 / y0);
354 if (y0 < 0)
355 rotateAngle += M_PI;
356 }
357 xf = x0 * std::cos(rotateAngle) - y0 * std::sin(rotateAngle);
358 yf = x0 * std::sin(rotateAngle) + y0 * std::cos(rotateAngle);
359 zf = z0;
360 if (flipZ) zf = z0 * -1;
361 }
362
363 // Get average of values for strip hit pairs
364 // TODO: this needs to be fixed in the future, for this to work for other cases
365 if (hit->isStrip()) {
366
367 if (hit->getHitType() != HitType::spacepoint) { // this is a strip but not a SP!
368 if (m_useCartesian) {
369 float xf_scaled = (xf) / (getXScale());
370 float yf_scaled = (yf) / (getYScale());
371 float zf_scaled = (zf) / (getZScale());
372
373 // Get average of two hits for strip hits
374 inputTensorValues.push_back(xf_scaled);
375 inputTensorValues.push_back(yf_scaled);
376 inputTensorValues.push_back(zf_scaled);
377
378 }
379 else {
380 float rf_scaled = (rf) / (getRScale());
381 float phif_scaled = (phif) / (getPhiScale());
382 float zf_scaled = (zf) / (getZScale());
383 // Get average of two hits for strip hits
384 inputTensorValues.push_back(rf_scaled);
385 inputTensorValues.push_back(phif_scaled);
386 inputTensorValues.push_back(zf_scaled);
387 }
388 }
389 else if (!gotSecondSP) {
390 tmp_xf = xf;
391 tmp_yf = yf;
392 tmp_zf = zf;
393 tmp_phif = phif;
394 tmp_rf = rf;
395 gotSecondSP = true;
396 }
397 else {
398 gotSecondSP = false;
399 if (m_useCartesian) {
400 float xf_scaled = (xf + tmp_xf) / (2.*getXScale());
401 float yf_scaled = (yf + tmp_yf) / (2.*getYScale());
402 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
403
404 // Get average of two hits for strip hits
405 inputTensorValues.push_back(xf_scaled);
406 inputTensorValues.push_back(yf_scaled);
407 inputTensorValues.push_back(zf_scaled);
408 index++;
409 }
410 else {
411 float rf_scaled = (rf + tmp_rf) / (2.*getRScale());
412 float phif_scaled = (phif + tmp_phif) / (2.*getPhiScale());
413 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
414 inputTensorValues.push_back(rf_scaled);
415 inputTensorValues.push_back(phif_scaled);
416 inputTensorValues.push_back(zf_scaled);
417 }
418 }
419 }
420 else {
421 if (m_useCartesian) {
422 float xf_scaled = (xf) / (getXScale());
423 float yf_scaled = (yf) / (getYScale());
424 float zf_scaled = (zf) / (getZScale());
425 inputTensorValues.push_back(xf_scaled);
426 inputTensorValues.push_back(yf_scaled);
427 inputTensorValues.push_back(zf_scaled);
428 index++;
429 }
430 else {
431 float rf_scaled = (rf) / (getRScale());
432 float phif_scaled = (phif) / (getPhiScale());
433 float zf_scaled = (zf) / (getZScale());
434 inputTensorValues.push_back(rf_scaled);
435 inputTensorValues.push_back(phif_scaled);
436 inputTensorValues.push_back(zf_scaled);
437 }
438 }
439 }
440
441 if (inputTensorValues.size() != planeMap->getNLogiLayers()*3) {
442 inputTensorValues.resize(planeMap->getNLogiLayers()*3);
443 }
444 inputTensorValues.resize(15); // Retain only the first 15 values for consistency
445
446 inputTensorValuesAll.push_back(inputTensorValues);
447 FPGATrackSimTrack track_cand;
448 n_track++;
449 track_cand.setTrackID(n_track);
450 track_cand.setNLayers(planeMap->getNLogiLayers());
451 track_cand.setNMissing(nMissing);
452 for (unsigned ihit = 0; ihit < hit_list.size(); ihit++) {
453 track_cand.setFPGATrackSimHit(ihit, hit_list[ihit]);
454 }
455 tracks.push_back(track_cand);
456
457 ATH_MSG_DEBUG("NN InputTensorValues:");
458 ATH_MSG_DEBUG(inputTensorValues);
459 } // loop over combinations
460 } // loop over roads
461
463 auto NNoutputs = m_fakeNN_1st.runONNXInference(inputTensorValuesAll);
464
465 for (unsigned itrack = 0; itrack < NNoutputs.size(); itrack++) {
466
467 float nn_val = NNoutputs[itrack][0];
468 ATH_MSG_DEBUG("NN output:" << nn_val);
469 double chi2 = (1 - nn_val) * (tracks[itrack].getNCoords() - tracks[itrack].getNMissing() - 5);
470 //std::cout << "1st stage" << chi2 << std::endl;
471 tracks[itrack].setOrigChi2(chi2);
472 tracks[itrack].setChi2(chi2);
473 }
474
475 // Add truth info
476 for (FPGATrackSimTrack &t : tracks) {
477 compute_truth(t); // match the track to a geant particle using the
478 // channel-level geant info in the hit data.
479 }
480 return StatusCode::SUCCESS;
481}
482
483
484StatusCode FPGATrackSimNNTrackTool::getTracks_2nd(std::vector<FPGATrackSimRoad> &roads, std::vector<FPGATrackSimTrack> &tracks) {
485
487 int n_track = 0;
488 std::vector<std::vector<float> >inputTensorValuesAll;
489
490 // Loop over roads
491 for (auto const &iroad : roads) {
492
493 double y = iroad.getY();
494
495 const FPGATrackSimPlaneMap *planeMap = m_FPGATrackSimMapping->PlaneMap_2nd(iroad.getSubRegion());
496 // Get info on layers with missing hits
497 int nMissing = 0;
498 layer_bitmask_t missing_mask = iroad.getNWCLayers();
499 layer_bitmask_t hit_mask = 0x0;
500 for (unsigned ilayer = 0; ilayer < 13; ilayer++) {
501 if ((missing_mask >> ilayer) & 0x1) {
502 nMissing++;
503 if (planeMap->isPixel(ilayer)) nMissing++;
504 }
505 else {
506 hit_mask |= (0x1 << ilayer);
507 }
508 }
509
510 // Create a template track with common parameters filled already for
511 // initializing below
514 temp.setNLayers(13);
515 temp.setBankID(-1);
516 temp.setPatternID(iroad.getPID());
517 temp.setFirstSectorID(iroad.getSector());
518 temp.setHitMap(hit_mask);
519 temp.setNMissing(nMissing);
520 temp.setQOverPt(y);
521
522 temp.setSubRegion(iroad.getSubRegion());
523 temp.setHoughX(iroad.getX());
524 temp.setHoughY(iroad.getY());
525 temp.setHoughXBin(iroad.getXBin());
526 temp.setHoughYBin(iroad.getYBin());
528 // Get a list of indices for all possible combinations given a certain
529 // number of layers
530 std::vector<std::vector<int>> combs =
531 getComboIndices(iroad.getNHits_layer());
532
533 // Loop over possible combinations for this road
534 for (size_t icomb = 0; icomb < combs.size(); icomb++) {
535 std::vector<float> inputTensorValues;
536
537 // list of indices for this particular combination
538 std::vector<int> const &hit_indices = combs[icomb];
539 std::vector<std::shared_ptr<const FPGATrackSimHit>> hit_list;
540
541 // Loop over all layers
542 for (unsigned layer = 0; layer < 13; layer++) {
543
544 // Check to see if this is a valid hit
545 if (hit_indices[layer] >= 0) {
546
547 std::shared_ptr<const FPGATrackSimHit> hit = iroad.getHitPtrs(layer)[hit_indices[layer]];
548 // Add this hit to the road
549 if (hit->isReal()){
550 hit_list.push_back(std::move(hit));
551 }
552 }
553 }
554
555 // Sort the list by radial distance
556 std::sort(hit_list.begin(), hit_list.end(),
557 [](std::shared_ptr<const FPGATrackSimHit> &hit1, std::shared_ptr<const FPGATrackSimHit> &hit2) {
558 double rho1 = std::hypot(hit1->getX(), hit1->getY());
559 double rho2 = std::hypot(hit2->getX(), hit2->getY());
560 return rho1 < rho2;
561 });
562
563
564 int index = 1;
565 bool flipZ = false;
566 double rotateAngle = 0;
567 bool gotSecondSP = false;
568 float tmp_xf;
569 float tmp_yf;
570 float tmp_zf;
571 float tmp_rf;
572 float tmp_phif;
573 // Loop over all hits
574 for (const auto &hit : hit_list) {
575
576 // Need to rotate hits
577 float x0 = hit->getX();
578 float y0 = hit->getY();
579 float z0 = hit->getZ();
580 float r0 = std::sqrt(x0*x0+y0*y0);
581 float phi0 = hit->getGPhi();
582 float xf = x0;
583 float yf = y0;
584 float zf = z0;
585 float rf = r0;
586 float phif = phi0;
587
588 if (m_useCartesian) {
589 if (index == 1) {
590 if (z0 < 0)
591 flipZ = true;
592 rotateAngle = std::atan(x0 / y0);
593 if (y0 < 0)
594 rotateAngle += M_PI;
595 }
596 xf = x0 * std::cos(rotateAngle) - y0 * std::sin(rotateAngle);
597 yf = x0 * std::sin(rotateAngle) + y0 * std::cos(rotateAngle);
598 zf = z0;
599
600 if (flipZ) zf = z0 * -1;
601 }
602
603 // Get average of values for strip hit pairs
604 // TODO: this needs to be fixed in the future, for this to work for other cases
605 if (hit->isStrip()) {
606
607 if (hit->getHitType() != HitType::spacepoint) { // this is a strip but not a SP!
608 if (m_useCartesian) {
609 float xf_scaled = (xf) / (getXScale());
610 float yf_scaled = (yf) / (getYScale());
611 float zf_scaled = (zf) / (getZScale());
612
613 // Get average of two hits for strip hits
614 inputTensorValues.push_back(xf_scaled);
615 inputTensorValues.push_back(yf_scaled);
616 inputTensorValues.push_back(zf_scaled);
617 }
618 else {
619 float rf_scaled = (rf) / (getRScale());
620 float phif_scaled = (phif) / (getPhiScale());
621 float zf_scaled = (zf) / (getZScale());
622 // Get average of two hits for strip hits
623 inputTensorValues.push_back(rf_scaled);
624 inputTensorValues.push_back(phif_scaled);
625 inputTensorValues.push_back(zf_scaled);
626 }
627 }
628 else if (!gotSecondSP) {
629 tmp_xf = xf;
630 tmp_yf = yf;
631 tmp_zf = zf;
632 tmp_rf = rf;
633 tmp_phif = phif;
634 gotSecondSP = true;
635 }
636 else {
637 gotSecondSP = false;
638 if (m_useCartesian) {
639 float xf_scaled = (xf + tmp_xf) / (2.*getXScale());
640 float yf_scaled = (yf + tmp_yf) / (2.*getYScale());
641 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
642
643 // Get average of two hits for strip hits
644 inputTensorValues.push_back(xf_scaled);
645 inputTensorValues.push_back(yf_scaled);
646 inputTensorValues.push_back(zf_scaled);
647 index++;
648 }
649 else {
650 float rf_scaled = (rf + tmp_rf) / (2.*getRScale());
651 float phif_scaled = (phif + tmp_phif) / (2.*getPhiScale());
652 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
653 inputTensorValues.push_back(rf_scaled);
654 inputTensorValues.push_back(phif_scaled);
655 inputTensorValues.push_back(zf_scaled);
656 }
657 }
658 }
659 else {
660 if (m_useCartesian) {
661 float xf_scaled = (xf) / (getXScale());
662 float yf_scaled = (yf) / (getYScale());
663 float zf_scaled = (zf) / (getZScale());
664 inputTensorValues.push_back(xf_scaled);
665 inputTensorValues.push_back(yf_scaled);
666 inputTensorValues.push_back(zf_scaled);
667 index++;
668 }
669 else {
670 float rf_scaled = (rf) / (getRScale());
671 float phif_scaled = (phif) / (getPhiScale());
672 float zf_scaled = (zf) / (getZScale());
673 inputTensorValues.push_back(rf_scaled);
674 inputTensorValues.push_back(phif_scaled);
675 inputTensorValues.push_back(zf_scaled);
676 }
677 }
678 }
679
680
681 if (inputTensorValues.size() < 39) {
682 inputTensorValues.resize(39, 0.0f); // Resize to 39 and fill with 0.0f
683 }
684 else if (inputTensorValues.size() > 39) {
685 inputTensorValues.resize(39); // Resize to 39 and keep the first 39 elements
686 }
687 inputTensorValuesAll.push_back(inputTensorValues);
688
689 ATH_MSG_DEBUG("NN InputTensorValues:");
690 ATH_MSG_DEBUG(inputTensorValues);
691
692 n_track++;
693 FPGATrackSimTrack track_cand;
694 track_cand.setTrackID(n_track);
695 track_cand.setNLayers(13);
696 track_cand.setNMissing(nMissing);
697 for (unsigned ihit = 0; ihit < hit_list.size(); ihit++) {
698 track_cand.setFPGATrackSimHit(ihit, hit_list[ihit]);
699 }
700 tracks.push_back(track_cand);
701
702 } // loop over combinations
703 } // loop over roads
704
706 auto NNoutputs = m_fakeNN_2nd.runONNXInference(inputTensorValuesAll);
707 for (unsigned itrack = 0; itrack < NNoutputs.size(); itrack++) {
708
709 float nn_val = NNoutputs[itrack][0];
710 ATH_MSG_DEBUG("NN output:" << nn_val);
711
712 double chi2 = (1 - nn_val) * (tracks[itrack].getNCoords() - tracks[itrack].getNMissing() - 5);
713
714 tracks[itrack].setOrigChi2(chi2);
715 tracks[itrack].setChi2(chi2);
716 }
717
718 // Add truth info
719 for (FPGATrackSimTrack &t : tracks) {
720 compute_truth(t); // match the track to a geant particle using the
721 // channel-level geant info in the hit data.
722 }
723
724 return StatusCode::SUCCESS;
725}
726
727StatusCode FPGATrackSimNNTrackTool::getTracks_GNN(std::vector<FPGATrackSimRoad> &roads, std::vector<FPGATrackSimTrack> &tracks) {
728
730 int n_track = 0;
731
732 std::vector<std::vector<float> >inputTensorValuesAll;
733
734 // Loop over roads
735 for (auto const &iroad : roads) {
736 // Just used to get number of layers considered
737 const FPGATrackSimPlaneMap *planeMap = m_FPGATrackSimMapping->PlaneMap_1st(iroad.getSubRegion());
738
739 double y = iroad.getY();
740
741 // Get info on layers with missing hits
742 int nMissing = 0;
743 layer_bitmask_t missing_mask = 0;
744 layer_bitmask_t hit_mask = 0x0;
745 for (unsigned ilayer = 0; ilayer < 13; ilayer++) {
746 if ((missing_mask >> ilayer) & 0x1) {
747 nMissing++;
748 if (planeMap->isPixel(ilayer)) nMissing++;
749 }
750 else {
751 hit_mask |= (0x1 << ilayer);
752 }
753 }
754
755
756 // Create a template track with common parameters filled already for
757 // initializing below
760 temp.setNLayers(planeMap->getNLogiLayers());
761 temp.setBankID(-1);
762 temp.setPatternID(iroad.getPID());
763 temp.setFirstSectorID(iroad.getSector());
764 temp.setHitMap(hit_mask);
765 temp.setNMissing(nMissing);
766 temp.setQOverPt(y);
767
768 temp.setSubRegion(iroad.getSubRegion());
769 temp.setHoughX(iroad.getX());
770 temp.setHoughY(iroad.getY());
771 temp.setHoughXBin(iroad.getXBin());
772 temp.setHoughYBin(iroad.getYBin());
773
775 // Get a list of indices for all possible combinations given a certain
776 // number of layers
777 std::vector<std::vector<int>> combs;
778 std::vector<std::shared_ptr<const FPGATrackSimHit>> all_hits;
779
780 std::vector<std::shared_ptr<const FPGATrackSimHit>> all_pixel_hits;
781 std::vector<std::shared_ptr<const FPGATrackSimHit>> all_strip_hits;
782 size_t pixelCount = 0;
783
784 for (unsigned layer = 0; layer < iroad.getNLayers(); ++layer) {
785 all_hits.insert(all_hits.end(), iroad.getHitPtrs(layer).begin(), iroad.getHitPtrs(layer).end());
786 }
787
788 for (const auto& hit : all_hits) {
789 if(hit->isPixel()) {
790 pixelCount++;
791 }
792 }
793
794 if (pixelCount < 1) continue; // Cannot use a form a track candidate from a road that does not have a pixel hit
795
796 std::vector<float> inputTensorValues;
797 std::vector<std::shared_ptr<const FPGATrackSimHit>> hit_list;
798
799 for (const auto &hit : all_hits) {
800 if (hit->isReal()) {
801 hit_list.push_back(hit);
802 }
803 }
804
805 if (hit_list.size() < m_minNumberOfRealHitsInATrack) continue;
806
807 // Sort the list by radial distance
808 std::sort(hit_list.begin(), hit_list.end(),
809 [](std::shared_ptr<const FPGATrackSimHit> &hit1, std::shared_ptr<const FPGATrackSimHit> &hit2) {
810 double rho1 = std::hypot(hit1->getX(), hit1->getY());
811 double rho2 = std::hypot(hit2->getX(), hit2->getY());
812 return rho1 < rho2;
813 });
814
815
816 int index = 1;
817 bool flipZ = false;
818 double rotateAngle = 0;
819 bool gotSecondSP = false;
820 float tmp_xf;
821 float tmp_yf;
822 float tmp_zf;
823 float tmp_phif;
824 float tmp_rf;
825
826 // Loop over all hits
827 for (const auto &hit : hit_list) {
828 // Need to rotate hits
829 float x0 = hit->getX();
830 float y0 = hit->getY();
831 float z0 = hit->getZ();
832 float r0 = std::sqrt(x0*x0+y0*y0);
833 float phi0 = hit->getGPhi();
834 float xf = x0;
835 float yf = y0;
836 float zf = z0;
837 float rf = r0;
838 float phif = phi0;
839
840 if (m_useCartesian) {
841 if (index == 1) {
842 if (z0 < 0)
843 flipZ = true;
844 rotateAngle = std::atan(x0 / y0);
845 if (y0 < 0)
846 rotateAngle += M_PI;
847 }
848 xf = x0 * std::cos(rotateAngle) - y0 * std::sin(rotateAngle);
849 yf = x0 * std::sin(rotateAngle) + y0 * std::cos(rotateAngle);
850 zf = z0;
851
852 if (flipZ) zf = z0 * -1;
853 }
854
855 // Get average of values for strip hit pairs
856 // TODO: this needs to be fixed in the future, for this to work for other cases
857 if (hit->isStrip()) {
858
859 if (hit->getHitType() != HitType::spacepoint) { // this is a strip but not a SP!
860 if (m_useCartesian) {
861 float xf_scaled = (xf) / (getXScale());
862 float yf_scaled = (yf) / (getYScale());
863 float zf_scaled = (zf) / (getZScale());
864
865 // Get average of two hits for strip hits
866 inputTensorValues.push_back(xf_scaled);
867 inputTensorValues.push_back(yf_scaled);
868 inputTensorValues.push_back(zf_scaled);
869
870 }
871 else {
872 float rf_scaled = (rf) / (getRScale());
873 float phif_scaled = (phif) / (getPhiScale());
874 float zf_scaled = (zf) / (getZScale());
875 // Get average of two hits for strip hits
876 inputTensorValues.push_back(rf_scaled);
877 inputTensorValues.push_back(phif_scaled);
878 inputTensorValues.push_back(zf_scaled);
879 }
880 }
881 else if (!gotSecondSP) {
882 tmp_xf = xf;
883 tmp_yf = yf;
884 tmp_zf = zf;
885 tmp_phif = phif;
886 tmp_rf = rf;
887 gotSecondSP = true;
888 }
889 else {
890 gotSecondSP = false;
891 if (m_useCartesian) {
892 float xf_scaled = (xf + tmp_xf) / (2.*getXScale());
893 float yf_scaled = (yf + tmp_yf) / (2.*getYScale());
894 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
895
896 // Get average of two hits for strip hits
897 inputTensorValues.push_back(xf_scaled);
898 inputTensorValues.push_back(yf_scaled);
899 inputTensorValues.push_back(zf_scaled);
900 index++;
901 }
902 else {
903 float rf_scaled = (rf + tmp_rf) / (2.*getRScale());
904 float phif_scaled = (phif + tmp_phif) / (2.*getPhiScale());
905 float zf_scaled = (zf + tmp_zf) / (2.*getZScale());
906 inputTensorValues.push_back(rf_scaled);
907 inputTensorValues.push_back(phif_scaled);
908 inputTensorValues.push_back(zf_scaled);
909 }
910 }
911 }
912 else {
913 if (m_useCartesian) {
914 float xf_scaled = (xf) / (getXScale());
915 float yf_scaled = (yf) / (getYScale());
916 float zf_scaled = (zf) / (getZScale());
917 inputTensorValues.push_back(xf_scaled);
918 inputTensorValues.push_back(yf_scaled);
919 inputTensorValues.push_back(zf_scaled);
920 index++;
921 }
922 else {
923 float rf_scaled = (rf) / (getRScale());
924 float phif_scaled = (phif) / (getPhiScale());
925 float zf_scaled = (zf) / (getZScale());
926 inputTensorValues.push_back(rf_scaled);
927 inputTensorValues.push_back(phif_scaled);
928 inputTensorValues.push_back(zf_scaled);
929 }
930 }
931 }
932
933 // NN Estimator can either be 5 or 9 spacepoints as inputs
934 // Let this be decided by m_nInputsGNN
935
936 // NN Estimator needs 9 spacepoints -> 27 inputs
937 // If there are more than 9 spacepoints entered, then it accepts the first 9
938 // If there are less than 9 spacepoints, then it enters no values for it (although I actually probably need to just reject these)
939 inputTensorValues.resize(m_nInputsGNN * 3);
940
941 inputTensorValuesAll.push_back(inputTensorValues);
942 FPGATrackSimTrack track_cand;
943 track_cand.setTrackID(n_track);
944 track_cand.setNLayers(hit_list.size());
945 for (unsigned ihit = 0; ihit < hit_list.size(); ihit++) {
946 track_cand.setFPGATrackSimHit(ihit, hit_list[ihit]);
947 }
948 tracks.push_back(track_cand);
949
950
951 ATH_MSG_DEBUG("NN InputTensorValues:");
952 ATH_MSG_DEBUG(inputTensorValues);
953 } // loop over roads
954
956 auto NNoutputs = m_fakeNN_1st.runONNXInference(inputTensorValuesAll);
957
958 for (unsigned itrack = 0; itrack < NNoutputs.size(); itrack++) {
959
960 float nn_val = NNoutputs[itrack][0];
961 ATH_MSG_DEBUG("NN output:" << nn_val);
962 double chi2 = (1 - nn_val) * (tracks[itrack].getNCoords() - tracks[itrack].getNMissing() - 5);
963 tracks[itrack].setOrigChi2(chi2);
964 tracks[itrack].setChi2(chi2);
965 }
966
967 // Add truth info
968 for (FPGATrackSimTrack &t : tracks) {
969 compute_truth(t); // match the track to a geant particle using the
970 // channel-level geant info in the hit data.
971 }
972
973 return StatusCode::SUCCESS;
974}
975
976
977
978
979// Borrowed same code from TrackFitter - probably a nicer way to inherit instead
981 std::vector<FPGATrackSimMultiTruth> mtv;
982
983 unsigned nl = (m_do2ndStage ? 13 : 5);
984 const auto& hits = t.getFPGATrackSimHitPtrs();
985 for (unsigned layer = 0; layer < nl; layer++) {
986 if (!(t.getHitMap() & (1 << layer))) continue;
987
988 // Sanity check that we have enough hits.
989 if (layer < hits.size() && hits[layer])
990 mtv.push_back(hits[layer]->getTruth());
991 // adjust weight for hits without (and also with) a truth match, so that
992 // each is counted with the same weight.
993 mtv.back().assign_equal_normalization();
994 }
995
996 FPGATrackSimMultiTruth mt(std::accumulate(mtv.begin(), mtv.end(), FPGATrackSimMultiTruth(),
998 // frac is then the fraction of the total number of hits on the track
999 // attributed to the barcode.
1000
1003 const bool ok = mt.best(tbarcode, tfrac);
1004 if (ok) {
1005 t.setEventIndex(tbarcode.first);
1006 t.setBarcode(tbarcode.second);
1007 t.setBarcodeFrac(tfrac);
1008 }
1009}
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
std::vector< std::vector< int > > getComboIndices(std::vector< size_t > const &sizes)
Given a vector of sizes (of arrays), generates a vector of all combinations of indices to index one e...
Map for NN tracking.
Utilize NN score to build track candidates.
uint32_t layer_bitmask_t
#define y
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
bool best(FPGATrackSimMultiTruth::Barcode &code, FPGATrackSimMultiTruth::Weight &weight) const
std::pair< unsigned long, unsigned long > Barcode
Gaudi::Property< int > m_nInputsGNN
StatusCode getTracks_GNN(std::vector< FPGATrackSimRoad > &roads, std::vector< FPGATrackSimTrack > &tracks)
StatusCode getTracks_1st(std::vector< FPGATrackSimRoad > &roads, std::vector< FPGATrackSimTrack > &tracks)
OnnxRuntimeBase(TString fileName)
FPGATrackSimNNTrackTool(const std::string &, const std::string &, const IInterface *)
Gaudi::Property< bool > m_doGNNTracking
virtual StatusCode initialize() override
Gaudi::Property< unsigned int > m_minNumberOfRealHitsInATrack
ServiceHandle< IFPGATrackSimMappingSvc > m_FPGATrackSimMapping
StatusCode getTracks_2nd(std::vector< FPGATrackSimRoad > &roads, std::vector< FPGATrackSimTrack > &tracks)
ServiceHandle< ITHistSvc > m_tHistSvc
Gaudi::Property< bool > m_useCartesian
void compute_truth(FPGATrackSimTrack &newtrk) const
StatusCode setTrackParameters(std::vector< FPGATrackSimTrack > &tracks, bool isFirst, const FPGATrackSimTrackPars &min, const FPGATrackSimTrackPars &max)
uint32_t getNLogiLayers() const
bool isPixel(int pl) const
void setTrackStage(TrackStage v)
void setFPGATrackSimHit(unsigned i, std::shared_ptr< const FPGATrackSimHit > hit)
void setNLayers(int)
set the number of layers in the track.
ToolHandle< IFPGATrackSimRoadFilterTool > m_spRoadFilterTool
StatusCode setRoadSectors(std::vector< FPGATrackSimRoad > &roads)
FPGATrackSimTrackingToolBase(const std::string &type, const std::string &name, const IInterface *parent)
double chi2(TH1 *h0, TH1 *h1)
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.