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