Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
InttClusterizer.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file InttClusterizer.cc
1 #include "InttClusterizer.h"
2 #include "CylinderGeomIntt.h"
3 
4 #include <trackbase/InttDefs.h>
9 #include <trackbase/TrkrHit.h>
10 #include <trackbase/TrkrHitSet.h>
12 
14 #include <trackbase/RawHit.h>
15 #include <trackbase/RawHitSet.h>
17 
20 
22 #include <fun4all/SubsysReco.h>
23 
24 #include <phool/PHCompositeNode.h>
25 #include <phool/PHIODataNode.h>
26 #include <phool/PHNode.h>
27 #include <phool/PHNodeIterator.h>
28 #include <phool/PHObject.h> // for PHObject
29 #include <phool/getClass.h>
30 #include <phool/phool.h>
31 
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
34 #pragma GCC diagnostic ignored "-Wshadow"
35 #include <boost/graph/adjacency_list.hpp>
36 #include <boost/graph/connected_components.hpp>
37 #pragma GCC diagnostic pop
38 
39 #include <array>
40 #include <cmath>
41 #include <iostream>
42 #include <memory> // for unique_ptr, make_...
43 #include <set>
44 #include <vector> // for vector
45 
46 namespace
47 {
48 
50  template <class T>
51  inline constexpr T square(const T& x)
52  {
53  return x * x;
54  }
55 } // namespace
56 
57 bool InttClusterizer::ladder_are_adjacent(const std::pair<TrkrDefs::hitkey, TrkrHit*>& lhs, const std::pair<TrkrDefs::hitkey, TrkrHit*>& rhs, const int layer)
58 {
59  if (get_z_clustering(layer))
60  {
61  if (fabs(InttDefs::getCol(lhs.first) - InttDefs::getCol(rhs.first)) <= 1)
62  {
63  if (fabs(InttDefs::getRow(lhs.first) - InttDefs::getRow(rhs.first)) <= 1)
64  {
65  return true;
66  }
67  }
68  }
69  else if (fabs(InttDefs::getCol(lhs.first) - InttDefs::getCol(rhs.first)) == 0)
70  {
71  if (fabs(InttDefs::getRow(lhs.first) - InttDefs::getRow(rhs.first)) <= 1)
72  {
73  return true;
74  }
75  }
76 
77  return false;
78 }
79 
81 {
82  if (get_z_clustering(layer))
83  {
84  if (fabs(lhs->getPhiBin() - rhs->getPhiBin()) <= 1) // col
85  {
86  if (fabs(lhs->getTBin() - rhs->getTBin()) <= 1) // Row
87  {
88  return true;
89  }
90  }
91  }
92  else if (fabs(lhs->getPhiBin() - rhs->getPhiBin()) <= 1)
93  {
94  if (fabs(lhs->getTBin() - rhs->getTBin()) == 0)
95  {
96  return true;
97  }
98  }
99 
100  return false;
101 }
102 
104  unsigned int /*min_layer*/,
105  unsigned int /*max_layer*/)
106  : SubsysReco(name)
107 {
108 }
109 
111 {
112  /*
113  // get node containing the digitized hits
114  _hits = findNode::getClass<SvtxHitMap>(topNode, "SvtxHitMap");
115  if (!_hits)
116  {
117  std::cout << PHWHERE << "ERROR: Can't find node SvtxHitMap" << std::endl;
118  return Fun4AllReturnCodes::ABORTRUN;
119  }
120  */
121 
122  //-----------------
123  // Add Cluster Node
124  //-----------------
125 
126  PHNodeIterator iter(topNode);
127 
128  // Looking for the DST node
129  PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
130  if (!dstNode)
131  {
132  std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
134  }
135  PHNodeIterator iter_dst(dstNode);
136 
137  // Create the Cluster and association nodes if required
138  auto trkrclusters = findNode::getClass<TrkrClusterContainer>(dstNode, "TRKR_CLUSTER");
139  if (!trkrclusters)
140  {
141  PHNodeIterator dstiter(dstNode);
142  PHCompositeNode* DetNode =
143  dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", "TRKR"));
144  if (!DetNode)
145  {
146  DetNode = new PHCompositeNode("TRKR");
147  dstNode->addNode(DetNode);
148  }
149 
150  trkrclusters = new TrkrClusterContainerv4;
151  PHIODataNode<PHObject>* TrkrClusterContainerNode =
152  new PHIODataNode<PHObject>(trkrclusters, "TRKR_CLUSTER", "PHObject");
153  DetNode->addNode(TrkrClusterContainerNode);
154  }
155 
156  auto clusterhitassoc = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
157  if (!clusterhitassoc)
158  {
159  PHNodeIterator dstiter(dstNode);
160  PHCompositeNode* DetNode =
161  dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", "TRKR"));
162  if (!DetNode)
163  {
164  DetNode = new PHCompositeNode("TRKR");
165  dstNode->addNode(DetNode);
166  }
167 
168  clusterhitassoc = new TrkrClusterHitAssocv3;
169  PHIODataNode<PHObject>* newNode = new PHIODataNode<PHObject>(clusterhitassoc, "TRKR_CLUSTERHITASSOC", "PHObject");
170  DetNode->addNode(newNode);
171  }
172 
173  // Add the multimap holding the INTT cluster-crossing associations
174  {
175  PHNodeIterator dstiter(dstNode);
176  PHCompositeNode* DetNode =
177  dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", "TRKR"));
178  if (!DetNode)
179  {
180  DetNode = new PHCompositeNode("TRKR");
181  dstNode->addNode(DetNode);
182  }
183 
184  auto clustercrossingassoc = new TrkrClusterCrossingAssocv1;
185  PHIODataNode<PHObject>* newNode = new PHIODataNode<PHObject>(clustercrossingassoc, "TRKR_CLUSTERCROSSINGASSOC", "PHObject");
186  DetNode->addNode(newNode);
187  }
188 
189  //---------------------
190  // Calculate Thresholds
191  //---------------------
192 
193  CalculateLadderThresholds(topNode);
194 
195  //----------------
196  // Report Settings
197  //----------------
198 
199  if (Verbosity() > 0)
200  {
201  std::cout << "====================== InttClusterizer::InitRun() =====================" << std::endl;
202  std::cout << " Fraction of expected thickness MIP energy = " << _fraction_of_mip << std::endl;
203  for (auto& iter_tmp : _thresholds_by_layer)
204  {
205  std::cout << " Cluster Threshold in Layer #" << iter_tmp.first << " = " << 1.0e6 * iter_tmp.second << " keV" << std::endl;
206  }
207  for (auto& iter_tmp : _make_z_clustering)
208  {
209  std::cout << " Z-dimension Clustering in Layer #" << iter_tmp.first << " = " << std::boolalpha << iter_tmp.second << std::noboolalpha << std::endl;
210  }
211  for (auto& _make_e_weight : _make_e_weights)
212  {
213  std::cout << " Energy weighting clusters in Layer #" << _make_e_weight.first << " = " << std::boolalpha << _make_e_weight.second << std::noboolalpha << std::endl;
214  }
215  std::cout << "===========================================================================" << std::endl;
216  }
217 
219  {
220  // get the node
221  mClusHitsVerbose = findNode::getClass<ClusHitsVerbosev1>(topNode, "Trkr_SvtxClusHitsVerbose");
222  if (!mClusHitsVerbose)
223  {
224  PHNodeIterator dstiter(dstNode);
225  auto DetNode = dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", "TRKR"));
226  if (!DetNode)
227  {
228  DetNode = new PHCompositeNode("TRKR");
229  dstNode->addNode(DetNode);
230  }
232  auto newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject");
233  DetNode->addNode(newNode);
234  }
235  }
236 
238 }
239 
241 {
242  // get node containing the digitized hits
243  if (!do_read_raw)
244  {
245  m_hits = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
246  if (!m_hits)
247  {
248  std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl;
250  }
251  }
252  else
253  {
254  // get node containing the digitized hits
255  m_rawhits = findNode::getClass<RawHitSetContainer>(topNode, "TRKR_RAWHITSET");
256  if (!m_rawhits)
257  {
258  std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl;
260  }
261  }
262 
263  // get node for clusters
264  m_clusterlist = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
265  if (!m_clusterlist)
266  {
267  std::cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTER." << std::endl;
269  }
270 
271  // get node for cluster hit associations
272  m_clusterhitassoc = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
273  if (!m_clusterhitassoc)
274  {
275  std::cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTERHITASSOC" << std::endl;
277  }
278 
279  // get node for cluster-crossing associations
280  m_clustercrossingassoc = findNode::getClass<TrkrClusterCrossingAssoc>(topNode, "TRKR_CLUSTERCROSSINGASSOC");
282  {
283  std::cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTERCROSINGASSOC" << std::endl;
285  }
286 
287  if (!do_read_raw)
288  {
289  ClusterLadderCells(topNode);
290  }
291  else
292  {
293  ClusterLadderCellsRaw(topNode);
294  }
295  PrintClusters(topNode);
296 
298 }
299 
301 {
302  /*
303  PHG4CellContainer* cells = findNode::getClass<PHG4CellContainer>(topNode, "G4CELL_INTT");
304  if (!cells) return;
305  */
306 
307  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_INTT");
308  if (!geom_container)
309  {
310  return;
311  }
312 
313  PHG4CylinderGeomContainer::ConstRange layerrange = geom_container->get_begin_end();
314  for (PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first;
315  layeriter != layerrange.second;
316  ++layeriter)
317  {
318  // index mapping
319  int layer = layeriter->second->get_layer();
320 
321  // cluster threshold
322  float thickness = (layeriter->second)->get_thickness();
323  float threshold = _fraction_of_mip * 0.003876 * thickness;
324  _thresholds_by_layer.insert(std::make_pair(layer, threshold));
325 
326  // fill in a default z_clustering value if not present
327  if (_make_z_clustering.find(layer) == _make_z_clustering.end())
328  {
329  _make_z_clustering.insert(std::make_pair(layer, false));
330  }
331 
332  if (_make_e_weights.find(layer) == _make_e_weights.end())
333  {
334  _make_e_weights.insert(std::make_pair(layer, false));
335  }
336  }
337 
338  return;
339 }
340 
342 {
343  if (Verbosity() > 0)
344  {
345  std::cout << "Entering InttClusterizer::ClusterLadderCells " << std::endl;
346  }
347 
348  //----------
349  // Get Nodes
350  //----------
351 
352  // get the geometry node
353  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_INTT");
354  if (!geom_container)
355  {
356  return;
357  }
358 
359  //-----------
360  // Clustering
361  //-----------
362 
363  // loop over the InttHitSet objects
364  TrkrHitSetContainer::ConstRange hitsetrange =
366  for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
367  hitsetitr != hitsetrange.second;
368  ++hitsetitr)
369  {
370  // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor
371  TrkrHitSet* hitset = hitsetitr->second;
372 
373  if (Verbosity() > 1)
374  {
375  std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl;
376  }
377  if (Verbosity() > 2)
378  {
379  hitset->identify();
380  }
381 
382  // we have a single hitset, get the info that identifies the sensor
383  int layer = TrkrDefs::getLayer(hitsetitr->first);
384  int ladder_z_index = InttDefs::getLadderZId(hitsetitr->first);
385 
386  // we will need the geometry object for this layer to get the global position
387  CylinderGeomIntt* geom = dynamic_cast<CylinderGeomIntt*>(geom_container->GetLayerGeom(layer));
388  float pitch = geom->get_strip_y_spacing();
389  float length = geom->get_strip_z_spacing();
390 
391  // fill a vector of hits to make things easier - gets every hit in the hitset
392  std::vector<std::pair<TrkrDefs::hitkey, TrkrHit*>> hitvec;
393  TrkrHitSet::ConstRange hitrangei = hitset->getHits();
394  for (TrkrHitSet::ConstIterator hitr = hitrangei.first;
395  hitr != hitrangei.second;
396  ++hitr)
397  {
398  hitvec.emplace_back(hitr->first, hitr->second);
399  }
400  if (Verbosity() > 2)
401  {
402  std::cout << "hitvec.size(): " << hitvec.size() << std::endl;
403  }
404 
405  using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
406  Graph G;
407 
408  // Find adjacent strips
409  for (unsigned int i = 0; i < hitvec.size(); i++)
410  {
411  for (unsigned int j = i + 1; j < hitvec.size(); j++)
412  {
413  if (ladder_are_adjacent(hitvec[i], hitvec[j], layer))
414  {
415  add_edge(i, j, G);
416  }
417  }
418 
419  add_edge(i, i, G);
420  }
421 
422  // Find the connections between the vertices of the graph (vertices are the rawhits,
423  // connections are made when they are adjacent to one another)
424  std::vector<int> component(num_vertices(G));
425 
426  // this is the actual clustering, performed by boost
427  connected_components(G, &component[0]);
428 
429  // Loop over the components(hit cells) compiling a list of the
430  // unique connected groups (ie. clusters).
431  std::set<int> cluster_ids; // unique components
432 
433  std::multimap<int, std::pair<TrkrDefs::hitkey, TrkrHit*>> clusters;
434  for (unsigned int i = 0; i < component.size(); i++)
435  {
436  cluster_ids.insert(component[i]); // one entry per unique cluster id
437  clusters.insert(std::make_pair(component[i], hitvec[i])); // multiple entries per unique cluster id
438  }
439 
440  // loop over the cluster ID's and make the clusters from the connected hits
441  for (int clusid : cluster_ids)
442  {
443  // std::cout << " intt clustering: add cluster number " << clusid << std::endl;
444  // get all hits for this cluster ID only
445  std::pair<std::multimap<int, std::pair<TrkrDefs::hitkey, TrkrHit*>>::iterator,
446  std::multimap<int, std::pair<TrkrDefs::hitkey, TrkrHit*>>::iterator>
447  clusrange = clusters.equal_range(clusid);
448 
449  // make the cluster directly in the node tree
450  TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid);
451 
452  if (Verbosity() > 2)
453  {
454  std::cout << "Filling cluster with key " << ckey << std::endl;
455  }
456 
457  // get the bunch crossing number from the hitsetkey
458  short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey());
459 
460  // determine the size of the cluster in phi and z, useful for track fitting the cluster
461  std::set<int> phibins;
462  std::set<int> zbins;
463 
464  // determine the cluster position...
465  double xlocalsum = 0.0;
466  double ylocalsum = 0.0;
467  double zlocalsum = 0.0;
468  unsigned int clus_adc = 0.0;
469  unsigned int clus_maxadc = 0.0;
470  unsigned nhits = 0;
471  // std::cout << PHWHERE << " ckey " << ckey << ":" << std::endl;
472  for (std::multimap<int, std::pair<TrkrDefs::hitkey, TrkrHit*>>::iterator mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter)
473  {
474  // mapiter->second.first is the hit key
475  // std::cout << " adding hitkey " << mapiter->second.first << std::endl;
476  int col = InttDefs::getCol((mapiter->second).first);
477  int row = InttDefs::getRow((mapiter->second).first);
478  zbins.insert(col);
479  phibins.insert(row);
480 
481  // mapiter->second.second is the hit
482  unsigned int hit_adc = (mapiter->second).second->getAdc();
483 
484  // Add clusterkey/bunch crossing to mmap
485  m_clustercrossingassoc->addAssoc(ckey, crossing);
486 
487  // now get the positions from the geometry
488  double local_hit_location[3] = {0., 0., 0.};
489  geom->find_strip_center_localcoords(ladder_z_index,
490  row, col,
491  local_hit_location);
492 
493  if (_make_e_weights[layer])
494  {
495  xlocalsum += local_hit_location[0] * (double) hit_adc;
496  ylocalsum += local_hit_location[1] * (double) hit_adc;
497  zlocalsum += local_hit_location[2] * (double) hit_adc;
498  }
499  else
500  {
501  xlocalsum += local_hit_location[0];
502  ylocalsum += local_hit_location[1];
503  zlocalsum += local_hit_location[2];
504  }
505  if (hit_adc > clus_maxadc)
506  {
507  clus_maxadc = hit_adc;
508  }
509  clus_adc += hit_adc;
510  ++nhits;
511 
512  // add this cluster-hit association to the association map of (clusterkey,hitkey)
513  m_clusterhitassoc->addAssoc(ckey, mapiter->second.first);
514 
515  if (Verbosity() > 2)
516  {
517  std::cout << " nhits = " << nhits << std::endl;
518  }
519  if (Verbosity() > 2)
520  {
521  std::cout << " From geometry object: hit x " << local_hit_location[0] << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl;
522  std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " << ylocalsum / nhits << " clusz " << zlocalsum / nhits << " hit_adc " << hit_adc << std::endl;
523  }
524  }
525 
526  static const float invsqrt12 = 1. / sqrt(12);
527 
528  // scale factors (phi direction)
529  /*
530  they corresponds to clusters of size 1 and 2 in phi
531  other clusters, which are very few and pathological, get a scale factor of 1
532  These scale factors are applied to produce cluster pulls with width unity
533  */
534 
535  float phierror = pitch * invsqrt12;
536 
537  static constexpr std::array<double, 3> scalefactors_phi = {{0.85, 0.4, 0.33}};
538  if (phibins.size() == 1 && layer < 5)
539  {
540  phierror *= scalefactors_phi[0];
541  }
542  else if (phibins.size() == 2 && layer < 5)
543  {
544  phierror *= scalefactors_phi[1];
545  }
546  else if (phibins.size() == 2 && layer > 4)
547  {
548  phierror *= scalefactors_phi[2];
549  }
550  // z error.
551  const float zerror = zbins.size() * length * invsqrt12;
552 
553  double cluslocaly = NAN;
554  double cluslocalz = NAN;
555 
556  if (_make_e_weights[layer])
557  {
558  cluslocaly = ylocalsum / (double) clus_adc;
559  cluslocalz = zlocalsum / (double) clus_adc;
560  }
561  else
562  {
563  cluslocaly = ylocalsum / nhits;
564  cluslocalz = zlocalsum / nhits;
565  }
566 
567  auto clus = std::make_unique<TrkrClusterv5>();
568  clus->setAdc(clus_adc);
569  clus->setMaxAdc(clus_maxadc);
570  clus->setLocalX(cluslocaly);
571  clus->setLocalY(cluslocalz);
572  clus->setPhiError(phierror);
573  clus->setZError(zerror);
574  clus->setPhiSize(phibins.size());
575  clus->setZSize(zbins.size());
576  // All silicon surfaces have a 1-1 map to hitsetkey.
577  // So set subsurface key to 0
578  clus->setSubSurfKey(0);
579 
580  if (Verbosity() > 2)
581  {
582  clus->identify();
583  }
584 
585  m_clusterlist->addClusterSpecifyKey(ckey, clus.release());
586 
587  } // end loop over cluster ID's
588  } // end loop over hitsets
589 
590  if (Verbosity() > 2)
591  {
592  // check that the associations were written correctly
593  std::cout << "After InttClusterizer, cluster-hit associations are:" << std::endl;
595  }
596 
597  if (Verbosity() > 0)
598  {
599  std::cout << " Cluster-crossing associations are:" << std::endl;
601  }
602 
603  return;
604 }
606 {
607  if (Verbosity() > 0)
608  {
609  std::cout << "Entering InttClusterizer::ClusterLadderCells " << std::endl;
610  }
611 
612  //----------
613  // Get Nodes
614  //----------
615 
616  // get the geometry node
617  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_INTT");
618  if (!geom_container)
619  {
620  return;
621  }
622 
623  //-----------
624  // Clustering
625  //-----------
626 
627  // loop over the InttHitSet objects
628  RawHitSetContainer::ConstRange hitsetrange =
630  for (RawHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
631  hitsetitr != hitsetrange.second;
632  ++hitsetitr)
633  {
634  // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor
635  RawHitSet* hitset = hitsetitr->second;
636 
637  if (Verbosity() > 1)
638  {
639  std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl;
640  }
641  if (Verbosity() > 2)
642  {
643  hitset->identify();
644  }
645 
646  // we have a single hitset, get the info that identifies the sensor
647  int layer = TrkrDefs::getLayer(hitsetitr->first);
648  int ladder_z_index = InttDefs::getLadderZId(hitsetitr->first);
649 
650  // we will need the geometry object for this layer to get the global position
651  CylinderGeomIntt* geom = dynamic_cast<CylinderGeomIntt*>(geom_container->GetLayerGeom(layer));
652  float pitch = geom->get_strip_y_spacing();
653  float length = geom->get_strip_z_spacing();
654 
655  // fill a vector of hits to make things easier - gets every hit in the hitset
656  std::vector<RawHit*> hitvec;
657  // int sector = InttDefs::getLadderPhiId(hitsetitr->first);
658  // int side = InttDefs::getLadderZId(hitsetitr->first);
659 
660  RawHitSet::ConstRange hitrangei = hitset->getHits();
661  for (RawHitSet::ConstIterator hitr = hitrangei.first;
662  hitr != hitrangei.second;
663  ++hitr)
664  {
665  // unsigned short iphi = (*hitr)->getPhiBin();
666  // unsigned short it = (*hitr)->getTBin();
667  // std::cout << " intt layer " << layer << " sector: " << sector << " side " << side << " col: " << iphi << " row " << it << std::endl;
668  hitvec.push_back((*hitr));
669  }
670  if (Verbosity() > 2)
671  {
672  std::cout << "hitvec.size(): " << hitvec.size() << std::endl;
673  }
674 
675  using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>;
676  Graph G;
677 
678  // Find adjacent strips
679  for (unsigned int i = 0; i < hitvec.size(); i++)
680  {
681  for (unsigned int j = i + 1; j < hitvec.size(); j++)
682  {
683  if (ladder_are_adjacent(hitvec[i], hitvec[j], layer))
684  {
685  add_edge(i, j, G);
686  }
687  }
688 
689  add_edge(i, i, G);
690  }
691 
692  // Find the connections between the vertices of the graph (vertices are the rawhits,
693  // connections are made when they are adjacent to one another)
694  std::vector<int> component(num_vertices(G));
695 
696  // this is the actual clustering, performed by boost
697  connected_components(G, &component[0]);
698 
699  // Loop over the components(hit cells) compiling a list of the
700  // unique connected groups (ie. clusters).
701  std::set<int> cluster_ids; // unique components
702 
703  std::multimap<int, RawHit*> clusters;
704  for (unsigned int i = 0; i < component.size(); i++)
705  {
706  cluster_ids.insert(component[i]); // one entry per unique cluster id
707  clusters.insert(std::make_pair(component[i], hitvec[i])); // multiple entries per unique cluster id
708  }
709 
710  // loop over the cluster ID's and make the clusters from the connected hits
711  for (int clusid : cluster_ids)
712  {
713  // std::cout << " intt clustering: add cluster number " << clusid << std::endl;
714  // get all hits for this cluster ID only
715  auto clusrange = clusters.equal_range(clusid);
716 
717  // make the cluster directly in the node tree
718  TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid);
719 
720  if (Verbosity() > 2)
721  {
722  std::cout << "Filling cluster with key " << ckey << std::endl;
723  }
724 
725  // get the bunch crossing number from the hitsetkey
726  short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey());
727 
728  // determine the size of the cluster in phi and z, useful for track fitting the cluster
729  std::set<int> phibins;
730  std::set<int> zbins;
731 
732  // determine the cluster position...
733  double xlocalsum = 0.0;
734  double ylocalsum = 0.0;
735  double zlocalsum = 0.0;
736  unsigned int clus_adc = 0.0;
737  unsigned nhits = 0;
738 
739  // std::cout << PHWHERE << " ckey " << ckey << ":" << std::endl;
740 
741  std::map<int, unsigned int> m_phi, m_z; // hold data for
742  for (auto mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter)
743  {
744  // mapiter->second.first is the hit key
745  // std::cout << " adding hitkey " << mapiter->second.first << std::endl;
746  const auto energy = (mapiter->second)->getAdc();
747  int col = (mapiter->second)->getPhiBin();
748  int row = (mapiter->second)->getTBin();
749  // std::cout << " found Tbin(row) " << row << " Phibin(col) " << col << std::endl;
750  zbins.insert(col);
751  phibins.insert(row);
752 
753  if (mClusHitsVerbose)
754  {
755  auto pnew = m_phi.try_emplace(row, energy);
756  if (!pnew.second)
757  {
758  pnew.first->second += energy;
759  }
760 
761  pnew = m_z.try_emplace(col, energy);
762  if (!pnew.second)
763  {
764  pnew.first->second += energy;
765  }
766  }
767 
768  // mapiter->second.second is the hit
769  unsigned int hit_adc = (mapiter->second)->getAdc();
770 
771  // Add clusterkey/bunch crossing to mmap
772  m_clustercrossingassoc->addAssoc(ckey, crossing);
773 
774  // now get the positions from the geometry
775  double local_hit_location[3] = {0., 0., 0.};
776  geom->find_strip_center_localcoords(ladder_z_index,
777  row, col,
778  local_hit_location);
779 
780  if (_make_e_weights[layer])
781  {
782  xlocalsum += local_hit_location[0] * (double) hit_adc;
783  ylocalsum += local_hit_location[1] * (double) hit_adc;
784  zlocalsum += local_hit_location[2] * (double) hit_adc;
785  }
786  else
787  {
788  xlocalsum += local_hit_location[0];
789  ylocalsum += local_hit_location[1];
790  zlocalsum += local_hit_location[2];
791  }
792 
793  clus_adc += hit_adc;
794  ++nhits;
795 
796  // add this cluster-hit association to the association map of (clusterkey,hitkey)
797  // m_clusterhitassoc->addAssoc(ckey, mapiter->second.first);
798 
799  if (Verbosity() > 2)
800  {
801  std::cout << " nhits = " << nhits << std::endl;
802  }
803  if (Verbosity() > 2)
804  {
805  std::cout << " From geometry object: hit x " << local_hit_location[0] << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl;
806  std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy " << ylocalsum / nhits << " clusz " << zlocalsum / nhits << " hit_adc " << hit_adc << std::endl;
807  }
808  }
809 
810  if (mClusHitsVerbose)
811  {
812  if (Verbosity() > 10)
813  {
814  for (auto const& hit : m_phi)
815  {
816  std::cout << " m_phi(" << hit.first << " : " << hit.second << ") " << std::endl;
817  }
818  }
819  for (auto& hit : m_phi)
820  {
821  mClusHitsVerbose->addPhiHit(hit.first, (float) hit.second);
822  }
823  for (auto& hit : m_z)
824  {
825  mClusHitsVerbose->addZHit(hit.first, (float) hit.second);
826  }
828  }
829 
830  static const float invsqrt12 = 1. / sqrt(12);
831 
832  // scale factors (phi direction)
833  /*
834  they corresponds to clusters of size 1 and 2 in phi
835  other clusters, which are very few and pathological, get a scale factor of 1
836  These scale factors are applied to produce cluster pulls with width unity
837  */
838 
839  float phierror = pitch * invsqrt12;
840 
841  static constexpr std::array<double, 3> scalefactors_phi = {{0.85, 0.4, 0.33}};
842  if (phibins.size() == 1 && layer < 5)
843  {
844  phierror *= scalefactors_phi[0];
845  }
846  else if (phibins.size() == 2 && layer < 5)
847  {
848  phierror *= scalefactors_phi[1];
849  }
850  else if (phibins.size() == 2 && layer > 4)
851  {
852  phierror *= scalefactors_phi[2];
853  }
854  // z error.
855  const float zerror = zbins.size() * length * invsqrt12;
856 
857  double cluslocaly = NAN;
858  double cluslocalz = NAN;
859 
860  if (_make_e_weights[layer])
861  {
862  cluslocaly = ylocalsum / (double) clus_adc;
863  cluslocalz = zlocalsum / (double) clus_adc;
864  }
865  else
866  {
867  cluslocaly = ylocalsum / nhits;
868  cluslocalz = zlocalsum / nhits;
869  }
870 
871  auto clus = std::make_unique<TrkrClusterv5>();
872  clus->setAdc(clus_adc);
873  clus->setLocalX(cluslocaly);
874  clus->setLocalY(cluslocalz);
875  clus->setPhiError(phierror);
876  clus->setZError(zerror);
877  clus->setPhiSize(phibins.size());
878  clus->setZSize(zbins.size());
879  // All silicon surfaces have a 1-1 map to hitsetkey.
880  // So set subsurface key to 0
881  clus->setSubSurfKey(0);
882 
883  if (Verbosity() > 2)
884  {
885  clus->identify();
886  }
887 
888  m_clusterlist->addClusterSpecifyKey(ckey, clus.release());
889 
890  } // end loop over cluster ID's
891  } // end loop over hitsets
892 
893  if (Verbosity() > 2)
894  {
895  // check that the associations were written correctly
896  std::cout << "After InttClusterizer, cluster-hit associations are:" << std::endl;
898  }
899 
900  if (Verbosity() > 0)
901  {
902  std::cout << " Cluster-crossing associations are:" << std::endl;
904  }
905 
906  return;
907 }
908 
910 {
911  if (Verbosity() > 1)
912  {
913  TrkrClusterContainer* clusterlist = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
914  if (!clusterlist)
915  {
916  return;
917  }
918 
919  std::cout << "================= After InttClusterizer::process_event() ====================" << std::endl;
920 
921  std::cout << " There are " << clusterlist->size() << " clusters recorded: " << std::endl;
922 
923  clusterlist->identify();
924 
925  std::cout << "===========================================================================" << std::endl;
926  }
927 
928  return;
929 }