Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4MvtxHitReco.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4MvtxHitReco.cc
1 // this is the new trackbase version
2 
3 #include "PHG4MvtxHitReco.h"
4 
6 #include <mvtx/MvtxHitPruner.h>
7 
8 #include <trackbase/MvtxDefs.h>
9 #include <trackbase/TrkrDefs.h>
10 #include <trackbase/TrkrHit.h> // // make iwyu happy
11 #include <trackbase/TrkrHitSet.h>
12 #include <trackbase/TrkrHitSetContainer.h> // make iwyu happy
14 #include <trackbase/TrkrHitTruthAssoc.h> // make iwyu happy
16 #include <trackbase/TrkrHitv2.h> // for TrkrHit
17 
25 
26 #include <g4detectors/PHG4CylinderGeom.h> // for PHG4CylinderGeom
28 
29 #include <g4main/PHG4Hit.h>
31 #include <g4main/PHG4Utils.h>
33 
35 #include <fun4all/SubsysReco.h> // for SubsysReco
36 
37 #include <phool/PHCompositeNode.h>
38 #include <phool/PHIODataNode.h>
39 #include <phool/PHNode.h> // for PHNode
40 #include <phool/PHNodeIterator.h>
41 #include <phool/PHObject.h> // for PHObject
42 #include <phool/PHRandomSeed.h> // for PHRandomSeed
43 #include <phool/getClass.h>
44 #include <phool/phool.h> // for PHWHERE
45 
46 #include <G4SystemOfUnits.hh> // for microsecond
47 
48 #include <TVector3.h> // for TVector3, ope...
49 
50 #include <cassert> // for assert
51 #include <cmath>
52 #include <cstdlib>
53 #include <iostream>
54 #include <memory> // for allocator_tra...
55 #include <vector> // for vector
56 #include <set> // for vector
57 
59  : SubsysReco(name)
60  , PHParameterInterface(name)
61  , m_detector(detector)
62  , m_tmin(-5000.)
63  , m_tmax(5000.)
64  , m_strobe_width(5.)
65  , m_strobe_separation(0.)
66  , m_truth_hits { new TrkrHitSetContainerv1 }
67 {
68  if (Verbosity())
69  {
70  std::cout << "Creating PHG4MvtxHitReco for detector = " << detector << std::endl;
71  }
72  // initialize rng
73  const uint seed = PHRandomSeed();
74  m_rng.reset(gsl_rng_alloc(gsl_rng_mt19937));
75  gsl_rng_set(m_rng.get(), seed);
76 
78 }
79 
81 {
83 
84  m_tmin = get_double_param("mvtx_tmin");
85  m_tmax = get_double_param("mvtx_tmax");
86  m_strobe_width = get_double_param("mvtx_strobe_width");
87  m_strobe_separation = get_double_param("mvtx_strobe_separation");
88  m_in_sphenix_srdo = (bool) get_int_param("mvtx_in_sphenix_srdo");
89 
91 
92  // printout
93  std::cout
94  << "PHG4MvtxHitReco::InitRun\n"
95  << " m_tmin: " << m_tmin << "ns, m_tmax: " << m_tmax << "ns\n"
96  << " m_strobe_width: " << m_strobe_width << "\n"
97  << " m_strobe_separation: " << m_strobe_separation << "\n"
98  << " m_extended_readout_time: " << m_extended_readout_time << "\n"
99  << " m_in_sphenix_srdo: " << (m_in_sphenix_srdo ? "true" : "false") << "\n"
100  << std::endl;
101 
103  PHNodeIterator iter(topNode);
104  auto dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
105  assert(dstNode);
106 
108  auto runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
109  assert(runNode);
110 
111  PHNodeIterator runiter(runNode);
112  auto runDetNode = dynamic_cast<PHCompositeNode *>(runiter.findFirst("PHCompositeNode", m_detector));
113  if (!runDetNode)
114  {
115  runDetNode = new PHCompositeNode(m_detector);
116  runNode->addNode(runDetNode);
117  }
118  std::string paramNodeName = "G4CELLPARAM_" + m_detector;
119  SaveToNodeTree(runDetNode, paramNodeName);
120 
121  // create hitset container if needed
122  auto hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
123  if (!hitsetcontainer)
124  {
125  PHNodeIterator dstiter(dstNode);
126  auto trkrnode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
127  if (!trkrnode)
128  {
129  trkrnode = new PHCompositeNode("TRKR");
130  dstNode->addNode(trkrnode);
131  }
132 
133  hitsetcontainer = new TrkrHitSetContainerv1;
134  auto newNode = new PHIODataNode<PHObject>(hitsetcontainer, "TRKR_HITSET", "PHObject");
135  trkrnode->addNode(newNode);
136  }
137 
138  // create hit truth association if needed
139  auto hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
140  if (!hittruthassoc)
141  {
142  PHNodeIterator dstiter(dstNode);
143  auto trkrnode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
144  if (!trkrnode)
145  {
146  trkrnode = new PHCompositeNode("TRKR");
147  dstNode->addNode(trkrnode);
148  }
149 
150  hittruthassoc = new TrkrHitTruthAssocv1;
151  auto newNode = new PHIODataNode<PHObject>(hittruthassoc, "TRKR_HITTRUTHASSOC", "PHObject");
152  trkrnode->addNode(newNode);
153  }
154 
155  // get the nodes for the truth clustering
156  m_truthtracks = findNode::getClass<TrkrTruthTrackContainer>(topNode, "TRKR_TRUTHTRACKCONTAINER");
157  if (!m_truthtracks)
158  {
159  PHNodeIterator dstiter(dstNode);
161  auto newNode = new PHIODataNode<PHObject>(m_truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject");
162  dstNode->addNode(newNode);
163  }
164 
165  m_truthclusters = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_TRUTHCLUSTERCONTAINER");
166  if (!m_truthclusters)
167  {
169  auto newNode = new PHIODataNode<PHObject>(m_truthclusters, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject");
170  dstNode->addNode(newNode);
171  }
172 
173  m_truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
174  if (!m_truthinfo)
175  {
176  std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl;
178  }
179 
181  // get the node
182  mClusHitsVerbose = findNode::getClass<ClusHitsVerbosev1>(topNode, "Trkr_TruthClusHitsVerbose");
183  if (!mClusHitsVerbose)
184  {
185  PHNodeIterator dstiter(dstNode);
186  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
187  if (!DetNode)
188  {
189  DetNode = new PHCompositeNode("TRKR");
190  dstNode->addNode(DetNode);
191  }
193  auto newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_TruthClusHitsVerbose", "PHObject");
194  DetNode->addNode(newNode);
195  }
196  }
197 
199 }
200 
202 {
203  ActsGeometry *tgeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
204  if (!tgeometry)
205  {
206  std::cout << "Could not locate acts geometry" << std::endl;
207  exit(1);
208  }
209 
210  // G4Hits
211  const std::string g4hitnodename = "G4HIT_" + m_detector;
212  auto g4hitContainer = findNode::getClass<PHG4HitContainer>(topNode, g4hitnodename);
213  assert(g4hitContainer);
214 
215  // geometry
216  const std::string geonodename = "CYLINDERGEOM_" + m_detector;
217  auto geoNode = findNode::getClass<PHG4CylinderGeomContainer>(topNode, geonodename);
218  assert(geoNode);
219 
220  // Get the TrkrHitSetContainer node
221  auto trkrHitSetContainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
222  assert(trkrHitSetContainer);
223 
224  // Get the TrkrHitTruthAssoc node
225  auto hitTruthAssoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
226  assert(hitTruthAssoc);
227 
228  // Generate strobe zero relative to trigger time
229  double strobe_zero_tm_start = generate_strobe_zero_tm_start();
230 
231  // assumes we want the range of accepted times to be from 0 to m_extended_readout_time
232  std::pair<double, double> alpide_pulse = generate_alpide_pulse(0.0); // this currently just returns fixed values
233  double clearance = 200.0; // 0.2 microsecond for luck
234  m_tmax = m_extended_readout_time + alpide_pulse.first + clearance;
235  m_tmin = alpide_pulse.second - clearance;
236 
237  // The above limits will select g4hit times of 0 up to m_extended_readout_time (only) with extensions by clearance
238  // But we really want to select all g4hit times that will be strobed, so replace clearance with something derived from
239  // the strobe start time in future
240 
241  if (Verbosity() > 0)
242  std::cout << " m_strobe_width " << m_strobe_width << " m_strobe_separation " << m_strobe_separation << " strobe_zero_tm_start " << strobe_zero_tm_start << " m_extended_readout_time " << m_extended_readout_time << std::endl;
243 
244  // loop over all of the layers in the g4hit container
245  auto layer_range = g4hitContainer->getLayers();
246  for (auto layer_it = layer_range.first; layer_it != layer_range.second; ++layer_it)
247  {
248  // get layer
249  const auto layer = *layer_it;
250  assert(layer < 3);
251 
252  // we need the geometry object for this layer
253  auto layergeom = dynamic_cast<CylinderGeom_Mvtx *>(geoNode->GetLayerGeom(layer));
254  assert(layergeom);
255 
256  // loop over the hits in this layer
257  const PHG4HitContainer::ConstRange g4hit_range = g4hitContainer->getHits(layer);
258 
259  // Get some layer parameters for later use
260  double xpixw = layergeom->get_pixel_x();
261  double xpixw_half = xpixw / 2.0;
262  double zpixw = layergeom->get_pixel_z();
263  double zpixw_half = zpixw / 2.0;
264  int maxNX = layergeom->get_NX();
265  int maxNZ = layergeom->get_NZ();
266 
267  // Now loop over all g4 hits for this layer
268  for (auto g4hit_it = g4hit_range.first; g4hit_it != g4hit_range.second; ++g4hit_it)
269  {
270  // get hit
271  auto g4hit = g4hit_it->second;
272 
273  truthcheck_g4hit(g4hit, topNode);
274 
275  //cout << "From PHG4MvtxHitReco: Call hit print method: " << std::endl;
276  if (Verbosity() > 4)
277  g4hit->print();
278 
279  unsigned int n_replica = 1;
280 
281  //Function returns ns
282  //std::pair<double, double> alpide_pulse = generate_alpide_pulse(g4hit->get_edep());
283 
284  double lead_edge = g4hit->get_t(0) * ns + alpide_pulse.first;
285  double fall_edge = g4hit->get_t(1) * ns + alpide_pulse.second;
286 
287  if (Verbosity() > 0)
288  std::cout << " MvtxHitReco: t0 " << g4hit->get_t(0) << " t1 " << g4hit->get_t(1) << " lead_edge " << lead_edge
289  << " fall_edge " << fall_edge << " tmin " << m_tmin << " tmax " << m_tmax << std::endl;
290 
291  // check that the signal occurred witin the time window 0 to extended_readout_time, discard if not
292  if (lead_edge > m_tmax or fall_edge < m_tmin) continue;
293 
294  double t0_strobe_frame = get_strobe_frame(lead_edge, strobe_zero_tm_start);
295  double t1_strobe_frame = get_strobe_frame(fall_edge, strobe_zero_tm_start);
296  n_replica += t1_strobe_frame - t0_strobe_frame;
297 
298  if (Verbosity() > 1)
299  {
300  std::cout
301  << "MVTX is in strobed timing mode\n"
302  << "layer " << layer << " t0(ns) " << g4hit->get_t(0) << " t1(ns) " << g4hit->get_t(1) << "\n"
303  << "strobe_zero_tm_start(us): " << strobe_zero_tm_start / microsecond << "\n"
304  << "strobe width(us): " << m_strobe_width / microsecond << "\n"
305  << "strobe separation(us): " << m_strobe_separation / microsecond << "\n"
306  << "alpide pulse start(us): " << alpide_pulse.first / microsecond << "\n"
307  << "alpide pulse end(us): " << alpide_pulse.second / microsecond << "\n"
308  << "tm_zero_strobe_frame: " << t0_strobe_frame << "\n"
309  << "tm_one_strobe_frame: " << t1_strobe_frame << "\n"
310  << "number of hit replica: " << n_replica << "\n"
311  << std::endl;
312  }
313 
314  assert(n_replica >= 1);
315 
316  // get_property_int(const PROPERTY prop_id) const {return INT_MIN;}
317  int stave_number = g4hit->get_property_int(PHG4Hit::prop_stave_index);
318  int chip_number = g4hit->get_property_int(PHG4Hit::prop_chip_index);
319 
320  TVector3 local_in(g4hit->get_local_x(0), g4hit->get_local_y(0), g4hit->get_local_z(0));
321  TVector3 local_out(g4hit->get_local_x(1), g4hit->get_local_y(1), g4hit->get_local_z(1));
322  TVector3 midpoint((local_in.X() + local_out.X()) / 2.0, (local_in.Y() + local_out.Y()) / 2.0, (local_in.Z() + local_out.Z()) / 2.0);
323 
324  if (Verbosity() > 2)
325  {
326  std::cout
327  << " world entry point position: "
328  << g4hit->get_x(0) << " " << g4hit->get_y(0) << " " << g4hit->get_z(0) << "\n"
329  << " world exit point position: "
330  << g4hit->get_x(1) << " " << g4hit->get_y(1) << " " << g4hit->get_z(1) << "\n"
331  << " local coords of entry point from G4 "
332  << g4hit->get_local_x(0) << " " << g4hit->get_local_y(0) << " " << g4hit->get_local_z(0)
333  << std::endl;
334 
335  TVector3 world_in(g4hit->get_x(0), g4hit->get_y(0), g4hit->get_z(0));
336  auto hskey = MvtxDefs::genHitSetKey(layer, stave_number, chip_number, 0);
337  auto surf = tgeometry->maps().getSiliconSurface(hskey);
338 
339  TVector3 local_in_check = layergeom->get_local_from_world_coords(surf, tgeometry, world_in);
340  std::cout
341  << " local coords of entry point from geom (a check) "
342  << local_in_check.X() << " " << local_in_check.Y() << " " << local_in_check.Z() << "\n"
343  << " local coords of exit point from G4 "
344  << g4hit->get_local_x(1) << " " << g4hit->get_local_y(1) << " " << g4hit->get_local_z(1)
345  << "\n"
346  << " local coords of exit point from geom (a check) "
347  << local_out.X() << " " << local_out.Y() << " " << local_out.Z()
348  << std::endl;
349  }
350  /*
351  if (Verbosity() > 4)
352  {
353  // As a check, get the positions of the hit pixels in world coordinates from the geo object
354  auto hskey = MvtxDefs::genHitSetKey(*layer,stave_number,chip_number,strobe);
355  auto surf = tgeometry->maps().getSiliconSurface(hskey);
356 
357  TVector3 location_in = layergeom->get_world_from_local_coords(surf,tgeometry, local_in);
358  TVector3 location_out = layergeom->get_world_from_local_coords(surf,tgeometry, local_out);
359 
360  std::cout
361  << std::endl
362  << " PHG4MvtxHitReco: Found world entry location from geometry for "
363  << " stave number " << stave_number
364  << " half stave number " << half_stave_number
365  << " module number " << module_number
366  << " chip number " << chip_number
367  << std::endl
368  << " x = " << location_in.X()
369  << " y = " << location_in.Y()
370  << " z = " << location_in.Z()
371  << " radius " << sqrt(pow(location_in.X(), 2) + pow(location_in.Y(), 2))
372  << " angle " << atan(location_in.Y() / location_in.X())
373  << std::endl;
374  << " PHG4MvtxHitReco: The world entry location from G4 was "
375  << " x = " << g4hit->get_x(0)
376  << " y = " << g4hit->get_y(0)
377  << " z = " << g4hit->get_z(0)
378  << " radius " << sqrt(pow(g4hit->get_x(0), 2) + pow(g4hit->get_y(0), 2))
379  << " angle " << atan(g4hit->get_y(0) / g4hit->get_x(0))
380  << std::endl;
381  << " difference in x = " << g4hit->get_x(0) - location_in.X()
382  << " difference in y = " << g4hit->get_y(0) - location_in.Y()
383  << " difference in z = " << g4hit->get_z(0) - location_in.Z()
384  << " difference in radius = "
385  << sqrt(pow(g4hit->get_x(0), 2) + pow(g4hit->get_y(0), 2)) - sqrt(pow(location_in.X(), 2) + pow(location_in.Y(), 2))
386  << " in angle = " << atan(g4hit->get_y(0) / g4hit->get_x(0)) - atan(location_in.Y() / location_in.X())
387  << std::endl;
388  }
389  */
390  // Get the pixel number of the entry location
391  int pixel_number_in = layergeom->get_pixel_from_local_coords(local_in);
392  // Get the pixel number of the exit location
393  int pixel_number_out = layergeom->get_pixel_from_local_coords(local_out);
394 
395  if (pixel_number_in < 0 || pixel_number_out < 0)
396  {
397  std::cout
398  << "Oops! got negative pixel number in layer " << layergeom->get_layer()
399  << " pixel_number_in " << pixel_number_in
400  << " pixel_number_out " << pixel_number_out
401  << " local_in = " << local_in.X() << " " << local_in.Y() << " " << local_in.Z()
402  << " local_out = " << local_out.X() << " " << local_out.Y() << " " << local_out.Z()
403  << std::endl;
405  }
406 
407  if (Verbosity() > 3)
408  {
409  std::cout
410  << "entry pixel number " << pixel_number_in
411  << " exit pixel number " << pixel_number_out
412  << std::endl;
413  }
414 
415  std::vector<int> vpixel;
416  std::vector<int> vxbin;
417  std::vector<int> vzbin;
418  std::vector<std::pair<double, double> > venergy;
419  //double trklen = 0.0;
420 
421  //===================================================
422  // OK, now we have found which sensor the hit is in, extracted the hit
423  // position in local sensor coordinates, and found the pixel numbers of the
424  // entry point and exit point
425 
426  //====================================================
427  // Beginning of charge sharing implementation
428  // Find tracklet line inside sensor
429  // Divide tracklet line into n segments (vary n until answer stabilizes)
430  // Find centroid of each segment
431  // Diffuse charge at each centroid
432  // Apportion charge between neighboring pixels
433  // Add the pixel energy contributions from different track segments together
434  //====================================================
435 
436  TVector3 pathvec = local_in - local_out;
437 
438  // See figure 7.3 of the thesis by Lucasz Maczewski (arXiv:10053.3710) for diffusion simulations in a MAPS epitaxial layer
439  // The diffusion widths below were inspired by those plots, corresponding to where the probability drops off to 1/3 of the peak value
440  // However note that we make the simplifying assumption that the probability distribution is flat within this diffusion width,
441  // while in the simulation it is not
442  //double diffusion_width_max = 35.0e-04; // maximum diffusion radius 35 microns, in cm
443  //double diffusion_width_min = 12.0e-04; // minimum diffusion radius 12 microns, in cm
444  double diffusion_width_max = 25.0e-04; // maximum diffusion radius 35 microns, in cm
445  double diffusion_width_min = 8.0e-04; // minimum diffusion radius 12 microns, in cm
446 
447  double ydrift_max = pathvec.Y();
448  int nsegments = 4;
449 
450  // we want to make a list of all pixels possibly affected by this hit
451  // we take the entry and exit locations in local coordinates, and build
452  // a rectangular array of pixels that encompasses both, with "nadd" pixels added all around
453 
454  int xbin_in = layergeom->get_pixel_X_from_pixel_number(pixel_number_in);
455  int zbin_in = layergeom->get_pixel_Z_from_pixel_number(pixel_number_in);
456  int xbin_out = layergeom->get_pixel_X_from_pixel_number(pixel_number_out);
457  int zbin_out = layergeom->get_pixel_Z_from_pixel_number(pixel_number_out);
458 
459  int xbin_max, xbin_min;
460  int nadd = 2;
461  if (xbin_in > xbin_out)
462  {
463  xbin_max = xbin_in + nadd;
464  xbin_min = xbin_out - nadd;
465  }
466  else
467  {
468  xbin_max = xbin_out + nadd;
469  xbin_min = xbin_in - nadd;
470  }
471 
472  int zbin_max, zbin_min;
473  if (zbin_in > zbin_out)
474  {
475  zbin_max = zbin_in + nadd;
476  zbin_min = zbin_out - nadd;
477  }
478  else
479  {
480  zbin_max = zbin_out + nadd;
481  zbin_min = zbin_in - nadd;
482  }
483 
484  // need to check that values of xbin and zbin are within the valid range
485  // YCM: Fix pixel range: Xbin (row) 0 to 511, Zbin (col) 0 to 1023
486  if (xbin_min < 0) xbin_min = 0;
487  if (zbin_min < 0) zbin_min = 0;
488  if (xbin_max >= maxNX) xbin_max = maxNX - 1;
489  if (zbin_max >= maxNZ) xbin_max = maxNZ - 1;
490 
491  if (Verbosity() > 1)
492  {
493  std::cout << " xbin_in " << xbin_in << " xbin_out " << xbin_out << " xbin_min " << xbin_min << " xbin_max " << xbin_max << std::endl;
494  std::cout << " zbin_in " << zbin_in << " zbin_out " << zbin_out << " zbin_min " << zbin_min << " zbin_max " << zbin_max << std::endl;
495  }
496 
497  // skip this hit if it involves an unreasonable number of pixels
498  // 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)
499  if (xbin_max - xbin_min > 12 || zbin_max - zbin_min > 12) continue;
500 
501  // this hit is skipped earlier if this dimensioning would be exceeded
502  double pixenergy[12][12] = {}; // init to 0
503  double pixeion[12][12] = {}; // init to 0
504 
505  // Loop over track segments and diffuse charge at each segment location, collect energy in pixels
506  for (int i = 0; i < nsegments; i++)
507  {
508  // Find the tracklet segment location
509  // If there are n segments of equal length, we want 2*n intervals
510  // The 1st segment is centered at interval 1, the 2nd at interval 3, the nth at interval 2n -1
511  double interval = 2 * (double) i + 1;
512  double frac = interval / (double) (2 * nsegments);
513  TVector3 segvec(pathvec.X() * frac, pathvec.Y() * frac, pathvec.Z() * frac);
514  segvec = segvec + local_out;
515 
516  // Find the distance to the back of the sensor from the segment location
517  // That projection changes only the value of y
518  double ydrift = segvec.Y() - local_out.Y();
519 
520  // Caculate the charge diffusion over this drift distance
521  // increases from diffusion width_min to diffusion_width_max
522  double ydiffusion_radius = diffusion_width_min + (ydrift / ydrift_max) * (diffusion_width_max - diffusion_width_min);
523 
524  if (Verbosity() > 5)
525  {
526  std::cout
527  << " segment " << i
528  << " interval " << interval
529  << " frac " << frac
530  << " local_in.X " << local_in.X()
531  << " local_in.Z " << local_in.Z()
532  << " local_in.Y " << local_in.Y()
533  << " pathvec.X " << pathvec.X()
534  << " pathvec.Z " << pathvec.Z()
535  << " pathvec.Y " << pathvec.Y()
536  << " segvec.X " << segvec.X()
537  << " segvec.Z " << segvec.Z()
538  << " segvec.Y " << segvec.Y()
539  << " ydrift " << ydrift
540  << " ydrift_max " << ydrift_max
541  << " ydiffusion_radius " << ydiffusion_radius
542  << std::endl;
543  }
544  // Now find the area of overlap of the diffusion circle with each pixel and apportion the energy
545  for (int ix = xbin_min; ix <= xbin_max; ix++)
546  {
547  for (int iz = zbin_min; iz <= zbin_max; iz++)
548  {
549  // Find the pixel corners for this pixel number
550  int pixnum = layergeom->get_pixel_number_from_xbin_zbin(ix, iz);
551 
552  if (pixnum < 0)
553  {
554  std::cout
555  << " pixnum < 0 , pixnum = " << pixnum << "\n"
556  << " ix " << ix << " iz " << iz << "\n"
557  << " xbin_min " << xbin_min << " zbin_min " << zbin_min << "\n"
558  << " xbin_max " << xbin_max << " zbin_max " << zbin_max << "\n"
559  << " maxNX " << maxNX << " maxNZ " << maxNZ
560  << std::endl;
561  }
562 
563  TVector3 tmp = layergeom->get_local_coords_from_pixel(pixnum);
564  // note that (x1,z1) is the top left corner, (x2,z2) is the bottom right corner of the pixel - circle_rectangle_intersection expects this ordering
565  double x1 = tmp.X() - xpixw_half;
566  double z1 = tmp.Z() + zpixw_half;
567  double x2 = tmp.X() + xpixw_half;
568  double z2 = tmp.Z() - zpixw_half;
569 
570  // here segvec.X and segvec.Z are the center of the circle, and diffusion_radius is the circle radius
571  // circle_rectangle_intersection returns the overlap area of the circle and the pixel. It is very fast if there is no overlap.
572  double pixarea_frac = PHG4Utils::circle_rectangle_intersection(x1, z1, x2, z2, segvec.X(), segvec.Z(), ydiffusion_radius) / (M_PI * pow(ydiffusion_radius, 2));
573  // assume that the energy is deposited uniformly along the tracklet length, so that this segment gets the fraction 1/nsegments of the energy
574  pixenergy[ix - xbin_min][iz - zbin_min] += pixarea_frac * g4hit->get_edep() / (float) nsegments;
575  if (g4hit->has_property(PHG4Hit::prop_eion))
576  {
577  pixeion[ix - xbin_min][iz - zbin_min] += pixarea_frac * g4hit->get_eion() / (float) nsegments;
578  }
579  if (Verbosity() > 5)
580  {
581  std::cout
582  << " pixnum " << pixnum << " xbin " << ix << " zbin " << iz
583  << " pixel_area fraction of circle " << pixarea_frac << " accumulated pixel energy " << pixenergy[ix - xbin_min][iz - zbin_min]
584  << std::endl;
585  }
586  }
587  }
588  } // end loop over segments
589 
590  // 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
591  for (int ix = xbin_min; ix <= xbin_max; ix++)
592  {
593  for (int iz = zbin_min; iz <= zbin_max; iz++)
594  {
595  if (pixenergy[ix - xbin_min][iz - zbin_min] > 0.0)
596  {
597  int pixnum = layergeom->get_pixel_number_from_xbin_zbin(ix, iz);
598  vpixel.push_back(pixnum);
599  vxbin.push_back(ix);
600  vzbin.push_back(iz);
601  std::pair<double, double> tmppair = std::make_pair(pixenergy[ix - xbin_min][iz - zbin_min], pixeion[ix - xbin_min][iz - zbin_min]);
602  venergy.push_back(tmppair);
603  if (Verbosity() > 1)
604  {
605  std::cout
606  << " Added pixel number " << pixnum << " xbin " << ix
607  << " zbin " << iz << " to vectors with energy " << pixenergy[ix - xbin_min][iz - zbin_min]
608  << std::endl;
609  }
610  }
611  }
612  }
613 
614  //===================================
615  // End of charge sharing implementation
616  //===================================
617 
618  // loop over all fired cells for this g4hit and add them to the TrkrHitSet
619  for (unsigned int i1 = 0; i1 < vpixel.size(); i1++) // loop over all fired cells
620  {
621  // This is the new storage object version
622  //====================================
623  for (unsigned int i_rep = 0; i_rep < n_replica; i_rep++)
624  {
625  int strobe = t0_strobe_frame + i_rep;
626  // to fit in a 5 bit field in the hitsetkey [-16,15]
627  if (strobe < -16) strobe = -16;
628  if (strobe >= 16) strobe = 15;
629 
630  // We need to create the TrkrHitSet if not already made - each TrkrHitSet should correspond to a chip for the Mvtx
631  TrkrDefs::hitsetkey hitsetkey = MvtxDefs::genHitSetKey(layer, stave_number, chip_number, strobe);
632  // Use existing hitset or add new one if needed
633  TrkrHitSetContainer::Iterator hitsetit = trkrHitSetContainer->findOrAddHitSet(hitsetkey);
634 
635  // generate the key for this hit
636  TrkrDefs::hitkey hitkey = MvtxDefs::genHitKey(vzbin[i1], vxbin[i1]);
637  // See if this hit already exists
638  TrkrHit* hit = nullptr;
639  hit = hitsetit->second->getHit(hitkey);
640  if (!hit)
641  {
642  // Otherwise, create a new one
643  hit = new TrkrHitv2();
644  hitsetit->second->addHitSpecificKey(hitkey, hit);
645  }
646 
647  // Either way, add the energy to it
648  double hitenergy = venergy[i1].first * TrkrDefs::MvtxEnergyScaleup;
649  hit->addEnergy(hitenergy);
650 
651  addtruthhitset(hitsetkey, hitkey, hitenergy);
652 
653  if (Verbosity() > 0)
654  std::cout << " added hit " << hitkey << " to hitset " << hitsetkey << " with strobe id " << strobe << " in layer " << layer
655  << " with energy " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << std::endl;
656 
657  // now we update the TrkrHitTruthAssoc map - the map contains <hitsetkey, std::pair <hitkey, g4hitkey> >
658  // There is only one TrkrHit per pixel, but there may be multiple g4hits
659  // How do we know how much energy from PHG4Hit went into TrkrHit? We don't, have to sort it out in evaluator to save memory
660 
661  // we set the strobe ID to zero in the hitsetkey
662  // we use the findOrAdd method to keep from adding identical entries
663  TrkrDefs::hitsetkey bare_hitsetkey = zero_strobe_bits(hitsetkey);
664  hitTruthAssoc->findOrAddAssoc(bare_hitsetkey, hitkey, g4hit_it->first);
665  }
666  } // end loop over hit cells
667  } // end loop over g4hits for this layer
668 
669 
670  } // end loop over layers
671 
672  // print the list of entries in the association table
673  if (Verbosity() > 2)
674  {
675  std::cout << "From PHG4MvtxHitReco: " << std::endl;
676  hitTruthAssoc->identify();
677  }
678 
679  // spit out the truth clusters
680 
681  end_event_truthcluster(topNode);
682 
683  if (Verbosity() > 3) {
684  int nclusprint = -1;
685  std::cout << PHWHERE << ": content of clusters " << std::endl;
686  auto& tmap = m_truthtracks->getMap();
687  std::cout << " Number of tracks: " << tmap.size() << std::endl;
688  for (auto& _pair : tmap) {
689  auto& track = _pair.second;
690 
691  printf("id(%2i) phi:eta:pt(", (int)track->getTrackid());
692  std::cout << "phi:eta:pt(";
693  printf("%5.2f:%5.2f:%5.2f", track->getPhi(), track->getPseudoRapidity(), track->getPt());
694  /* Form("%5.2:%5.2:%5.2", track->getPhi(), track->getPseudoRapidity(), track->getPt()) */
695  //<<track->getPhi()<<":"<<track->getPseudoRapidity()<<":"<<track->getPt()
696  std::cout << ") nclusters(" << track->getClusters().size() <<") ";
697  int nclus = 0;
698  for (auto cluskey : track->getClusters()) {
699  std::cout << " "
700  << ((int) TrkrDefs::getHitSetKeyFromClusKey(cluskey)) <<":index(" <<
701  ((int) TrkrDefs::getClusIndex(cluskey)) << ")" << std::endl;
702  ++nclus;
703  if (nclusprint > 0 && nclus >= nclusprint) {
704  std::cout << " ... ";
705  break;
706  }
707  }
708  }
709  std::cout << PHWHERE << " ----- end of clusters " << std::endl;
710  }
711 
712  if (m_is_emb) {
713  cluster_truthhits(topNode); // the last track was truth -- cluster it
714  prior_g4hit = nullptr;
715  }
716 
718 }
719 
720 std::pair<double, double> PHG4MvtxHitReco::generate_alpide_pulse(const double energy_deposited)
721 {
722  // We need to translate energy deposited to num/ electrons released
723  if (Verbosity() > 2)
724  {
725  std::cout << "energy_deposited: " << energy_deposited << std::endl;
726  }
727  //int silicon_band_gap = 1.12; //Band gap energy in eV
728  //int Q_in = rand() % 5000 + 50;
729  //int clipping_point = 110;
730  //double ToT_start = Q_in < 200 ? 395.85*exp(-0.5*pow((Q_in+851.43)/286.91, 2)) : 0.5;
731  //double ToT_end = Q_in < clipping_point ? 5.90*exp(-0.5*pow((Q_in-99.86)/54.80, 2)) : 5.8 - 6.4e-4 * Q_in;
732 
733  //return make_pair(ToT_start*1e3, ToT_end*1e3);
734  // Using constant alpide pulse length
735  return std::make_pair<double, double>(1.5 * microsecond, 5.9 * microsecond);
736 }
737 
739 {
740  return -1. * gsl_rng_uniform_pos(m_rng.get()) * (m_strobe_separation + m_strobe_width);
741 }
742 
743 int PHG4MvtxHitReco::get_strobe_frame(double alpide_time, double strobe_zero_tm_start)
744 {
745  int strobe_frame = int((alpide_time - strobe_zero_tm_start) / (m_strobe_width + m_strobe_separation));
746  strobe_frame += (alpide_time < strobe_zero_tm_start) ? -1 : 0;
747  return strobe_frame;
748 }
749 
750 void PHG4MvtxHitReco::set_timing_window(const int detid, const double tmin, const double tmax)
751 {
752  if (false)
753  {
754  std::cout
755  << "PHG4MvtxHitReco: Set Mvtx timing window parameters from macro for layer = "
756  << detid << " to tmin = " << tmin << " tmax = " << tmax
757  << std::endl;
758  }
759 
760  return;
761 }
762 
764 {
765  //cout << "PHG4MvtxHitReco: Setting Mvtx timing window defaults to tmin = -5000 and tmax = 5000 ns" << std::endl;
766  set_default_double_param("mvtx_tmin", -5000);
767  set_default_double_param("mvtx_tmax", 5000);
768  set_default_double_param("mvtx_strobe_width", 5 * microsecond);
769  set_default_double_param("mvtx_strobe_separation", 0.);
770  set_default_int_param("mvtx_in_sphenix_srdo", (int) false);
771  return;
772 }
773 
775 {
776  unsigned int layer = TrkrDefs::getLayer(hitsetkey);
777  unsigned int stave = MvtxDefs::getStaveId(hitsetkey);
778  unsigned int chip = MvtxDefs::getChipId(hitsetkey);
779  TrkrDefs::hitsetkey bare_hitsetkey = MvtxDefs::genHitSetKey(layer, stave, chip, 0);
780 
781  return bare_hitsetkey;
782 }
783 
785  delete m_truth_hits;
786 }
787 
789  int new_trkid = (g4hit==nullptr) ? -1 : g4hit->get_trkid();
790  bool is_new_track = (new_trkid != m_trkid);
791  if (Verbosity()>5) std::cout << PHWHERE << std::endl << " -> Checking status of PHG4Hit. Track id("<<new_trkid<<")" << std::endl;
792  if (!is_new_track) {
793  /* FIXME */
794  /* std::cout << " FIXME PEAR Checking g4hit : " << g4hit->get_x(0) << " " */
795  /* << g4hit->get_y(0) << " " << g4hit->get_z(0) */
796  /* << " trackid("<<g4hit->get_trkid() << ") " << std::endl; */
797  if (m_is_emb) {
798  /* std::cout << " FIXME Checking MVTX g4hit : " << g4hit->get_x(0) << " " */
799  /* << g4hit->get_y(0) << " " << g4hit->get_z(0) */
800  /* << " trackid("<<g4hit->get_trkid() << ") " << std::endl; */
801  if (prior_g4hit!=nullptr
802  && ( std::abs(prior_g4hit->get_x(0)-g4hit->get_x(0)) > max_g4hitstep
803  || std::abs(prior_g4hit->get_y(0)-g4hit->get_y(0)) > max_g4hitstep
804  )
805  )
806  {
807  // this is a looper track -- cluster hits up to this point already
808  cluster_truthhits(topNode);
809  }
810  prior_g4hit = g4hit;
811  }
812  return;
813  }
814  // <- STATUS: this is a new track
815  if (Verbosity()>2) std::cout << PHWHERE << std::endl << " -> Found new embedded track with id: " << new_trkid << std::endl;
816  if (m_is_emb) {
817  cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track
818  m_current_track = nullptr;
819  prior_g4hit = nullptr;
820  }
821  m_trkid = new_trkid;
823  if (m_is_emb) {
825  prior_g4hit = g4hit;
826  }
827 }
828 
830  if (m_is_emb) {
831  cluster_truthhits(topNode); // cluster m_truth_hits and add m_current_track
832  m_current_track = nullptr;
833  m_trkid = -1;
834  m_is_emb = false;
835  }
836  m_hitsetkey_cnt.clear();
837 }
838 
842  float neffelectrons)
843 {
844  if (!m_is_emb) return;
846  // See if this hit already exists
847  TrkrHit *hit = nullptr;
848  hit = hitsetit->second->getHit(hitkey);
849  if (!hit)
850  {
851  // create a new one
852  hit = new TrkrHitv2();
853  hitsetit->second->addHitSpecificKey(hitkey, hit);
854  }
855  // Either way, add the energy to it -- adc values will be added at digitization
856  hit->addEnergy(neffelectrons);
857 }
858 
860  // clusterize the mvtx hits in m_truth_hits, put them in m_truthclusters, and put the id's in m_current_track
861  // ----------------------------------------------------------------------------------------------------
862  // Digitization -- simplified from g4mvtx/PHG4MvtxDigitizer --
863  // ----------------------------------------------------------------------------------------------------
864 
865  /* // We want all hitsets for the Mvtx */
866  /* TrkrHitSetContainer::ConstRange hitset_range = m_truth_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); */
867  /* for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first; */
868  /* hitset_iter != hitset_range.second; */
869  /* ++hitset_iter) */
870  /* { */
871  /* // we have an iterator to one TrkrHitSet for the mvtx from the trkrHitSetContainer */
872  /* // get the hitset key so we can find the layer */
873  /* TrkrDefs::hitsetkey hitsetkey = hitset_iter->first; */
874  /* int layer = TrkrDefs::getLayer(hitsetkey); */
875  /* // FIXME */
876  /* /1* if (Verbosity() > 1) std::cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; *1/ */
877  /* std::cout << "PHG4MvtxDigitizer: found hitset with key: " << hitsetkey << " in layer " << layer << std::endl; */
878 
879  /* // get all of the hits from this hitset */
880  /* TrkrHitSet *hitset = hitset_iter->second; */
881  /* TrkrHitSet::ConstRange hit_range = hitset->getHits(); */
882  /* std::set<TrkrDefs::hitkey> hits_rm; */
883  /* for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; */
884  /* hit_iter != hit_range.second; */
885  /* ++hit_iter) */
886  /* { */
887  /* TrkrHit *hit = hit_iter->second; */
888 
889  /* // Convert the signal value to an ADC value and write that to the hit */
890  /* // Unsigned int adc = hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup *_energy_scale[layer]); */
891  /* if (Verbosity() > 0) */
892  /* std::cout << " PHG4MvtxDigitizer: found hit with key: " << hit_iter->first << " and signal " << hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup << " in layer " << layer << std::endl; */
893  /* // Remove the hits with energy under threshold */
894  /* bool rm_hit = false; */
895  /* // FIXME: */
896  /* double _energy_threshold = 0.; // FIXME */
897  /* const double dummy_pixel_thickness = 0.001; */
898  /* const double mip_e = 0.003876; */
899  /* double _energy_scale = mip_e * dummy_pixel_thickness; // FIXME: note: this doesn't actually */
900  /* // matter either here or for the Svtx Tracks -- the energy is digital -- either the hit is there or it isn't */
901  /* double _max_adc = 255; */
902  /* if ((hit->getEnergy() / TrkrDefs::MvtxEnergyScaleup) < _energy_threshold) */
903  /* { */
904  /* if (Verbosity() > 0) std::cout << " remove hit, below energy threshold of " << _energy_threshold << std::endl; */
905  /* rm_hit = true; */
906  /* } */
907  /* unsigned short adc = (unsigned short) (hit->getEnergy() / (TrkrDefs::MvtxEnergyScaleup * _energy_scale)); */
908  /* if (adc > _max_adc) adc = _max_adc; */
909  /* hit->setAdc(adc); */
910 
911  /* if (rm_hit) hits_rm.insert(hit_iter->first); */
912  /* } */
913 
914  /* for (const auto &key : hits_rm) */
915  /* { */
916  /* if (Verbosity() > 0) std::cout << " PHG4MvtxDigitizer: remove hit with key: " << key << std::endl; */
917  /* hitset->removeHit(key); */
918  /* } */
919  /* } */
920 
921  // ----------------------------------------------------------------------------------------------------
922  // Prune hits -- simplified from mvtx/MvtxHitReco
923  // ----------------------------------------------------------------------------------------------------
924  std::multimap<TrkrDefs::hitsetkey, TrkrDefs::hitsetkey> hitset_multimap; // will map (bare hitset, hitset with strobe)
925  std::set<TrkrDefs::hitsetkey> bare_hitset_set; // list of all physical sensor hitsetkeys (i.e. with strobe set to zero)
926 
927  TrkrHitSetContainer::ConstRange hitsetrange = m_truth_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); // actually m_truth_hits can only have MVTX hits at this point...
928  for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
929  hitsetitr != hitsetrange.second;
930  ++hitsetitr)
931  {
932  auto hitsetkey = hitsetitr->first;
933 
934  // get the hitsetkey value for strobe 0
935  unsigned int layer = TrkrDefs::getLayer(hitsetitr->first);
936  unsigned int stave = MvtxDefs::getStaveId(hitsetitr->first);
937  unsigned int chip = MvtxDefs::getChipId(hitsetitr->first);
938  auto bare_hitsetkey = MvtxDefs::genHitSetKey(layer, stave, chip, 0);
939 
940  hitset_multimap.insert(std::make_pair(bare_hitsetkey, hitsetkey));
941  bare_hitset_set.insert(bare_hitsetkey);
942 
943  if(Verbosity() > 0) std::cout << " found hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl;
944  }
945 
946  // Now consolidate all hits into the hitset with strobe 0, and delete the other hitsets
947  //==============================================================
948  for(auto bare_it = bare_hitset_set.begin(); bare_it != bare_hitset_set.end(); ++bare_it)
949  {
950  auto bare_hitsetkey = *bare_it;
951  TrkrHitSet* bare_hitset = (m_truth_hits->findOrAddHitSet(bare_hitsetkey))->second;
952  if(Verbosity() > 0) std::cout << " bare_hitset " << bare_hitsetkey << " initially has " << bare_hitset->size() << " hits " << std::endl;
953 
954  auto bare_hitsetrange= hitset_multimap.equal_range(bare_hitsetkey);
955  for(auto it = bare_hitsetrange.first; it != bare_hitsetrange.second; ++ it)
956  {
957  auto hitsetkey = it->second;
958 
959  int strobe = MvtxDefs::getStrobeId(hitsetkey);
960  if(strobe != 0)
961  {
962  if(Verbosity() > 0) std::cout << " process hitsetkey " << hitsetkey << " for bare_hitsetkey " << bare_hitsetkey << std::endl;
963 
964  // copy all hits to the hitset with strobe 0
966 
967  if(Verbosity() > 0)
968  std::cout << " hitsetkey " << hitsetkey << " has strobe " << strobe << " and has " << hitset->size() << " hits, so copy it" << std::endl;
969 
970  TrkrHitSet::ConstRange hitrangei = hitset->getHits();
971  for (TrkrHitSet::ConstIterator hitr = hitrangei.first;
972  hitr != hitrangei.second;
973  ++hitr)
974  {
975  auto hitkey = hitr->first;
976  if(Verbosity() > 0) std::cout << " found hitkey " << hitkey << std::endl;
977  // if it is already there, leave it alone, this is a duplicate hit
978  auto tmp_hit = bare_hitset->getHit(hitkey);
979  if(tmp_hit)
980  {
981  if(Verbosity() > 0) std::cout << " hitkey " << hitkey << " is already in bare hitsest, do not copy" << std::endl;
982  continue;
983  }
984 
985  // otherwise copy the hit over
986  if(Verbosity() > 0) std::cout << " copying over hitkey " << hitkey << std::endl;
987  auto old_hit = hitr->second;
988  TrkrHit *new_hit = new TrkrHitv2();
989  new_hit->setAdc(old_hit->getAdc());
990  bare_hitset->addHitSpecificKey(hitkey, new_hit);
991  }
992 
993  // all hits are copied over to the strobe zero hitset, remove this hitset
995  }
996  }
997  }
998 
999  // ----------------------------------------------------------------------------------------------------
1000  // cluster hits -- simplified from mvtx/MvtxClusterizer
1001  // ----------------------------------------------------------------------------------------------------
1002  PHG4CylinderGeomContainer* geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MVTX");
1003  if (!geom_container) {
1004  std::cout << PHWHERE << std::endl;
1005  std::cout << "WARNING: cannot find the geometry CYLINDERGEOM_MVTX" << std::endl;
1006  m_truth_hits->Reset();
1007  return;
1008  }
1009 
1010  //-----------
1011  // Clustering
1012  //-----------
1013 
1014  // loop over each MvtxHitSet object (chip)
1016  for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first;
1017  hitsetitr != hitsetrange.second;
1018  ++hitsetitr)
1019  { // hitsetitr : pair(TrkrDefs::hitsetkey, TrkrHitSet>; TrkrHitSet : map <HitKey, TrkrHit>
1020  TrkrHitSet *hitset = hitsetitr->second; // hitset : map <TrkrDefs::hitkey, TrkrHit>
1021 
1022  /* if (true) */
1023  if(Verbosity() > 0)
1024  {
1025  unsigned int layer = TrkrDefs::getLayer (hitsetitr ->first);
1026  unsigned int stave = MvtxDefs::getStaveId (hitsetitr ->first);
1027  unsigned int chip = MvtxDefs::getChipId (hitsetitr ->first);
1028  unsigned int strobe = MvtxDefs::getStrobeId (hitsetitr ->first);
1029  std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first << " layer " << layer << " stave " << stave << " chip " << chip << " strobe " << strobe << std::endl;
1030  }
1031 
1032  if (Verbosity() > 2)
1033  hitset->identify();
1034 
1035  TrkrHitSet::ConstRange hitrangei = hitset->getHits();
1036 
1037  auto hitsetkey = hitset->getHitSetKey();
1038  auto ckey = TrkrDefs::genClusKey(hitsetkey, 0); // there is only one cluster made per cluskey
1039 
1040  // determine the size of the cluster in phi and z
1041  std::set<int> phibins;
1042  std::set<int> zbins;
1043 
1044  // determine the cluster position...
1045  double locxsum = 0.;
1046  double loczsum = 0.;
1047 
1048  double locclusx = NAN;
1049  double locclusz = NAN;
1050 
1051  // we need the geometry object for this layer to get the global positions
1052  int layer = TrkrDefs::getLayer(ckey);
1053  auto layergeom = dynamic_cast<CylinderGeom_Mvtx *>(geom_container->GetLayerGeom(layer));
1054  if (!layergeom)
1055  exit(1);
1056 
1057 
1058  // make a tunable threshold for energy in a given hit
1059  // -- percentage of someting? (total cluster energy)
1060  double sum_adc { 0. };
1061  for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit) {
1062  sum_adc += ihit->second->getAdc();
1063  }
1064  const double threshold = sum_adc * m_pixel_thresholdrat; //FIXME -- tune this as needed
1065  std::map<int,unsigned int> m_iphi, m_it, m_iphiCut, m_itCut; // FIXME
1066  /* const unsigned int npixels = std::distance( hitrangei.first, hitrangei.second ); */
1067  // to tune this parameter: run a bunch of tracks and compare truth sizes and reco sizes,
1068  // should come out the same
1069  double npixels {0.};
1070  for ( auto ihit = hitrangei.first; ihit != hitrangei.second; ++ihit)
1071  {
1072  const auto adc = ihit->second->getAdc();
1073  int col = MvtxDefs::getCol( ihit->first);
1074  int row = MvtxDefs::getRow( ihit->first);
1075 
1076  if (mClusHitsVerbose) {
1077  std::map<int,unsigned int>& m_phi = (adc<threshold) ? m_iphiCut : m_iphi;
1078  std::map<int,unsigned int>& m_z = (adc<threshold) ? m_itCut : m_it;
1079 
1080  auto pnew = m_phi.try_emplace(row,adc);
1081  if (!pnew.second) pnew.first->second += adc;
1082 
1083  pnew = m_z.try_emplace(col,adc);
1084  if (!pnew.second) pnew.first->second += adc;
1085  }
1086  if (adc<threshold) continue;
1087 
1088  // size
1089  npixels += 1.;
1090  zbins.insert(col);
1091  phibins.insert(row);
1092 
1093  // get local coordinates, in stave reference frame, for hit
1094  auto local_coords = layergeom->get_local_coords_from_pixel(row,col);
1095 
1096  /*
1097  manually offset position along y (thickness of the sensor),
1098  to account for effective hit position in the sensor, resulting from diffusion.
1099  Effective position corresponds to 1um above the middle of the sensor
1100  */
1101  local_coords.SetY( 1e-4 );
1102 
1103  // update cluster position
1104  locxsum += local_coords.X();
1105  loczsum += local_coords.Z();
1106  // add the association between this cluster key and this hitkey to the table
1107  } //mapiter
1108  if (mClusHitsVerbose) {
1109  if (Verbosity()>10) {
1110  for (auto& hit : m_iphi) {
1111  std::cout << " m_phi(" << hit.first <<" : " << hit.second<<") " << std::endl;
1112  }
1113  }
1114  for (auto& hit : m_iphi) mClusHitsVerbose->addPhiHit (hit.first, (float)hit.second);
1115  for (auto& hit : m_it) mClusHitsVerbose->addZHit (hit.first, (float)hit.second);
1116  for (auto& hit : m_iphiCut) mClusHitsVerbose->addPhiCutHit (hit.first, (float)hit.second);
1117  for (auto& hit : m_itCut) mClusHitsVerbose->addZCutHit (hit.first, (float)hit.second);
1118  }
1119 
1120  // This is the local position
1121  locclusx = locxsum / npixels;
1122  locclusz = loczsum / npixels;
1123 
1124  const double pitch = layergeom->get_pixel_x();
1125  const double length = layergeom->get_pixel_z();
1126  const double phisize = phibins.size() * pitch;
1127  const double zsize = zbins.size() * length;
1128 
1129  /* if (true) { */
1130  if(Verbosity() > 0) {
1131  std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer << " rad " << layergeom->get_radius() << " phibins " << phibins.size() << " pitch " << pitch << " phisize " << phisize
1132  << " zbins " << zbins.size() << " length " << length << " zsize " << zsize
1133  << " local x " << locclusx << " local y " << locclusz
1134  << std::endl;
1135  }
1136 
1137  // ok force it use use cluster version v4 for now (Valgrind is not happy with application of v5)
1138  /* if (m_cluster_version==4){ */
1139  if (m_cluster_version == 4) {
1140  auto clus = std::make_unique<TrkrClusterv4>();
1141  clus->setAdc(npixels);
1142  clus->setLocalX(locclusx);
1143  clus->setLocalY(locclusz);
1144 
1145  clus->setPhiSize(phibins.size());
1146  clus->setZSize(zbins.size());
1147  // All silicon surfaces have a 1-1 map to hitsetkey.
1148  // So set subsurface key to 0
1149  clus->setSubSurfKey(0);
1150 
1151  if (Verbosity() > 2) clus->identify();
1152 
1153  // get the count of how many clusters have allready been added to this hitsetkey (possibly from other embedded tracks tracks)
1154  m_hitsetkey_cnt.try_emplace(hitsetkey,0);
1155  unsigned int& cnt = m_hitsetkey_cnt[hitsetkey];
1156  ckey = TrkrDefs::genClusKey(hitsetkey, cnt);
1157  m_truthclusters->addClusterSpecifyKey(ckey, clus.release());
1158  m_current_track->addCluster(ckey);
1159  if (mClusHitsVerbose) {
1160  mClusHitsVerbose->push_hits(ckey);
1161  }
1162  ++cnt;
1163  } else {
1164  std::cout << PHWHERE << std::endl;
1165  std::cout << "Error: only cluster version 4 allowed." << std::endl;
1166  } // loop over hitsets
1167  }
1168  m_truth_hits->Reset();
1169  prior_g4hit = nullptr;
1170  return;
1171 }