Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHTruthTrackSeeding.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHTruthTrackSeeding.cc
1 #include "PHTruthTrackSeeding.h"
2 
6 
9 
12 
15 
17 
18 #include <g4eval/SvtxClusterEval.h>
19 #include <g4eval/SvtxEvalStack.h>
20 #include <g4eval/SvtxEvaluator.h>
21 #include <g4eval/SvtxTrackEval.h>
22 
23 #include <g4main/PHG4Hit.h> // for PHG4Hit
24 #include <g4main/PHG4Particle.h> // for PHG4Particle
26 #include <g4main/PHG4HitDefs.h> // for keytype
28 #include <g4main/PHG4VtxPoint.h>
29 
30 #include <phool/PHCompositeNode.h>
31 #include <phool/PHIODataNode.h>
32 #include <phool/PHNode.h>
33 #include <phool/PHNodeIterator.h>
34 #include <phool/PHObject.h>
35 #include <phool/getClass.h>
36 #include <phool/phool.h>
37 #include <phool/PHRandomSeed.h>
38 
39 #include <trackbase/TrkrCluster.h>
43 
47 
48 #include <TDatabasePDG.h>
49 #include <TParticlePDG.h>
50 
51 #include <gsl/gsl_randist.h>
52 #include <gsl/gsl_rng.h> // for gsl_rng_alloc
53 
54 #include <cassert>
55 #include <cstdlib> // for exit
56 #include <iostream> // for operator<<, std::endl
57 #include <map> // for multimap, map<>::c...
58 #include <memory>
59 #include <set>
60 #include <utility> // for pair
61 
62 class PHCompositeNode;
63 
64 namespace
65 { template< class T> inline constexpr T square( const T& x ) { return x*x; } }
66 
68  : PHTrackSeeding(name)
69  , _clustereval(nullptr)
70 {
71  // initialize random generator
72  const uint seed = PHRandomSeed();
73  m_rng.reset( gsl_rng_alloc(gsl_rng_mt19937) );
74  gsl_rng_set( m_rng.get(), seed );
75 }
76 
78 {
79  std::cout << "Enter PHTruthTrackSeeding:: Setup" << std::endl ;
80 
81  int ret = PHTrackSeeding::Setup(topNode);
82  if (ret != Fun4AllReturnCodes::EVENT_OK) return ret;
83 
84  ret = GetNodes(topNode);
85  if (ret != Fun4AllReturnCodes::EVENT_OK) return ret;
86 
87  ret = CreateNodes(topNode);
88  if (ret != Fun4AllReturnCodes::EVENT_OK) return ret;
89 
90  _clustereval = new SvtxClusterEval(topNode);
91  _clustereval->do_caching(true);
93 }
94 
96 {
97  _clustereval->next_event(topNode);
98  _track_map_combined->Clear();
99 
100  using TrkClustersMap = std::map<int, std::set<TrkrCluster*> >;
101  TrkClustersMap m_trackID_clusters;
102 
103  std::vector<TrkrDefs::cluskey> ClusterKeyListSilicon;
104  std::vector<TrkrDefs::cluskey> ClusterKeyListTpc;
105 
107  for (PHG4TruthInfoContainer::ConstIterator iter = range.first;
108  iter != range.second;
109  ++iter){
110  ClusterKeyListSilicon.clear();
111  ClusterKeyListTpc.clear();
112  PHG4Particle* g4particle = iter->second;
113 
114  if (g4particle==NULL){
115  std::cout <<__PRETTY_FUNCTION__<<" - validity check failed: missing truth particle" << std::endl;
116  exit(1);
117  }
118 
119  const float gtrackID = g4particle->get_track_id();
120 
121  // momentum cut-off
122  if (_min_momentum>0){
123  const double monentum2 =
124  g4particle->get_px() * g4particle->get_px()+
125  g4particle->get_py() * g4particle->get_py()+
126  g4particle->get_pz() * g4particle->get_pz();
127 
128  if (monentum2 < _min_momentum * _min_momentum){
129  if (Verbosity() >= 3){
130  std::cout <<__PRETTY_FUNCTION__<<" ignore low momentum particle "<< gtrackID << std::endl;
131  g4particle->identify();
132  }
133  continue;
134  }
135  }
136 
137  for(unsigned int layer = _min_layer;layer < _max_layer;layer++){
139  if(cluskey!=0)
140  {
141  unsigned int trkrid = TrkrDefs::getTrkrId(cluskey);
142  if(trkrid == TrkrDefs::mvtxId || trkrid == TrkrDefs::inttId)
143  ClusterKeyListSilicon.push_back(cluskey);
144  else
145  ClusterKeyListTpc.push_back(cluskey);
146  }
147  }
148 
149  unsigned int nsi = ClusterKeyListSilicon.size();
150  unsigned int ntpc = ClusterKeyListTpc.size();
151 
152  if( nsi+ntpc < _min_clusters_per_track)
153  continue;
154 
155  if(nsi > 0)
156  {
157  buildTrackSeed(ClusterKeyListSilicon, g4particle, _track_map_silicon);
158  }
159  if(ntpc > 0)
160  {
161  buildTrackSeed(ClusterKeyListTpc, g4particle, _track_map);
162  }
163 
164  if(nsi > 0 && ntpc > 0)
165  {
166  // Create the SvtxTrackSeed for the full track
167  auto track = std::make_unique<SvtxTrackSeed_v1>();
170  track->set_tpc_seed_index(_track_map->size()-1);
171  track->set_silicon_seed_index(_track_map_silicon->size()-1);
172 
173  _track_map_combined->insert(track.get());
174  }
175  }
176 
177  if(Verbosity() > 0)
178  {
179  // loop over the assembled tracks
180  for (unsigned int phtrk_iter = 0;
181  phtrk_iter < _track_map_combined->size();
182  ++phtrk_iter)
183  {
184  auto seed = _track_map_combined->get(phtrk_iter);
185  if(!seed) continue;
186 
187  auto tpc_index = seed->get_tpc_seed_index();
188  auto silicon_index = seed->get_silicon_seed_index();
189 
190  std::cout << "SvtxSeedTrack: " << phtrk_iter
191  << " tpc_index " << tpc_index
192  << " silicon_index " << silicon_index
193  << std::endl;
194 
195  std::cout << " ---------- silicon tracklet " << silicon_index << std::endl;
196  auto silicon_tracklet = _track_map_silicon->get(silicon_index);
197  if(!silicon_tracklet) continue;
198  silicon_tracklet->identify();
199 
200  std::cout << " ---------- tpc tracklet " << tpc_index << std::endl;
201  auto tpc_tracklet = _track_map->get(tpc_index);
202  if(!tpc_tracklet) continue;
203  tpc_tracklet->identify();
204  }
205  }
206 
207  //==================================
208 
210 }
211 
212 void PHTruthTrackSeeding::buildTrackSeed(std::vector<TrkrDefs::cluskey> clusters, PHG4Particle *g4particle, TrackSeedContainer* container)
213 {
214  // This method is called separately for silicon and tpc seeds
215 
216  auto track = std::make_unique<TrackSeed_FastSim_v1>();
217  bool silicon = false;
218  bool tpc = false;
219  for (const auto& cluskey : clusters){
222  { silicon = true; }
224  { tpc = true; }
225  track->insert_cluster_key(cluskey);
226  }
227 
228  const auto particle = TDatabasePDG::Instance()->GetParticle(g4particle->get_pid());
229  int charge = 1;
230  if(particle)
231  {
232  if(particle->Charge() < 0)
233  { charge = -1; }
234  }
235 
236  auto random1 = gsl_ran_flat(m_rng.get(), 0.95, 1.05);
237  float px = g4particle->get_px() * random1;
238  float py = g4particle->get_py() * random1;
239  float pz = g4particle->get_pz() * random1;
240  const auto g4vertex = m_g4truth_container->GetVtx(g4particle->get_vtx_id());
241  auto random2 = gsl_ran_flat(m_rng.get(), -0.02, 0.02);
242  float x = g4vertex->get_x() + random2;
243  float y = g4vertex->get_y() + random2;
244  float z = g4vertex->get_z() + random2;
245 
246  float pt = sqrt(px*px+py*py);
247  float phi = atan2(py,px);
248  float R = 100 * pt / (0.3*1.4);
249  float theta = atan2(pt,pz);
250  if(theta < 0)
251  { theta += M_PI; }
252  if(theta > M_PI)
253  { theta -= M_PI; }
254 
255  float eta = -log(tan(theta/2.));
256 
257  // We have two equations, phi = atan2(-(X0-x),y-Y0) and
258  //R^2 = (x-X0)^2 + (y-Y0)^2. Solve for X0 and Y0 knowing R and phi
259  float tanphisq = square(tan(phi));
260  float a = tanphisq + 1;
261  float b =-2*y*(tanphisq+1);
262  float c = (tanphisq+1)*square(y)-square(R);
263 
264  float Y0_1 = (-b + sqrt(square(b)-4*a*c)) / (2.*a);
265  float Y0_2 = (-b - sqrt(square(b)-4*a*c)) / (2.*a);
266  float X0_1 = sqrt(pow(R, 2) - pow(Y0_1 - y, 2)) + x;
267  float X0_2 = -sqrt(pow(R, 2) - pow(Y0_2 - y, 2)) + x;
268  track->set_X0(X0_1);
269  track->set_Y0(Y0_1);
270  track->set_qOverR(charge / R);
271  track->set_slope(1. / tan(theta));
272  track->set_Z0(z);
273 
274  if(tpc)
275  {
276  // if this is the TPC, the track Z0 depends on the crossing
277  // we must determine Z0 from the clusters instead of the truth for the TPC
278  // this method calculates the Z0 and z slope from a fit to the clusters and overwrites them
279  unsigned int start_layer = 7;
280  unsigned int end_layer = 54;
281  track->lineFit(m_clusterMap, tgeometry, start_layer, end_layer);
282  }
283 
285 
286  float newphi = track->get_phi(m_clusterMap, tgeometry);
289  if( fabs(newphi-phi) > 0.03)
290  {
291  track->set_X0(X0_2);
292  newphi = track->get_phi(m_clusterMap, tgeometry);
293 
294  if( fabs(newphi-phi) > 0.03)
295  {
296  track->set_Y0(Y0_2);
297  newphi = track->get_phi(m_clusterMap, tgeometry);
298 
299  if( fabs(newphi-phi) > 0.03)
300  {
301  track->set_X0(X0_1);
302  newphi = track->get_phi(m_clusterMap, tgeometry);
303  }
304  }
305  }
306 
307  if(Verbosity() > 2)
308  {
309  std::cout << "Charge is " << charge << std::endl;
310  std::cout << "truth/reco px " << px << ", " << track->get_px(m_clusterMap, tgeometry) << std::endl;
311  std::cout << "truth/reco py " << py << ", " << track->get_py(m_clusterMap, tgeometry) << std::endl;
312  std::cout << "truth/reco pz " << pz << ", " << track->get_pz() << std::endl;
313  std::cout << "truth/reco pt " << pt << ", " << track->get_pt() << std::endl;
314  std::cout << "truth/reco phi " << phi << ", " << track->get_phi(m_clusterMap, tgeometry) << std::endl;
315  std::cout << "truth/reco eta " << eta << ", " << track->get_eta() << std::endl;
316  std::cout << "truth/reco x " << x << ", " << track->get_x() << std::endl;
317  std::cout << "truth/reco y " << y << ", " << track->get_y() << std::endl;
318  std::cout << "truth/reco z " << z << ", " << track->get_z() << std::endl;
319 
320  }
321 
322  // set intt crossing
323  if(silicon)
324  {
325  // silicon tracklet
326  /* inspired from PHtruthSiliconAssociation */
327  const auto intt_crossings = getInttCrossings(track.get());
328  if(intt_crossings.empty())
329  {
330  if(Verbosity() > 1) std::cout << "PHTruthTrackSeeding::Process - Silicon track " << container->size() - 1 << " has no INTT clusters" << std::endl;
331  return ;
332  } else if( intt_crossings.size() > 1 ) {
333  if(Verbosity() > 1)
334  { std::cout << "PHTruthTrackSeeding::Process - INTT crossings not all the same for track " << container->size() - 1 << " crossing_keep - dropping this match " << std::endl; }
335 
336  } else {
337  const auto& crossing = *intt_crossings.begin();
338  track->set_crossing(crossing);
339  if(Verbosity() > 1)
340  std::cout << "PHTruthTrackSeeding::Process - Combined track " << container->size() - 1 << " bunch crossing " << crossing << std::endl;
341  }
342  } // end if _min_layer
343  else
344  {
345  // no INTT layers, crossing is unknown
346  track->set_crossing(SHRT_MAX);
347  }
348 
349  container->insert(track.get());
350 }
352 {
353  // create nodes...
354  PHNodeIterator iter(topNode);
355 
356  PHCompositeNode* dstNode = static_cast<PHCompositeNode*>(iter.findFirst(
357  "PHCompositeNode", "DST"));
358  if (!dstNode)
359  {
360  std::cerr << PHWHERE << "DST Node missing, doing nothing." << std::endl;
362  }
363  PHNodeIterator iter_dst(dstNode);
364 
365  // Create the SVTX node
366  PHCompositeNode* tb_node =
367  dynamic_cast<PHCompositeNode*>(iter_dst.findFirst("PHCompositeNode",
368  "SVTX"));
369  if (!tb_node)
370  {
371  tb_node = new PHCompositeNode("SVTX");
372  dstNode->addNode(tb_node);
373  if (Verbosity() > 0)
374  std::cout << PHWHERE << "SVTX node added" << std::endl;
375  }
376 
377  _track_map = findNode::getClass<TrackSeedContainer>(topNode,"TpcTrackSeedContainer");
378  if(!_track_map)
379  {
381  PHIODataNode<PHObject>* tracks_node =
382  new PHIODataNode<PHObject>(_track_map, "TpcTrackSeedContainer", "PHObject");
383  tb_node->addNode(tracks_node);
384  }
385 
386  _track_map_silicon = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
387  if(!_track_map_silicon)
388  {
390  PHIODataNode<PHObject>* tracks_node =
391  new PHIODataNode<PHObject>(_track_map_silicon, "SiliconTrackSeedContainer", "PHObject");
392  tb_node->addNode(tracks_node);
393  }
394 
395  _track_map_combined = findNode::getClass<TrackSeedContainer>(topNode, "SvtxTrackSeedContainer");
397  {
399  PHIODataNode<PHObject> *node2 = new PHIODataNode<PHObject>(_track_map_combined, "SvtxTrackSeedContainer","PHObject");
400  tb_node->addNode(node2);
401  }
402 
404 }
406 {
407 
408  tgeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
409  if(!tgeometry)
410  {
411  std::cerr << PHWHERE << "Error, can' find needed Acts nodes " << std::endl;
413  }
414 
415  m_clusterMap = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
416 
417  if(!m_clusterMap)
418  {
419  std::cerr << PHWHERE << "Error: Can't find node TRKR_CLUSTER" << std::endl ;
421  }
422 
423  m_cluster_crossing_map = findNode::getClass<TrkrClusterCrossingAssoc>(topNode, "TRKR_CLUSTERCROSSINGASSOC");
425  {
426  std::cerr << PHWHERE << " ERROR: Can't find TRKR_CLUSTERCROSSINGASSOC " << std::endl ;
428  }
429 
430  m_g4truth_container = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
431  if (!m_g4truth_container)
432  {
433  std::cerr << PHWHERE << " ERROR: Can't find node G4TruthInfo" << std::endl ;
435  }
436 
437  hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
438  if (!hittruthassoc)
439  {
440  std::cout << PHWHERE << "Failed to find TRKR_HITTRUTHASSOC node, quit!" << std::endl ;
441  exit(1);
442  }
443 
444  using nodePair = std::pair<std::string, PHG4HitContainer*&>;
445  std::initializer_list<nodePair> nodes =
446  {
447  { "G4HIT_TPC", phg4hits_tpc },
448  { "G4HIT_INTT", phg4hits_intt },
449  { "G4HIT_MVTX", phg4hits_mvtx },
450  { "G4HIT_MICROMEGAS", phg4hits_micromegas }
451  };
452 
453  for( auto&& node: nodes )
454  {
455  if( !( node.second = findNode::getClass<PHG4HitContainer>( topNode, node.first ) ) )
456  { std::cerr << PHWHERE << " PHG4HitContainer " << node.first << " not found" << std::endl; }
457  }
458 
460 }
461 
463 { return 0; }
464 
465 
466 //_____________________________________________________________________________________________
467 std::set<short int> PHTruthTrackSeeding::getInttCrossings(TrackSeed *si_track) const
468 {
469  if( Verbosity() )
470  std::cout << "PHTruthTrackSeeding::getInttCrossings - entering " << std::endl;
471 
472  std::set<short int> intt_crossings;
473 
474  // If the Si track contains an INTT hit, use it to get the bunch crossing offset
475  // loop over associated clusters to get keys for silicon cluster
476 
477  for( auto iter = si_track->begin_cluster_keys();
478  iter != si_track->end_cluster_keys(); ++iter)
479  {
480 
481  const TrkrDefs::cluskey& cluster_key = *iter;
482  const unsigned int trkrid = TrkrDefs::getTrkrId(cluster_key);
483  if(Verbosity() > 0) std::cout << " trkrid " << trkrid << " cluster_key " << cluster_key << std::endl;
484  if(trkrid == TrkrDefs::inttId)
485  {
486 
487  // get layer from cluster key
488  const unsigned int layer = TrkrDefs::getLayer(cluster_key);
489 
490  // get the bunch crossings for all hits in this cluster
491  const auto crossings = m_cluster_crossing_map->getCrossings(cluster_key);
492  for(auto iter = crossings.first; iter != crossings.second; ++iter)
493  {
494  const auto& [key, crossing] = *iter;
495  if( Verbosity() )
496  { std::cout << " PHTruthTrackSeeding::getInttCrossings - si Track cluster " << key << " layer " << layer << " crossing " << crossing << std::endl; }
497  intt_crossings.insert(crossing);
498  }
499  }
500  }
501 
502  return intt_crossings;
503 }