Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackEvaluation.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TrackEvaluation.cc
1 
6 #include "TrackEvaluation.h"
7 
11 
12 #include <g4main/PHG4Hit.h>
14 #include <g4main/PHG4Hitv1.h>
15 #include <g4main/PHG4Particle.h>
17 #include <g4main/PHG4VtxPoint.h>
18 
21 
22 #include <trackbase/ActsGeometry.h>
24 #include <trackbase/InttDefs.h>
25 #include <trackbase/MvtxDefs.h>
26 #include <trackbase/TpcDefs.h>
27 #include <trackbase/TrkrCluster.h>
30 #include <trackbase/TrkrDefs.h>
31 #include <trackbase/TrkrHit.h>
32 #include <trackbase/TrkrHitSet.h>
37 
39 
40 #include <phool/PHCompositeNode.h>
41 #include <phool/PHNodeIterator.h>
42 #include <phool/getClass.h>
43 
44 #include <TVector3.h>
45 
46 #include <algorithm>
47 #include <bitset>
48 #include <cassert>
49 #include <iostream>
50 #include <numeric>
51 
52 //_____________________________________________________________________
53 namespace
54 {
55 
57  template <class T>
58  class range_adaptor
59  {
60  public:
61  explicit range_adaptor(const T& range)
62  : m_range(range)
63  {
64  }
65  inline const typename T::first_type& begin() { return m_range.first; }
66  inline const typename T::second_type& end() { return m_range.second; }
67 
68  private:
69  T m_range;
70  };
71 
73  template <class T>
74  inline constexpr T square(const T& x)
75  {
76  return x * x;
77  }
78 
80  template <class T>
81  inline constexpr T get_r(T x, T y)
82  {
83  return std::sqrt(square(x) + square(y));
84  }
85 
87  template <class T>
88  T get_pt(T px, T py)
89  {
90  return std::sqrt(square(px) + square(py));
91  }
92 
94  template <class T>
95  T get_p(T px, T py, T pz)
96  {
97  return std::sqrt(square(px) + square(py) + square(pz));
98  }
99 
101  template <class T>
102  T get_eta(T p, T pz)
103  {
104  return std::log((p + pz) / (p - pz)) / 2;
105  }
106 
108  struct interpolation_data_t
109  {
110  using list = std::vector<interpolation_data_t>;
111  double x() const { return position.x(); }
112  double y() const { return position.y(); }
113  double z() const { return position.z(); }
114 
115  double px() const { return momentum.x(); }
116  double py() const { return momentum.y(); }
117  double pz() const { return momentum.z(); }
118 
119  TVector3 position;
120  TVector3 momentum;
121  double weight = 1;
122  };
123 
125  template <double (interpolation_data_t::*accessor)() const>
126  double average(const interpolation_data_t::list& hits)
127  {
128  // calculate all terms needed for the interpolation
129  // need to use double everywhere here due to numerical divergences
130  double sw = 0;
131  double swx = 0;
132 
133  bool valid(false);
134  for (const auto& hit : hits)
135  {
136  const double x = (hit.*accessor)();
137  if (std::isnan(x))
138  {
139  continue;
140  }
141 
142  const double w = hit.weight;
143  if (w <= 0)
144  {
145  continue;
146  }
147 
148  valid = true;
149  sw += w;
150  swx += w * x;
151  }
152 
153  if (!valid)
154  {
155  return NAN;
156  }
157  return swx / sw;
158  }
159 
161  std::vector<TrkrDefs::cluskey> get_cluster_keys(SvtxTrack* track)
162  {
163  std::vector<TrkrDefs::cluskey> out;
164  for (const auto& seed : {track->get_silicon_seed(), track->get_tpc_seed()})
165  {
166  if (seed)
167  {
168  std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out));
169  }
170  }
171 
172  return out;
173  }
174 
176  inline int is_primary(PHG4Particle* particle)
177  {
178  return particle->get_parent_id() == 0;
179  }
180 
182  int64_t get_mask(SvtxTrack* track)
183  {
184  const auto cluster_keys = get_cluster_keys(track);
185  return std::accumulate(cluster_keys.begin(), cluster_keys.end(), int64_t(0),
186  [](int64_t value, const TrkrDefs::cluskey& key)
187  {
188  return TrkrDefs::getLayer(key) < 64 ? value | (1LL << TrkrDefs::getLayer(key)) : value;
189  });
190  }
191 
193  template <int type>
194  int get_clusters(SvtxTrack* track)
195  {
196  const auto cluster_keys = get_cluster_keys(track);
197  return std::count_if(cluster_keys.begin(), cluster_keys.end(),
198  [](const TrkrDefs::cluskey& key)
199  { return TrkrDefs::getTrkrId(key) == type; });
200  }
201 
204  {
206 
207  trackStruct.charge = track->get_charge();
208  trackStruct.nclusters = track->size_cluster_keys();
209  trackStruct.mask = get_mask(track);
210  trackStruct.nclusters_mvtx = get_clusters<TrkrDefs::mvtxId>(track);
211  trackStruct.nclusters_intt = get_clusters<TrkrDefs::inttId>(track);
212  trackStruct.nclusters_tpc = get_clusters<TrkrDefs::tpcId>(track);
213  trackStruct.nclusters_micromegas = get_clusters<TrkrDefs::micromegasId>(track);
214 
215  trackStruct.chisquare = track->get_chisq();
216  trackStruct.ndf = track->get_ndf();
217 
218  trackStruct.x = track->get_x();
219  trackStruct.y = track->get_y();
220  trackStruct.z = track->get_z();
221  trackStruct.r = get_r(trackStruct.x, trackStruct.y);
222  trackStruct.phi = std::atan2(trackStruct.y, trackStruct.x);
223 
224  trackStruct.px = track->get_px();
225  trackStruct.py = track->get_py();
226  trackStruct.pz = track->get_pz();
227  trackStruct.pt = get_pt(trackStruct.px, trackStruct.py);
228  trackStruct.p = get_p(trackStruct.px, trackStruct.py, trackStruct.pz);
229  trackStruct.eta = get_eta(trackStruct.p, trackStruct.pz);
230 
231  return trackStruct;
232  }
233 
235  void add_cluster_size(TrackEvaluationContainerv1::ClusterStruct& cluster, TrkrCluster* trk_clus)
236  {
237  cluster.size = trk_clus->getSize();
238  cluster.phi_size = trk_clus->getPhiSize();
239  cluster.z_size = trk_clus->getZSize();
240  cluster.ovlp = trk_clus->getOverlap();
241  cluster.edge = trk_clus->getEdge();
242  cluster.adc = trk_clus->getAdc();
243  cluster.max_adc = trk_clus->getMaxAdc();
244  }
245 
247  void add_cluster_energy(TrackEvaluationContainerv1::ClusterStruct& cluster, TrkrDefs::cluskey clus_key,
248  TrkrClusterHitAssoc* cluster_hit_map,
249  TrkrHitSetContainer* hitsetcontainer)
250  {
251  // check container
252  if (!(cluster_hit_map && hitsetcontainer))
253  {
254  return;
255  }
256 
257  // for now this is only filled for micromegas
258  const auto detId = TrkrDefs::getTrkrId(clus_key);
259  if (detId != TrkrDefs::micromegasId)
260  {
261  return;
262  }
263 
264  const auto hitset_key = TrkrDefs::getHitSetKeyFromClusKey(clus_key);
265  const auto hitset = hitsetcontainer->findHitSet(hitset_key);
266  if (!hitset)
267  {
268  return;
269  }
270 
271  const auto range = cluster_hit_map->getHits(clus_key);
272  cluster.energy_max = 0;
273  cluster.energy_sum = 0;
274 
275  for (const auto& pair : range_adaptor(range))
276  {
277  const auto hit = hitset->getHit(pair.second);
278  if (hit)
279  {
280  const auto energy = hit->getEnergy();
281  cluster.energy_sum += energy;
282  if (energy > cluster.energy_max)
283  {
284  cluster.energy_max = energy;
285  }
286  }
287  }
288  }
289 
290  // ad}d truth information
291  void add_truth_information(TrackEvaluationContainerv1::TrackStruct& track, PHG4Particle* particle, PHG4TruthInfoContainer* truthinfo)
292  {
293  if (particle)
294  {
295  PHG4VtxPoint* vtx = truthinfo->GetVtx(particle->get_vtx_id());
296  track.is_primary = is_primary(particle);
297  track.pid = particle->get_pid();
298  track.gtrackID = particle->get_track_id();
299  track.truth_t = vtx->get_t();
300  track.truth_px = particle->get_px();
301  track.truth_py = particle->get_py();
302  track.truth_pz = particle->get_pz();
303  track.truth_pt = get_pt(track.truth_px, track.truth_py);
304  track.truth_p = get_p(track.truth_px, track.truth_py, track.truth_pz);
305  track.truth_eta = get_eta(track.truth_p, track.truth_pz);
306  }
307  }
308 
309  // calculate intersection between line and circle
310  double line_circle_intersection(const TVector3& p0, const TVector3& p1, double radius)
311  {
312  const double A = square(p1.x() - p0.x()) + square(p1.y() - p0.y());
313  const double B = 2 * p0.x() * (p1.x() - p0.x()) + 2 * p0.y() * (p1.y() - p0.y());
314  const double C = square(p0.x()) + square(p0.y()) - square(radius);
315  const double delta = square(B) - 4 * A * C;
316  if (delta < 0)
317  {
318  return -1;
319  }
320 
321  // check first intersection
322  const double tup = (-B + std::sqrt(delta)) / (2 * A);
323  if (tup >= 0 && tup < 1)
324  {
325  return tup;
326  }
327 
328  // check second intersection
329  const double tdn = (-B - sqrt(delta)) / (2 * A);
330  if (tdn >= 0 && tdn < 1)
331  {
332  return tdn;
333  }
334 
335  // no valid extrapolation
336  return -1;
337  }
338 
339  // print to stream
340  [[maybe_unused]] inline std::ostream& operator<<(std::ostream& out, const TrackEvaluationContainerv1::ClusterStruct& cluster)
341  {
342  out << "ClusterStruct" << std::endl;
343  out << " cluster: (" << cluster.x << "," << cluster.y << "," << cluster.z << ")" << std::endl;
344  out << " track: (" << cluster.trk_x << "," << cluster.trk_y << "," << cluster.trk_z << ")" << std::endl;
345  out << " truth: (" << cluster.truth_x << "," << cluster.truth_y << "," << cluster.truth_z << ")" << std::endl;
346  return out;
347  }
348 
349  [[maybe_unused]] inline std::ostream& operator<<(std::ostream& out, const TVector3& position)
350  {
351  out << "(" << position.x() << ", " << position.y() << ", " << position.z() << ")";
352  return out;
353  }
354 
355 } // namespace
356 
357 //_____________________________________________________________________
359  : SubsysReco(name)
360 {
361 }
362 
363 //_____________________________________________________________________
365 {
366  // find DST node
367  PHNodeIterator iter(topNode);
368  auto dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
369  if (!dstNode)
370  {
371  std::cout << "TrackEvaluation::Init - DST Node missing" << std::endl;
373  }
374 
375  // get EVAL node
376  iter = PHNodeIterator(dstNode);
377  auto evalNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "EVAL"));
378  if (!evalNode)
379  {
380  // create
381  std::cout << "TrackEvaluation::Init - EVAL node missing - creating" << std::endl;
382  evalNode = new PHCompositeNode("EVAL");
383  dstNode->addNode(evalNode);
384  }
385 
386  auto newNode = new PHIODataNode<PHObject>(new TrackEvaluationContainerv1, "TrackEvaluationContainer", "PHObject");
387  evalNode->addNode(newNode);
388 
390 }
391 
392 //_____________________________________________________________________
394 {
396 }
397 
398 //_____________________________________________________________________
400 {
401  // load nodes
402  auto res = load_nodes(topNode);
403  if (res != Fun4AllReturnCodes::EVENT_OK)
404  {
405  return res;
406  }
407 
408  // cleanup output container
409  std::cout << "start..." << std::endl;
410  if (m_container)
411  {
412  m_container->Reset();
413  }
414  std::cout << "event..." << std::endl;
415  if (m_flags & EvalEvent)
416  {
417  evaluate_event();
418  }
419  std::cout << "clusters..." << std::endl;
420  if (m_flags & EvalClusters)
421  {
423  }
424  std::cout << "tracks..." << std::endl;
425  if (m_flags & EvalTracks)
426  {
427  evaluate_tracks();
428  }
429  std::cout << "end..." << std::endl;
430  // clear maps
431  m_g4hit_map.clear();
433 }
434 
435 //_____________________________________________________________________
437 {
439 }
440 
441 //_____________________________________________________________________
443 {
444  // acts geometry
445  m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
447 
448  // get necessary nodes
449  m_track_map = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
450 
451  // cluster map
452  m_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "CORRECTED_TRKR_CLUSTER");
453  if (!m_cluster_map)
454  {
455  m_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
456  }
457 
458  // cluster hit association map
459  m_cluster_hit_map = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
460 
461  // cluster hit association map
462  m_hit_truth_map = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
463 
464  // local container
465  m_container = findNode::getClass<TrackEvaluationContainerv1>(topNode, "TrackEvaluationContainer");
466 
467  // hitset container
468  m_hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
469 
470  // g4hits
471  m_g4hits_tpc = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_TPC");
472  m_g4hits_intt = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_INTT");
473  m_g4hits_mvtx = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MVTX");
474  m_g4hits_micromegas = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MICROMEGAS");
475 
476  // g4 truth info
477  m_g4truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
478 
479  // tpc geometry
480  m_tpc_geom_container = findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
481  assert(m_tpc_geom_container);
482 
483  // micromegas geometry
484  m_micromegas_geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MICROMEGAS_FULL");
485 
487 }
488 
489 //_____________________________________________________________________
491 {
492  if (!m_container)
493  {
494  return;
495  }
496 
497  // create event struct
499  if (m_cluster_map)
500  {
501  for (const auto& hitsetkey : m_cluster_map->getHitSetKeys())
502  {
503  const auto trkrId = TrkrDefs::getTrkrId(hitsetkey);
504  const auto layer = TrkrDefs::getLayer(hitsetkey);
506 
507  // fill cluster related information
509  const int nclusters = std::distance(clusters.first, clusters.second);
510 
511  switch (trkrId)
512  {
513  case TrkrDefs::mvtxId:
514  event.nclusters_mvtx += nclusters;
515  break;
516  case TrkrDefs::inttId:
517  event.nclusters_intt += nclusters;
518  break;
519  case TrkrDefs::tpcId:
520  event.nclusters_tpc += nclusters;
521  break;
523  event.nclusters_micromegas += nclusters;
524  break;
525  }
526 
527  event.nclusters[layer] += nclusters;
528  }
529  }
530 
531  // store
532  m_container->addEvent(event);
533 }
534 
535 //_____________________________________________________________________
537 {
539  {
540  return;
541  }
542 
543  // clear array
545  SvtxTrack* track = nullptr;
546  // first loop over hitsets
547  for (const auto& hitsetkey : m_cluster_map->getHitSetKeys())
548  {
549  for (const auto& [key, cluster] : range_adaptor(m_cluster_map->getClusters(hitsetkey)))
550  {
551  // create cluster structure
552  auto cluster_struct = create_cluster(key, cluster, track);
553  add_cluster_size(cluster_struct, cluster);
554  add_cluster_energy(cluster_struct, key, m_cluster_hit_map, m_hitsetcontainer);
555 
556  // truth information
557  const auto g4hits = find_g4hits(key);
558  const bool is_micromegas(TrkrDefs::getTrkrId(key) == TrkrDefs::micromegasId);
559  if (is_micromegas)
560  {
561  const int tileid = MicromegasDefs::getTileId(key);
562  add_truth_information_micromegas(cluster_struct, tileid, g4hits);
563  }
564  else
565  {
566  add_truth_information(cluster_struct, g4hits);
567  }
568 
569  // add in array
570  m_container->addCluster(cluster_struct);
571  }
572  }
573 }
574 
575 //_____________________________________________________________________
577 {
579  {
580  return;
581  }
582 
583  // clear array
585  for (const auto& [track_id, track] : *m_track_map)
586  {
587  auto track_struct = create_track(track);
588 
589  // truth information
590  const auto [id, contributors] = get_max_contributor(track);
591  track_struct.contributors = contributors;
592 
593  // get particle
594  auto particle = m_g4truthinfo->GetParticle(id);
595  track_struct.embed = get_embed(particle);
596  ::add_truth_information(track_struct, particle, m_g4truthinfo);
597 
598  // running iterator over track states, used to match a given cluster to a track state
599  auto state_iter = track->begin_states();
600  // loop over clusters
601  for (const auto& cluster_key : get_cluster_keys(track))
602  {
603  auto cluster = m_cluster_map->findCluster(cluster_key);
604  if (!cluster)
605  {
606  std::cout << "TrackEvaluation::evaluate_tracks - unable to find cluster for key " << cluster_key << std::endl;
607  continue;
608  }
609  // create new cluster struct
610  auto cluster_struct = create_cluster(cluster_key, cluster, track);
611  add_cluster_size(cluster_struct, cluster);
612  add_cluster_energy(cluster_struct, cluster_key, m_cluster_hit_map, m_hitsetcontainer);
613  // truth information
614  const auto g4hits = find_g4hits(cluster_key);
615  const bool is_micromegas(TrkrDefs::getTrkrId(cluster_key) == TrkrDefs::micromegasId);
616  if (is_micromegas)
617  {
618  const int tileid = MicromegasDefs::getTileId(cluster_key);
619  add_truth_information_micromegas(cluster_struct, tileid, g4hits);
620  }
621  else
622  {
623  add_truth_information(cluster_struct, g4hits);
624  }
625 
626  // find track state that is the closest to cluster
627  /* this assumes that both clusters and states are sorted along r */
628  const auto radius(cluster_struct.r);
629  float dr_min = -1;
630  for (auto iter = state_iter; iter != track->end_states(); ++iter)
631  {
632  const auto dr = std::abs(radius - get_r(iter->second->get_x(), iter->second->get_y()));
633  if (dr_min < 0 || dr < dr_min)
634  {
635  state_iter = iter;
636  dr_min = dr;
637  }
638  else
639  {
640  break;
641  }
642  }
643 
644  // store track state in cluster struct
645  if (is_micromegas)
646  {
647  const int tileid = MicromegasDefs::getTileId(cluster_key);
648  add_trk_information_micromegas(cluster_struct, tileid, state_iter->second);
649  }
650  else
651  {
652  add_trk_information(cluster_struct, state_iter->second);
653  }
654 
655  // add to track
656  track_struct.clusters.push_back(cluster_struct);
657  }
658  m_container->addTrack(track_struct);
659  }
660 }
661 
662 //_____________________________________________________________________
664 {
665  // check maps
667  {
668  return G4HitSet();
669  }
670 
671  // check if in map
672  auto map_iter = m_g4hit_map.lower_bound(cluster_key);
673  if (map_iter != m_g4hit_map.end() && cluster_key == map_iter->first)
674  {
675  return map_iter->second;
676  }
677 
678  // find hitset associated to cluster
679  G4HitSet out;
680  const auto hitset_key = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
681  for (const auto& [first, hit_key] : range_adaptor(m_cluster_hit_map->getHits(cluster_key)))
682  {
683  // store hits to g4hit associations
684  TrkrHitTruthAssoc::MMap g4hit_map;
685  m_hit_truth_map->getG4Hits(hitset_key, hit_key, g4hit_map);
686 
687  // find corresponding g4 hist
688  for (auto& truth_iter : g4hit_map)
689  {
690  const auto g4hit_key = truth_iter.second.second;
691  PHG4Hit* g4hit = nullptr;
692 
693  switch (TrkrDefs::getTrkrId(hitset_key))
694  {
695  case TrkrDefs::mvtxId:
696  if (m_g4hits_mvtx)
697  {
698  g4hit = m_g4hits_mvtx->findHit(g4hit_key);
699  }
700  break;
701 
702  case TrkrDefs::inttId:
703  if (m_g4hits_intt)
704  {
705  g4hit = m_g4hits_intt->findHit(g4hit_key);
706  }
707  break;
708 
709  case TrkrDefs::tpcId:
710  if (m_g4hits_tpc)
711  {
712  g4hit = m_g4hits_tpc->findHit(g4hit_key);
713  }
714  break;
715 
718  {
719  g4hit = m_g4hits_micromegas->findHit(g4hit_key);
720  }
721  break;
722 
723  default:
724  break;
725  }
726 
727  if (g4hit)
728  {
729  out.insert(g4hit);
730  }
731  else
732  {
733  std::cout << "TrackEvaluation::find_g4hits - g4hit not found " << g4hit_key << std::endl;
734  }
735  }
736  }
737 
738  // insert in map and return
739  return m_g4hit_map.insert(map_iter, std::make_pair(cluster_key, std::move(out)))->second;
740 }
741 
742 //_____________________________________________________________________
743 std::pair<int, int> TrackEvaluation::get_max_contributor(SvtxTrack* track) const
744 {
746  {
747  return {0, 0};
748  }
749 
750  // maps MC track id and number of matching g4hits
751  using IdMap = std::map<int, int>;
752  IdMap contributor_map;
753 
754  // loop over clusters
755  for (const auto& cluster_key : get_cluster_keys(track))
756  {
757  for (const auto& hit : find_g4hits(cluster_key))
758  {
759  const int trkid = hit->get_trkid();
760  auto iter = contributor_map.lower_bound(trkid);
761  if (iter == contributor_map.end() || iter->first != trkid)
762  {
763  contributor_map.insert(iter, std::make_pair(trkid, 1));
764  }
765  else
766  {
767  ++iter->second;
768  }
769  }
770  }
771 
772  if (contributor_map.empty())
773  {
774  return {0, 0};
775  }
776  else
777  {
778  return *std::max_element(
779  contributor_map.cbegin(), contributor_map.cend(),
780  [](const IdMap::value_type& first, const IdMap::value_type& second)
781  { return first.second < second.second; });
782  }
783 }
784 
785 //_____________________________________________________________________
787 {
788  return (m_g4truthinfo && particle) ? m_g4truthinfo->isEmbeded(particle->get_primary_id()) : 0;
789 }
790 
791 //_____________________________________________________________________
793 {
794  TrackSeed* si_seed = nullptr;
795  TrackSeed* tpc_seed = nullptr;
796  if (track != nullptr)
797  {
798  si_seed = track->get_silicon_seed();
799  tpc_seed = track->get_tpc_seed();
800  }
801  // get global coordinates
802  Acts::Vector3 global;
803  global = m_tGeometry->getGlobalPosition(key, cluster);
805  cluster_struct.layer = TrkrDefs::getLayer(key);
806  cluster_struct.x = global.x();
807  cluster_struct.y = global.y();
808  cluster_struct.z = global.z();
809  cluster_struct.r = get_r(cluster_struct.x, cluster_struct.y);
810  cluster_struct.phi = std::atan2(cluster_struct.y, cluster_struct.x);
811  cluster_struct.phi_error = 0.0;
812  cluster_struct.z_error = 0.0;
813  cluster_struct.trk_alpha = 0.0;
814  cluster_struct.trk_beta = 0.0;
815 
816  ClusterErrorPara ClusErrPara;
817 
818  if (track != nullptr)
819  {
820  float r = cluster_struct.r;
821 
822  if (cluster_struct.layer >= 7)
823  {
824  auto para_errors_mm = ClusErrPara.get_clusterv5_modified_error(cluster, r, key);
825 
826  cluster_struct.phi_error = cluster->getRPhiError() / cluster_struct.r;
827  cluster_struct.z_error = cluster->getZError();
828  cluster_struct.para_phi_error = sqrt(para_errors_mm.first) / cluster_struct.r;
829  cluster_struct.para_z_error = sqrt(para_errors_mm.second);
830  // float R = TMath::Abs(1.0/tpc_seed->get_qOverR());
831  cluster_struct.trk_radius = 1.0 / tpc_seed->get_qOverR();
832  cluster_struct.trk_alpha = (r * r) / (2 * r * TMath::Abs(1.0 / tpc_seed->get_qOverR()));
833  cluster_struct.trk_beta = atan(tpc_seed->get_slope());
834  }
835  else
836  {
837  auto para_errors_mvtx = ClusErrPara.get_cluster_error(cluster, r, key, si_seed->get_qOverR(), si_seed->get_slope());
838  cluster_struct.phi_error = sqrt(para_errors_mvtx.first) / cluster_struct.r;
839  cluster_struct.z_error = sqrt(para_errors_mvtx.second);
840  // float R = TMath::Abs(1.0/si_seed->get_qOverR());
841  cluster_struct.trk_radius = 1.0 / tpc_seed->get_qOverR();
842  cluster_struct.trk_alpha = (r * r) / (2 * r * TMath::Abs(1.0 / tpc_seed->get_qOverR()));
843  cluster_struct.trk_beta = atan(si_seed->get_slope());
844  }
845  }
846 
847  return cluster_struct;
848 }
849 
850 //_____________________________________________________________________
852 {
853  // need to extrapolate to the right r
854  const auto trk_r = get_r(state->get_x(), state->get_y());
855  const auto dr = cluster.r - trk_r;
856  const auto trk_drdt = (state->get_x() * state->get_px() + state->get_y() * state->get_py()) / trk_r;
857  const auto trk_dxdr = state->get_px() / trk_drdt;
858  const auto trk_dydr = state->get_py() / trk_drdt;
859  const auto trk_dzdr = state->get_pz() / trk_drdt;
860 
861  // store state position
862  cluster.trk_x = state->get_x() + dr * trk_dxdr;
863  cluster.trk_y = state->get_y() + dr * trk_dydr;
864  cluster.trk_z = state->get_z() + dr * trk_dzdr;
865  cluster.trk_r = get_r(cluster.trk_x, cluster.trk_y);
866  cluster.trk_phi = std::atan2(cluster.trk_y, cluster.trk_x);
867 
868  /* store local momentum information */
869  cluster.trk_px = state->get_px();
870  cluster.trk_py = state->get_py();
871  cluster.trk_pz = state->get_pz();
872 
873  /*
874  store state angles in (r,phi) and (r,z) plans
875  they are needed to study space charge distortions
876  */
877  const auto cosphi(std::cos(cluster.trk_phi));
878  const auto sinphi(std::sin(cluster.trk_phi));
879  const auto trk_pphi = -state->get_px() * sinphi + state->get_py() * cosphi;
880  const auto trk_pr = state->get_px() * cosphi + state->get_py() * sinphi;
881  const auto trk_pz = state->get_pz();
882  cluster.trk_alpha = std::atan2(trk_pphi, trk_pr);
883  cluster.trk_beta = std::atan2(trk_pz, trk_pr);
884  cluster.trk_phi_error = state->get_phi_error();
885  cluster.trk_z_error = state->get_z_error();
886 }
887 
888 //_____________________________________________________________________
890 {
891  // get geometry cylinder from layer
892  const auto layer = cluster.layer;
893  const auto layergeom = dynamic_cast<CylinderGeomMicromegas*>(m_micromegas_geom_container->GetLayerGeom(layer));
894  assert(layergeom);
895 
896  // convert cluster position to local tile coordinates
897  const TVector3 cluster_world(cluster.x, cluster.y, cluster.z);
898  const auto cluster_local = layergeom->get_local_from_world_coords(tileid, m_tGeometry, cluster_world);
899 
900  // convert track position to local tile coordinates
901  TVector3 track_world(state->get_x(), state->get_y(), state->get_z());
902  TVector3 track_local = layergeom->get_local_from_world_coords(tileid, m_tGeometry, track_world);
903 
904  // convert direction to local tile coordinates
905  const TVector3 direction_world(state->get_px(), state->get_py(), state->get_pz());
906  const TVector3 direction_local = layergeom->get_local_from_world_vect(tileid, m_tGeometry, direction_world);
907 
908  // extrapolate to same local z (should be zero) as cluster
909  const auto delta_z = cluster_local.z() - track_local.z();
910  track_local += TVector3(
911  delta_z * direction_local.x() / direction_local.z(),
912  delta_z * direction_local.y() / direction_local.z(),
913  delta_z);
914 
915  // convert back to global coordinates
916  track_world = layergeom->get_world_from_local_coords(tileid, m_tGeometry, track_local);
917 
918  // store state position
919  cluster.trk_x = track_world.x();
920  cluster.trk_y = track_world.y();
921  cluster.trk_z = track_world.z();
922  cluster.trk_r = get_r(cluster.trk_x, cluster.trk_y);
923  cluster.trk_phi = std::atan2(cluster.trk_y, cluster.trk_x);
924 
925  /* store local momentum information */
926  cluster.trk_px = state->get_px();
927  cluster.trk_py = state->get_py();
928  cluster.trk_pz = state->get_pz();
929 
930  /*
931  store state angles in (r,phi) and (r,z) plans
932  they are needed to study space charge distortions
933  */
934  const auto cosphi(std::cos(cluster.trk_phi));
935  const auto sinphi(std::sin(cluster.trk_phi));
936  const auto trk_pphi = -state->get_px() * sinphi + state->get_py() * cosphi;
937  const auto trk_pr = state->get_px() * cosphi + state->get_py() * sinphi;
938  const auto trk_pz = state->get_pz();
939  cluster.trk_alpha = std::atan2(trk_pphi, trk_pr);
940  cluster.trk_beta = std::atan2(trk_pz, trk_pr);
941  cluster.trk_phi_error = state->get_phi_error();
942  cluster.trk_z_error = state->get_z_error();
943 }
944 
945 //_____________________________________________________________________
946 void TrackEvaluation::add_truth_information(TrackEvaluationContainerv1::ClusterStruct& cluster, const std::set<PHG4Hit*>& g4hits) const
947 {
948  // store number of contributing g4hits
949  cluster.truth_size = g4hits.size();
950 
951  // get layer, tpc flag and corresponding layer geometry
952  const auto layer = cluster.layer;
953  const bool is_tpc(layer >= 7 && layer < 55);
954  const PHG4TpcCylinderGeom* layergeom = is_tpc ? m_tpc_geom_container->GetLayerCellGeom(layer) : nullptr;
955  const auto rin = layergeom ? layergeom->get_radius() - layergeom->get_thickness() / 2 : 0;
956  const auto rout = layergeom ? layergeom->get_radius() + layergeom->get_thickness() / 2 : 0;
957 
958  // convert hits to list of interpolation_data_t
959  interpolation_data_t::list hits;
960  for (const auto& g4hit : g4hits)
961  {
962  interpolation_data_t::list tmp_hits;
963  const auto weight = g4hit->get_edep();
964  for (int i = 0; i < 2; ++i)
965  {
966  const TVector3 g4hit_world(g4hit->get_x(i), g4hit->get_y(i), g4hit->get_z(i));
967  const TVector3 momentum_world(g4hit->get_px(i), g4hit->get_py(i), g4hit->get_pz(i));
968  tmp_hits.push_back({.position = g4hit_world, .momentum = momentum_world, .weight = weight});
969  }
970 
971  if (is_tpc)
972  {
973  // add layer boundary checks
974  // ensure first hit has lowest r
975  auto r0 = get_r(tmp_hits[0].x(), tmp_hits[0].y());
976  auto r1 = get_r(tmp_hits[1].x(), tmp_hits[1].y());
977  if (r0 > r1)
978  {
979  std::swap(tmp_hits[0], tmp_hits[1]);
980  std::swap(r0, r1);
981  }
982 
983  // do nothing if out of bound
984  if (r1 <= rin || r0 >= rout)
985  {
986  continue;
987  }
988 
989  // keep track of original deltar
990  const auto dr_old = r1 - r0;
991 
992  // clamp r0 to rin
993  if (r0 < rin)
994  {
995  const auto t = line_circle_intersection(tmp_hits[0].position, tmp_hits[1].position, rin);
996  if (t < 0)
997  {
998  continue;
999  }
1000 
1001  tmp_hits[0].position = tmp_hits[0].position * (1. - t) + tmp_hits[1].position * t;
1002  tmp_hits[0].momentum = tmp_hits[0].momentum * (1. - t) + tmp_hits[1].momentum * t;
1003  r0 = rin;
1004  }
1005 
1006  if (r1 > rout)
1007  {
1008  const auto t = line_circle_intersection(tmp_hits[0].position, tmp_hits[1].position, rout);
1009  if (t < 0)
1010  {
1011  continue;
1012  }
1013 
1014  tmp_hits[1].position = tmp_hits[0].position * (1. - t) + tmp_hits[1].position * t;
1015  tmp_hits[1].momentum = tmp_hits[0].momentum * (1. - t) + tmp_hits[1].momentum * t;
1016  r1 = rout;
1017  }
1018 
1019  // update weights, only if clamping occured
1020  const auto dr_new = r1 - r0;
1021  tmp_hits[0].weight *= dr_new / dr_old;
1022  tmp_hits[1].weight *= dr_new / dr_old;
1023  }
1024 
1025  // store in global list
1026  hits.push_back(std::move(tmp_hits[0]));
1027  hits.push_back(std::move(tmp_hits[1]));
1028  }
1029 
1030  // add truth position
1031  cluster.truth_x = average<&interpolation_data_t::x>(hits);
1032  cluster.truth_y = average<&interpolation_data_t::y>(hits);
1033  cluster.truth_z = average<&interpolation_data_t::z>(hits);
1034 
1035  // add truth momentum information
1036  cluster.truth_px = average<&interpolation_data_t::px>(hits);
1037  cluster.truth_py = average<&interpolation_data_t::py>(hits);
1038  cluster.truth_pz = average<&interpolation_data_t::pz>(hits);
1039 
1040  cluster.truth_r = get_r(cluster.truth_x, cluster.truth_y);
1041  cluster.truth_phi = std::atan2(cluster.truth_y, cluster.truth_x);
1042 
1043  /*
1044  store state angles in (r,phi) and (r,z) plans
1045  they are needed to study space charge distortions
1046  */
1047  const auto cosphi(std::cos(cluster.truth_phi));
1048  const auto sinphi(std::sin(cluster.truth_phi));
1049  const auto truth_pphi = -cluster.truth_px * sinphi + cluster.truth_py * cosphi;
1050  const auto truth_pr = cluster.truth_px * cosphi + cluster.truth_py * sinphi;
1051 
1052  cluster.truth_alpha = std::atan2(truth_pphi, truth_pr);
1053  cluster.truth_beta = std::atan2(cluster.truth_pz, truth_pr);
1054 }
1055 
1056 //_____________________________________________________________________
1057 void TrackEvaluation::add_truth_information_micromegas(TrackEvaluationContainerv1::ClusterStruct& cluster, int tileid, const std::set<PHG4Hit*>& g4hits) const
1058 {
1059  // store number of contributing g4hits
1060  cluster.truth_size = g4hits.size();
1061 
1062  const auto layer = cluster.layer;
1063  const auto layergeom = dynamic_cast<CylinderGeomMicromegas*>(m_micromegas_geom_container->GetLayerGeom(layer));
1064  assert(layergeom);
1065 
1066  // convert cluster position to local tile coordinates
1067  const TVector3 cluster_world(cluster.x, cluster.y, cluster.z);
1068  const auto cluster_local = layergeom->get_local_from_world_coords(tileid, m_tGeometry, cluster_world);
1069 
1070  // convert hits to list of interpolation_data_t
1071  interpolation_data_t::list hits;
1072  for (const auto& g4hit : g4hits)
1073  {
1074  const auto weight = g4hit->get_edep();
1075  for (int i = 0; i < 2; ++i)
1076  {
1077  // convert position to local
1078  TVector3 g4hit_world(g4hit->get_x(i), g4hit->get_y(i), g4hit->get_z(i));
1079  auto g4hit_local = layergeom->get_local_from_world_coords(tileid, m_tGeometry, g4hit_world);
1080 
1081  // convert momentum to local
1082  TVector3 momentum_world(g4hit->get_px(i), g4hit->get_py(i), g4hit->get_pz(i));
1083  TVector3 momentum_local = layergeom->get_local_from_world_vect(tileid, m_tGeometry, momentum_world);
1084 
1085  hits.push_back({.position = g4hit_local, .momentum = momentum_local, .weight = weight});
1086  }
1087  }
1088 
1089  // do position interpolation
1090  const TVector3 interpolation_local(
1091  average<&interpolation_data_t::x>(hits),
1092  average<&interpolation_data_t::y>(hits),
1093  average<&interpolation_data_t::z>(hits));
1094 
1095  // convert back to global
1096  const TVector3 interpolation_world = layergeom->get_world_from_local_coords(tileid, m_tGeometry, interpolation_local);
1097 
1098  // do momentum interpolation
1099  const TVector3 momentum_local(
1100  average<&interpolation_data_t::px>(hits),
1101  average<&interpolation_data_t::py>(hits),
1102  average<&interpolation_data_t::pz>(hits));
1103 
1104  // convert back to global
1105  const TVector3 momentum_world = layergeom->get_world_from_local_vect(tileid, m_tGeometry, momentum_local);
1106 
1107  cluster.truth_x = interpolation_world.x();
1108  cluster.truth_y = interpolation_world.y();
1109  cluster.truth_z = interpolation_world.z();
1110  cluster.truth_r = get_r(cluster.truth_x, cluster.truth_y);
1111  cluster.truth_phi = std::atan2(cluster.truth_y, cluster.truth_x);
1112 
1113  /* add truth momentum information */
1114  cluster.truth_px = momentum_world.x();
1115  cluster.truth_py = momentum_world.y();
1116  cluster.truth_pz = momentum_world.z();
1117 
1118  /*
1119  store state angles in (r,phi) and (r,z) plans
1120  they are needed to study space charge distortions
1121  */
1122  const auto cosphi(std::cos(cluster.truth_phi));
1123  const auto sinphi(std::sin(cluster.truth_phi));
1124  const auto truth_pphi = -cluster.truth_px * sinphi + cluster.truth_py * cosphi;
1125  const auto truth_pr = cluster.truth_px * cosphi + cluster.truth_py * sinphi;
1126 
1127  cluster.truth_alpha = std::atan2(truth_pphi, truth_pr);
1128  cluster.truth_beta = std::atan2(cluster.truth_pz, truth_pr);
1129 }