Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4InttHitReco.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4InttHitReco.cc
1 #include "PHG4InttHitReco.h"
2 
4 
5 #include <g4detectors/PHG4CylinderGeom.h> // for PHG4CylinderGeom
7 
11 #include <trackbase/InttDefs.h>
15 #include <trackbase/TrkrDefs.h>
16 #include <trackbase/TrkrHit.h> // for TrkrHit
17 #include <trackbase/TrkrHitSet.h>
22 #include <trackbase/TrkrHitv2.h> // for TrkrHit
23 
24 #include <phparameter/PHParameterInterface.h> // for PHParameterInterface
25 
26 #include <g4main/PHG4Hit.h>
28 #include <g4main/PHG4Utils.h>
30 
32 #include <fun4all/SubsysReco.h> // for SubsysReco
33 
34 #include <phool/PHCompositeNode.h>
35 #include <phool/PHIODataNode.h>
36 #include <phool/PHNode.h> // for PHNode
37 #include <phool/PHNodeIterator.h>
38 #include <phool/PHObject.h> // for PHObject
39 #include <phool/getClass.h>
40 #include <phool/phool.h> // for PHWHERE
41 
42 #include <TSystem.h>
43 
44 #include <cmath>
45 #include <cstdlib>
46 #include <iostream>
47 #include <map> // for _Rb_tree_const_it...
48 #include <memory> // for allocator_traits<...
49 #include <utility> // for pair, swap, make_...
50 #include <vector> // for vector
51 
52 
53 // update to make sure to clusterize clusters in loopers
54 
56  : SubsysReco(name)
57  , PHParameterInterface(name)
58  , m_Detector("INTT")
59  , m_Tmin(NAN)
60  , m_Tmax(NAN)
61  , m_crossingPeriod(NAN)
62  , m_truth_hits { new TrkrHitSetContainerv1 }
63 {
65 
66  m_HitNodeName = "G4HIT_" + m_Detector;
67  m_CellNodeName = "G4CELL_" + m_Detector;
68  m_GeoNodeName = "CYLINDERGEOM_" + m_Detector;
69  m_LocalOutVec = gsl_vector_alloc(3);
70  m_PathVec = gsl_vector_alloc(3);
71  m_SegmentVec = gsl_vector_alloc(3);
72 }
73 
75 {
76  gsl_vector_free(m_LocalOutVec);
77  gsl_vector_free(m_PathVec);
78  gsl_vector_free(m_SegmentVec);
79  delete m_truth_hits;
80 }
81 
83 {
84  PHNodeIterator iter(topNode);
85 
86  // Looking for the DST node
87  PHCompositeNode *dstNode;
88  dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
89  if (!dstNode)
90  {
91  std::cout << PHWHERE << "DST Node missing, exiting." << std::endl;
92  gSystem->Exit(1);
93  exit(1);
94  }
95 
96  PHCompositeNode *runNode;
97  runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
98  if (!runNode)
99  {
100  std::cout << Name() << "RUN Node missing, exiting." << std::endl;
101  gSystem->Exit(1);
102  exit(1);
103  }
104  PHCompositeNode *parNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PAR"));
105  if (!parNode)
106  {
107  std::cout << Name() << "PAR Node missing, exiting." << std::endl;
108  gSystem->Exit(1);
109  exit(1);
110  }
111  std::string paramnodename = "G4CELLPARAM_" + m_Detector;
112 
113  PHNodeIterator runiter(runNode);
114  PHCompositeNode *RunDetNode = dynamic_cast<PHCompositeNode *>(runiter.findFirst("PHCompositeNode", m_Detector));
115  if (!RunDetNode)
116  {
117  RunDetNode = new PHCompositeNode(m_Detector);
118  runNode->addNode(RunDetNode);
119  }
120 
121  PHG4HitContainer *g4hit = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
122  if (!g4hit)
123  {
124  std::cout << "Could not locate g4 hit node " << m_HitNodeName << std::endl;
125  exit(1);
126  }
127 
128  auto hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
129  if (!hitsetcontainer)
130  {
131  PHNodeIterator dstiter(dstNode);
132  PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
133  if (!DetNode)
134  {
135  DetNode = new PHCompositeNode("TRKR");
136  dstNode->addNode(DetNode);
137  }
138 
139  hitsetcontainer = new TrkrHitSetContainerv1;
140  PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(hitsetcontainer, "TRKR_HITSET", "PHObject");
141  DetNode->addNode(newNode);
142  }
143 
144  auto hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
145  if (!hittruthassoc)
146  {
147  PHNodeIterator dstiter(dstNode);
148  PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
149  if (!DetNode)
150  {
151  DetNode = new PHCompositeNode("TRKR");
152  dstNode->addNode(DetNode);
153  }
154 
155  hittruthassoc = new TrkrHitTruthAssocv1;
156  PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(hittruthassoc, "TRKR_HITTRUTHASSOC", "PHObject");
157  DetNode->addNode(newNode);
158  }
159 
160  PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode, m_GeoNodeName);
161  if (!geo)
162  {
163  std::cout << "Could not locate geometry node " << m_GeoNodeName << std::endl;
164  exit(1);
165  }
166 
167  if (Verbosity() > 0)
168  {
169  geo->identify();
170  }
171 
173  SaveToNodeTree(RunDetNode, paramnodename);
174  // save this to the parNode for use
175  PHNodeIterator parIter(parNode);
176  PHCompositeNode *ParDetNode = dynamic_cast<PHCompositeNode *>(parIter.findFirst("PHCompositeNode", m_Detector));
177  if (!ParDetNode)
178  {
179  ParDetNode = new PHCompositeNode(m_Detector);
180  parNode->addNode(ParDetNode);
181  }
182  PutOnParNode(ParDetNode, m_GeoNodeName);
183  m_Tmin = get_double_param("tmin");
184  m_Tmax = get_double_param("tmax");
185  m_crossingPeriod = get_double_param("beam_crossing_period");
186 
187  // get the nodes for the truth clustering
188  m_truthtracks = findNode::getClass<TrkrTruthTrackContainer>(topNode, "TRKR_TRUTHTRACKCONTAINER");
189  if (!m_truthtracks)
190  {
191  PHNodeIterator dstiter(dstNode);
193  auto newNode = new PHIODataNode<PHObject>(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject");
194  dstNode->addNode(newNode);
195  }
196 
197  m_truthclusters = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_TRUTHCLUSTERCONTAINER");
198  if (!m_truthclusters)
199  {
201  auto newNode = new PHIODataNode<PHObject>(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject");
202  dstNode->addNode(newNode);
203  }
204 
205  m_truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
206  if (!m_truthinfo)
207  {
208  std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl;
210  }
211 
212  // get cluster hits verbose (the hit and energy) information
214  // get the node
215  mClusHitsVerbose = findNode::getClass<ClusHitsVerbosev1>(topNode, "Trkr_TruthClusHitsVerbose");
216  if (!mClusHitsVerbose)
217  {
218  PHNodeIterator dstiter(dstNode);
219  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
220  if (!DetNode)
221  {
222  DetNode = new PHCompositeNode("TRKR");
223  dstNode->addNode(DetNode);
224  }
226  auto newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_TruthClusHitsVerbose", "PHObject");
227  DetNode->addNode(newNode);
228  }
229  }
230 
232 }
233 
235 {
236  PHG4HitContainer *g4hit = findNode::getClass<PHG4HitContainer>(topNode, m_HitNodeName);
237  if (!g4hit)
238  {
239  std::cout << "Could not locate g4 hit node " << m_HitNodeName << std::endl;
240  exit(1);
241  }
242 
243  // Get the TrkrHitSetContainer node
244  auto hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
245  if (!hitsetcontainer)
246  {
247  std::cout << "Could not locate TRKR_HITSET node, quit! " << std::endl;
248  exit(1);
249  }
250 
251  // Get the TrkrHitTruthAssoc node
252  auto hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
253  if (!hittruthassoc)
254  {
255  std::cout << "Could not locate TRKR_HITTRUTHASSOC node, quit! " << std::endl;
256  exit(1);
257  }
258 
259  PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode, m_GeoNodeName);
260  if (!geo)
261  {
262  std::cout << "Could not locate geometry node " << m_GeoNodeName << std::endl;
263  exit(1);
264  }
265  // loop over all of the layers in the hit container
266  // we need the geometry object for this layer
267  if (Verbosity() > 2) std::cout << " PHG4InttHitReco: Loop over hits" << std::endl;
268  PHG4HitContainer::ConstRange hit_begin_end = g4hit->getHits();
269 
270 
271  for (PHG4HitContainer::ConstIterator hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter)
272  {
273  const int sphxlayer = hiter->second->get_detid();
274  CylinderGeomIntt *layergeom = dynamic_cast<CylinderGeomIntt *>(geo->GetLayerGeom(sphxlayer));
275 
276 
277  // checking ADC timing integration window cut
278  // uses default values for now
279  // these should depend on layer radius
280  if (hiter->second->get_t(0) > m_Tmax) continue;
281  if (hiter->second->get_t(1) < m_Tmin) continue;
282 
283  truthcheck_g4hit(hiter->second, topNode);
284 
285  float time = (hiter->second->get_t(0) + hiter->second->get_t(1)) / 2.0;
286 
287  // I made this (small) diffusion up for now, we will get actual values for the Intt later
288  double diffusion_width = 5.0e-04; // diffusion radius 5 microns, in cm
289 
290  const int ladder_z_index = hiter->second->get_ladder_z_index();
291  const int ladder_phi_index = hiter->second->get_ladder_phi_index();
292 
293  // What we have is a hit in the sensor. We have not yet assigned the strip(s) that were hit, we do that here
294  //========================================================================
295 
296 // initialize them. In case find_strip_index_values does not set them we can pick this up
297  int strip_y_index_in = -99999;
298  int strip_z_index_in = -99999;
299  int strip_y_index_out = -99999;
300  int strip_z_index_out = -99999;
301 
302  layergeom->find_strip_index_values(ladder_z_index, hiter->second->get_local_y(0), hiter->second->get_local_z(0), strip_y_index_in, strip_z_index_in);
303  layergeom->find_strip_index_values(ladder_z_index, hiter->second->get_local_y(1), hiter->second->get_local_z(1), strip_y_index_out, strip_z_index_out);
304  if (strip_y_index_in == -99999 ||
305  strip_z_index_in == -99999 ||
306  strip_y_index_out == -99999 ||
307  strip_z_index_out == -99999)
308  {
309  std::cout << "setting of strip indices failed" << std::endl;
310  std::cout << "strip_y_index_in: " << strip_y_index_in << std::endl;
311  std::cout << "strip_z_index_in: " << strip_z_index_in << std::endl;
312  std::cout << "strip_y_index_out: " << strip_y_index_out << std::endl;
313  std::cout << "strip_z_index_out: " << strip_y_index_out << std::endl;
314  gSystem->Exit(1);
315  exit(1);
316  }
317  if (Verbosity() > 5)
318  {
319  // check to see if we get back the positions from these strip index values
320  double check_location[3] = {-1, -1, -1};
321  layergeom->find_strip_center_localcoords(ladder_z_index, strip_y_index_in, strip_z_index_in, check_location);
322  std::cout << " G4 entry location = " << hiter->second->get_local_x(0) << " " << hiter->second->get_local_y(0) << " " << hiter->second->get_local_z(0) << std::endl;
323  std::cout << " Check entry location = " << check_location[0] << " " << check_location[1] << " " << check_location[2] << std::endl;
324  layergeom->find_strip_center_localcoords(ladder_z_index, strip_y_index_out, strip_z_index_out, check_location);
325  std::cout << " G4 exit location = " << hiter->second->get_local_x(1) << " " << hiter->second->get_local_y(1) << " " << hiter->second->get_local_z(1) << std::endl;
326  std::cout << " Check exit location = " << check_location[0] << " " << check_location[1] << " " << check_location[2] << std::endl;
327  }
328 
329  // Now we find how many strips were crossed by this track, and divide the energy between them
330  int minstrip_z = strip_z_index_in;
331  int maxstrip_z = strip_z_index_out;
332  if (minstrip_z > maxstrip_z) std::swap(minstrip_z, maxstrip_z);
333 
334  int minstrip_y = strip_y_index_in;
335  int maxstrip_y = strip_y_index_out;
336  if (minstrip_y > maxstrip_y) std::swap(minstrip_y, maxstrip_y);
337 
338  // Use an algorithm similar to the one for the MVTX pixels, since it facilitates adding charge diffusion
339  // for now we assume small charge diffusion
340  std::vector<int> vybin;
341  std::vector<int> vzbin;
342  //std::vector<double> vlen;
343  std::vector<std::pair<double, double> > venergy;
344 
345  //====================================================
346  // Beginning of charge sharing implementation
347  // Find tracklet line inside sensor
348  // Divide tracklet line into n segments (vary n until answer stabilizes)
349  // Find centroid of each segment
350  // Diffuse charge at each centroid
351  // Apportion charge between neighboring pixels
352  // Add the pixel energy contributions from different track segments together
353  //====================================================
354 
355  // skip this hit if it involves an unreasonable number of pixels
356  // this skips it if either the xbin or ybin range traversed is greater than 8 (for 8 adding two pixels at each end makes the range 12)
357  if (maxstrip_y - minstrip_y > 12 || maxstrip_z - minstrip_z > 12)
358  {
359  continue;
360  }
361  // this hit is skipped above if this dimensioning would be exceeded
362  double stripenergy[13][13] = {}; // init to 0
363  double stripeion[13][13] = {}; // init to 0
364 
365  int nsegments = 10;
366  // Loop over track segments and diffuse charge at each segment location, collect energy in pixels
367  // Get the entry point of the hit in sensor local coordinates
368  gsl_vector_set(m_PathVec, 0, hiter->second->get_local_x(0));
369  gsl_vector_set(m_PathVec, 1, hiter->second->get_local_y(0));
370  gsl_vector_set(m_PathVec, 2, hiter->second->get_local_z(0));
371  gsl_vector_set(m_LocalOutVec, 0, hiter->second->get_local_x(1));
372  gsl_vector_set(m_LocalOutVec, 1, hiter->second->get_local_y(1));
373  gsl_vector_set(m_LocalOutVec, 2, hiter->second->get_local_z(1));
374  gsl_vector_sub(m_PathVec, m_LocalOutVec);
375  for (int i = 0; i < nsegments; i++)
376  {
377  // Find the tracklet segment location
378  // If there are n segments of equal length, we want 2*n intervals
379  // The 1st segment is centered at interval 1, the 2nd at interval 3, the nth at interval 2n -1
380  double interval = 2 * (double) i + 1;
381  double frac = interval / (double) (2 * nsegments);
382  gsl_vector_memcpy(m_SegmentVec, m_PathVec);
383  gsl_vector_scale(m_SegmentVec, frac);
384  gsl_vector_add(m_SegmentVec, m_LocalOutVec);
385  // Caculate the charge diffusion over this drift distance
386  // increases from diffusion width_min to diffusion_width_max
387  double diffusion_radius = diffusion_width;
388 
389  if (Verbosity() > 5)
390  std::cout << " segment " << i
391  << " interval " << interval
392  << " frac " << frac
393  << " local_in.X " << hiter->second->get_local_x(0)
394  << " local_in.Z " << hiter->second->get_local_z(0)
395  << " local_in.Y " << hiter->second->get_local_y(0)
396  << " pathvec.X " << gsl_vector_get(m_PathVec, 0)
397  << " pathvec.Z " << gsl_vector_get(m_PathVec, 2)
398  << " pathvec.Y " << gsl_vector_get(m_PathVec, 1)
399  << " segvec.X " << gsl_vector_get(m_SegmentVec, 0)
400  << " segvec.Z " << gsl_vector_get(m_SegmentVec, 2)
401  << " segvec.Y " << gsl_vector_get(m_SegmentVec, 1) << std::endl
402  << " diffusion_radius " << diffusion_radius
403  << std::endl;
404 
405  // Now find the area of overlap of the diffusion circle with each pixel and apportion the energy
406  for (int iz = minstrip_z; iz <= maxstrip_z; iz++)
407  {
408  for (int iy = minstrip_y; iy <= maxstrip_y; iy++)
409  {
410  // Find the pixel corners for this pixel number
411  double location[3] = {-1, -1, -1};
412  layergeom->find_strip_center_localcoords(ladder_z_index, iy, iz, location);
413  // note that (y1,z1) is the top left corner, (y2,z2) is the bottom right corner of the pixel - circle_rectangle_intersection expects this ordering
414  double y1 = location[1] - layergeom->get_strip_y_spacing() / 2.0;
415  double y2 = location[1] + layergeom->get_strip_y_spacing() / 2.0;
416  double z1 = location[2] + layergeom->get_strip_z_spacing() / 2.0;
417  double z2 = location[2] - layergeom->get_strip_z_spacing() / 2.0;
418 
419  // here m_SegmentVec.1 (Y) and m_SegmentVec.2 (Z) are the center of the circle, and diffusion_radius is the circle radius
420  // circle_rectangle_intersection returns the overlap area of the circle and the pixel. It is very fast if there is no overlap.
421  double striparea_frac = PHG4Utils::circle_rectangle_intersection(y1, z1, y2, z2, gsl_vector_get(m_SegmentVec, 1), gsl_vector_get(m_SegmentVec, 2), diffusion_radius) / (M_PI * (diffusion_radius * diffusion_radius));
422  // assume that the energy is deposited uniformly along the tracklet length, so that this segment gets the fraction 1/nsegments of the energy
423  stripenergy[iy - minstrip_y][iz - minstrip_z] += striparea_frac * hiter->second->get_edep() / (float) nsegments;
424  if (hiter->second->has_property(PHG4Hit::prop_eion))
425  {
426  stripeion[iy - minstrip_y][iz - minstrip_z] += striparea_frac * hiter->second->get_eion() / (float) nsegments;
427  }
428  if (Verbosity() > 5)
429  {
430  std::cout << " strip y index " << iy << " strip z index " << iz
431  << " strip area fraction of circle " << striparea_frac << " accumulated pixel energy " << stripenergy[iy - minstrip_y][iz - minstrip_z]
432  << std::endl;
433  }
434  }
435  }
436  } // end loop over segments
437  // now we have the energy deposited in each pixel, summed over all tracklet segments. We make a vector of all pixels with non-zero energy deposited
438 
439  for (int iz = minstrip_z; iz <= maxstrip_z; iz++)
440  {
441  for (int iy = minstrip_y; iy <= maxstrip_y; iy++)
442  {
443  if (stripenergy[iy - minstrip_y][iz - minstrip_z] > 0.0)
444  {
445  vybin.push_back(iy);
446  vzbin.push_back(iz);
447  std::pair<double, double> tmppair = std::make_pair(stripenergy[iy - minstrip_y][iz - minstrip_z], stripeion[iy - minstrip_y][iz - minstrip_z]);
448  venergy.push_back(tmppair);
449  if (Verbosity() > 1)
450  {
451  std::cout << " Added ybin " << iy << " zbin " << iz << " to vectors with energy " << stripenergy[iy - minstrip_y][iz - minstrip_z] << std::endl;
452  }
453  }
454  }
455  }
456 
457  //===================================
458  // End of charge sharing implementation
459  //===================================
460 
461  for (unsigned int i1 = 0; i1 < vybin.size(); i1++) // loop over all fired cells
462  {
463  // We add the Intt TrkrHitsets directly to the node using hitsetcontainer
464 
465  // Get the hit crossing
466  int crossing = (int) (round( time / m_crossingPeriod) );
467  // crossing has to fit into 5 bits
468  if(crossing < -512) crossing = -512;
469  if(crossing > 511) crossing = 511;
470  // We need to create the TrkrHitSet if not already made - each TrkrHitSet should correspond to a sensor for the Intt ?
471  // The hitset key includes the layer, the ladder_z_index (sensors numbered 0-3) and ladder_phi_index (azimuthal location of ladder) for this hit
472  TrkrDefs::hitsetkey hitsetkey = InttDefs::genHitSetKey(sphxlayer, ladder_z_index, ladder_phi_index, crossing);
473 
474  // Use existing hitset or add new one if needed
475  TrkrHitSetContainer::Iterator hitsetit = hitsetcontainer->findOrAddHitSet(hitsetkey);
476 
477  // generate the key for this hit
478  TrkrDefs::hitkey hitkey = InttDefs::genHitKey(vzbin[i1], vybin[i1]);
479  // See if this hit already exists
480  TrkrHit *hit = hitsetit->second->getHit(hitkey);
481  if (!hit)
482  {
483  // Otherwise, create a new one
484  hit = new TrkrHitv2();
485  hitsetit->second->addHitSpecificKey(hitkey, hit);
486  }
487 
488  // Either way, add the energy to it
489  if (Verbosity() > 2)
490  {
491  std::cout << "add energy " << venergy[i1].first << " to intthit " << std::endl;
492  }
493 
494  double hit_energy = venergy[i1].first * TrkrDefs::InttEnergyScaleup;
495  hit->addEnergy(hit_energy);
496 
497  addtruthhitset(hitsetkey, hitkey, hit_energy);
498 
499  // Add this hit to the association map
500  hittruthassoc->addAssoc(hitsetkey, hitkey, hiter->first);
501 
502  if (Verbosity() > 2)
503  {
504  std::cout << "PHG4InttHitReco: added hit wirh hitsetkey " << hitsetkey << " hitkey " << hitkey << " g4hitkey " << hiter->first << " energy " << hit->getEnergy() << std::endl;
505  }
506  }
507  } // end loop over g4hits
508 
509  // print the list of entries in the association table
510  if (Verbosity() > 0)
511  {
512  std::cout << "From PHG4InttHitReco: " << std::endl;
513  hitsetcontainer->identify();
514  hittruthassoc->identify();
515  }
516 
517  if (m_is_emb) {
518  cluster_truthhits(topNode); // the last track was truth -- make it's clusters
519  prior_g4hit = nullptr;
520  }
521 
522  end_event_truthcluster( topNode );
524 } // end process_event
525 
527 {
528  // if we ever need separate timing windows, don't patch around here!
529  // use PHParameterContainerInterface which
530  // provides for multiple layers/detector types
531  set_default_double_param("tmax", 7020.0); // max upper time window for extended readout
532  set_default_double_param("tmin", -20.0); // min lower time window for extended readout
533  set_default_double_param("beam_crossing_period", 106.0);
534 
535  return;
536 }
537 
539  if (g4hit==nullptr) return;
540  int new_trkid = g4hit->get_trkid();
541 
542  bool is_new_track = (new_trkid != m_trkid);
543  if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<<new_trkid<<")" << std::endl;
544  if (!is_new_track) {
545  // check to see if it is an embedded track that meets the looper condition:
546  if (m_is_emb) {
547  if (prior_g4hit!=nullptr
548  && ( std::abs(prior_g4hit->get_x(0)-g4hit->get_x(0)) > max_g4hitstep
549  || std::abs(prior_g4hit->get_y(0)-g4hit->get_y(0)) > max_g4hitstep
550  )
551  )
552  {
553  // this is a looper track -- cluster hits up to this point already
554  cluster_truthhits(topNode);
555  }
556  prior_g4hit = g4hit;
557  }
558  return;
559  }
560  // <- STATUS: this is a new track
561  if (Verbosity()>2) std::cout << PHWHERE << std::endl << " -> Found new embedded track with id: " << new_trkid << std::endl;
562  if (m_is_emb) {
563  //cluster the old track
564  cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track
565  m_current_track = nullptr;
566  prior_g4hit = nullptr;
567  }
568  m_trkid = new_trkid;
570  if (m_is_emb) {
572  prior_g4hit = g4hit;
573  }
574 }
575 
577  if (m_is_emb) {
578  cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track
579  m_current_track = nullptr;
580  m_trkid = -1;
581  m_is_emb = false;
582  }
583  m_hitsetkey_cnt.clear();
584 }
585 
589  float neffelectrons)
590 {
591  if (!m_is_emb) return;
593  // See if this hit already exists
594  TrkrHit *hit = nullptr;
595  hit = hitsetit->second->getHit(hitkey);
596  if (!hit)
597  {
598  // create a new one
599  hit = new TrkrHitv2();
600  hitsetit->second->addHitSpecificKey(hitkey, hit);
601  }
602  // Either way, add the energy to it -- adc values will be added at digitization
603  hit->addEnergy(neffelectrons);
604 }
605 
607  // -----------------------------------------------
608  // Digitize, adapted from g4intt/PHG4InttDigitizer
609  // -----------------------------------------------
610  //
611  // Note: not using digitization, because as currently implemented, the SvtxTrack clusters
612  // don't use the adc weighting from the digitization code anyway.
613  //
614  // don't use the dead map for truth tracks
615  /* TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); */
616  /* for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; */
617  /* hitset_iter != hitset_range.second; */
618  /* ++hitset_iter) */
619  /* { */
620  /* // we have an itrator to one TrkrHitSet for the intt from the trkrHitSetContainer */
621  /* // get the hitset key so we can find the layer */
622  /* TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; */
623  /* const int layer = TrkrDefs::getLayer(hitsetkey); */
624  /* const int ladder_phi = InttDefs::getLadderPhiId(hitsetkey); */
625  /* const int ladder_z = InttDefs::getLadderZId(hitsetkey); */
626 
627  /* if (Verbosity() > 1) */
628  /* { */
629  /* std::cout << "PHG4InttDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; */
630  /* } */
631  /* // get all of the hits from this hitset */
632  /* TrkrHitSet *hitset = hitset_iter->second; */
633  /* TrkrHitSet::ConstRange hit_range = hitset->getHits(); */
634  /* /1* std::set<TrkrDefs::hitkey> dead_hits; // hits on dead channel *1/ // no dead channels implemented */
635  /* for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; */
636  /* hit_iter != hit_range.second; */
637  /* ++hit_iter) */
638  /* { */
639  /* // ++m_nCells; // not really used by PHG4InttDigitizer */
640 
641  /* TrkrHit *hit = hit_iter->second; */
642  /* TrkrDefs::hitkey hitkey = hit_iter->first; */
643  /* int strip_col = InttDefs::getCol(hitkey); // strip z index */
644  /* int strip_row = InttDefs::getRow(hitkey); // strip phi index */
645 
646  /* // FIXME need energy scales here */
647  /* if (_energy_scale.count(layer) > 1) */
648  /* { */
649  /* assert(!"Error: _energy_scale has two or more keys."); */
650  /* } */
651  /* const float mip_e = _energy_scale[layer]; */
652 
653  /* std::vector<std::pair<double, double> > vadcrange = _max_fphx_adc[layer]; */
654 
655  /* int adc = 0; */
656  /* for (unsigned int irange = 0; irange < vadcrange.size(); ++irange) */
657  /* { */
658  /* if (hit->getEnergy() / TrkrDefs::InttEnergyScaleup >= vadcrange[irange].first * */
659  /* (double) mip_e && hit->getEnergy() / TrkrDefs::InttEnergyScaleup */
660  /* < vadcrange[irange].second * (double) mip_e) */
661  /* { */
662  /* adc = (unsigned short) irange; */
663  /* } */
664  /* } */
665  /* hit->setAdc(adc); */
666 
667  /* if (Verbosity() > 2) */
668  /* { */
669  /* std::cout << "PHG4InttDigitizer: found hit with layer " << layer << " ladder_z " << ladder_z << " ladder_phi " << ladder_phi */
670  /* << " strip_col " << strip_col << " strip_row " << strip_row << " adc " << hit->getAdc() << std::endl; */
671  /* } */
672  /* } // end loop over hits in this hitset */
673 
674  /* // remove hits on dead channel in TRKR_HITSET and TRKR_HITTRUTHASSOC */
675  /* for (const auto &key : dead_hits) */
676  /* { */
677  /* if (Verbosity() > 2) */
678  /* { */
679  /* std::cout << " PHG4InttDigitizer: remove hit with key: " << key << std::endl; */
680  /* } */
681  /* hitset->removeHit(key); */
682  /* } */
683  /* } // end loop over hitsets */
684 
685  // -----------------------------------------------
686  // Cluster, adapted from intt/InttClusterizer
687  // -----------------------------------------------
688  if (Verbosity() > 1) std::cout << "Clustering truth clusters" << std::endl;
689 
690  //-----------
691  // Clustering
692  //-----------
693  // get the geometry node
694  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_INTT");
695  if (!geom_container) return;
696 
697 
698  // loop over the InttHitSet objects
699  TrkrHitSetContainer::ConstRange hitsetrange =
700  m_truth_hits->getHitSets(TrkrDefs::TrkrId::inttId); // from TruthClusterizerBase
701 
702  for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
703  hitsetitr != hitsetrange.second; ++hitsetitr)
704  {
705  // Each hitset contains only hits that are clusterizable - i.e. belong to a single sensor
706  TrkrHitSet* hitset = hitsetitr->second;
708 
709  // cluster this hitset; all pixels in it are, by definition, part of the same clusters
710 
711  if ( Verbosity() > 1 ) std::cout << "InttClusterizer found hitsetkey " << hitsetitr->first << std::endl;
712  if ( Verbosity() > 2 ) hitset->identify();
713 
714  // we have a single hitset, get the info that identifies the sensor
715 
716  if (Verbosity() > 2)
717  std::cout << "Filling cluster with hitsetkey " << ((int)hitsetkey) << std::endl;
718 
719  // get the bunch crossing number from the hitsetkey
720  /* short int crossing = InttDefs::getTimeBucketId(hitset->getHitSetKey()); */
721 
722  // determine the size of the cluster in phi and z, useful for track fitting the cluster
723  std::set<int> phibins;
724  std::set<int> zbins;
725 
726  // determine the cluster position...
727  double xlocalsum = 0.0;
728  double ylocalsum = 0.0;
729  double zlocalsum = 0.0;
730  unsigned int clus_adc = 0.0;
731  unsigned nhits = 0;
732 
733  // aggregate the adc values
734  double sum_adc {0};
735  TrkrHitSet::ConstRange hitrangei = hitset->getHits();
736  for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) {
737  sum_adc += ihit->second->getAdc();
738  }
739 
740  // tune this energy threshold in the same maner of the MVTX, namely to get the same kind of pixel sizes
741  // as the SvtxTrack clusters
742  /* const double threshold = sum_adc * m_truth_pixelthreshold; */
743  const double threshold = sum_adc * m_pixel_thresholdrat; //FIXME -- tune this as needed
744  std::map<int,unsigned int> m_iphi, m_it, m_iphiCut, m_itCut; // FIXME
745 
746  int layer = TrkrDefs::getLayer ( hitsetkey );
747  CylinderGeomIntt* geom = dynamic_cast<CylinderGeomIntt*>(geom_container->GetLayerGeom(layer));
748 
749  int ladder_z_index = InttDefs::getLadderZId ( hitsetkey );
750 
751  for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit)
752  {
753  int col = InttDefs::getCol ( ihit->first );
754  int row = InttDefs::getRow ( ihit->first );
755  auto adc = ihit->second->getAdc();
756 
757  if (mClusHitsVerbose) {
758  std::map<int,unsigned int>& m_phi = (adc<threshold) ? m_iphiCut : m_iphi;
759  std::map<int,unsigned int>& m_z = (adc<threshold) ? m_itCut : m_it;
760 
761  auto pnew = m_phi.try_emplace(row,adc);
762  if (!pnew.second) pnew.first->second += adc;
763 
764  pnew = m_z.try_emplace(col,adc);
765  if (!pnew.second) pnew.first->second += adc;
766  }
767  if (adc<threshold) continue;
768 
769  clus_adc += adc;
770  zbins .insert(col);
771  phibins .insert(row);
772 
773  // now get the positions from the geometry
774  double local_hit_location[3] = {0., 0., 0.};
775 
776  geom->find_strip_center_localcoords(ladder_z_index, row, col, local_hit_location);
777 
778  xlocalsum += local_hit_location[0];
779  ylocalsum += local_hit_location[1];
780  zlocalsum += local_hit_location[2];
781 
782  ++nhits;
783 
784  if (Verbosity() > 6)
785  {
786  std::cout << " From geometry object: hit x " << local_hit_location[0]
787  << " hit y " << local_hit_location[1] << " hit z " << local_hit_location[2] << std::endl;
788  std::cout << " nhits " << nhits << " clusx = " << xlocalsum / nhits << " clusy "
789  << ylocalsum / nhits << " clusz " << zlocalsum / nhits << std::endl;
790  }
791  // NOTE:
792  /* if (_make_e_weights[layer]) */ // these values are all false by default
793  /* if ( false ) // the current implementation of the code does not weight by adc values */
794  /* // therefore the default here is to use use adc to cut the outliers and nothing else */
795  /* { */
796  /* xlocalsum += local_hit_location[0] * (double) hit_adc; */
797  /* ylocalsum += local_hit_location[1] * (double) hit_adc; */
798  /* zlocalsum += local_hit_location[2] * (double) hit_adc; */
799  /* } */
800  /* else */
801  /* { */
802  /* } */
803  /* if(hit_adc > clus_maxadc) clus_maxadc = hit_adc; */ //FIXME: do we want this value to be set?
804  /* clus_energy += hit_adc; */
805  }
806  if (mClusHitsVerbose) {
807  if (Verbosity()>10) {
808  for (auto& hit : m_iphi) {
809  std::cout << " m_phi(" << hit.first <<" : " << hit.second<<") " << std::endl;
810  }
811  }
812  for (auto& hit : m_iphi) mClusHitsVerbose->addPhiHit (hit.first, (float)hit.second);
813  for (auto& hit : m_it) mClusHitsVerbose->addZHit (hit.first, (float)hit.second);
814  for (auto& hit : m_iphiCut) mClusHitsVerbose->addPhiCutHit (hit.first, (float)hit.second);
815  for (auto& hit : m_itCut) mClusHitsVerbose->addZCutHit (hit.first, (float)hit.second);
816  }
817 
818 
819  // add this cluster-hit association to the association map of (clusterkey,hitkey)
820  if (Verbosity() > 2) std::cout << " nhits = " << nhits << std::endl;
821 
822  /* static const float invsqrt12 = 1./sqrt(12); */
823  // scale factors (phi direction)
824  /*
825  they corresponds to clusters of size 1 and 2 in phi
826  other clusters, which are very few and pathological, get a scale factor of 1
827  These scale factors are applied to produce cluster pulls with width unity
828  */
829 
830  /* float phierror = pitch * invsqrt12; */
831 
832  /* static constexpr std::array<double, 3> scalefactors_phi = {{ 0.85, 0.4, 0.33 }}; */
833  /* if( phibins.size() == 1 && layer < 5) phierror*=scalefactors_phi[0]; */
834  /* else if( phibins.size() == 2 && layer < 5) phierror*=scalefactors_phi[1]; */
835  /* else if( phibins.size() == 2 && layer > 4) phierror*=scalefactors_phi[2]; */
836  /* // z error. All clusters have a z-size of 1. */
837  /* const float zerror = length * invsqrt12; */
838  if (nhits == 0) continue;
839 
840  double cluslocaly = ylocalsum / nhits;
841  double cluslocalz = zlocalsum / nhits;
842 
843  //if (_make_e_weights[layer]) // FIXME: this is always false for now
844  /* { */
845  /* cluslocaly = ylocalsum / (double) clus_adc; */
846  /* cluslocalz = zlocalsum / (double) clus_adc; */
847  /* } */
848  /* else */
849  /* { */
850  /* } */
851  if ( m_cluster_version==4 ){
852  auto clus = std::make_unique<TrkrClusterv4>();
853  clus->setAdc(clus_adc);
854  clus->setPhiSize(phibins.size());
855  clus->setZSize(1);
856 
857  if(Verbosity() > 10) clus->identify();
858 
859  clus->setLocalX(cluslocaly);
860  clus->setLocalY(cluslocalz);
861  // silicon has a 1-1 map between hitsetkey and surfaces. So set to 0
862  clus->setSubSurfKey(0);
863 
864  m_hitsetkey_cnt.try_emplace(hitsetkey,0);
865  unsigned int& cnt = m_hitsetkey_cnt[hitsetkey];
866  TrkrDefs::cluskey ckey = TrkrDefs::genClusKey(hitsetkey, cnt);
867  m_truthclusters->addClusterSpecifyKey(ckey, clus.release());
869  if (mClusHitsVerbose) {
871  if (Verbosity()>10) std::cout << " ClusHitsVerbose.size (in INTT): "
872  << mClusHitsVerbose->getMap().size() << std::endl;
873  }
874  ++cnt;
875  } // end loop over hitsets
876  }
877 
878  m_truth_hits->Reset();
879  prior_g4hit = nullptr;
880  return;
881 }