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