File indexing completed on 2025-08-06 08:19:13
0001
0002
0003
0004
0005
0006 #include "TrackEvaluation.h"
0007
0008 #include <g4detectors/PHG4CylinderGeomContainer.h>
0009 #include <g4detectors/PHG4TpcCylinderGeom.h>
0010 #include <g4detectors/PHG4TpcCylinderGeomContainer.h>
0011
0012 #include <g4main/PHG4Hit.h>
0013 #include <g4main/PHG4HitContainer.h>
0014 #include <g4main/PHG4Hitv1.h>
0015 #include <g4main/PHG4Particle.h>
0016 #include <g4main/PHG4TruthInfoContainer.h>
0017 #include <g4main/PHG4VtxPoint.h>
0018
0019 #include <micromegas/CylinderGeomMicromegas.h>
0020 #include <micromegas/MicromegasDefs.h>
0021
0022 #include <trackbase/ActsGeometry.h>
0023 #include <trackbase/ClusterErrorPara.h>
0024 #include <trackbase/InttDefs.h>
0025 #include <trackbase/MvtxDefs.h>
0026 #include <trackbase/TpcDefs.h>
0027 #include <trackbase/TrkrCluster.h>
0028 #include <trackbase/TrkrClusterContainer.h>
0029 #include <trackbase/TrkrClusterHitAssoc.h>
0030 #include <trackbase/TrkrDefs.h>
0031 #include <trackbase/TrkrHit.h>
0032 #include <trackbase/TrkrHitSet.h>
0033 #include <trackbase/TrkrHitSetContainer.h>
0034 #include <trackbase/TrkrHitTruthAssoc.h>
0035 #include <trackbase_historic/SvtxTrack.h>
0036 #include <trackbase_historic/SvtxTrackMap.h>
0037
0038 #include <fun4all/Fun4AllReturnCodes.h>
0039
0040 #include <phool/PHCompositeNode.h>
0041 #include <phool/PHNodeIterator.h>
0042 #include <phool/getClass.h>
0043
0044 #include <TVector3.h>
0045
0046 #include <algorithm>
0047 #include <bitset>
0048 #include <cassert>
0049 #include <iostream>
0050 #include <numeric>
0051
0052
0053 namespace
0054 {
0055
0056
0057 template <class T>
0058 class range_adaptor
0059 {
0060 public:
0061 explicit range_adaptor(const T& range)
0062 : m_range(range)
0063 {
0064 }
0065 inline const typename T::first_type& begin() { return m_range.first; }
0066 inline const typename T::second_type& end() { return m_range.second; }
0067
0068 private:
0069 T m_range;
0070 };
0071
0072
0073 template <class T>
0074 inline constexpr T square(const T& x)
0075 {
0076 return x * x;
0077 }
0078
0079
0080 template <class T>
0081 inline constexpr T get_r(T x, T y)
0082 {
0083 return std::sqrt(square(x) + square(y));
0084 }
0085
0086
0087 template <class T>
0088 T get_pt(T px, T py)
0089 {
0090 return std::sqrt(square(px) + square(py));
0091 }
0092
0093
0094 template <class T>
0095 T get_p(T px, T py, T pz)
0096 {
0097 return std::sqrt(square(px) + square(py) + square(pz));
0098 }
0099
0100
0101 template <class T>
0102 T get_eta(T p, T pz)
0103 {
0104 return std::log((p + pz) / (p - pz)) / 2;
0105 }
0106
0107
0108 struct interpolation_data_t
0109 {
0110 using list = std::vector<interpolation_data_t>;
0111 double x() const { return position.x(); }
0112 double y() const { return position.y(); }
0113 double z() const { return position.z(); }
0114
0115 double px() const { return momentum.x(); }
0116 double py() const { return momentum.y(); }
0117 double pz() const { return momentum.z(); }
0118
0119 TVector3 position;
0120 TVector3 momentum;
0121 double weight = 1;
0122 };
0123
0124
0125 template <double (interpolation_data_t::*accessor)() const>
0126 double average(const interpolation_data_t::list& hits)
0127 {
0128
0129
0130 double sw = 0;
0131 double swx = 0;
0132
0133 bool valid(false);
0134 for (const auto& hit : hits)
0135 {
0136 const double x = (hit.*accessor)();
0137 if (std::isnan(x))
0138 {
0139 continue;
0140 }
0141
0142 const double w = hit.weight;
0143 if (w <= 0)
0144 {
0145 continue;
0146 }
0147
0148 valid = true;
0149 sw += w;
0150 swx += w * x;
0151 }
0152
0153 if (!valid)
0154 {
0155 return NAN;
0156 }
0157 return swx / sw;
0158 }
0159
0160
0161 std::vector<TrkrDefs::cluskey> get_cluster_keys(SvtxTrack* track)
0162 {
0163 std::vector<TrkrDefs::cluskey> out;
0164 for (const auto& seed : {track->get_silicon_seed(), track->get_tpc_seed()})
0165 {
0166 if (seed)
0167 {
0168 std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out));
0169 }
0170 }
0171
0172 return out;
0173 }
0174
0175
0176 inline int is_primary(PHG4Particle* particle)
0177 {
0178 return particle->get_parent_id() == 0;
0179 }
0180
0181
0182 int64_t get_mask(SvtxTrack* track)
0183 {
0184 const auto cluster_keys = get_cluster_keys(track);
0185 return std::accumulate(cluster_keys.begin(), cluster_keys.end(), int64_t(0),
0186 [](int64_t value, const TrkrDefs::cluskey& key)
0187 {
0188 return TrkrDefs::getLayer(key) < 64 ? value | (1LL << TrkrDefs::getLayer(key)) : value;
0189 });
0190 }
0191
0192
0193 template <int type>
0194 int get_clusters(SvtxTrack* track)
0195 {
0196 const auto cluster_keys = get_cluster_keys(track);
0197 return std::count_if(cluster_keys.begin(), cluster_keys.end(),
0198 [](const TrkrDefs::cluskey& key)
0199 { return TrkrDefs::getTrkrId(key) == type; });
0200 }
0201
0202
0203 TrackEvaluationContainerv1::TrackStruct create_track(SvtxTrack* track)
0204 {
0205 TrackEvaluationContainerv1::TrackStruct trackStruct;
0206
0207 trackStruct.charge = track->get_charge();
0208 trackStruct.nclusters = track->size_cluster_keys();
0209 trackStruct.mask = get_mask(track);
0210 trackStruct.nclusters_mvtx = get_clusters<TrkrDefs::mvtxId>(track);
0211 trackStruct.nclusters_intt = get_clusters<TrkrDefs::inttId>(track);
0212 trackStruct.nclusters_tpc = get_clusters<TrkrDefs::tpcId>(track);
0213 trackStruct.nclusters_micromegas = get_clusters<TrkrDefs::micromegasId>(track);
0214
0215 trackStruct.chisquare = track->get_chisq();
0216 trackStruct.ndf = track->get_ndf();
0217
0218 trackStruct.x = track->get_x();
0219 trackStruct.y = track->get_y();
0220 trackStruct.z = track->get_z();
0221 trackStruct.r = get_r(trackStruct.x, trackStruct.y);
0222 trackStruct.phi = std::atan2(trackStruct.y, trackStruct.x);
0223
0224 trackStruct.px = track->get_px();
0225 trackStruct.py = track->get_py();
0226 trackStruct.pz = track->get_pz();
0227 trackStruct.pt = get_pt(trackStruct.px, trackStruct.py);
0228 trackStruct.p = get_p(trackStruct.px, trackStruct.py, trackStruct.pz);
0229 trackStruct.eta = get_eta(trackStruct.p, trackStruct.pz);
0230
0231 return trackStruct;
0232 }
0233
0234
0235 void add_cluster_size(TrackEvaluationContainerv1::ClusterStruct& cluster, TrkrCluster* trk_clus)
0236 {
0237 cluster.size = trk_clus->getSize();
0238 cluster.phi_size = trk_clus->getPhiSize();
0239 cluster.z_size = trk_clus->getZSize();
0240 cluster.ovlp = trk_clus->getOverlap();
0241 cluster.edge = trk_clus->getEdge();
0242 cluster.adc = trk_clus->getAdc();
0243 cluster.max_adc = trk_clus->getMaxAdc();
0244 }
0245
0246
0247 void add_cluster_energy(TrackEvaluationContainerv1::ClusterStruct& cluster, TrkrDefs::cluskey clus_key,
0248 TrkrClusterHitAssoc* cluster_hit_map,
0249 TrkrHitSetContainer* hitsetcontainer)
0250 {
0251
0252 if (!(cluster_hit_map && hitsetcontainer))
0253 {
0254 return;
0255 }
0256
0257
0258 const auto detId = TrkrDefs::getTrkrId(clus_key);
0259 if (detId != TrkrDefs::micromegasId)
0260 {
0261 return;
0262 }
0263
0264 const auto hitset_key = TrkrDefs::getHitSetKeyFromClusKey(clus_key);
0265 const auto hitset = hitsetcontainer->findHitSet(hitset_key);
0266 if (!hitset)
0267 {
0268 return;
0269 }
0270
0271 const auto range = cluster_hit_map->getHits(clus_key);
0272 cluster.energy_max = 0;
0273 cluster.energy_sum = 0;
0274
0275 for (const auto& pair : range_adaptor(range))
0276 {
0277 const auto hit = hitset->getHit(pair.second);
0278 if (hit)
0279 {
0280 const auto energy = hit->getEnergy();
0281 cluster.energy_sum += energy;
0282 if (energy > cluster.energy_max)
0283 {
0284 cluster.energy_max = energy;
0285 }
0286 }
0287 }
0288 }
0289
0290
0291 void add_truth_information(TrackEvaluationContainerv1::TrackStruct& track, PHG4Particle* particle, PHG4TruthInfoContainer* truthinfo)
0292 {
0293 if (particle)
0294 {
0295 PHG4VtxPoint* vtx = truthinfo->GetVtx(particle->get_vtx_id());
0296 track.is_primary = is_primary(particle);
0297 track.pid = particle->get_pid();
0298 track.gtrackID = particle->get_track_id();
0299 track.truth_t = vtx->get_t();
0300 track.truth_px = particle->get_px();
0301 track.truth_py = particle->get_py();
0302 track.truth_pz = particle->get_pz();
0303 track.truth_pt = get_pt(track.truth_px, track.truth_py);
0304 track.truth_p = get_p(track.truth_px, track.truth_py, track.truth_pz);
0305 track.truth_eta = get_eta(track.truth_p, track.truth_pz);
0306 }
0307 }
0308
0309
0310 double line_circle_intersection(const TVector3& p0, const TVector3& p1, double radius)
0311 {
0312 const double A = square(p1.x() - p0.x()) + square(p1.y() - p0.y());
0313 const double B = 2 * p0.x() * (p1.x() - p0.x()) + 2 * p0.y() * (p1.y() - p0.y());
0314 const double C = square(p0.x()) + square(p0.y()) - square(radius);
0315 const double delta = square(B) - 4 * A * C;
0316 if (delta < 0)
0317 {
0318 return -1;
0319 }
0320
0321
0322 const double tup = (-B + std::sqrt(delta)) / (2 * A);
0323 if (tup >= 0 && tup < 1)
0324 {
0325 return tup;
0326 }
0327
0328
0329 const double tdn = (-B - sqrt(delta)) / (2 * A);
0330 if (tdn >= 0 && tdn < 1)
0331 {
0332 return tdn;
0333 }
0334
0335
0336 return -1;
0337 }
0338
0339
0340 [[maybe_unused]] inline std::ostream& operator<<(std::ostream& out, const TrackEvaluationContainerv1::ClusterStruct& cluster)
0341 {
0342 out << "ClusterStruct" << std::endl;
0343 out << " cluster: (" << cluster.x << "," << cluster.y << "," << cluster.z << ")" << std::endl;
0344 out << " track: (" << cluster.trk_x << "," << cluster.trk_y << "," << cluster.trk_z << ")" << std::endl;
0345 out << " truth: (" << cluster.truth_x << "," << cluster.truth_y << "," << cluster.truth_z << ")" << std::endl;
0346 return out;
0347 }
0348
0349 [[maybe_unused]] inline std::ostream& operator<<(std::ostream& out, const TVector3& position)
0350 {
0351 out << "(" << position.x() << ", " << position.y() << ", " << position.z() << ")";
0352 return out;
0353 }
0354
0355 }
0356
0357
0358 TrackEvaluation::TrackEvaluation(const std::string& name)
0359 : SubsysReco(name)
0360 {
0361 }
0362
0363
0364 int TrackEvaluation::Init(PHCompositeNode* topNode)
0365 {
0366
0367 PHNodeIterator iter(topNode);
0368 auto dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
0369 if (!dstNode)
0370 {
0371 std::cout << "TrackEvaluation::Init - DST Node missing" << std::endl;
0372 return Fun4AllReturnCodes::ABORTEVENT;
0373 }
0374
0375
0376 iter = PHNodeIterator(dstNode);
0377 auto evalNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "EVAL"));
0378 if (!evalNode)
0379 {
0380
0381 std::cout << "TrackEvaluation::Init - EVAL node missing - creating" << std::endl;
0382 evalNode = new PHCompositeNode("EVAL");
0383 dstNode->addNode(evalNode);
0384 }
0385
0386 auto newNode = new PHIODataNode<PHObject>(new TrackEvaluationContainerv1, "TrackEvaluationContainer", "PHObject");
0387 evalNode->addNode(newNode);
0388
0389 return Fun4AllReturnCodes::EVENT_OK;
0390 }
0391
0392
0393 int TrackEvaluation::InitRun(PHCompositeNode* )
0394 {
0395 return Fun4AllReturnCodes::EVENT_OK;
0396 }
0397
0398
0399 int TrackEvaluation::process_event(PHCompositeNode* topNode)
0400 {
0401
0402 auto res = load_nodes(topNode);
0403 if (res != Fun4AllReturnCodes::EVENT_OK)
0404 {
0405 return res;
0406 }
0407
0408
0409 std::cout << "start..." << std::endl;
0410 if (m_container)
0411 {
0412 m_container->Reset();
0413 }
0414 std::cout << "event..." << std::endl;
0415 if (m_flags & EvalEvent)
0416 {
0417 evaluate_event();
0418 }
0419 std::cout << "clusters..." << std::endl;
0420 if (m_flags & EvalClusters)
0421 {
0422 evaluate_clusters();
0423 }
0424 std::cout << "tracks..." << std::endl;
0425 if (m_flags & EvalTracks)
0426 {
0427 evaluate_tracks();
0428 }
0429 std::cout << "end..." << std::endl;
0430
0431 m_g4hit_map.clear();
0432 return Fun4AllReturnCodes::EVENT_OK;
0433 }
0434
0435
0436 int TrackEvaluation::End(PHCompositeNode* )
0437 {
0438 return Fun4AllReturnCodes::EVENT_OK;
0439 }
0440
0441
0442 int TrackEvaluation::load_nodes(PHCompositeNode* topNode)
0443 {
0444
0445 m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0446 assert(m_tGeometry);
0447
0448
0449 m_track_map = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
0450
0451
0452 m_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "CORRECTED_TRKR_CLUSTER");
0453 if (!m_cluster_map)
0454 {
0455 m_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0456 }
0457
0458
0459 m_cluster_hit_map = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
0460
0461
0462 m_hit_truth_map = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
0463
0464
0465 m_container = findNode::getClass<TrackEvaluationContainerv1>(topNode, "TrackEvaluationContainer");
0466
0467
0468 m_hitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
0469
0470
0471 m_g4hits_tpc = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_TPC");
0472 m_g4hits_intt = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_INTT");
0473 m_g4hits_mvtx = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MVTX");
0474 m_g4hits_micromegas = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MICROMEGAS");
0475
0476
0477 m_g4truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0478
0479
0480 m_tpc_geom_container = findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
0481 assert(m_tpc_geom_container);
0482
0483
0484 m_micromegas_geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MICROMEGAS_FULL");
0485
0486 return Fun4AllReturnCodes::EVENT_OK;
0487 }
0488
0489
0490 void TrackEvaluation::evaluate_event()
0491 {
0492 if (!m_container)
0493 {
0494 return;
0495 }
0496
0497
0498 TrackEvaluationContainerv1::EventStruct event;
0499 if (m_cluster_map)
0500 {
0501 for (const auto& hitsetkey : m_cluster_map->getHitSetKeys())
0502 {
0503 const auto trkrId = TrkrDefs::getTrkrId(hitsetkey);
0504 const auto layer = TrkrDefs::getLayer(hitsetkey);
0505 assert(layer < TrackEvaluationContainerv1::EventStruct::max_layer);
0506
0507
0508 const auto clusters = m_cluster_map->getClusters(hitsetkey);
0509 const int nclusters = std::distance(clusters.first, clusters.second);
0510
0511 switch (trkrId)
0512 {
0513 case TrkrDefs::mvtxId:
0514 event.nclusters_mvtx += nclusters;
0515 break;
0516 case TrkrDefs::inttId:
0517 event.nclusters_intt += nclusters;
0518 break;
0519 case TrkrDefs::tpcId:
0520 event.nclusters_tpc += nclusters;
0521 break;
0522 case TrkrDefs::micromegasId:
0523 event.nclusters_micromegas += nclusters;
0524 break;
0525 }
0526
0527 event.nclusters[layer] += nclusters;
0528 }
0529 }
0530
0531
0532 m_container->addEvent(event);
0533 }
0534
0535
0536 void TrackEvaluation::evaluate_clusters()
0537 {
0538 if (!(m_cluster_map && m_hitsetcontainer && m_container))
0539 {
0540 return;
0541 }
0542
0543
0544 m_container->clearClusters();
0545 SvtxTrack* track = nullptr;
0546
0547 for (const auto& hitsetkey : m_cluster_map->getHitSetKeys())
0548 {
0549 for (const auto& [key, cluster] : range_adaptor(m_cluster_map->getClusters(hitsetkey)))
0550 {
0551
0552 auto cluster_struct = create_cluster(key, cluster, track);
0553 add_cluster_size(cluster_struct, cluster);
0554 add_cluster_energy(cluster_struct, key, m_cluster_hit_map, m_hitsetcontainer);
0555
0556
0557 const auto g4hits = find_g4hits(key);
0558 const bool is_micromegas(TrkrDefs::getTrkrId(key) == TrkrDefs::micromegasId);
0559 if (is_micromegas)
0560 {
0561 const int tileid = MicromegasDefs::getTileId(key);
0562 add_truth_information_micromegas(cluster_struct, tileid, g4hits);
0563 }
0564 else
0565 {
0566 add_truth_information(cluster_struct, g4hits);
0567 }
0568
0569
0570 m_container->addCluster(cluster_struct);
0571 }
0572 }
0573 }
0574
0575
0576 void TrackEvaluation::evaluate_tracks()
0577 {
0578 if (!(m_track_map && m_cluster_map && m_container))
0579 {
0580 return;
0581 }
0582
0583
0584 m_container->clearTracks();
0585 for (const auto& [track_id, track] : *m_track_map)
0586 {
0587 auto track_struct = create_track(track);
0588
0589
0590 const auto [id, contributors] = get_max_contributor(track);
0591 track_struct.contributors = contributors;
0592
0593
0594 auto particle = m_g4truthinfo->GetParticle(id);
0595 track_struct.embed = get_embed(particle);
0596 ::add_truth_information(track_struct, particle, m_g4truthinfo);
0597
0598
0599 auto state_iter = track->begin_states();
0600
0601 for (const auto& cluster_key : get_cluster_keys(track))
0602 {
0603 auto cluster = m_cluster_map->findCluster(cluster_key);
0604 if (!cluster)
0605 {
0606 std::cout << "TrackEvaluation::evaluate_tracks - unable to find cluster for key " << cluster_key << std::endl;
0607 continue;
0608 }
0609
0610 auto cluster_struct = create_cluster(cluster_key, cluster, track);
0611 add_cluster_size(cluster_struct, cluster);
0612 add_cluster_energy(cluster_struct, cluster_key, m_cluster_hit_map, m_hitsetcontainer);
0613
0614 const auto g4hits = find_g4hits(cluster_key);
0615 const bool is_micromegas(TrkrDefs::getTrkrId(cluster_key) == TrkrDefs::micromegasId);
0616 if (is_micromegas)
0617 {
0618 const int tileid = MicromegasDefs::getTileId(cluster_key);
0619 add_truth_information_micromegas(cluster_struct, tileid, g4hits);
0620 }
0621 else
0622 {
0623 add_truth_information(cluster_struct, g4hits);
0624 }
0625
0626
0627
0628 const auto radius(cluster_struct.r);
0629 float dr_min = -1;
0630 for (auto iter = state_iter; iter != track->end_states(); ++iter)
0631 {
0632 const auto dr = std::abs(radius - get_r(iter->second->get_x(), iter->second->get_y()));
0633 if (dr_min < 0 || dr < dr_min)
0634 {
0635 state_iter = iter;
0636 dr_min = dr;
0637 }
0638 else
0639 {
0640 break;
0641 }
0642 }
0643
0644
0645 if (is_micromegas)
0646 {
0647 const int tileid = MicromegasDefs::getTileId(cluster_key);
0648 add_trk_information_micromegas(cluster_struct, tileid, state_iter->second);
0649 }
0650 else
0651 {
0652 add_trk_information(cluster_struct, state_iter->second);
0653 }
0654
0655
0656 track_struct.clusters.push_back(cluster_struct);
0657 }
0658 m_container->addTrack(track_struct);
0659 }
0660 }
0661
0662
0663 TrackEvaluation::G4HitSet TrackEvaluation::find_g4hits(TrkrDefs::cluskey cluster_key) const
0664 {
0665
0666 if (!(m_cluster_hit_map && m_hit_truth_map))
0667 {
0668 return G4HitSet();
0669 }
0670
0671
0672 auto map_iter = m_g4hit_map.lower_bound(cluster_key);
0673 if (map_iter != m_g4hit_map.end() && cluster_key == map_iter->first)
0674 {
0675 return map_iter->second;
0676 }
0677
0678
0679 G4HitSet out;
0680 const auto hitset_key = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
0681 for (const auto& [first, hit_key] : range_adaptor(m_cluster_hit_map->getHits(cluster_key)))
0682 {
0683
0684 TrkrHitTruthAssoc::MMap g4hit_map;
0685 m_hit_truth_map->getG4Hits(hitset_key, hit_key, g4hit_map);
0686
0687
0688 for (auto& truth_iter : g4hit_map)
0689 {
0690 const auto g4hit_key = truth_iter.second.second;
0691 PHG4Hit* g4hit = nullptr;
0692
0693 switch (TrkrDefs::getTrkrId(hitset_key))
0694 {
0695 case TrkrDefs::mvtxId:
0696 if (m_g4hits_mvtx)
0697 {
0698 g4hit = m_g4hits_mvtx->findHit(g4hit_key);
0699 }
0700 break;
0701
0702 case TrkrDefs::inttId:
0703 if (m_g4hits_intt)
0704 {
0705 g4hit = m_g4hits_intt->findHit(g4hit_key);
0706 }
0707 break;
0708
0709 case TrkrDefs::tpcId:
0710 if (m_g4hits_tpc)
0711 {
0712 g4hit = m_g4hits_tpc->findHit(g4hit_key);
0713 }
0714 break;
0715
0716 case TrkrDefs::micromegasId:
0717 if (m_g4hits_micromegas)
0718 {
0719 g4hit = m_g4hits_micromegas->findHit(g4hit_key);
0720 }
0721 break;
0722
0723 default:
0724 break;
0725 }
0726
0727 if (g4hit)
0728 {
0729 out.insert(g4hit);
0730 }
0731 else
0732 {
0733 std::cout << "TrackEvaluation::find_g4hits - g4hit not found " << g4hit_key << std::endl;
0734 }
0735 }
0736 }
0737
0738
0739 return m_g4hit_map.insert(map_iter, std::make_pair(cluster_key, std::move(out)))->second;
0740 }
0741
0742
0743 std::pair<int, int> TrackEvaluation::get_max_contributor(SvtxTrack* track) const
0744 {
0745 if (!(m_track_map && m_cluster_map && m_g4truthinfo))
0746 {
0747 return {0, 0};
0748 }
0749
0750
0751 using IdMap = std::map<int, int>;
0752 IdMap contributor_map;
0753
0754
0755 for (const auto& cluster_key : get_cluster_keys(track))
0756 {
0757 for (const auto& hit : find_g4hits(cluster_key))
0758 {
0759 const int trkid = hit->get_trkid();
0760 auto iter = contributor_map.lower_bound(trkid);
0761 if (iter == contributor_map.end() || iter->first != trkid)
0762 {
0763 contributor_map.insert(iter, std::make_pair(trkid, 1));
0764 }
0765 else
0766 {
0767 ++iter->second;
0768 }
0769 }
0770 }
0771
0772 if (contributor_map.empty())
0773 {
0774 return {0, 0};
0775 }
0776 else
0777 {
0778 return *std::max_element(
0779 contributor_map.cbegin(), contributor_map.cend(),
0780 [](const IdMap::value_type& first, const IdMap::value_type& second)
0781 { return first.second < second.second; });
0782 }
0783 }
0784
0785
0786 int TrackEvaluation::get_embed(PHG4Particle* particle) const
0787 {
0788 return (m_g4truthinfo && particle) ? m_g4truthinfo->isEmbeded(particle->get_primary_id()) : 0;
0789 }
0790
0791
0792 TrackEvaluationContainerv1::ClusterStruct TrackEvaluation::create_cluster(TrkrDefs::cluskey key, TrkrCluster* cluster, SvtxTrack* track) const
0793 {
0794 TrackSeed* si_seed = nullptr;
0795 TrackSeed* tpc_seed = nullptr;
0796 if (track != nullptr)
0797 {
0798 si_seed = track->get_silicon_seed();
0799 tpc_seed = track->get_tpc_seed();
0800 }
0801
0802 Acts::Vector3 global;
0803 global = m_tGeometry->getGlobalPosition(key, cluster);
0804 TrackEvaluationContainerv1::ClusterStruct cluster_struct;
0805 cluster_struct.layer = TrkrDefs::getLayer(key);
0806 cluster_struct.x = global.x();
0807 cluster_struct.y = global.y();
0808 cluster_struct.z = global.z();
0809 cluster_struct.r = get_r(cluster_struct.x, cluster_struct.y);
0810 cluster_struct.phi = std::atan2(cluster_struct.y, cluster_struct.x);
0811 cluster_struct.phi_error = 0.0;
0812 cluster_struct.z_error = 0.0;
0813 cluster_struct.trk_alpha = 0.0;
0814 cluster_struct.trk_beta = 0.0;
0815
0816 ClusterErrorPara ClusErrPara;
0817
0818 if (track != nullptr)
0819 {
0820 float r = cluster_struct.r;
0821
0822 if (cluster_struct.layer >= 7)
0823 {
0824 auto para_errors_mm = ClusErrPara.get_clusterv5_modified_error(cluster, r, key);
0825
0826 cluster_struct.phi_error = cluster->getRPhiError() / cluster_struct.r;
0827 cluster_struct.z_error = cluster->getZError();
0828 cluster_struct.para_phi_error = sqrt(para_errors_mm.first) / cluster_struct.r;
0829 cluster_struct.para_z_error = sqrt(para_errors_mm.second);
0830
0831 cluster_struct.trk_radius = 1.0 / tpc_seed->get_qOverR();
0832 cluster_struct.trk_alpha = (r * r) / (2 * r * TMath::Abs(1.0 / tpc_seed->get_qOverR()));
0833 cluster_struct.trk_beta = atan(tpc_seed->get_slope());
0834 }
0835 else
0836 {
0837 auto para_errors_mvtx = ClusErrPara.get_cluster_error(cluster, r, key, si_seed->get_qOverR(), si_seed->get_slope());
0838 cluster_struct.phi_error = sqrt(para_errors_mvtx.first) / cluster_struct.r;
0839 cluster_struct.z_error = sqrt(para_errors_mvtx.second);
0840
0841 cluster_struct.trk_radius = 1.0 / tpc_seed->get_qOverR();
0842 cluster_struct.trk_alpha = (r * r) / (2 * r * TMath::Abs(1.0 / tpc_seed->get_qOverR()));
0843 cluster_struct.trk_beta = atan(si_seed->get_slope());
0844 }
0845 }
0846
0847 return cluster_struct;
0848 }
0849
0850
0851 void TrackEvaluation::add_trk_information(TrackEvaluationContainerv1::ClusterStruct& cluster, SvtxTrackState* state) const
0852 {
0853
0854 const auto trk_r = get_r(state->get_x(), state->get_y());
0855 const auto dr = cluster.r - trk_r;
0856 const auto trk_drdt = (state->get_x() * state->get_px() + state->get_y() * state->get_py()) / trk_r;
0857 const auto trk_dxdr = state->get_px() / trk_drdt;
0858 const auto trk_dydr = state->get_py() / trk_drdt;
0859 const auto trk_dzdr = state->get_pz() / trk_drdt;
0860
0861
0862 cluster.trk_x = state->get_x() + dr * trk_dxdr;
0863 cluster.trk_y = state->get_y() + dr * trk_dydr;
0864 cluster.trk_z = state->get_z() + dr * trk_dzdr;
0865 cluster.trk_r = get_r(cluster.trk_x, cluster.trk_y);
0866 cluster.trk_phi = std::atan2(cluster.trk_y, cluster.trk_x);
0867
0868
0869 cluster.trk_px = state->get_px();
0870 cluster.trk_py = state->get_py();
0871 cluster.trk_pz = state->get_pz();
0872
0873
0874
0875
0876
0877 const auto cosphi(std::cos(cluster.trk_phi));
0878 const auto sinphi(std::sin(cluster.trk_phi));
0879 const auto trk_pphi = -state->get_px() * sinphi + state->get_py() * cosphi;
0880 const auto trk_pr = state->get_px() * cosphi + state->get_py() * sinphi;
0881 const auto trk_pz = state->get_pz();
0882 cluster.trk_alpha = std::atan2(trk_pphi, trk_pr);
0883 cluster.trk_beta = std::atan2(trk_pz, trk_pr);
0884 cluster.trk_phi_error = state->get_phi_error();
0885 cluster.trk_z_error = state->get_z_error();
0886 }
0887
0888
0889 void TrackEvaluation::add_trk_information_micromegas(TrackEvaluationContainerv1::ClusterStruct& cluster, int tileid, SvtxTrackState* state) const
0890 {
0891
0892 const auto layer = cluster.layer;
0893 const auto layergeom = dynamic_cast<CylinderGeomMicromegas*>(m_micromegas_geom_container->GetLayerGeom(layer));
0894 assert(layergeom);
0895
0896
0897 const TVector3 cluster_world(cluster.x, cluster.y, cluster.z);
0898 const auto cluster_local = layergeom->get_local_from_world_coords(tileid, m_tGeometry, cluster_world);
0899
0900
0901 TVector3 track_world(state->get_x(), state->get_y(), state->get_z());
0902 TVector3 track_local = layergeom->get_local_from_world_coords(tileid, m_tGeometry, track_world);
0903
0904
0905 const TVector3 direction_world(state->get_px(), state->get_py(), state->get_pz());
0906 const TVector3 direction_local = layergeom->get_local_from_world_vect(tileid, m_tGeometry, direction_world);
0907
0908
0909 const auto delta_z = cluster_local.z() - track_local.z();
0910 track_local += TVector3(
0911 delta_z * direction_local.x() / direction_local.z(),
0912 delta_z * direction_local.y() / direction_local.z(),
0913 delta_z);
0914
0915
0916 track_world = layergeom->get_world_from_local_coords(tileid, m_tGeometry, track_local);
0917
0918
0919 cluster.trk_x = track_world.x();
0920 cluster.trk_y = track_world.y();
0921 cluster.trk_z = track_world.z();
0922 cluster.trk_r = get_r(cluster.trk_x, cluster.trk_y);
0923 cluster.trk_phi = std::atan2(cluster.trk_y, cluster.trk_x);
0924
0925
0926 cluster.trk_px = state->get_px();
0927 cluster.trk_py = state->get_py();
0928 cluster.trk_pz = state->get_pz();
0929
0930
0931
0932
0933
0934 const auto cosphi(std::cos(cluster.trk_phi));
0935 const auto sinphi(std::sin(cluster.trk_phi));
0936 const auto trk_pphi = -state->get_px() * sinphi + state->get_py() * cosphi;
0937 const auto trk_pr = state->get_px() * cosphi + state->get_py() * sinphi;
0938 const auto trk_pz = state->get_pz();
0939 cluster.trk_alpha = std::atan2(trk_pphi, trk_pr);
0940 cluster.trk_beta = std::atan2(trk_pz, trk_pr);
0941 cluster.trk_phi_error = state->get_phi_error();
0942 cluster.trk_z_error = state->get_z_error();
0943 }
0944
0945
0946 void TrackEvaluation::add_truth_information(TrackEvaluationContainerv1::ClusterStruct& cluster, const std::set<PHG4Hit*>& g4hits) const
0947 {
0948
0949 cluster.truth_size = g4hits.size();
0950
0951
0952 const auto layer = cluster.layer;
0953 const bool is_tpc(layer >= 7 && layer < 55);
0954 const PHG4TpcCylinderGeom* layergeom = is_tpc ? m_tpc_geom_container->GetLayerCellGeom(layer) : nullptr;
0955 const auto rin = layergeom ? layergeom->get_radius() - layergeom->get_thickness() / 2 : 0;
0956 const auto rout = layergeom ? layergeom->get_radius() + layergeom->get_thickness() / 2 : 0;
0957
0958
0959 interpolation_data_t::list hits;
0960 for (const auto& g4hit : g4hits)
0961 {
0962 interpolation_data_t::list tmp_hits;
0963 const auto weight = g4hit->get_edep();
0964 for (int i = 0; i < 2; ++i)
0965 {
0966 const TVector3 g4hit_world(g4hit->get_x(i), g4hit->get_y(i), g4hit->get_z(i));
0967 const TVector3 momentum_world(g4hit->get_px(i), g4hit->get_py(i), g4hit->get_pz(i));
0968 tmp_hits.push_back({.position = g4hit_world, .momentum = momentum_world, .weight = weight});
0969 }
0970
0971 if (is_tpc)
0972 {
0973
0974
0975 auto r0 = get_r(tmp_hits[0].x(), tmp_hits[0].y());
0976 auto r1 = get_r(tmp_hits[1].x(), tmp_hits[1].y());
0977 if (r0 > r1)
0978 {
0979 std::swap(tmp_hits[0], tmp_hits[1]);
0980 std::swap(r0, r1);
0981 }
0982
0983
0984 if (r1 <= rin || r0 >= rout)
0985 {
0986 continue;
0987 }
0988
0989
0990 const auto dr_old = r1 - r0;
0991
0992
0993 if (r0 < rin)
0994 {
0995 const auto t = line_circle_intersection(tmp_hits[0].position, tmp_hits[1].position, rin);
0996 if (t < 0)
0997 {
0998 continue;
0999 }
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
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
1026 hits.push_back(std::move(tmp_hits[0]));
1027 hits.push_back(std::move(tmp_hits[1]));
1028 }
1029
1030
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
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
1045
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
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
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
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
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
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
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
1096 const TVector3 interpolation_world = layergeom->get_world_from_local_coords(tileid, m_tGeometry, interpolation_local);
1097
1098
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
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
1114 cluster.truth_px = momentum_world.x();
1115 cluster.truth_py = momentum_world.y();
1116 cluster.truth_pz = momentum_world.z();
1117
1118
1119
1120
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 }