Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MvtxClusterizer.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MvtxClusterizer.cc
1 
7 #include "MvtxClusterizer.h"
8 #include "CylinderGeom_Mvtx.h"
9 
12 
18 #include <trackbase/TrkrDefs.h> // for hitkey, getLayer
19 #include <trackbase/MvtxDefs.h>
20 #include <trackbase/TrkrHitv2.h>
21 #include <trackbase/TrkrHitSet.h>
24 
25 #include <trackbase/RawHit.h>
26 #include <trackbase/RawHitSet.h>
28 
30 #include <fun4all/SubsysReco.h> // for SubsysReco
31 
32 #include <phool/PHCompositeNode.h>
33 #include <phool/PHIODataNode.h>
34 #include <phool/PHNode.h> // for PHNode
35 #include <phool/PHNodeIterator.h>
36 #include <phool/PHObject.h> // for PHObject
37 #include <phool/getClass.h>
38 #include <phool/phool.h> // for PHWHERE
39 
40 #include <TMatrixFfwd.h> // for TMatrixF
41 #include <TMatrixT.h> // for TMatrixT, operator*
42 #include <TMatrixTUtils.h> // for TMatrixTRow
43 #include <TVector3.h>
44 
45 #pragma GCC diagnostic push
46 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
47 #include <boost/graph/adjacency_list.hpp>
48 #pragma GCC diagnostic pop
49 
50 #include <boost/graph/connected_components.hpp>
51 
52 #include <array>
53 #include <cmath>
54 #include <cstdlib> // for exit
55 #include <iostream>
56 #include <map> // for multimap<>::iterator
57 #include <set> // for set, set<>::iterator
58 #include <string>
59 #include <vector> // for vector
60 
61 using namespace boost;
62 using namespace std;
63 
64 namespace
65 {
66 
68  template<class T>
69  inline constexpr T square( const T& x ) { return x*x; }
70 }
71 
72 bool MvtxClusterizer::are_adjacent(const std::pair<TrkrDefs::hitkey, TrkrHit*> &lhs, const std::pair<TrkrDefs::hitkey, TrkrHit*> &rhs)
73 {
74  if (GetZClustering())
75  {
76  // column is first, row is second
77  if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) <= 1)
78  {
79  if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1)
80  {
81  return true;
82  }
83  }
84  }
85  else
86  {
87  if (fabs( MvtxDefs::getCol(lhs.first) - MvtxDefs::getCol(rhs.first) ) == 0)
88  {
89  if (fabs( MvtxDefs::getRow(lhs.first) - MvtxDefs::getRow(rhs.first) ) <= 1)
90  {
91  return true;
92  }
93  }
94  }
95 
96  return false;
97 }
98 
100 {
101  if (GetZClustering())
102  {
103  // column is first, row is second
104  if (fabs( lhs->getPhiBin() - rhs->getPhiBin()) <= 1)//col
105  {
106  if (fabs( lhs->getTBin() - rhs->getTBin() ) <= 1)//Row
107  {
108  return true;
109  }
110  }
111  }
112  else
113  {
114  if (fabs(lhs->getPhiBin() - rhs->getPhiBin() ) == 0)
115  {
116  if (fabs( lhs->getTBin() - rhs->getTBin() ) <= 1)
117  {
118  return true;
119  }
120  }
121  }
122 
123  return false;
124 }
125 
127  : SubsysReco(name)
128  , m_hits(nullptr)
129  , m_rawhits(nullptr)
130  , m_clusterlist(nullptr)
131  , m_clusterhitassoc(nullptr)
132  , m_makeZClustering(true)
133 {
134 }
135 
137 {
138  //-----------------
139  // Add Cluster Node
140  //-----------------
141 
142  PHNodeIterator iter(topNode);
143 
144  // Looking for the DST node
145  PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
146  if (!dstNode)
147  {
148  cout << PHWHERE << "DST Node missing, doing nothing." << endl;
150  }
151  PHNodeIterator iter_dst(dstNode);
152 
153  // Create the SVX node if required
154  PHCompositeNode *svxNode = dynamic_cast<PHCompositeNode *>(iter_dst.findFirst("PHCompositeNode", "TRKR"));
155  if (!svxNode)
156  {
157  svxNode = new PHCompositeNode("TRKR");
158  dstNode->addNode(svxNode);
159  }
160 
161  // Create the Cluster node if required
162  auto trkrclusters = findNode::getClass<TrkrClusterContainer>(dstNode, "TRKR_CLUSTER");
163  if (!trkrclusters)
164  {
165  PHNodeIterator dstiter(dstNode);
166  PHCompositeNode *DetNode =
167  dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
168  if (!DetNode)
169  {
170  DetNode = new PHCompositeNode("TRKR");
171  dstNode->addNode(DetNode);
172  }
173 
174  trkrclusters = new TrkrClusterContainerv4;
175  PHIODataNode<PHObject> *TrkrClusterContainerNode =
176  new PHIODataNode<PHObject>(trkrclusters, "TRKR_CLUSTER", "PHObject");
177  DetNode->addNode(TrkrClusterContainerNode);
178  }
179 
180  auto clusterhitassoc = findNode::getClass<TrkrClusterHitAssoc>(topNode,"TRKR_CLUSTERHITASSOC");
181  if(!clusterhitassoc)
182  {
183  PHNodeIterator dstiter(dstNode);
184  PHCompositeNode *DetNode =
185  dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
186  if (!DetNode)
187  {
188  DetNode = new PHCompositeNode("TRKR");
189  dstNode->addNode(DetNode);
190  }
191 
192  clusterhitassoc = new TrkrClusterHitAssocv3;
193  PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(clusterhitassoc, "TRKR_CLUSTERHITASSOC", "PHObject");
194  DetNode->addNode(newNode);
195  }
196 
197  // Get the cluster hits verbose node, if required
199  // get the node
200  mClusHitsVerbose = findNode::getClass<ClusHitsVerbose>(topNode, "Trkr_SvtxClusHitsVerbose");
201  if (!mClusHitsVerbose)
202  {
203  PHNodeIterator dstiter(dstNode);
204  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
205  if (!DetNode)
206  {
207  DetNode = new PHCompositeNode("TRKR");
208  dstNode->addNode(DetNode);
209  }
211  auto newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject");
212  DetNode->addNode(newNode);
213  }
214  }
215 
216 
217 
218  //----------------
219  // Report Settings
220  //----------------
221 
222  if (Verbosity() > 0)
223  {
224  cout << "====================== MvtxClusterizer::InitRun() =====================" << endl;
225  cout << " Z-dimension Clustering = " << boolalpha << m_makeZClustering << noboolalpha << endl;
226  cout << "===========================================================================" << endl;
227  }
228 
230 }
231 
233 {
234  // get node containing the digitized hits
235  if(!do_read_raw){
236  m_hits = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
237  if (!m_hits)
238  {
239  cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << endl;
241  }
242  }else{
243  // get node containing the digitized hits
244  m_rawhits = findNode::getClass<RawHitSetContainer>(topNode, "TRKR_RAWHITSET");
245  if (!m_rawhits)
246  {
247  std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl;
249  }
250  }
251 
252  // get node for clusters
253  m_clusterlist = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
254  if (!m_clusterlist)
255  {
256  cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTER." << endl;
258  }
259 
260  // get node for cluster hit associations
261  m_clusterhitassoc = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
262  if (!m_clusterhitassoc)
263  {
264  cout << PHWHERE << " ERROR: Can't find TRKR_CLUSTERHITASSOC" << endl;
266  }
267 
268  // run clustering
269  if(!do_read_raw){
270  ClusterMvtx(topNode);
271  }else{
272  ClusterMvtxRaw(topNode);
273  }
274  PrintClusters(topNode);
275 
276  // done
278 }
279 
281 {
282  if (Verbosity() > 0)
283  cout << "Entering MvtxClusterizer::ClusterMvtx " << endl;
284 
285  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MVTX");
286  if (!geom_container) return;
287 
288  //-----------
289  // Clustering
290  //-----------
291 
292  // loop over each MvtxHitSet object (chip)
293  TrkrHitSetContainer::ConstRange hitsetrange =
295  for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
296  hitsetitr != hitsetrange.second;
297  ++hitsetitr)
298  {
299  TrkrHitSet *hitset = hitsetitr->second;
300 
301  if(Verbosity() > 0)
302  {
303  unsigned int layer = TrkrDefs::getLayer(hitsetitr->first);
304  unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first);
305  unsigned int chip = MvtxDefs::getChipId(hitsetitr->first);
306  unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first);
307  cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << endl;
308  }
309 
310  if (Verbosity() > 2)
311  hitset->identify();
312 
313  // fill a vector of hits to make things easier
314  std::vector <std::pair< TrkrDefs::hitkey, TrkrHit*> > hitvec;
315 
316  TrkrHitSet::ConstRange hitrangei = hitset->getHits();
317  for (TrkrHitSet::ConstIterator hitr = hitrangei.first;
318  hitr != hitrangei.second;
319  ++hitr)
320  {
321  hitvec.push_back(make_pair(hitr->first, hitr->second));
322  }
323  if (Verbosity() > 2) cout << "hitvec.size(): " << hitvec.size() << endl;
324 
325  if(Verbosity() > 0)
326  {
327  for (unsigned int i = 0; i < hitvec.size(); i++)
328  {
329  auto hitkey = hitvec[i].first;
330  auto row = MvtxDefs::getRow(hitkey);
331  auto col = MvtxDefs::getCol(hitkey);
332  std::cout << " hitkey " << hitkey << " row " << row << " col " << col << std::endl;
333  }
334 
335  }
336 
337  // do the clustering
338  typedef adjacency_list<vecS, vecS, undirectedS> Graph;
339  Graph G;
340 
341  // loop over hits in this chip
342  for (unsigned int i = 0; i < hitvec.size(); i++)
343  {
344  for (unsigned int j = 0; j < hitvec.size(); j++)
345  {
346  if (are_adjacent(hitvec[i], hitvec[j]))
347  add_edge(i, j, G);
348  }
349  }
350 
351  // Find the connections between the vertices of the graph (vertices are the rawhits,
352  // connections are made when they are adjacent to one another)
353  vector<int> component(num_vertices(G));
354 
355  // this is the actual clustering, performed by boost
356  connected_components(G, &component[0]);
357 
358  // Loop over the components(hits) compiling a list of the
359  // unique connected groups (ie. clusters).
360  set<int> cluster_ids; // unique components
361  //multimap<int, pixel> clusters;
362  multimap<int, std::pair<TrkrDefs::hitkey, TrkrHit*> > clusters;
363  for (unsigned int i = 0; i < component.size(); i++)
364  {
365  cluster_ids.insert(component[i]);
366  clusters.insert(make_pair(component[i], hitvec[i]));
367  }
368  int total_clusters = 0;
369  for (set<int>::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter)
370  {
371  int clusid = *clusiter;
372  auto clusrange = clusters.equal_range(clusid);
373 
374  if (Verbosity() > 2) cout << "Filling cluster id " << clusid << " of " << std::distance(cluster_ids.begin(),clusiter )<< endl;
375 
376  ++total_clusters;
377  auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid);
378 
379  // determine the size of the cluster in phi and z
380  set<int> phibins;
381  set<int> zbins;
382  std::map<int,unsigned int> m_phi, m_z; // Note, there are no "cut" bins for Svtx Clusters
383 
384  // determine the cluster position...
385  double locxsum = 0.;
386  double loczsum = 0.;
387  const unsigned int nhits = std::distance( clusrange.first, clusrange.second );
388 
389  double locclusx = NAN;
390  double locclusz = NAN;
391 
392  // we need the geometry object for this layer to get the global positions
393  int layer = TrkrDefs::getLayer(ckey);
394  auto layergeom = dynamic_cast<CylinderGeom_Mvtx *>(geom_container->GetLayerGeom(layer));
395  if (!layergeom)
396  exit(1);
397 
398  for ( auto mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter)
399  {
400  // size
401  const auto energy = (mapiter->second).second->getAdc();
402  int col = MvtxDefs::getCol( (mapiter->second).first);
403  int row = MvtxDefs::getRow( (mapiter->second).first);
404  zbins.insert(col);
405  phibins.insert(row);
406 
407  if (mClusHitsVerbose) {
408  auto pnew = m_phi.try_emplace(row,energy);
409  if (!pnew.second) pnew.first->second += energy;
410 
411  pnew = m_z.try_emplace(col,energy);
412  if (!pnew.second) pnew.first->second += energy;
413  }
414 
415  // get local coordinates, in stae reference frame, for hit
416  auto local_coords = layergeom->get_local_coords_from_pixel(row,col);
417 
418  /*
419  manually offset position along y (thickness of the sensor),
420  to account for effective hit position in the sensor, resulting from diffusion.
421  Effective position corresponds to 1um above the middle of the sensor
422  */
423  local_coords.SetY( 1e-4 );
424 
425  // update cluster position
426  locxsum += local_coords.X();
427  loczsum += local_coords.Z();
428  // add the association between this cluster key and this hitkey to the table
429  m_clusterhitassoc->addAssoc(ckey, mapiter->second.first);
430 
431  } //mapiter
432 
433  if (mClusHitsVerbose) {
434  if (Verbosity()>10) {
435  for (auto& hit : m_phi) {
436  std::cout << " m_phi(" << hit.first <<" : " << hit.second<<") " << std::endl;
437  }
438  }
439  for (auto& hit : m_phi) mClusHitsVerbose->addPhiHit (hit.first, (float)hit.second);
440  for (auto& hit : m_z) mClusHitsVerbose->addZHit (hit.first, (float)hit.second);
442  }
443 
444 
445  // This is the local position
446  locclusx = locxsum / nhits;
447  locclusz = loczsum / nhits;
448 
449  const double pitch = layergeom->get_pixel_x();
450  const double length = layergeom->get_pixel_z();
451  const double phisize = phibins.size() * pitch;
452  const double zsize = zbins.size() * length;
453 
454  static const double invsqrt12 = 1./std::sqrt(12);
455 
456  // scale factors (phi direction)
457  /*
458  they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in phi and z
459  other clusters, which are very few and pathological, get a scale factor of 1
460  These scale factors are applied to produce cluster pulls with width unity
461  */
462 
463  double phierror = pitch * invsqrt12;
464 
465  static constexpr std::array<double, 7> scalefactors_phi = {{ 0.36, 0.6,0.37,0.49,0.4,0.37,0.33 }};
466  if(phibins.size() == 1 && zbins.size() == 1) phierror*=scalefactors_phi[0];
467  else if(phibins.size() == 2 && zbins.size() == 1) phierror*=scalefactors_phi[1];
468  else if(phibins.size() == 1 && zbins.size() == 2) phierror*=scalefactors_phi[2];
469  else if( phibins.size() == 2 && zbins.size() == 2 ) phierror*=scalefactors_phi[0];
470  else if( phibins.size() == 2 && zbins.size() == 3 ) phierror*=scalefactors_phi[1];
471  else if( phibins.size() == 3 && zbins.size() == 2 ) phierror*=scalefactors_phi[2];
472  else if( phibins.size() == 3 && zbins.size() == 3 ) phierror*=scalefactors_phi[3];
473 
474 
475  // scale factors (z direction)
476  /*
477  they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z and phi
478  other clusters, which are very few and pathological, get a scale factor of 1
479  */
480  static constexpr std::array<double, 4> scalefactors_z = {{ 0.47, 0.48, 0.71, 0.55 }};
481  double zerror = length*invsqrt12;
482  if( zbins.size() == 2 && phibins.size() == 2 ) zerror*=scalefactors_z[0];
483  else if( zbins.size() == 2 && phibins.size() == 3 ) zerror*=scalefactors_z[1];
484  else if( zbins.size() == 3 && phibins.size() == 2 ) zerror*=scalefactors_z[2];
485  else if( zbins.size() == 3 && phibins.size() == 3 ) zerror*=scalefactors_z[3];
486 
487  if(Verbosity() > 0)
488  cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize
489  << " zbins " << zbins.size() << " length " << length << " zsize " << zsize
490  << " local x " << locclusx << " local y " << locclusz
491  << endl;
492 
493  auto clus = std::make_unique<TrkrClusterv5>();
494  clus->setAdc(nhits);
495  clus->setMaxAdc(1);
496  clus->setLocalX(locclusx);
497  clus->setLocalY(locclusz);
498  clus->setPhiError(phierror);
499  clus->setZError(zerror);
500  clus->setPhiSize(phibins.size());
501  clus->setZSize(zbins.size());
502  // All silicon surfaces have a 1-1 map to hitsetkey.
503  // So set subsurface key to 0
504  clus->setSubSurfKey(0);
505 
506  if (Verbosity() > 2)
507  clus->identify();
508 
509  m_clusterlist->addClusterSpecifyKey(ckey, clus.release());
510 
511  } // clusitr loop
512  } // loop over hitsets
513 
514  if(Verbosity() > 1)
515  {
516  // check that the associations were written correctly
518  }
519 
520  return;
521 }
522 
524 {
525  if (Verbosity() > 0)
526  cout << "Entering MvtxClusterizer::ClusterMvtx " << endl;
527 
528  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MVTX");
529  if (!geom_container) return;
530 
531  //-----------
532  // Clustering
533  //-----------
534 
535  // loop over each MvtxHitSet object (chip)
536  RawHitSetContainer::ConstRange hitsetrange =
538  for (RawHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
539  hitsetitr != hitsetrange.second;
540  ++hitsetitr)
541  {
542  RawHitSet *hitset = hitsetitr->second;
543 
544  if(Verbosity() > 0)
545  {
546  unsigned int layer = TrkrDefs::getLayer(hitsetitr->first);
547  unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first);
548  unsigned int chip = MvtxDefs::getChipId(hitsetitr->first);
549  unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first);
550  cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << endl;
551  }
552 
553  if (Verbosity() > 2)
554  hitset->identify();
555 
556  // fill a vector of hits to make things easier
557  std::vector <RawHit*> hitvec;
558 
559  RawHitSet::ConstRange hitrangei = hitset->getHits();
560  for (RawHitSet::ConstIterator hitr = hitrangei.first;
561  hitr != hitrangei.second;
562  ++hitr)
563  {
564  hitvec.push_back((*hitr));
565  }
566  if (Verbosity() > 2) cout << "hitvec.size(): " << hitvec.size() << endl;
567 
568 
569  // do the clustering
570  typedef adjacency_list<vecS, vecS, undirectedS> Graph;
571  Graph G;
572 
573  // loop over hits in this chip
574  for (unsigned int i = 0; i < hitvec.size(); i++)
575  {
576  for (unsigned int j = 0; j < hitvec.size(); j++)
577  {
578  if (are_adjacent(hitvec[i], hitvec[j]))
579  add_edge(i, j, G);
580  }
581  }
582 
583  // Find the connections between the vertices of the graph (vertices are the rawhits,
584  // connections are made when they are adjacent to one another)
585  vector<int> component(num_vertices(G));
586 
587  // this is the actual clustering, performed by boost
588  connected_components(G, &component[0]);
589 
590  // Loop over the components(hits) compiling a list of the
591  // unique connected groups (ie. clusters).
592  set<int> cluster_ids; // unique components
593  //multimap<int, pixel> clusters;
594 
595  multimap<int, RawHit* > clusters;
596  for (unsigned int i = 0; i < component.size(); i++)
597  {
598  cluster_ids.insert(component[i]);
599  clusters.insert(make_pair(component[i], hitvec[i]));
600  }
601  // cout << "found cluster #: "<< clusters.size()<< endl;
602  // loop over the componenets and make clusters
603  for (set<int>::iterator clusiter = cluster_ids.begin(); clusiter != cluster_ids.end(); ++clusiter)
604  {
605  int clusid = *clusiter;
606  auto clusrange = clusters.equal_range(clusid);
607 
608  if (Verbosity() > 2) cout << "Filling cluster id " << clusid << " of " << std::distance(cluster_ids.begin(),clusiter )<< endl;
609 
610  // make the cluster directly in the node tree
611  auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid);
612 
613  // determine the size of the cluster in phi and z
614  set<int> phibins;
615  set<int> zbins;
616 
617  // determine the cluster position...
618  double locxsum = 0.;
619  double loczsum = 0.;
620  const unsigned int nhits = std::distance( clusrange.first, clusrange.second );
621 
622  double locclusx = NAN;
623  double locclusz = NAN;
624 
625  // we need the geometry object for this layer to get the global positions
626  int layer = TrkrDefs::getLayer(ckey);
627  auto layergeom = dynamic_cast<CylinderGeom_Mvtx *>(geom_container->GetLayerGeom(layer));
628  if (!layergeom)
629  exit(1);
630 
631  for ( auto mapiter = clusrange.first; mapiter != clusrange.second; ++mapiter)
632  {
633  // size
634  int col = (mapiter->second)->getPhiBin();
635  int row = (mapiter->second)->getTBin();
636  zbins.insert(col);
637  phibins.insert(row);
638 
639  // get local coordinates, in stae reference frame, for hit
640  auto local_coords = layergeom->get_local_coords_from_pixel(row,col);
641 
642  /*
643  manually offset position along y (thickness of the sensor),
644  to account for effective hit position in the sensor, resulting from diffusion.
645  Effective position corresponds to 1um above the middle of the sensor
646  */
647  local_coords.SetY( 1e-4 );
648 
649  // update cluster position
650  locxsum += local_coords.X();
651  loczsum += local_coords.Z();
652  // add the association between this cluster key and this hitkey to the table
653  // m_clusterhitassoc->addAssoc(ckey, mapiter->second.first);
654 
655  } //mapiter
656 
657  // This is the local position
658  locclusx = locxsum / nhits;
659  locclusz = loczsum / nhits;
660 
661  const double pitch = layergeom->get_pixel_x();
662  // std::cout << " pitch: " << pitch << std::endl;
663  const double length = layergeom->get_pixel_z();
664  // std::cout << " length: " << length << std::endl;
665  const double phisize = phibins.size() * pitch;
666  const double zsize = zbins.size() * length;
667 
668  static const double invsqrt12 = 1./std::sqrt(12);
669 
670  // scale factors (phi direction)
671  /*
672  they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in phi and z
673  other clusters, which are very few and pathological, get a scale factor of 1
674  These scale factors are applied to produce cluster pulls with width unity
675  */
676 
677  double phierror = pitch * invsqrt12;
678 
679  static constexpr std::array<double, 7> scalefactors_phi = {{ 0.36, 0.6,0.37,0.49,0.4,0.37,0.33 }};
680  if(phibins.size() == 1 && zbins.size() == 1) phierror*=scalefactors_phi[0];
681  else if(phibins.size() == 2 && zbins.size() == 1) phierror*=scalefactors_phi[1];
682  else if(phibins.size() == 1 && zbins.size() == 2) phierror*=scalefactors_phi[2];
683  else if( phibins.size() == 2 && zbins.size() == 2 ) phierror*=scalefactors_phi[0];
684  else if( phibins.size() == 2 && zbins.size() == 3 ) phierror*=scalefactors_phi[1];
685  else if( phibins.size() == 3 && zbins.size() == 2 ) phierror*=scalefactors_phi[2];
686  else if( phibins.size() == 3 && zbins.size() == 3 ) phierror*=scalefactors_phi[3];
687 
688 
689  // scale factors (z direction)
690  /*
691  they corresponds to clusters of size (2,2), (2,3), (3,2) and (3,3) in z and phi
692  other clusters, which are very few and pathological, get a scale factor of 1
693  */
694  static constexpr std::array<double, 4> scalefactors_z = {{ 0.47, 0.48, 0.71, 0.55 }};
695  double zerror = length*invsqrt12;
696  if( zbins.size() == 2 && phibins.size() == 2 ) zerror*=scalefactors_z[0];
697  else if( zbins.size() == 2 && phibins.size() == 3 ) zerror*=scalefactors_z[1];
698  else if( zbins.size() == 3 && phibins.size() == 2 ) zerror*=scalefactors_z[2];
699  else if( zbins.size() == 3 && phibins.size() == 3 ) zerror*=scalefactors_z[3];
700 
701  if(Verbosity() > 0)
702  cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize
703  << " zbins " << zbins.size() << " length " << length << " zsize " << zsize
704  << " local x " << locclusx << " local y " << locclusz
705  << endl;
706 
707  auto clus = std::make_unique<TrkrClusterv5>();
708  clus->setAdc(nhits);
709  clus->setMaxAdc(1);
710  clus->setLocalX(locclusx);
711  clus->setLocalY(locclusz);
712  clus->setPhiError(phierror);
713  clus->setZError(zerror);
714  clus->setPhiSize(phibins.size());
715  clus->setZSize(zbins.size());
716  // All silicon surfaces have a 1-1 map to hitsetkey.
717  // So set subsurface key to 0
718  clus->setSubSurfKey(0);
719 
720  if (Verbosity() > 2)
721  clus->identify();
722 
723  m_clusterlist->addClusterSpecifyKey(ckey, clus.release());
724 
725 
726  } // clusitr loop
727  } // loop over hitsets
728 
729  if(Verbosity() > 1)
730  {
731  // check that the associations were written correctly
733  }
734 
735  return;
736 }
737 
739 {
740  if (Verbosity() > 0)
741  {
742  TrkrClusterContainer *clusterlist = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
743  if (!clusterlist) return;
744 
745  cout << "================= After MvtxClusterizer::process_event() ====================" << endl;
746 
747  cout << " There are " << clusterlist->size() << " clusters recorded: " << endl;
748 
749  if(Verbosity() > 3) clusterlist->identify();
750 
751  cout << "===========================================================================" << endl;
752  }
753 
754  return;
755 }
756