ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimClusteringTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
10#include <algorithm>
11#include <cmath>
12
13
14namespace{
15 //For deciding eta || phi columns in modules
16 constexpr unsigned int ETA = 1;
17 constexpr unsigned int PHI = 0;
18}
19
20FPGATrackSimClusteringTool::FPGATrackSimClusteringTool(const std::string& algname, const std::string &name, const IInterface *ifc) :
21 base_class(algname, name, ifc)
22{
23}
24
26 ATH_CHECK(m_lorentzAngleTool.retrieve(EnableTool{m_LorentzAngleShift >=0}));
27 return StatusCode::SUCCESS;
28}
29
30
31StatusCode FPGATrackSimClusteringTool::DoClustering(FPGATrackSimLogicalEventInputHeader &header, std::vector<FPGATrackSimCluster> &clusters) const
32{
33 for (int i = 0; i<header.nTowers(); i++)
34 {
35 // Retreive the hits from the tower
36 FPGATrackSimTowerInputHeader& tower = *header.getTower(i);
38 hits.reserve(tower.hits().size());
39 for (auto& hit : tower.hits()) {
40 hits.push_back(std::make_unique<FPGATrackSimHit>(hit));
41 }
42
43 HitPtrContainer hitsPerModule;
44 std::vector<FPGATrackSimCluster> towerClusters;
45
47 for (auto &hit : hits)
49 }
50
51 splitAndSortHits(std::move(hits), hitsPerModule);
52 SortedClustering(std::move(hitsPerModule), towerClusters);
53 normaliseClusters(towerClusters);
54
55 //remove the old hits from the tower...
56 tower.clearHits();
57 tower.reserveHits(towerClusters.size());
58 clusters.clear();
59 clusters.reserve(towerClusters.size());
60 if(i > 1)
61 ATH_MSG_WARNING("more than one tower, m_clusters is only going to contain those from the last one");
62
63 unsigned cluster_count = 0;
64 unsigned int pixelCounter = 0;
65 unsigned int stripCounter = 0;
66 for ( auto &cluster: towerClusters){
67 SetMinMaxIndicies(cluster);
70
71 FPGATrackSimHit cluster_as_FPGATrackSimhit = cluster.getClusterEquiv();
72 cluster_as_FPGATrackSimhit.setHitType(HitType::clustered);
73 cluster_as_FPGATrackSimhit.setParentageMask(cluster_count); // making use of unused m_parentageMask to keep track of cluster index
74
75 if(cluster_as_FPGATrackSimhit.getDetType() == SiliconTech::pixel)
76 {
77 cluster_as_FPGATrackSimhit.setCluster1ID(pixelCounter);
78 pixelCounter++;
79 }
80 else if(cluster_as_FPGATrackSimhit.getDetType() == SiliconTech::strip)
81 {
82 cluster_as_FPGATrackSimhit.setCluster1ID(stripCounter);
83 stripCounter++;
84 }
85 if(m_LorentzAngleShift>= 0){
86 ATH_CHECK(m_lorentzAngleTool->updateHitPosition(cluster_as_FPGATrackSimhit, m_LorentzAngleShift));
87 }
88 tower.addHit(cluster_as_FPGATrackSimhit);
89 cluster.setClusterEquiv(cluster_as_FPGATrackSimhit);
90 //send back a copy for monitoring and to check when writing out hits in each road
91 clusters.push_back(cluster);
92 cluster_count++;
93 }
94 }
95 ATH_MSG_DEBUG("Produced "<< clusters.size()<< " clusters");
96 return StatusCode::SUCCESS;
97}
98
100 //Set the min and max indices for the cluster equivalent
101 FPGATrackSimHit clusterEquiv = cluster.getClusterEquiv();
102 int maxPhiIdx{-std::numeric_limits<int>::max()}, maxEtaIdx{-std::numeric_limits<int>::max()};
103 int minPhiIdx{std::numeric_limits<int>::max()}, minEtaIdx{std::numeric_limits<int>::max()};
104 for (const FPGATrackSimHit& hit : cluster.getHitList()){
105 maxPhiIdx = std::max(maxPhiIdx, static_cast<int>(hit.getPhiIndex()));
106 minPhiIdx = std::min(minPhiIdx, static_cast<int>(hit.getPhiIndex()));
107 maxEtaIdx = std::max(maxEtaIdx, static_cast<int>(hit.getEtaIndex()));
108 minEtaIdx = std::min(minEtaIdx, static_cast<int>(hit.getEtaIndex()));
109 }
110 clusterEquiv.setMinPhiIndex(minPhiIdx);
111 clusterEquiv.setMaxPhiIndex(maxPhiIdx);
112 clusterEquiv.setMinEtaIndex(minEtaIdx);
113 clusterEquiv.setMaxEtaIndex(maxEtaIdx);
114 cluster.setClusterEquiv(clusterEquiv);
115}
116
117//Attempt to implement clustering using FPGATrackSim objects.
118void FPGATrackSimClusteringTool::SortedClustering(HitPtrContainer&& sorted_hits, std::vector<FPGATrackSimCluster> &clusters) const {
119 std::vector<FPGATrackSimCluster> moduleClusters;
120 //Loop over the sorted modules that we have
121 for( HitPtrCollection & moduleHits: sorted_hits){
122 //Make the clusters for this module
123 Clustering(std::move(moduleHits), moduleClusters);
124 //Put these clusters into the output list
125 clusters.insert(clusters.end(), moduleClusters.begin(), moduleClusters.end());
126 //Clear the vector or this will get messy
127 moduleClusters.clear();
128 }
129}
130
131
132void FPGATrackSimClusteringTool::Clustering(HitPtrCollection &&moduleHits, std::vector<FPGATrackSimCluster> &moduleClusters) const {
133 FPGATrackSimHit clusterEquiv;
134 bool newHit;
135
136 //To hold the current cluster vars for comparison
137 //loop over the hits that we have been passed for this module
138 for( auto& hit: moduleHits){
139 bool is_clustered_hit = false;
140 std::vector<FPGATrackSimCluster>::iterator it_added_clus;
141
142 //Loop over the clusters we have already made, check if this hit should be added to them?
143 for(std::vector<FPGATrackSimCluster>::iterator it = moduleClusters.begin(); it != moduleClusters.end(); ++it) {
144 if(hit->isPixel()) {
146 if (!is_clustered_hit) {
147 is_clustered_hit = true;
148 it_added_clus = it;
149 } else {
150 int cPhi = it->getClusterEquiv().getPhiIndex();
151 int cPhiWidth = it->getClusterEquiv().getPhiWidth();
152 int cEta = it->getClusterEquiv().getEtaIndex();
153 int cEtaWidth = it->getClusterEquiv().getEtaWidth();
154 int fCPhi = it_added_clus->getClusterEquiv().getPhiIndex();
155 int fCPhiWidth = it_added_clus->getClusterEquiv().getPhiWidth();
156 int fCEta = it_added_clus->getClusterEquiv().getEtaIndex();
157 int fCEtaWidth = it_added_clus->getClusterEquiv().getEtaWidth();
158
159 clusterEquiv = it_added_clus->getClusterEquiv();
160
161 // set new phi & phi width
162 if (cPhi < fCPhi) {
163 clusterEquiv.setPhiIndex(cPhi);
164 if (cPhi + cPhiWidth < fCPhi + fCPhiWidth)
165 clusterEquiv.setPhiWidth(fCPhiWidth + (fCPhi - cPhi));
166 else
167 clusterEquiv.setPhiWidth(cPhiWidth);
168 } else {
169 clusterEquiv.setPhiIndex(fCPhi);
170 if (!(cPhi + cPhiWidth < fCPhi + fCPhiWidth))
171 clusterEquiv.setPhiWidth(cPhiWidth + (cPhi - fCPhi));
172 else
173 clusterEquiv.setPhiWidth(fCPhiWidth);
174 }
175
176 // set new eta & eta width
177 if (cEta < fCEta) {
178 clusterEquiv.setEtaIndex(cEta);
179 if (cEta + cEtaWidth < fCEta + fCEtaWidth)
180 clusterEquiv.setEtaWidth(fCEtaWidth + (fCEta - cEta));
181 else
182 clusterEquiv.setEtaWidth(cEtaWidth);
183 } else {
184 clusterEquiv.setEtaIndex(fCEta);
185 if (!(cEta + cEtaWidth < fCEta + fCEtaWidth))
186 clusterEquiv.setEtaWidth(cEtaWidth + (cEta - fCEta));
187 else
188 clusterEquiv.setEtaWidth(fCEtaWidth);
189 }
190
191 it_added_clus->setClusterEquiv(clusterEquiv);
192
193 for (auto& hit : it->getHitList()) {
194 newHit = true;
195 for (auto& finalHit : it_added_clus->getHitList()) {
196 if (hit.getEtaIndex() == finalHit.getEtaIndex() &&
197 hit.getPhiIndex() == finalHit.getPhiIndex())
198 newHit = false;
199 }
200 if (newHit) {
202 clusterEquiv = it_added_clus->getClusterEquiv();
203 float xOld = clusterEquiv.getX();
204 float yOld = clusterEquiv.getY();
205 float zOld = clusterEquiv.getZ();
206 float xPhiOld = clusterEquiv.getPhiCoord();
207 float xEtaOld = clusterEquiv.getEtaCoord();
208 float cPhiOld = clusterEquiv.getCentroidPhiIndex();
209 float cEtaOld = clusterEquiv.getCentroidEtaIndex();
210 float xNew = hit.getX();
211 float yNew = hit.getY();
212 float zNew = hit.getZ();
213 float xPhiNew = hit.getPhiCoord();
214 float xEtaNew = hit.getEtaCoord();
215 float cPhiNew = hit.getPhiIndex();
216 float cEtaNew = hit.getEtaIndex();
217 int tot = clusterEquiv.getToT();
218 int totNew = hit.getToT();
220 // n+1 because that is old + new now
221 int n = it_added_clus->getHitList().size();
222 clusterEquiv.setX((xOld*n + xNew) / (n+1));
223 clusterEquiv.setY((yOld*n + yNew) / (n+1));
224 clusterEquiv.setZ((zOld*n + zNew) / (n+1));
225 clusterEquiv.setPhiCoord((xPhiOld*n + xPhiNew) / (n+1));
226 clusterEquiv.setEtaCoord((xEtaOld*n + xEtaNew) / (n+1));
227 clusterEquiv.setCentroidPhiIndex((cPhiOld*n + cPhiNew) / (n+1));
228 clusterEquiv.setCentroidEtaIndex((cEtaOld*n + cEtaNew) / (n+1));
229 } else {
230 clusterEquiv.setX((xOld*tot + xNew*totNew) / (tot+totNew));
231 clusterEquiv.setY((yOld*tot + yNew*totNew) / (tot+totNew));
232 clusterEquiv.setZ((zOld*tot + zNew*totNew) / (tot+totNew));
233 clusterEquiv.setPhiCoord((xPhiOld*tot + xPhiNew*totNew) / (tot+totNew));
234 clusterEquiv.setEtaCoord((xEtaOld*tot + xEtaNew*totNew) / (tot+totNew));
235 clusterEquiv.setCentroidPhiIndex((cPhiOld*tot + cPhiNew*totNew) / (tot+totNew));
236 clusterEquiv.setCentroidEtaIndex((cEtaOld*tot + cEtaNew*totNew) / (tot+totNew));
237 }
238 clusterEquiv.setToT(tot + totNew);
239 it_added_clus->setClusterEquiv(clusterEquiv);
240 it_added_clus->push_backHitList(hit);
241 }
242 }
243
244 // move the last cluster to the newly freed spot in the cluster array if the merged cluster was not
245 // already the last cluster, decrease loop counter by one, so that this cluster gets also checked
246 // against the current hit
247 if (it != moduleClusters.end() - 1) {
248 *it = moduleClusters.back();
249 moduleClusters.pop_back();
250 it -= 1;
251 } else {
252 moduleClusters.pop_back();
253 break;
254 }
255 }
256 }
257 }
258 if(hit->isStrip()){
260 is_clustered_hit = true;
261 }
262 }
263
264 //If it is the first hit or a not clustered hit, then start a new cluster and add it to the output vector
265 if((!is_clustered_hit) || (moduleClusters.size() == 0)){
266 FPGATrackSimCluster cluster;
267 if(hit->isPixel()){
268 // No need to check the return code here
270 } else if(hit->isStrip()){
272 }
273 //Put this cluster into the output hits. Will update it in place.
274 moduleClusters.push_back(cluster);
275 }
276 }
277 moduleHits.clear();
278}
279
280void FPGATrackSimClusteringTool::splitAndSortHits(HitPtrCollection &&hits, HitPtrContainer &hitsPerModule, int &eta_phi) const {
281 splitHitsToModules(std::move(hits), hitsPerModule);
282 sortHitsOnModules(hitsPerModule, eta_phi);
283}
284
285
287 splitHitsToModules(std::move(hits), hitsPerModule);
288 sortHitsOnModules(hitsPerModule);
289}
290
291/*Temporarilly sort the hits into module by module packets
292*/
294 //To hold the current module
295 HitPtrCollection currentModule;
296 uint hashing = 0;
297 //Split the incoming hits into hits by module
298 for ( auto& hit:hits){
299 if(hashing == 0){
300 hashing = hit->getIdentifierHash();
301 currentModule.push_back(std::move(hit));
302 } else if (hit->getIdentifierHash() == hashing) {
303 currentModule.push_back(std::move(hit));
304 } else {
305 hitsPerModule.push_back(std::exchange(currentModule, HitPtrCollection{}));
306 hashing = hit->getIdentifierHash();
307 currentModule.push_back(std::move(hit));
308 }
309 }
310
311 // Now push that last one
312 if (currentModule.size() > 0) hitsPerModule.push_back(std::move(currentModule));
313}
314
315void FPGATrackSimClusteringTool::sortHitsOnModules(HitPtrContainer &hitsPerModule, int &eta_phi) const{
316 //Loop over the module separated hits
317 for ( auto& module:hitsPerModule){
318 //Work out if columns are ETA (1) || PHI (0)
319 if(etaOrPhi(*module.at(0)) == true){
320 //Sort by ETA first
321 eta_phi = ETA;
322 if (module.size() > 1) {
323 if (module.at(0)->isStrip())
324 std::stable_sort(module.begin(), module.end(), FPGATrackSimCLUSTERING::sortITkInputEta);
325 }
326 if (module.size() > 1) {
327 if (module.at(0)->isStrip())
328 std::stable_sort(module.begin(), module.end(), FPGATrackSimCLUSTERING::sortITkInputPhi);
329 }
330 } else {
331 //Sort by PHI first
332 eta_phi = PHI;
333 if (module.size() > 1) {
334 if (module.at(0)->isStrip())
335 std::stable_sort(module.begin(), module.end(), FPGATrackSimCLUSTERING::sortITkInputPhi);
336 }
337 if (module.size() > 1) {
338 if (module.at(0)->isStrip())
339 std::stable_sort(module.begin(), module.end(), FPGATrackSimCLUSTERING::sortITkInputEta);
340 }
341 }
342 }
343}
344
346 //Loop over the module separated hits
347 for ( auto& module:hitsPerModule){
348 if (module.size() > 1) {
349 if (module.at(0)->isStrip())
350 std::stable_sort(module.begin(), module.end(), FPGATrackSimCLUSTERING::sortITkInputEta);
351 }
352 if (module.size() > 1) {
353 if (module.at(0)->isStrip())
354 std::stable_sort(module.begin(), module.end(), FPGATrackSimCLUSTERING::sortITkInputPhi);
355 }
356 }
357}
358
359
360
361//Need to remove the fpgatracksim::scaleHitFactor and normalise the widths
362void FPGATrackSimClusteringTool::normaliseClusters(std::vector<FPGATrackSimCluster> &clusters) const {
363 for( auto &cluster:clusters){
364 //Grab the cluster equiv
365 FPGATrackSimHit clusterEquiv = cluster.getClusterEquiv();
366 //Update the clusterEquiv's position and width
367 if(clusterEquiv.isStrip()){
368 //Clear the groupsize, set this to be one as we are only clustering one row.
369 clusterEquiv.setEtaWidth(1);
371 clusterEquiv.setPhiWidth(clusterEquiv.getPhiWidth()+1);
372 } else {
373 // Nothing to normalise for pixel clusters
374 continue;
375 }
376 cluster.setClusterEquiv(clusterEquiv);
377 }
378}
379
380
381/*Function to work out if we need to sort by eta or phi first.
382 *Depends on the position and orientation of the module in the detector.
383 * Currently backwards engineered from the MC. Need to ask ITk people to confirm.
384 */
386
387 /*This currently might get complicated as eta/phi ordering varies depending on the position in the detector.
388 * For ITK-20-00-00 Step 2.2 inclined duals layout, worked out by Naoki.
389 * Detector position | Module Type (# chip) | Column | Row |
390 * =============================================================================
391 * Barrel Layer 0 Eta module 1-6 | 2 (double) | eta | phi |
392 * Barrel Layer 0 Eta module 7-22 | 1 (single) | phi | eta |
393 * Barrel Layer 1 Eta module 1-6 | 3 (quad) | eta | phi |
394 * Barrel Layer 1 Eta module 7-19 | 3 | phi | eta |
395 * Barrel Layer 2 Eta module 1-11 | 3 | eta | phi |
396 * Barrel Layer 2 Eta module 12-22 | 2 | phi | eta |
397 * Barrel Layer 3 Eta module 1-12 | 3 | eta | phi |
398 * Barrel Layer 3 Eta module 13-25 | 2 | phi | eta |
399 * Barrel Layer 4 Eta module 1-13 | 3 | eta | phi |
400 * Barrel Layer 4 Eta module 14-26 | 2 | phi | eta |
401 * All Endcap modules | 3 | eta | phi |
402 * =============================================================================
403 * Module Type 1 = Single, 2, Dual, 3 Quad
404 * 328x400 blocks
405 * Hit type is essentially isPixel
406 * DetectorZone 0 = Barrel, -ive/+ive = endcaps
407 */
408
409 //Check if the two hits are from the same module
410 //If it is not a barrel module then sort eta as column
412 return ETA;
413 }
414 //Otherwise it is a barrel module and now things get more complicated
415 else {
416 //Start by looking at what layer it is in
417 if (hit.getPhysLayer() == 0 || hit.getPhysLayer() == 1) {
418 if (hit.getEtaModule() <=6) {
419 return ETA;
420 } else {
421 return PHI;
422 }
423 } else if (hit.getPhysLayer() == 2) {
424 if (hit.getEtaModule() <=11) {
425 return ETA;
426 } else {
427 return PHI;
428 }
429 } else if (hit.getPhysLayer() == 3) {
430 if (hit.getEtaModule() <=12) {
431 return ETA;
432 } else {
433 return PHI;
434 }
435 } else if (hit.getPhysLayer() == 4) {
436 if (hit.getEtaModule() <=13) {
437 return ETA;
438 } else {
439 return PHI;
440 }
441 }
442 }
443 //Default to ETA, but shouldn't reach here
444 return ETA;
445}
446
447
448
449void FPGATrackSimCLUSTERING::attachTruth(std::vector<FPGATrackSimHit> &hits){
450 for( auto& hit : hits) {
452 // record highest pt contribution to the combination (cluster
453 if(!hit.getTruth().isEmpty()) {
454 mt.add(hit.getTruth());
455 hit.setTruth(mt);
456 } else {
457 FPGATrackSimMultiTruth::Barcode uniquecode(hit.getEventIndex(), hit.getBarcode());
458 mt.maximize(uniquecode, hit.getBarcodePt());
459 hit.setTruth(mt);
460 }
461 }
462} //record truth for each raw channel in the cluster
463
464/*
465 * This function is used in the FPGATrackSimClusteringTools to see if a new hit should be added to the current cluster under construction.
466 * It checks if the hit is in a number of positions w.r.t. the cluster being formed: up/right, down/right, above, right, or inside a cluster that has formed a horseshoe.
467 */
468bool FPGATrackSimCLUSTERING::updatePixelCluster(FPGATrackSimCluster &currentCluster, FPGATrackSimHit &incomingHit, bool newCluster, bool digitalClustering){
469
470 if(newCluster){
471 FPGATrackSimHit newHit = incomingHit;
472 newHit.setEtaIndex(incomingHit.getEtaIndex());
473 newHit.setPhiIndex(incomingHit.getPhiIndex());
474 newHit.setEtaCoord(incomingHit.getEtaCoord());
475 newHit.setPhiCoord(incomingHit.getPhiCoord());
476 newHit.setCentroidPhiIndex(incomingHit.getPhiIndex());
477 newHit.setCentroidEtaIndex(incomingHit.getEtaIndex());
478 newHit.setEtaWidth(1);
479 newHit.setPhiWidth(1);
480 //Set the initial clusterEquiv to be the incoming hit with double precision
481 currentCluster.setClusterEquiv(newHit);
482 //Add the current hit to the list of hits
483 currentCluster.push_backHitList(incomingHit);
484 //It doesn't really matter, as we will be at the end of the hit loop, but we did technically "cluster" this hit
485 return true;
486 } else {
487 int hitCol = incomingHit.getEtaIndex();
488 int hitRow = incomingHit.getPhiIndex();
489
490 FPGATrackSimHit clusterEquiv = currentCluster.getClusterEquiv();
491 int clusterCol = clusterEquiv.getEtaIndex();
492 int clusterColWidth = clusterEquiv.getEtaWidth();
493 int clusterRow = clusterEquiv.getPhiIndex();
494 int clusterRowWidth = clusterEquiv.getPhiWidth();
495
496 if ((hitCol == clusterCol + clusterColWidth) && (hitRow == clusterRow + clusterRowWidth)) {
497 clusterColWidth++;
498 clusterRowWidth++;
499
500 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
501 } else if ((hitCol == clusterCol + clusterColWidth) && (hitRow == clusterRow - 1)) {
502 clusterColWidth++;
503 clusterRow--;
504 clusterRowWidth++;
505
506 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
507 } else if ((hitCol >= clusterCol) && (hitCol < clusterCol + clusterColWidth) && (hitRow == clusterRow + clusterRowWidth)) {
508 clusterRowWidth++;
509
510 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
511 } else if ((hitCol == clusterCol + clusterColWidth) && (hitRow >= clusterRow) && (hitRow < clusterRow + clusterRowWidth)) {
512 clusterColWidth++;
513
514 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
515 } else if ((hitCol >= clusterCol) && (hitCol < clusterCol + clusterColWidth) && (hitRow == clusterRow - 1)) {
516 clusterRow--;
517 clusterRowWidth++;
518
519 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
520 } else if ((hitCol == clusterCol - 1) && (hitRow == clusterRow - 1)) {
521 clusterCol--;
522 clusterColWidth++;
523 clusterRow--;
524 clusterRowWidth++;
525
526 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
527 } else if ((hitCol == clusterCol - 1) && (hitRow >= clusterRow) && (hitRow < clusterRow + clusterRowWidth)) {
528 clusterCol--;
529 clusterColWidth++;
530
531 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
532 } else if ((hitCol == clusterCol - 1) && (hitRow == clusterRow + clusterRowWidth)) {
533 clusterCol--;
534 clusterColWidth++;
535 clusterRowWidth++;
536
537 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
538 } else if ((hitCol >= clusterCol) && (hitCol < clusterCol + clusterColWidth) && (hitRow >= clusterRow) && (hitRow < clusterRow + clusterRowWidth)) {
539 return FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
540 } else {
541 return false;
542 }
543 }
544}
545
546/*
547 * This function is used in the FPGATrackSimClusteringTools to see if a new hit should be added to the current cluster under construction. It assumes double precision hits.
548 * It checks if the hit is in a number of positions w.r.t. the cluster being formed: up/right, down/right, above, right, or inside a cluster that has formed a horseshoe.
549 */
550bool FPGATrackSimCLUSTERING::updateStripCluster(FPGATrackSimCluster &currentCluster, FPGATrackSimHit &incomingHit, bool newCluster, bool digitalClustering){
551
553
554 // Shift initial widths 1->0, 2->2, 3->4, 4->6 etc...
555 //The groupSize is stored in the EtaWidth
557 // Now shift to pixel width equivalents, 0->0, 2->1, 4->2, 6->3 etc...
558 if(tempWidth > 0) tempWidth = tempWidth/fpgatracksim::scaleHitFactor;
559 if(newCluster){
560 FPGATrackSimHit newHit = incomingHit;
561 //Double the precision of the strip positions.
562 int tempCentroid = incomingHit.getPhiIndex()*fpgatracksim::scaleHitFactor;
563 // Now shift the centroid phi+phiWidth, and store the width (put it back in the PhiWidth)
564 newHit.setPhiIndex(incomingHit.getPhiIndex());
565 newHit.setCentroidPhiIndex(tempCentroid+tempWidth);
566 newHit.setPhiWidth(tempWidth);
567 //Set the initial clusterEquiv to be the incoming hit with double precision
568 currentCluster.setClusterEquiv(newHit);
569 //Add the current hit to the list of hits
570 currentCluster.push_backHitList(incomingHit);
571 //It doesn't really matter, as we will be at the end of the hit loop, but we did technically "cluster" this hit
572 return true;
573 } else {
574 //Now get the --START-- of the new strip cluster
575 int hitRow = incomingHit.getEtaIndex();
576 int hitCol = incomingHit.getPhiIndex()*fpgatracksim::scaleHitFactor;
577
578 FPGATrackSimHit clusterEquiv = currentCluster.getClusterEquiv();
579 int clusterRow = clusterEquiv.getEtaIndex();
580 int clusterRowWidth = clusterEquiv.getEtaWidth();
581 int clusterCol = clusterEquiv.getCentroidPhiIndex();
582 int clusterColWidth = clusterEquiv.getPhiWidth();
583
584 //Looking for a neighbour to the right. i.e. find the end of the current cluster (Col+width) and look in the next cell (+2). Compare this to the start of the new cluster. This is unlikely/impossible(?) to happen due to preclustering.
585 if(hitCol == clusterCol+clusterColWidth+fpgatracksim::scaleHitFactor && hitRow == clusterRow) {
586 //The new centroid will be the original column position, minus its width, plus the new width
587 //So subtract the original width...
588 clusterCol = clusterCol - clusterColWidth;
589 //The new width will be the combination of the current widths, ++
590 clusterColWidth = clusterColWidth+tempWidth+1;
591 //And add on the new width
592 clusterCol = clusterCol + clusterColWidth;
593 FPGATrackSimCLUSTERING::updateClusterContents(currentCluster, clusterRow, clusterRowWidth, clusterCol, clusterColWidth, incomingHit, digitalClustering);
594 return true;
595 } else return false;
596 }
597}
598
599
600bool FPGATrackSimCLUSTERING::updateClusterContents(FPGATrackSimCluster &currentCluster, int &clusterRow, int &clusterRowWidth, int &clusterCol, int &clusterColWidth, FPGATrackSimHit &incomingHit, bool digitalClustering) {
601 //Grab the cluster equiv
602 FPGATrackSimHit clusterEquiv = currentCluster.getClusterEquiv();
603 bool isConnected = false;
604
605 //Check if connected to another hit in the cluster
606 if(incomingHit.isPixel()){
607 for (auto & hit : currentCluster.getHitList()) {
608 auto hitEta = hit.getEtaIndex();
609 auto hitPhi = hit.getPhiIndex();
610 auto inHitEta = incomingHit.getEtaIndex();
611 auto inHitPhi = incomingHit.getPhiIndex();
612
613 if (((inHitEta == hitEta - 1) && (inHitPhi == hitPhi - 1)) ||
614 ((inHitEta == hitEta + 1) && (inHitPhi == hitPhi - 1)) ||
615 ((inHitEta == hitEta - 1) && (inHitPhi == hitPhi + 1)) ||
616 ((inHitEta == hitEta + 1) && (inHitPhi == hitPhi + 1)) ||
617 ((inHitEta == hitEta) && (inHitPhi == hitPhi - 1)) ||
618 ((inHitEta == hitEta) && (inHitPhi == hitPhi + 1)) ||
619 ((inHitEta == hitEta - 1) && (inHitPhi == hitPhi)) ||
620 ((inHitEta == hitEta + 1) && (inHitPhi == hitPhi))) {
621 isConnected = true;
622 break;
623 }
624 }
625 if (!isConnected)
626 return false;
627 }
628
629 //Update the clusterEquiv's position and width
630 if (incomingHit.isPixel()) {
631 clusterEquiv.setEtaIndex(clusterCol);
632 clusterEquiv.setEtaWidth(clusterColWidth);
633 clusterEquiv.setPhiIndex(clusterRow);
634 clusterEquiv.setPhiWidth(clusterRowWidth);
635 } else {
636 clusterEquiv.setEtaIndex(clusterRow);
637 clusterEquiv.setEtaWidth(clusterRowWidth);
638 clusterEquiv.setCentroidPhiIndex(clusterCol);
639 clusterEquiv.setPhiWidth(clusterColWidth);
640 }
641
642
643 float xOld = clusterEquiv.getX();
644 float yOld = clusterEquiv.getY();
645 float zOld = clusterEquiv.getZ();
646 float xPhiOld = clusterEquiv.getPhiCoord();
647 float xEtaOld = clusterEquiv.getEtaCoord();
648 float cPhiOld = clusterEquiv.getCentroidPhiIndex();
649 float cEtaOld = clusterEquiv.getCentroidEtaIndex();
650 float xNew = incomingHit.getX();
651 float yNew = incomingHit.getY();
652 float zNew = incomingHit.getZ();
653 float xPhiNew = incomingHit.getPhiCoord();
654 float xEtaNew = incomingHit.getEtaCoord();
655 float cPhiNew = incomingHit.getPhiIndex();
656 float cEtaNew = incomingHit.getEtaIndex();
657 int tot = clusterEquiv.getToT();
658 int totNew = incomingHit.getToT();
659 //As strips arrive pre-clustered, this is different for pixels/strips
660 if(incomingHit.isPixel()){
662 if (digitalClustering) {
663 // n+1 because that is old + new now
664 int n = currentCluster.getHitList().size();
665 clusterEquiv.setX((xOld*n + xNew) / (n+1));
666 clusterEquiv.setY((yOld*n + yNew) / (n+1));
667 clusterEquiv.setZ((zOld*n + zNew) / (n+1));
668 clusterEquiv.setPhiCoord((xPhiOld*n + xPhiNew) / (n+1));
669 clusterEquiv.setEtaCoord((xEtaOld*n + xEtaNew) / (n+1));
670 clusterEquiv.setCentroidPhiIndex((cPhiOld*n + cPhiNew) / (n+1));
671 clusterEquiv.setCentroidEtaIndex((cEtaOld*n + cEtaNew) / (n+1));
672 } else {
673 clusterEquiv.setX((xOld*tot + xNew*totNew) / (tot+totNew));
674 clusterEquiv.setY((yOld*tot + yNew*totNew) / (tot+totNew));
675 clusterEquiv.setZ((zOld*tot + zNew*totNew) / (tot+totNew));
676 clusterEquiv.setPhiCoord((xPhiOld*tot + xPhiNew*totNew) / (tot+totNew));
677 clusterEquiv.setEtaCoord((xEtaOld*tot + xEtaNew*totNew) / (tot+totNew));
678 clusterEquiv.setCentroidPhiIndex((cPhiOld*tot + cPhiNew*totNew) / (tot+totNew));
679 clusterEquiv.setCentroidEtaIndex((cEtaOld*tot + cEtaNew*totNew) / (tot+totNew));
680 }
681 } else {
682 //Phi width + 1 for the seed is the width of the current cluster
683 int N = currentCluster.getClusterEquiv().getPhiWidth()+1;
684 //Phi width of an incoming strip is the width of the cluster
685 int newN = incomingHit.getPhiWidth();
686 //Now as above, N+newN
687 clusterEquiv.setPhiCoord((xPhiOld*N + xPhiNew*newN) / (N+newN));
688 clusterEquiv.setX((xOld*N + xNew*newN) / (N+newN));
689 clusterEquiv.setY((yOld*N + yNew*newN) / (N+newN));
690 clusterEquiv.setZ((zOld*N + zNew*newN) / (N+newN));
691 }
692 clusterEquiv.setToT(tot + totNew);
693
694 //Put it back
695 currentCluster.setClusterEquiv(clusterEquiv);
696
697 //Pushback the hit into the hitlist
698 currentCluster.push_backHitList(incomingHit);
699
700 return true;
701}
702
703/* Sort for the ordering of ITk modules: Sort by ETA.
704*/
705bool FPGATrackSimCLUSTERING::sortITkInputEta(const std::unique_ptr<FPGATrackSimHit>& hitA, const std::unique_ptr<FPGATrackSimHit>& hitB)
706{
707 if (hitA->getIdentifierHash() != hitB->getIdentifierHash())
708 return hitA->getIdentifierHash() < hitB->getIdentifierHash();
709 return hitA->getEtaIndex() < hitB->getEtaIndex();
710}
711
712/* Sort for the ordering of ITk modules: Sort by PHI.
713*/
714bool FPGATrackSimCLUSTERING::sortITkInputPhi(const std::unique_ptr<FPGATrackSimHit>& hitA, const std::unique_ptr<FPGATrackSimHit>& hitB)
715{
716 if (hitA->getIdentifierHash() != hitB->getIdentifierHash())
717 return hitA->getIdentifierHash() < hitB->getIdentifierHash();
718 return hitA->getPhiIndex() < hitB->getPhiIndex();
719}
720
721/* Cap precision of the global coordinates in r, phi, z */
723 FPGATrackSimHit clusterEquiv = cluster.getClusterEquiv();
724 float pos[3] = { clusterEquiv.getR(), clusterEquiv.getGPhi(), clusterEquiv.getZ() };
725
726 pos[0] = std::trunc(pos[0] / m_coordRPrecision) * m_coordRPrecision;
727 pos[1] = std::trunc(pos[1] / m_coordPhiPrecision) * m_coordPhiPrecision;
728 pos[2] = std::trunc(pos[2] / m_coordZPrecision) * m_coordZPrecision;
729
730 clusterEquiv.setX(pos[0] * std::cos(pos[1]));
731 clusterEquiv.setY(pos[0] * std::sin(pos[1]));
732 clusterEquiv.setZ(pos[2]);
733
734 cluster.setClusterEquiv(clusterEquiv);
735}
736
738 float pos[3] = { hit.getR(), hit.getGPhi(), hit.getZ() };
739
740 pos[0] = std::trunc(pos[0] / m_coordRPrecision) * m_coordRPrecision;
741 pos[1] = std::trunc(pos[1] / m_coordPhiPrecision) * m_coordPhiPrecision;
742 pos[2] = std::trunc(pos[2] / m_coordZPrecision) * m_coordZPrecision;
743
744 hit.setX(pos[0] * std::cos(pos[1]));
745 hit.setY(pos[0] * std::sin(pos[1]));
746 hit.setZ(pos[2]);
747}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
unsigned int uint
void setClusterEquiv(const FPGATrackSimHit &input)
hitVector const & getHitList() const
FPGATrackSimHit const & getClusterEquiv() const
void push_backHitList(const FPGATrackSimHit &input)
Gaudi::Property< float > m_coordRPrecision
FPGATrackSimClusteringTool(const std::string &, const std::string &, const IInterface *)
Gaudi::Property< int > m_LorentzAngleShift
void sortHitsOnModules(HitPtrContainer &hitsPerModule, int &eta_phi) const
void reduceGlobalCoordPrecision(FPGATrackSimCluster &cluster) const
void SetMinMaxIndicies(FPGATrackSimCluster &cluster) const
void splitAndSortHits(HitPtrCollection &&hits, HitPtrContainer &hitsPerModule, int &eta_phi) const
Gaudi::Property< bool > m_reduceCoordPrecision
Gaudi::Property< float > m_coordZPrecision
void splitHitsToModules(HitPtrCollection &&hits, HitPtrContainer &hitsPerModule) const
void normaliseClusters(std::vector< FPGATrackSimCluster > &clusters) const
std::vector< std::unique_ptr< FPGATrackSimHit > > HitPtrCollection
void Clustering(HitPtrCollection &&, std::vector< FPGATrackSimCluster > &) const
virtual StatusCode initialize() override
ToolHandle< FPGATrackSim::LorentzAngleTool > m_lorentzAngleTool
Gaudi::Property< float > m_coordPhiPrecision
std::vector< HitPtrCollection > HitPtrContainer
bool etaOrPhi(const FPGATrackSimHit &hit) const
void SortedClustering(HitPtrContainer &&sorted_hits, std::vector< FPGATrackSimCluster > &) const
virtual StatusCode DoClustering(FPGATrackSimLogicalEventInputHeader &, std::vector< FPGATrackSimCluster > &) const override
Gaudi::Property< bool > m_digitalClustering
float getY() const
unsigned getToT() const
unsigned getPhiIndex() const
void setMinEtaIndex(int v)
void setCluster1ID(int v)
void setEtaIndex(unsigned v)
void setPhiIndex(unsigned v)
void setMinPhiIndex(int v)
float getPhiCoord() const
float getX() const
float getCentroidPhiIndex() const
void setHitType(HitType type)
float getGPhi() const
int getEtaModule(bool old=false) const
float getZ() const
void setPhiCoord(float v)
void setZ(float v)
float getR() const
unsigned getPhysLayer(bool old=false) const
void setX(float v)
void setCentroidPhiIndex(float v)
void setParentageMask(unsigned long v)
SiliconTech getDetType() const
void setToT(unsigned v)
bool isPixel() const
void setMaxEtaIndex(int v)
void setY(float v)
unsigned getEtaWidth() const
float getEtaCoord() const
DetectorZone getDetectorZone() const
void setEtaCoord(float v)
void setMaxPhiIndex(int v)
void setEtaWidth(unsigned v)
bool isStrip() const
void setPhiWidth(unsigned v)
float getCentroidEtaIndex() const
unsigned getEtaIndex() const
void setCentroidEtaIndex(float v)
unsigned getPhiWidth() const
void add(const FPGATrackSimMultiTruth::Barcode &code, const FPGATrackSimMultiTruth::Weight &weight)
void maximize(const FPGATrackSimMultiTruth::Barcode &code, const FPGATrackSimMultiTruth::Weight &weight)
std::pair< unsigned long, unsigned long > Barcode
const std::vector< FPGATrackSimHit > & hits() const
void addHit(const FPGATrackSimHit &s)
bool sortITkInputEta(const std::unique_ptr< FPGATrackSimHit > &hitA, const std::unique_ptr< FPGATrackSimHit > &hitB)
bool sortITkInputPhi(const std::unique_ptr< FPGATrackSimHit > &hitA, const std::unique_ptr< FPGATrackSimHit > &HitB)
bool updatePixelCluster(FPGATrackSimCluster &currentCluster, FPGATrackSimHit &incomingHit, bool newCluster, bool digitalClustering)
bool updateStripCluster(FPGATrackSimCluster &currentCluster, FPGATrackSimHit &incomingHit, bool newCluster, bool digitalClustering)
bool updateClusterContents(FPGATrackSimCluster &currentCluster, int &clusterRow, int &clusterRowWidth, int &clusterCol, int &clusterColWidth, FPGATrackSimHit &incomingHit, bool digitalClustering)
void attachTruth(std::vector< FPGATrackSimHit > &)
constexpr float scaleHitFactor
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP
Definition trapping_fp.h:24