Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4TpcElectronDrift.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4TpcElectronDrift.cc
1 // this is the new containers version
2 // it uses the same MapToPadPlane as the old containers version
3 
4 #include "PHG4TpcElectronDrift.h"
5 #include "PHG4TpcDistortion.h"
6 #include "PHG4TpcPadPlane.h" // for PHG4TpcPadPlane
7 
8 #include <g4main/PHG4Hit.h>
10 #include <g4main/PHG4Particlev3.h>
12 
14 #include <trackbase/TrkrDefs.h>
15 #include <trackbase/TrkrHit.h> // for TrkrHit
16 #include <trackbase/TrkrHitSet.h>
18 #include <trackbase/TrkrHitTruthAssoc.h> // for TrkrHitTruthA...
20 #include <trackbase/TrkrHitv2.h>
21 
22 #include <trackbase/TpcDefs.h>
25 
26 #include <trackbase/TrkrCluster.h>
27 
30 
33 
34 #include <phparameter/PHParameterInterface.h> // for PHParameterIn...
35 #include <phparameter/PHParameters.h>
36 #include <phparameter/PHParametersContainer.h>
37 
38 #include <pdbcalbase/PdbParameterMapContainer.h>
39 
41 #include <fun4all/Fun4AllServer.h>
42 #include <fun4all/SubsysReco.h> // for SubsysReco
43 
44 #include <phool/PHCompositeNode.h>
45 #include <phool/PHDataNode.h> // for PHDataNode
46 #include <phool/PHIODataNode.h>
47 #include <phool/PHNode.h> // for PHNode
48 #include <phool/PHNodeIterator.h>
49 #include <phool/PHObject.h> // for PHObject
50 #include <phool/PHRandomSeed.h>
51 #include <phool/getClass.h>
52 #include <phool/phool.h> // for PHWHERE
53 
54 #include <TFile.h>
55 #include <TH1.h>
56 #include <TH2.h>
57 #include <TNtuple.h>
58 #include <TSystem.h>
59 
60 #include <gsl/gsl_randist.h>
61 #include <gsl/gsl_rng.h> // for gsl_rng_alloc
62 
63 #include <array>
64 #include <cassert>
65 #include <cmath> // for sqrt, abs, NAN
66 #include <cstdlib> // for exit
67 #include <iostream>
68 #include <map> // for _Rb_tree_cons...
69 #include <utility> // for pair
70 
71 #include "TpcClusterBuilder.h"
72 
73 using std::cout;
74 using std::endl;
75 using std::setw;
76 
77 namespace
78 {
79  template <class T>
80  inline constexpr T square(const T &x)
81  {
82  return x * x;
83  }
84 } // namespace
85 
87  : SubsysReco(name)
88  , PHParameterInterface(name)
89  , temp_hitsetcontainer(new TrkrHitSetContainerv1)
90  , single_hitsetcontainer(new TrkrHitSetContainerv1)
91 {
93  RandomGenerator.reset(gsl_rng_alloc(gsl_rng_mt19937));
95 }
96 
97 //_____________________________________________________________
99 {
100  padplane->Init(topNode);
101  event_num = 0;
103 }
104 
105 //_____________________________________________________________
107 {
108  PHNodeIterator iter(topNode);
109 
110  // Looking for the DST node
111  PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
112  if (!dstNode)
113  {
114  std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
115  exit(1);
116  }
117  auto runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
118  auto parNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PAR"));
119  const std::string paramnodename = "G4CELLPARAM_" + detector;
120  const std::string geonodename = "G4CELLPAR_" + detector;
121  const std::string tpcgeonodename = "G4GEO_" + detector;
122  hitnodename = "G4HIT_" + detector;
123  PHG4HitContainer *g4hit = findNode::getClass<PHG4HitContainer>(topNode, hitnodename);
124  if (!g4hit)
125  {
126  std::cout << Name() << " Could not locate G4HIT node " << hitnodename << std::endl;
127  topNode->print();
128  gSystem->Exit(1);
129  exit(1);
130  }
131  // new containers
132  hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
133  if (!hitsetcontainer)
134  {
135  PHNodeIterator dstiter(dstNode);
136  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
137  if (!DetNode)
138  {
139  DetNode = new PHCompositeNode("TRKR");
140  dstNode->addNode(DetNode);
141  }
142 
144  auto newNode = new PHIODataNode<PHObject>(hitsetcontainer, "TRKR_HITSET", "PHObject");
145  DetNode->addNode(newNode);
146  }
147 
148  hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
149  if (!hittruthassoc)
150  {
151  PHNodeIterator dstiter(dstNode);
152  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
153  if (!DetNode)
154  {
155  DetNode = new PHCompositeNode("TRKR");
156  dstNode->addNode(DetNode);
157  }
158 
160  auto newNode = new PHIODataNode<PHObject>(hittruthassoc, "TRKR_HITTRUTHASSOC", "PHObject");
161  DetNode->addNode(newNode);
162  }
163 
164  truthtracks = findNode::getClass<TrkrTruthTrackContainer>(topNode, "TRKR_TRUTHTRACKCONTAINER");
165  if (!truthtracks)
166  {
167  PHNodeIterator dstiter(dstNode);
168  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
169  if (!DetNode)
170  {
171  DetNode = new PHCompositeNode("TRKR");
172  dstNode->addNode(DetNode);
173  }
174 
176  auto newNode = new PHIODataNode<PHObject>(truthtracks, "TRKR_TRUTHTRACKCONTAINER", "PHObject");
177  DetNode->addNode(newNode);
178  }
179 
180  truthclustercontainer = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_TRUTHCLUSTERCONTAINER");
182  {
183  PHNodeIterator dstiter(dstNode);
184  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
185  if (!DetNode)
186  {
187  DetNode = new PHCompositeNode("TRKR");
188  dstNode->addNode(DetNode);
189  }
190 
192  auto newNode = new PHIODataNode<PHObject>(truthclustercontainer, "TRKR_TRUTHCLUSTERCONTAINER", "PHObject");
193  DetNode->addNode(newNode);
194  }
195 
196  seggeonodename = "CYLINDERCELLGEOM_SVTX"; // + detector;
197  seggeo = findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, seggeonodename);
198  assert( seggeo );
199 
201  PHNodeIterator runIter(runNode);
202  auto RunDetNode = dynamic_cast<PHCompositeNode *>(runIter.findFirst("PHCompositeNode", detector));
203  if (!RunDetNode)
204  {
205  RunDetNode = new PHCompositeNode(detector);
206  runNode->addNode(RunDetNode);
207  }
208  SaveToNodeTree(RunDetNode, paramnodename);
209 
210  // save this to the parNode for use
211  PHNodeIterator parIter(parNode);
212  auto ParDetNode = dynamic_cast<PHCompositeNode *>(parIter.findFirst("PHCompositeNode", detector));
213  if (!ParDetNode)
214  {
215  ParDetNode = new PHCompositeNode(detector);
216  parNode->addNode(ParDetNode);
217  }
218  PutOnParNode(ParDetNode, geonodename);
219 
220  // find Tpc Geo
221  PHNodeIterator tpcpariter(ParDetNode);
222  auto tpcparams = findNode::getClass<PHParametersContainer>(ParDetNode, tpcgeonodename);
223  if (!tpcparams)
224  {
225  const std::string runparamname = "G4GEOPARAM_" + detector;
226  auto tpcpdbparams = findNode::getClass<PdbParameterMapContainer>(RunDetNode, runparamname);
227  if (tpcpdbparams)
228  {
229  tpcparams = new PHParametersContainer(detector);
230  if (Verbosity()) tpcpdbparams->print();
231  tpcparams->CreateAndFillFrom(tpcpdbparams, detector);
232  ParDetNode->addNode(new PHDataNode<PHParametersContainer>(tpcparams, tpcgeonodename));
233  }
234  else
235  {
236  std::cout << "PHG4TpcElectronDrift::InitRun - failed to find " << runparamname << " in order to initialize " << tpcgeonodename << ". Aborting run ..." << std::endl;
238  }
239  }
240  assert(tpcparams);
241 
242  if (Verbosity()) tpcparams->Print();
243  const PHParameters *tpcparam = tpcparams->GetParameters(0);
244  assert(tpcparam);
245  tpc_length = tpcparam->get_double_param("tpc_length");
246 
247  diffusion_long = get_double_param("diffusion_long");
248  added_smear_sigma_long = get_double_param("added_smear_long");
249  diffusion_trans = get_double_param("diffusion_trans");
251  added_smear_sigma_trans = get_double_param("added_smear_trans");
252  drift_velocity = get_double_param("drift_velocity");
253  // min_time to max_time is the time window for accepting drifted electrons after the trigger
254  min_time = 0.0;
255  max_time = get_double_param("max_time") + get_double_param("extended_readout_time");
256  electrons_per_gev = get_double_param("electrons_per_gev");
257  min_active_radius = get_double_param("min_active_radius");
258  max_active_radius = get_double_param("max_active_radius");
259 
260  if (Verbosity() > 0) {
261  std::cout << PHWHERE << " drift velocity " << drift_velocity << " extended_readout_time " << get_double_param("extended_readout_time") << " max time cutoff " << max_time << std::endl;
262  }
263 
264  auto se = Fun4AllServer::instance();
265  dlong = new TH1F("difflong", "longitudinal diffusion", 100, diffusion_long - diffusion_long / 2., diffusion_long + diffusion_long / 2.);
266  se->registerHisto(dlong);
267  dtrans = new TH1F("difftrans", "transversal diffusion", 100, diffusion_trans - diffusion_trans / 2., diffusion_trans + diffusion_trans / 2.);
268  se->registerHisto(dtrans);
269 
270  do_ElectronDriftQAHistos = false; // Whether or not to produce an ElectronDriftQA.root file with useful info
272  {
273  hitmapstart = new TH2F("hitmapstart", "g4hit starting X-Y locations", 1560, -78, 78, 1560, -78, 78);
274  hitmapend = new TH2F("hitmapend", "g4hit final X-Y locations", 1560, -78, 78, 1560, -78, 78);
275  z_startmap = new TH2F("z_startmap", "g4hit starting Z vs. R locations", 2000, -100, 100, 780, 0, 78);
276  deltaphi = new TH2F("deltaphi", "Total delta phi; phi (rad);#Delta phi (rad)", 600, -M_PI, M_PI, 1000, -.2, .2);
277  deltaRphinodiff = new TH2F("deltaRphinodiff", "Total delta R*phi, no diffusion; r (cm);#Delta R*phi (cm)", 600, 20, 80, 1000, -3, 5);
278  deltaphivsRnodiff = new TH2F("deltaphivsRnodiff", "Total delta phi vs. R; phi (rad);#Delta phi (rad)", 600, 20, 80, 1000, -.2, .2);
279  deltaz = new TH2F("deltaz", "Total delta z; z (cm);#Delta z (cm)", 1000, 0, 100, 1000, -.5, 5);
280  deltaphinodiff = new TH2F("deltaphinodiff", "Total delta phi (no diffusion, only SC distortion); phi (rad);#Delta phi (rad)", 600, -M_PI, M_PI, 1000, -.2, .2);
281  deltaphinodist = new TH2F("deltaphinodist", "Total delta phi (no SC distortion, only diffusion); phi (rad);#Delta phi (rad)", 600, -M_PI, M_PI, 1000, -.2, .2);
282  deltar = new TH2F("deltar", "Total Delta r; r (cm);#Delta r (cm)", 580, 20, 78, 1000, -3, 5);
283  deltarnodiff = new TH2F("deltarnodiff", "Delta r (no diffusion, only SC distortion); r (cm);#Delta r (cm)", 580, 20, 78, 1000, -2, 5);
284  deltarnodist = new TH2F("deltarnodist", "Delta r (no SC distortion, only diffusion); r (cm);#Delta r (cm)", 580, 20, 78, 1000, -2, 5);
285  }
286 
287  if (Verbosity())
288  {
289  // eval tree only when verbosity is on
290  m_outf.reset(new TFile("nt_out.root", "recreate"));
291  nt = new TNtuple("nt", "electron drift stuff", "hit:ts:tb:tsig:rad:zstart:zfinal");
292  nthit = new TNtuple("nthit", "TrkrHit collecting", "layer:phipad:zbin:neffelectrons");
293  ntfinalhit = new TNtuple("ntfinalhit", "TrkrHit collecting", "layer:phipad:zbin:neffelectrons");
294  ntpad = new TNtuple("ntpad", "electron by electron pad centroid", "layer:phigem:phiclus:zgem:zclus");
295  se->registerHisto(nt);
296  se->registerHisto(nthit);
297  se->registerHisto(ntpad);
298  }
299 
300  padplane->InitRun(topNode);
301 
302  // print all layers radii
303  if (Verbosity())
304  {
305  const auto range = seggeo->get_begin_end();
306  std::cout << "PHG4TpcElectronDrift::InitRun - layers: " << std::distance(range.first, range.second) << std::endl;
307  int counter = 0;
308  for (auto layeriter = range.first; layeriter != range.second; ++layeriter)
309  {
310  const auto radius = layeriter->second->get_radius();
311  std::cout << Form( "%.3f ", radius );
312  if( ++counter == 8 )
313  {
314  counter = 0;
315  std::cout << std::endl;
316  }
317  }
318  std::cout << std::endl;
319  }
320 
322  // get the node
323  mClusHitsVerbose = findNode::getClass<ClusHitsVerbosev1>(topNode, "Trkr_TruthClusHitsVerbose");
324  if (!mClusHitsVerbose)
325  {
326  PHNodeIterator dstiter(dstNode);
327  auto DetNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
328  if (!DetNode)
329  {
330  DetNode = new PHCompositeNode("TRKR");
331  dstNode->addNode(DetNode);
332  }
334  auto newNode = new PHIODataNode<PHObject>(mClusHitsVerbose, "Trkr_TruthClusHitsVerbose", "PHObject");
335  DetNode->addNode(newNode);
336  }
337  }
338 
340 }
341 
343 {
344  truth_track = nullptr; // track to which truth clusters are built
345 
346  m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
347  if(!m_tGeometry)
348  {
349  std::cout << PHWHERE << "ActsGeometry not found on node tree. Exiting" << std::endl;
351  }
352 
356  }
357 
358 
359  static constexpr unsigned int print_layer = 18;
360 
361  // tells m_distortionMap which event to look at
362  if (m_distortionMap)
363  {
364  m_distortionMap->load_event(event_num);
365  }
366 
367  // g4hits
368  auto g4hit = findNode::getClass<PHG4HitContainer>(topNode, hitnodename);
369  if (!g4hit)
370  {
371  std::cout << "Could not locate g4 hit node " << hitnodename << std::endl;
372  gSystem->Exit(1);
373  }
374  PHG4TruthInfoContainer *truthinfo =
375  findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
376 
377  m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
378  if(!m_tGeometry)
379  {
380  std::cout << PHWHERE
381  << "ActsGeometry not found on node tree. Exiting"
382  << std::endl;
384  }
385 
386  PHG4HitContainer::ConstRange hit_begin_end = g4hit->getHits();
387  unsigned int count_g4hits = 0;
388  // int count_electrons = 0;
389 
390  // double ecollectedhits = 0.0;
391  int ncollectedhits = 0;
392  double ihit = 0;
393  unsigned int dump_interval = 5000; // dump temp_hitsetcontainer to the node tree after this many g4hits
394  unsigned int dump_counter = 0;
395 
396  int trkid = -1;
397 
398  PHG4Hit* prior_g4hit = nullptr; // used to check for jumps in g4hits;
399  // if there is a big jump (such as crossing into the INTT area or out of the TPC)
400  // then cluster the truth clusters before adding a new hit. This prevents
401  // clustering loopers in the same HitSetKey surfaces in multiple passes
402  for (auto hiter = hit_begin_end.first; hiter != hit_begin_end.second; ++hiter)
403  {
404  count_g4hits++;
405  dump_counter++;
406 
407  const double t0 = fmax(hiter->second->get_t(0), hiter->second->get_t(1));
408  if (t0 > max_time)
409  {
410  continue;
411  }
412 
413  int trkid_new = hiter->second->get_trkid();
414  if (trkid != trkid_new)
415  { // starting a new track
416  prior_g4hit = nullptr;
418  trkid = trkid_new;
419 
420  if (Verbosity() > 1000) std::cout << " New track : " << trkid << " is embed? : ";
421 
422  if (truthinfo->isEmbeded(trkid)) {
423  truth_track = truthtracks->getTruthTrack(trkid, truthinfo);
425  if (Verbosity() > 1000) { std::cout << " YES embedded" << std::endl; }
426  } else {
427  truth_track = nullptr;
429  if (Verbosity() > 1000) { std::cout << " NOT embedded" << std::endl; }
430  }
431  }
432 
433  // see if there is a jump in x or y relative to previous PHG4Hit
435  if (prior_g4hit) {
436  // if the g4hits jump in x or y by > max_g4hit_jump, cluster the truth tracks
437  if ( std::abs(prior_g4hit->get_x(0)-hiter->second->get_x(0)) > max_g4hitstep
438  || std::abs(prior_g4hit->get_y(0)-hiter->second->get_y(0)) > max_g4hitstep
439  ) {
440  if(truth_track)
441  {
443  }
444  }
445  }
446  prior_g4hit = hiter->second;
447  }
448 
449  // for very high occupancy events, accessing the TrkrHitsets on the node tree
450  // for every drifted electron seems to be very slow
451  // Instead, use a temporary map to accumulate the charge from all
452  // drifted electrons, then copy to the node tree later
453 
454  double eion = hiter->second->get_eion();
455  unsigned int n_electrons = gsl_ran_poisson(RandomGenerator.get(), eion * electrons_per_gev);
456  // count_electrons += n_electrons;
457 
458  if (Verbosity() > 100)
459  std::cout << " new hit with t0, " << t0 << " g4hitid " << hiter->first
460  << " eion " << eion << " n_electrons " << n_electrons
461  << " entry z " << hiter->second->get_z(0) << " exit z "
462  << hiter->second->get_z(1) << " avg z"
463  << (hiter->second->get_z(0) + hiter->second->get_z(1)) / 2.0
464  << std::endl;
465 
466  if (n_electrons == 0) { continue; }
467 
468  if (Verbosity() > 100)
469  {
470  std::cout << std::endl
471  << "electron drift: g4hit " << hiter->first << " created electrons: "
472  << n_electrons << " from " << eion * 1000000 << " keV" << std::endl;
473  std::cout << " entry x,y,z = " << hiter->second->get_x(0) << " "
474  << hiter->second->get_y(0) << " " << hiter->second->get_z(0)
475  << " radius " << sqrt(pow(hiter->second->get_x(0), 2) +
476  pow(hiter->second->get_y(0), 2)) << std::endl;
477  std::cout << " exit x,y,z = " << hiter->second->get_x(1) << " "
478  << hiter->second->get_y(1) << " " << hiter->second->get_z(1)
479  << " radius " << sqrt(pow(hiter->second->get_x(1), 2) +
480  pow(hiter->second->get_y(1), 2)) << std::endl;
481  }
482 
483  for (unsigned int i = 0; i < n_electrons; i++)
484  {
485  // We choose the electron starting position at random from a flat
486  // distribution along the path length the parameter t is the fraction of
487  // the distance along the path betwen entry and exit points, it has
488  // values between 0 and 1
489  const double f = gsl_ran_flat(RandomGenerator.get(), 0.0, 1.0);
490 
491  const double x_start = hiter->second->get_x(0) + f * (hiter->second->get_x(1) - hiter->second->get_x(0));
492  const double y_start = hiter->second->get_y(0) + f * (hiter->second->get_y(1) - hiter->second->get_y(0));
493  const double z_start = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0));
494  const double t_start = hiter->second->get_t(0) + f * (hiter->second->get_t(1) - hiter->second->get_t(0));
495 
496  unsigned int side = 0;
497  if (z_start > 0) side = 1;
498 
499  const double r_sigma = diffusion_trans * sqrt(tpc_length / 2. - std::abs(z_start));
500  const double rantrans =
501  gsl_ran_gaussian(RandomGenerator.get(), r_sigma) +
502  gsl_ran_gaussian(RandomGenerator.get(), added_smear_sigma_trans);
503 
504  const double t_path = (tpc_length / 2. - std::abs(z_start)) / drift_velocity;
505  const double t_sigma = diffusion_long * sqrt(tpc_length / 2. - std::abs(z_start)) / drift_velocity;
506  const double rantime =
507  gsl_ran_gaussian(RandomGenerator.get(), t_sigma) +
508  gsl_ran_gaussian(RandomGenerator.get(), added_smear_sigma_long) / drift_velocity;
509  double t_final = t_start + t_path + rantime;
510 
511  if (t_final < min_time || t_final > max_time) continue;
512 
513  double z_final;
514  if (z_start < 0)
515  z_final = -tpc_length / 2. + t_final * drift_velocity;
516  else
517  z_final = tpc_length / 2. - t_final * drift_velocity;
518 
519  const double radstart = std::sqrt(square(x_start) + square(y_start));
520  const double phistart = std::atan2(y_start, x_start);
521  const double ranphi = gsl_ran_flat(RandomGenerator.get(), -M_PI, M_PI);
522 
523  double x_final = x_start + rantrans * std::cos(ranphi); // Initialize these to be only diffused first, will be overwritten if doing SC distortion
524  double y_final = y_start + rantrans * std::sin(ranphi);
525 
526  double rad_final = sqrt(square(x_final) + square(y_final));
527  double phi_final = atan2(y_final, x_final);
528 
530  {
531  z_startmap->Fill(z_start, radstart); // map of starting location in Z vs. R
532  deltaphinodist->Fill(phistart, rantrans / rad_final); // delta phi no distortion, just diffusion+smear
533  deltarnodist->Fill(radstart, rantrans); // delta r no distortion, just diffusion+smear
534  }
535 
536  if (m_distortionMap)
537  {
538  //zhangcanyu
539  const double reaches = m_distortionMap->get_reaches_readout(radstart, phistart, z_start);
540  if (reaches < thresholdforreachesreadout)
541  {
542  continue;
543  }
544 
545  const double r_distortion = m_distortionMap->get_r_distortion(radstart, phistart, z_start);
546  const double phi_distortion = m_distortionMap->get_rphi_distortion(radstart, phistart, z_start) / radstart;
547  const double z_distortion = m_distortionMap->get_z_distortion(radstart, phistart, z_start);
548 
549  rad_final += r_distortion;
550  phi_final += phi_distortion;
551  z_final += z_distortion;
552  if (z_start < 0)
553  t_final = (z_final + tpc_length / 2.0) / drift_velocity;
554  else
555  t_final = (tpc_length / 2.0 - z_final) / drift_velocity;
556 
557  x_final = rad_final * std::cos(phi_final);
558  y_final = rad_final * std::sin(phi_final);
559 
561  {
562  const double phi_final_nodiff = phistart + phi_distortion;
563  const double rad_final_nodiff = radstart + r_distortion;
564  deltarnodiff->Fill(radstart, rad_final_nodiff - radstart); //delta r no diffusion, just distortion
565  deltaphinodiff->Fill(phistart, phi_final_nodiff - phistart); //delta phi no diffusion, just distortion
566  deltaphivsRnodiff->Fill(radstart, phi_final_nodiff - phistart);
567  deltaRphinodiff->Fill(radstart, rad_final_nodiff * phi_final_nodiff - radstart * phistart);
568 
569  // Fill Diagnostic plots, written into ElectronDriftQA.root
570  hitmapstart->Fill(x_start, y_start); // G4Hit starting positions
571  hitmapend->Fill(x_final, y_final); //INcludes diffusion and distortion
572  deltar->Fill(radstart, rad_final - radstart); //total delta r
573  deltaphi->Fill(phistart, phi_final - phistart); // total delta phi
574  deltaz->Fill(z_start, z_distortion); // map of distortion in Z (time)
575  }
576  }
577 
578  // remove electrons outside of our acceptance. Careful though, electrons from just inside 30 cm can contribute in the 1st active layer readout, so leave a little margin
579  if (rad_final < min_active_radius - 2.0 || rad_final > max_active_radius + 1.0)
580  { continue; }
581 
582  if (Verbosity() > 1000)
583  {
584  std::cout << "electron " << i << " g4hitid " << hiter->first << " f " << f << std::endl;
585  std::cout << "radstart " << radstart << " x_start: " << x_start
586  << ", y_start: " << y_start
587  << ",z_start: " << z_start
588  << " t_start " << t_start
589  << " t_path " << t_path
590  << " t_sigma " << t_sigma
591  << " rantime " << rantime
592  << std::endl;
593 
594  std::cout << " rad_final " << rad_final << " x_final " << x_final
595  << " y_final " << y_final
596  << " z_final " << z_final << " t_final " << t_final
597  << " zdiff " << z_final - z_start << std::endl;
598  }
599 
600  if (Verbosity() > 0)
601  {
602  assert(nt);
603  nt->Fill(ihit, t_start, t_final, t_sigma, rad_final, z_start, z_final);
604  }
605  padplane->MapToPadPlane(truth_clusterer, single_hitsetcontainer.get(),
606  temp_hitsetcontainer.get(), hittruthassoc, x_final, y_final, t_final,
607  side, hiter, ntpad, nthit);
608  } // end loop over electrons for this g4hit
609 
611  for (TrkrHitSetContainer::ConstIterator single_hitset_iter = single_hitset_range.first;
612  single_hitset_iter != single_hitset_range.second;
613  ++single_hitset_iter)
614  {
615  // we have an itrator to one TrkrHitSet for the Tpc from the single_hitsetcontainer
616  TrkrDefs::hitsetkey node_hitsetkey = single_hitset_iter->first;
617  const unsigned int layer = TrkrDefs::getLayer(node_hitsetkey);
618  const int sector = TpcDefs::getSectorId(node_hitsetkey);
619  const int side = TpcDefs::getSide(node_hitsetkey);
620 
621  if (Verbosity() > 8)
622  std::cout << " hitsetkey " << node_hitsetkey << " layer " << layer << " sector " << sector << " side " << side << std::endl;
623  // get all of the hits from the single hitset
624  TrkrHitSet::ConstRange single_hit_range = single_hitset_iter->second->getHits();
625  for (TrkrHitSet::ConstIterator single_hit_iter = single_hit_range.first;
626  single_hit_iter != single_hit_range.second;
627  ++single_hit_iter)
628  {
629  TrkrDefs::hitkey single_hitkey = single_hit_iter->first;
630 
631  // Add the hit-g4hit association
632  // no need to check for duplicates, since the hit is new
633  hittruthassoc->addAssoc(node_hitsetkey, single_hitkey, hiter->first);
634  if (Verbosity() > 100)
635  std::cout << " adding assoc for node_hitsetkey " << node_hitsetkey << " single_hitkey " << single_hitkey << " g4hitkey " << hiter->first << std::endl;
636  }
637  }
638 
639  // Dump the temp_hitsetcontainer to the node tree and reset it
640  // - after every "dump_interval" g4hits
641  // - if this is the last g4hit
642  if (dump_counter >= dump_interval || count_g4hits == g4hit->size())
643  {
644  //std::cout << " dump_counter " << dump_counter << " count_g4hits " << count_g4hits << std::endl;
645 
646  double eg4hit = 0.0;
648  for (TrkrHitSetContainer::ConstIterator temp_hitset_iter = temp_hitset_range.first;
649  temp_hitset_iter != temp_hitset_range.second;
650  ++temp_hitset_iter)
651  {
652  // we have an itrator to one TrkrHitSet for the Tpc from the temp_hitsetcontainer
653  TrkrDefs::hitsetkey node_hitsetkey = temp_hitset_iter->first;
654  const unsigned int layer = TrkrDefs::getLayer(node_hitsetkey);
655  const int sector = TpcDefs::getSectorId(node_hitsetkey);
656  const int side = TpcDefs::getSide(node_hitsetkey);
657  if (Verbosity() > 100)
658  std::cout << "PHG4TpcElectronDrift: temp_hitset with key: " << node_hitsetkey << " in layer " << layer
659  << " with sector " << sector << " side " << side << std::endl;
660 
661  // find or add this hitset on the node tree
662  TrkrHitSetContainer::Iterator node_hitsetit = hitsetcontainer->findOrAddHitSet(node_hitsetkey);
663 
664  // get all of the hits from the temporary hitset
665  TrkrHitSet::ConstRange temp_hit_range = temp_hitset_iter->second->getHits();
666  for (TrkrHitSet::ConstIterator temp_hit_iter = temp_hit_range.first;
667  temp_hit_iter != temp_hit_range.second;
668  ++temp_hit_iter)
669  {
670  TrkrDefs::hitkey temp_hitkey = temp_hit_iter->first;
671  TrkrHit *temp_tpchit = temp_hit_iter->second;
672  if (Verbosity() > 10 && layer == print_layer)
673  {
674  std::cout << " temp_hitkey " << temp_hitkey << " layer " << layer << " pad " << TpcDefs::getPad(temp_hitkey)
675  << " z bin " << TpcDefs::getTBin(temp_hitkey)
676  << " energy " << temp_tpchit->getEnergy() << " eg4hit " << eg4hit << std::endl;
677 
678  eg4hit += temp_tpchit->getEnergy();
679  // ecollectedhits += temp_tpchit->getEnergy();
680  ncollectedhits++;
681  }
682 
683  // find or add this hit to the node tree
684  TrkrHit *node_hit = node_hitsetit->second->getHit(temp_hitkey);
685  if (!node_hit)
686  {
687  // Otherwise, create a new one
688  node_hit = new TrkrHitv2();
689  node_hitsetit->second->addHitSpecificKey(temp_hitkey, node_hit);
690  }
691 
692  // Either way, add the energy to it
693  node_hit->addEnergy(temp_tpchit->getEnergy());
694 
695  } // end loop over temp hits
696 
697  if (Verbosity() > 100 && layer == print_layer)
698  std::cout << " ihit " << ihit << " collected energy = " << eg4hit << std::endl;
699 
700  } // end loop over temp hitsets
701 
702  // erase all entries in the temp hitsetcontainer
703  temp_hitsetcontainer->Reset();
704 
705  // reset the dump counter
706  dump_counter = 0;
707  } // end copy of temp hitsetcontainer to node tree hitsetcontainer
708 
709  ++ihit;
710 
711  single_hitsetcontainer->Reset();
712 
713  } // end loop over g4hits
714 
717 
718  if (Verbosity() > 20)
719  {
720  std::cout << "From PHG4TpcElectronDrift: hitsetcontainer printout at end:" << std::endl;
721  // We want all hitsets for the Tpc
723  for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range.first;
724  hitset_iter != hitset_range.second;
725  ++hitset_iter)
726  {
727  // we have an itrator to one TrkrHitSet for the Tpc from the trkrHitSetContainer
728  TrkrDefs::hitsetkey hitsetkey = hitset_iter->first;
729  const unsigned int layer = TrkrDefs::getLayer(hitsetkey);
730  if (layer != print_layer) continue;
731  const int sector = TpcDefs::getSectorId(hitsetkey);
732  const int side = TpcDefs::getSide(hitsetkey);
733 
734  std::cout << "PHG4TpcElectronDrift: hitset with key: " << hitsetkey << " in layer " << layer << " with sector " << sector << " side " << side << std::endl;
735 
736  // get all of the hits from this hitset
737  TrkrHitSet *hitset = hitset_iter->second;
738  TrkrHitSet::ConstRange hit_range = hitset->getHits();
739  for (TrkrHitSet::ConstIterator hit_iter = hit_range.first;
740  hit_iter != hit_range.second;
741  ++hit_iter)
742  {
743  TrkrDefs::hitkey hitkey = hit_iter->first;
744  TrkrHit *tpchit = hit_iter->second;
745  std::cout << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) << " z bin " << TpcDefs::getTBin(hitkey)
746  << " energy " << tpchit->getEnergy() << std::endl;
747  }
748  }
749  }
750 
751  if (Verbosity() > 1000)
752  {
753  std::cout << "From PHG4TpcElectronDrift: hittruthassoc dump:" << std::endl;
755 
757  }
758 
759  ++event_num; // if doing more than one event, event_num will be incremented.
760 
761  if (Verbosity() > 500)
762  {
763  std::cout << " TruthTrackContainer results at end of event in PHG4TpcElectronDrift::process_event " << std::endl;
765  }
766 
767  if (Verbosity()>800) {
769  truth_clusterer.print_file(truthtracks,"drift_clusters.txt");
770  }
771 
773 }
774 
776 {
777  if (Verbosity() > 0)
778  {
779  assert(m_outf);
780  assert(nt);
781  assert(ntpad);
782  assert(nthit);
784 
785  m_outf->cd();
786  nt->Write();
787  ntpad->Write();
788  nthit->Write();
789  ntfinalhit->Write();
790  m_outf->Close();
791  }
793  {
794  EDrift_outf.reset(new TFile("ElectronDriftQA.root", "recreate"));
795  EDrift_outf->cd();
796  deltar->Write();
797  deltaphi->Write();
798  deltaz->Write();
799  deltarnodist->Write();
800  deltaphinodist->Write();
801  deltarnodiff->Write();
802  deltaphinodiff->Write();
803  deltaRphinodiff->Write();
804  deltaphivsRnodiff->Write();
805  hitmapstart->Write();
806  hitmapend->Write();
807  z_startmap->Write();
808  EDrift_outf->Close();
809  }
811 }
812 
813 void PHG4TpcElectronDrift::set_seed(const unsigned int seed)
814 {
816 }
817 
819 {
820  // Data on gasses @20 C and 760 Torr from the following source:
821  // http://www.slac.stanford.edu/pubs/icfa/summer98/paper3/paper3.pdf
822  // diffusion and drift velocity for 400kV for NeCF4 50/50 from calculations:
823  // http://skipper.physics.sunysb.edu/~prakhar/tpc/HTML_Gases/split.html
824  static constexpr double Ne_dEdx = 1.56; // keV/cm
825  static constexpr double CF4_dEdx = 7.00; // keV/cm
826  // double Ne_NPrimary = 12; // Number/cm
827  // double CF4_NPrimary = 51; // Number/cm
828  static constexpr double Ne_NTotal = 43; // Number/cm
829  static constexpr double CF4_NTotal = 100; // Number/cm
830  static constexpr double Tpc_NTot = 0.5 * Ne_NTotal + 0.5 * CF4_NTotal;
831  static constexpr double Tpc_dEdx = 0.5 * Ne_dEdx + 0.5 * CF4_dEdx;
832  static constexpr double Tpc_ElectronsPerKeV = Tpc_NTot / Tpc_dEdx;
833  set_default_double_param("diffusion_long", 0.012); // cm/SQRT(cm)
834  set_default_double_param("diffusion_trans", 0.004); // cm/SQRT(cm)
835  set_default_double_param("electrons_per_gev", Tpc_ElectronsPerKeV * 1000000.);
836  set_default_double_param("min_active_radius", 30.); // cm
837  set_default_double_param("max_active_radius", 78.); // cm
838  set_default_double_param("drift_velocity", 8.0 / 1000.0); // cm/ns
839  set_default_double_param("max_time", 13200.); //ns
840  set_default_double_param("extended_readout_time", 7000.); //ns
841 
842  // These are purely fudge factors, used to increase the resolution to 150 microns and 500 microns, respectively
843  // override them from the macro to get a different resolution
844  set_default_double_param("added_smear_trans", 0.085); // cm
845  set_default_double_param("added_smear_long", 0.105); // cm
846 
847  return;
848 }
849 
850 
852 {
853  m_distortionMap.reset(distortionMap);
854 }
855 
857 {
858  if (Verbosity()) std::cout << "Registering padplane " << std::endl;
859  padplane.reset(inpadplane);
860  padplane->Detector(Detector());
861  padplane->UpdateInternalParameters();
862  if (Verbosity()) std::cout << "padplane registered and parameters updated" << std::endl;
863 
864  return;
865 }