File indexing completed on 2025-08-06 08:18:35
0001 #include "PHTruthTrackSeeding.h"
0002
0003 #include <trackbase_historic/TrackSeed.h>
0004 #include <trackbase_historic/TrackSeedContainer.h>
0005 #include <trackbase_historic/TrackSeed_FastSim_v2.h>
0006
0007 #include <trackbase/TrkrCluster.h>
0008 #include <trackbase/TrkrClusterContainer.h>
0009
0010 #include <globalvertex/SvtxVertex.h>
0011 #include <globalvertex/SvtxVertexMap.h>
0012
0013 #include <trackbase/TrkrHitTruthAssoc.h>
0014 #include <trackbase_historic/ActsTransformations.h>
0015
0016 #include <fun4all/Fun4AllReturnCodes.h>
0017
0018 #include <g4eval/SvtxClusterEval.h>
0019 #include <g4eval/SvtxEvalStack.h>
0020 #include <g4eval/SvtxEvaluator.h>
0021 #include <g4eval/SvtxTrackEval.h>
0022
0023 #include <g4main/PHG4Hit.h> // for PHG4Hit
0024 #include <g4main/PHG4HitContainer.h>
0025 #include <g4main/PHG4HitDefs.h> // for keytype
0026 #include <g4main/PHG4Particle.h> // for PHG4Particle
0027 #include <g4main/PHG4TruthInfoContainer.h>
0028 #include <g4main/PHG4VtxPoint.h>
0029
0030 #include <phool/PHCompositeNode.h>
0031 #include <phool/PHIODataNode.h>
0032 #include <phool/PHNode.h>
0033 #include <phool/PHNodeIterator.h>
0034 #include <phool/PHObject.h>
0035 #include <phool/PHRandomSeed.h>
0036 #include <phool/getClass.h>
0037 #include <phool/phool.h>
0038
0039 #include <trackbase/TrkrCluster.h>
0040 #include <trackbase/TrkrClusterContainer.h>
0041 #include <trackbase/TrkrClusterCrossingAssoc.h>
0042 #include <trackbase/TrkrHitTruthAssoc.h>
0043
0044 #include <trackbase_historic/SvtxTrackSeed_v1.h>
0045 #include <trackbase_historic/TrackSeedContainer_v1.h>
0046 #include <trackbase_historic/TrackSeed_v2.h>
0047 #include <trackbase_historic/TrackSeedHelper.h>
0048
0049 #include <TDatabasePDG.h>
0050 #include <TParticlePDG.h>
0051
0052 #include <gsl/gsl_randist.h>
0053 #include <gsl/gsl_rng.h> // for gsl_rng_alloc
0054
0055 #include <cassert>
0056 #include <cmath>
0057 #include <cstdlib> // for exit
0058 #include <iostream> // for operator<<, std::endl
0059 #include <map> // for multimap, map<>::c...
0060 #include <memory>
0061 #include <set>
0062 #include <utility> // for pair
0063
0064 class PHCompositeNode;
0065
0066 namespace
0067 {
0068 template <class T>
0069 inline constexpr T square(const T& x)
0070 {
0071 return x * x;
0072 }
0073 }
0074
0075 PHTruthTrackSeeding::PHTruthTrackSeeding(const std::string& name)
0076 : PHTrackSeeding(name)
0077 , _clustereval(nullptr)
0078 {
0079
0080 const uint seed = PHRandomSeed();
0081 m_rng.reset(gsl_rng_alloc(gsl_rng_mt19937));
0082 gsl_rng_set(m_rng.get(), seed);
0083 }
0084
0085 int PHTruthTrackSeeding::Setup(PHCompositeNode* topNode)
0086 {
0087 std::cout << "Enter PHTruthTrackSeeding:: Setup" << std::endl;
0088
0089 int ret = PHTrackSeeding::Setup(topNode);
0090 if (ret != Fun4AllReturnCodes::EVENT_OK)
0091 {
0092 return ret;
0093 }
0094
0095 ret = GetNodes(topNode);
0096 if (ret != Fun4AllReturnCodes::EVENT_OK)
0097 {
0098 return ret;
0099 }
0100
0101 ret = CreateNodes(topNode);
0102 if (ret != Fun4AllReturnCodes::EVENT_OK)
0103 {
0104 return ret;
0105 }
0106
0107 _clustereval = new SvtxClusterEval(topNode);
0108 _clustereval->do_caching(true);
0109 return Fun4AllReturnCodes::EVENT_OK;
0110 }
0111
0112 int PHTruthTrackSeeding::Process(PHCompositeNode* topNode)
0113 {
0114 _clustereval->next_event(topNode);
0115 _track_map_combined->Clear();
0116
0117 using TrkClustersMap = std::map<int, std::set<TrkrCluster*> >;
0118 TrkClustersMap m_trackID_clusters;
0119
0120 std::vector<TrkrDefs::cluskey> ClusterKeyListSilicon;
0121 std::vector<TrkrDefs::cluskey> ClusterKeyListTpc;
0122
0123 PHG4TruthInfoContainer::ConstRange range = m_g4truth_container->GetPrimaryParticleRange();
0124 for (PHG4TruthInfoContainer::ConstIterator iter = range.first;
0125 iter != range.second;
0126 ++iter)
0127 {
0128 ClusterKeyListSilicon.clear();
0129 ClusterKeyListTpc.clear();
0130 PHG4Particle* g4particle = iter->second;
0131
0132 if (g4particle == nullptr)
0133 {
0134 std::cout << __PRETTY_FUNCTION__ << " - validity check failed: missing truth particle" << std::endl;
0135 exit(1);
0136 }
0137
0138 const float gtrackID = g4particle->get_track_id();
0139
0140
0141 if (_min_momentum > 0)
0142 {
0143 const double monentum2 =
0144 g4particle->get_px() * g4particle->get_px() +
0145 g4particle->get_py() * g4particle->get_py() +
0146 g4particle->get_pz() * g4particle->get_pz();
0147
0148 if (monentum2 < _min_momentum * _min_momentum)
0149 {
0150 if (Verbosity() >= 3)
0151 {
0152 std::cout << __PRETTY_FUNCTION__ << " ignore low momentum particle " << gtrackID << std::endl;
0153 g4particle->identify();
0154 }
0155 continue;
0156 }
0157 }
0158
0159 for (unsigned int layer = _min_layer; layer < _max_layer; layer++)
0160 {
0161 TrkrDefs::cluskey cluskey = _clustereval->best_cluster_by_nhit(gtrackID, layer);
0162 if (cluskey != 0)
0163 {
0164 unsigned int trkrid = TrkrDefs::getTrkrId(cluskey);
0165 if (trkrid == TrkrDefs::mvtxId || trkrid == TrkrDefs::inttId)
0166 {
0167 ClusterKeyListSilicon.push_back(cluskey);
0168 }
0169 else
0170 {
0171 ClusterKeyListTpc.push_back(cluskey);
0172 }
0173 }
0174 }
0175
0176 unsigned int nsi = ClusterKeyListSilicon.size();
0177 unsigned int ntpc = ClusterKeyListTpc.size();
0178
0179 if (nsi + ntpc < _min_clusters_per_track)
0180 {
0181 continue;
0182 }
0183
0184 if (nsi > 0)
0185 {
0186 buildTrackSeed(ClusterKeyListSilicon, g4particle, _track_map_silicon);
0187 }
0188 if (ntpc > 0)
0189 {
0190 buildTrackSeed(ClusterKeyListTpc, g4particle, _track_map);
0191 }
0192
0193 if (nsi > 0 && ntpc > 0)
0194 {
0195
0196 auto track = std::make_unique<SvtxTrackSeed_v1>();
0197
0198
0199 track->set_tpc_seed_index(_track_map->size() - 1);
0200 track->set_silicon_seed_index(_track_map_silicon->size() - 1);
0201
0202 _track_map_combined->insert(track.get());
0203 }
0204 }
0205
0206 if (Verbosity() > 0)
0207 {
0208
0209 for (unsigned int phtrk_iter = 0;
0210 phtrk_iter < _track_map_combined->size();
0211 ++phtrk_iter)
0212 {
0213 auto seed = _track_map_combined->get(phtrk_iter);
0214 if (!seed)
0215 {
0216 continue;
0217 }
0218
0219 auto tpc_index = seed->get_tpc_seed_index();
0220 auto silicon_index = seed->get_silicon_seed_index();
0221
0222 std::cout << "SvtxSeedTrack: " << phtrk_iter
0223 << " tpc_index " << tpc_index
0224 << " silicon_index " << silicon_index
0225 << std::endl;
0226
0227 std::cout << " ---------- silicon tracklet " << silicon_index << std::endl;
0228 auto silicon_tracklet = _track_map_silicon->get(silicon_index);
0229 if (!silicon_tracklet)
0230 {
0231 continue;
0232 }
0233 silicon_tracklet->identify();
0234
0235 std::cout << " ---------- tpc tracklet " << tpc_index << std::endl;
0236 auto tpc_tracklet = _track_map->get(tpc_index);
0237 if (!tpc_tracklet)
0238 {
0239 continue;
0240 }
0241 tpc_tracklet->identify();
0242 }
0243 }
0244
0245
0246
0247 return Fun4AllReturnCodes::EVENT_OK;
0248 }
0249
0250 void PHTruthTrackSeeding::buildTrackSeed(const std::vector<TrkrDefs::cluskey>& clusters, PHG4Particle* g4particle, TrackSeedContainer* container)
0251 {
0252
0253
0254 auto track = std::make_unique<TrackSeed_FastSim_v2>();
0255 bool silicon = false;
0256 bool tpc = false;
0257 for (const auto& cluskey : clusters)
0258 {
0259 if (TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::mvtxId ||
0260 TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::inttId)
0261 {
0262 silicon = true;
0263 }
0264 if (TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId)
0265 {
0266 tpc = true;
0267 }
0268 track->insert_cluster_key(cluskey);
0269 }
0270
0271 const auto particle = TDatabasePDG::Instance()->GetParticle(g4particle->get_pid());
0272 int charge = 1;
0273 if (particle)
0274 {
0275 if (particle->Charge() < 0)
0276 {
0277 charge = -1;
0278 }
0279 }
0280
0281 auto random1 = gsl_ran_flat(m_rng.get(), 0.95, 1.05);
0282 float px = g4particle->get_px() * random1;
0283 float py = g4particle->get_py() * random1;
0284 float pz = g4particle->get_pz() * random1;
0285 const auto g4vertex = m_g4truth_container->GetVtx(g4particle->get_vtx_id());
0286 auto random2 = gsl_ran_flat(m_rng.get(), -0.02, 0.02);
0287 float x = g4vertex->get_x() + random2;
0288 float y = g4vertex->get_y() + random2;
0289 float z = g4vertex->get_z() + random2;
0290
0291 float pt = std::sqrt(px * px + py * py);
0292 float phi = std::atan2(py, px);
0293 float R = 100 * pt / (0.3 * 1.4);
0294 float theta = std::atan2(pt, pz);
0295 if (theta < 0)
0296 {
0297 theta += M_PI;
0298 }
0299 if (theta > M_PI)
0300 {
0301 theta -= M_PI;
0302 }
0303
0304 float eta = -log(tan(theta / 2.));
0305
0306
0307
0308 const float tanphisq = square(std::tan(phi));
0309 const float a = tanphisq + 1;
0310 const float b = -2 * y * (tanphisq + 1);
0311 const float c = (tanphisq + 1) * square(y) - square(R);
0312
0313 const float Y0_1 = (-b + std::sqrt(square(b) - 4 * a * c)) / (2. * a);
0314 const float Y0_2 = (-b - std::sqrt(square(b) - 4 * a * c)) / (2. * a);
0315 const float X0_1 = sqrt(pow(R, 2) - pow(Y0_1 - y, 2)) + x;
0316 const float X0_2 = -sqrt(pow(R, 2) - pow(Y0_2 - y, 2)) + x;
0317 track->set_X0(X0_1);
0318 track->set_Y0(Y0_1);
0319 track->set_qOverR(charge / R);
0320 track->set_slope(1. / std::tan(theta));
0321 track->set_Z0(z);
0322
0323 if (tpc)
0324 {
0325
0326
0327
0328 const unsigned int start_layer = 7;
0329 const unsigned int end_layer = 55;
0330
0331
0332 std::map<TrkrDefs::cluskey, Acts::Vector3> positions;
0333 std::transform(track->begin_cluster_keys(), track->end_cluster_keys(), std::inserter(positions, positions.end()),
0334 [this](const auto& key)
0335 { return std::make_pair(key, tgeometry->getGlobalPosition(key, m_clusterMap->findCluster(key))); });
0336
0337 TrackSeedHelper::lineFit(track.get(), positions, start_layer, end_layer);
0338 }
0339
0340
0341
0342 auto newphi = TrackSeedHelper::get_phi_fastsim(track.get());
0343
0344
0345
0346 if (std::fabs(newphi - phi) > 0.03)
0347 {
0348 track->set_X0(X0_2);
0349 newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0350
0351 if (std::fabs(newphi - phi) > 0.03)
0352 {
0353 track->set_Y0(Y0_2);
0354 newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0355
0356 if (std::fabs(newphi - phi) > 0.03)
0357 {
0358 track->set_X0(X0_1);
0359 newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0360 }
0361 }
0362 }
0363
0364
0365 track->set_phi(newphi);
0366
0367 if (Verbosity() > 2)
0368 {
0369 std::cout << "Charge is " << charge << std::endl;
0370 std::cout << "truth/reco px " << px << ", " << track->get_px() << std::endl;
0371 std::cout << "truth/reco py " << py << ", " << track->get_py() << std::endl;
0372 std::cout << "truth/reco pz " << pz << ", " << track->get_pz() << std::endl;
0373 std::cout << "truth/reco pt " << pt << ", " << track->get_pt() << std::endl;
0374 std::cout << "truth/reco phi " << phi << ", " << track->get_phi() << std::endl;
0375 std::cout << "truth/reco eta " << eta << ", " << track->get_eta() << std::endl;
0376 std::cout << "truth/reco x " << x << ", " << TrackSeedHelper::get_x(track.get()) << std::endl;
0377 std::cout << "truth/reco y " << y << ", " << TrackSeedHelper::get_y(track.get()) << std::endl;
0378 std::cout << "truth/reco z " << z << ", " << TrackSeedHelper::get_z(track.get()) << std::endl;
0379 }
0380
0381
0382 if (silicon)
0383 {
0384
0385
0386 const auto intt_crossings = getInttCrossings(track.get());
0387 if (intt_crossings.empty())
0388 {
0389 if (Verbosity() > 1)
0390 {
0391 std::cout << "PHTruthTrackSeeding::Process - Silicon track " << container->size() - 1 << " has no INTT clusters" << std::endl;
0392 }
0393 return;
0394 }
0395 else if (intt_crossings.size() > 1)
0396 {
0397 if (Verbosity() > 1)
0398 {
0399 std::cout << "PHTruthTrackSeeding::Process - INTT crossings not all the same for track " << container->size() - 1 << " crossing_keep - dropping this match " << std::endl;
0400 }
0401 }
0402 else
0403 {
0404 const auto& crossing = *intt_crossings.begin();
0405 track->set_crossing(crossing);
0406 if (Verbosity() > 1)
0407 {
0408 std::cout << "PHTruthTrackSeeding::Process - Combined track " << container->size() - 1 << " bunch crossing " << crossing << std::endl;
0409 }
0410 }
0411 }
0412 else
0413 {
0414
0415 track->set_crossing(SHRT_MAX);
0416 }
0417
0418 container->insert(track.get());
0419 }
0420
0421 int PHTruthTrackSeeding::CreateNodes(PHCompositeNode* topNode)
0422 {
0423
0424 PHNodeIterator iter(topNode);
0425
0426 PHCompositeNode* dstNode = static_cast<PHCompositeNode*>(iter.findFirst(
0427 "PHCompositeNode", "DST"));
0428 if (!dstNode)
0429 {
0430 std::cerr << PHWHERE << "DST Node missing, doing nothing." << std::endl;
0431 return Fun4AllReturnCodes::ABORTEVENT;
0432 }
0433 PHNodeIterator iter_dst(dstNode);
0434
0435
0436 PHCompositeNode* tb_node =
0437 dynamic_cast<PHCompositeNode*>(iter_dst.findFirst("PHCompositeNode",
0438 "SVTX"));
0439 if (!tb_node)
0440 {
0441 tb_node = new PHCompositeNode("SVTX");
0442 dstNode->addNode(tb_node);
0443 if (Verbosity() > 0)
0444 {
0445 std::cout << PHWHERE << "SVTX node added" << std::endl;
0446 }
0447 }
0448
0449 _track_map = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
0450 if (!_track_map)
0451 {
0452 _track_map = new TrackSeedContainer_v1;
0453 PHIODataNode<PHObject>* tracks_node =
0454 new PHIODataNode<PHObject>(_track_map, "TpcTrackSeedContainer", "PHObject");
0455 tb_node->addNode(tracks_node);
0456 }
0457
0458 _track_map_silicon = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
0459 if (!_track_map_silicon)
0460 {
0461 _track_map_silicon = new TrackSeedContainer_v1;
0462 PHIODataNode<PHObject>* tracks_node =
0463 new PHIODataNode<PHObject>(_track_map_silicon, "SiliconTrackSeedContainer", "PHObject");
0464 tb_node->addNode(tracks_node);
0465 }
0466
0467 _track_map_combined = findNode::getClass<TrackSeedContainer>(topNode, "SvtxTrackSeedContainer");
0468 if (!_track_map_combined)
0469 {
0470 _track_map_combined = new TrackSeedContainer_v1;
0471 PHIODataNode<PHObject>* node2 = new PHIODataNode<PHObject>(_track_map_combined, "SvtxTrackSeedContainer", "PHObject");
0472 tb_node->addNode(node2);
0473 }
0474
0475 return Fun4AllReturnCodes::EVENT_OK;
0476 }
0477 int PHTruthTrackSeeding::GetNodes(PHCompositeNode* topNode)
0478 {
0479 tgeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0480 if (!tgeometry)
0481 {
0482 std::cerr << PHWHERE << "Error, can' find needed Acts nodes " << std::endl;
0483 return Fun4AllReturnCodes::ABORTEVENT;
0484 }
0485
0486 m_clusterMap = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0487
0488 if (!m_clusterMap)
0489 {
0490 std::cerr << PHWHERE << "Error: Can't find node TRKR_CLUSTER" << std::endl;
0491 return Fun4AllReturnCodes::ABORTEVENT;
0492 }
0493
0494 m_cluster_crossing_map = findNode::getClass<TrkrClusterCrossingAssoc>(topNode, "TRKR_CLUSTERCROSSINGASSOC");
0495 if (!m_cluster_crossing_map)
0496 {
0497 std::cerr << PHWHERE << " ERROR: Can't find TRKR_CLUSTERCROSSINGASSOC " << std::endl;
0498 return Fun4AllReturnCodes::ABORTEVENT;
0499 }
0500
0501 m_g4truth_container = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0502 if (!m_g4truth_container)
0503 {
0504 std::cerr << PHWHERE << " ERROR: Can't find node G4TruthInfo" << std::endl;
0505 return Fun4AllReturnCodes::ABORTEVENT;
0506 }
0507
0508 hittruthassoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
0509 if (!hittruthassoc)
0510 {
0511 std::cout << PHWHERE << "Failed to find TRKR_HITTRUTHASSOC node, quit!" << std::endl;
0512 exit(1);
0513 }
0514
0515 using nodePair = std::pair<std::string, PHG4HitContainer*&>;
0516 std::initializer_list<nodePair> nodes =
0517 {
0518 {"G4HIT_TPC", phg4hits_tpc},
0519 {"G4HIT_INTT", phg4hits_intt},
0520 {"G4HIT_MVTX", phg4hits_mvtx},
0521 {"G4HIT_MICROMEGAS", phg4hits_micromegas}};
0522
0523 for (auto&& node : nodes)
0524 {
0525 if (!(node.second = findNode::getClass<PHG4HitContainer>(topNode, node.first)))
0526 {
0527 std::cerr << PHWHERE << " PHG4HitContainer " << node.first << " not found" << std::endl;
0528 }
0529 }
0530
0531 return Fun4AllReturnCodes::EVENT_OK;
0532 }
0533
0534 int PHTruthTrackSeeding::End()
0535 {
0536 return 0;
0537 }
0538
0539
0540 std::set<short int> PHTruthTrackSeeding::getInttCrossings(TrackSeed* si_track) const
0541 {
0542 if (Verbosity())
0543 {
0544 std::cout << "PHTruthTrackSeeding::getInttCrossings - entering " << std::endl;
0545 }
0546
0547 std::set<short int> intt_crossings;
0548
0549
0550
0551
0552 for (auto iter = si_track->begin_cluster_keys();
0553 iter != si_track->end_cluster_keys(); ++iter)
0554 {
0555 const TrkrDefs::cluskey& cluster_key = *iter;
0556 const unsigned int trkrid = TrkrDefs::getTrkrId(cluster_key);
0557 if (Verbosity() > 0)
0558 {
0559 std::cout << " trkrid " << trkrid << " cluster_key " << cluster_key << std::endl;
0560 }
0561 if (trkrid == TrkrDefs::inttId)
0562 {
0563
0564 const unsigned int layer = TrkrDefs::getLayer(cluster_key);
0565
0566
0567 const auto crossings = m_cluster_crossing_map->getCrossings(cluster_key);
0568 for (auto iter_A = crossings.first; iter_A != crossings.second; ++iter_A)
0569 {
0570 const auto& [key, crossing] = *iter_A;
0571 if (Verbosity())
0572 {
0573 std::cout << " PHTruthTrackSeeding::getInttCrossings - si Track cluster " << key << " layer " << layer << " crossing " << crossing << std::endl;
0574 }
0575 intt_crossings.insert(crossing);
0576 }
0577 }
0578 }
0579
0580 return intt_crossings;
0581 }