File indexing completed on 2026-07-16 08:14:51
0001 #include "PHTruthTrackFitter.h"
0002
0003 #include <trackbase/ActsGeometry.h>
0004 #include <trackbase/TrkrCluster.h>
0005 #include <trackbase/TrkrClusterContainer.h>
0006 #include <trackbase/TrkrClusterHitAssoc.h>
0007 #include <trackbase/TrkrHitTruthAssoc.h>
0008
0009 #include <trackbase_historic/SvtxTrack.h>
0010 #include <trackbase_historic/SvtxTrackMap.h>
0011 #include <trackbase_historic/SvtxTrackMap_v2.h>
0012 #include <trackbase_historic/SvtxTrackState_v3.h>
0013 #include <trackbase_historic/SvtxTrack_v4.h>
0014 #include <trackbase_historic/TrackSeed.h>
0015 #include <trackbase_historic/TrackSeedContainer.h>
0016
0017 #include <fun4all/Fun4AllReturnCodes.h>
0018
0019 #include <g4main/PHG4Hit.h>
0020 #include <g4main/PHG4HitContainer.h>
0021 #include <g4main/PHG4Particle.h>
0022 #include <g4main/PHG4TruthInfoContainer.h>
0023 #include <g4main/PHG4VtxPoint.h>
0024
0025 #include <phool/PHCompositeNode.h>
0026 #include <phool/PHIODataNode.h>
0027 #include <phool/PHNode.h>
0028 #include <phool/PHNodeIterator.h>
0029 #include <phool/PHObject.h>
0030 #include <phool/getClass.h>
0031 #include <phool/phool.h>
0032
0033 #include <TDatabasePDG.h>
0034 #include <TParticlePDG.h>
0035
0036 #include <algorithm>
0037 #include <cmath>
0038 #include <iostream>
0039 #include <limits>
0040 #include <set>
0041 #include <utility>
0042 #include <vector>
0043
0044 namespace
0045 {
0046 template <class T>
0047 constexpr T square(const T& x)
0048 {
0049 return x * x;
0050 }
0051
0052 bool is_finite(float value)
0053 {
0054 return std::isfinite(value);
0055 }
0056
0057 float average_or(float a, float b, float fallback)
0058 {
0059 const bool aok = is_finite(a);
0060 const bool bok = is_finite(b);
0061
0062 if (aok && bok)
0063 {
0064 return 0.5 * (a + b);
0065 }
0066 if (aok)
0067 {
0068 return a;
0069 }
0070 if (bok)
0071 {
0072 return b;
0073 }
0074
0075 return fallback;
0076 }
0077
0078 bool valid_track_id(unsigned int trackid)
0079 {
0080 return trackid != std::numeric_limits<unsigned int>::max();
0081 }
0082
0083 class InterpolationData
0084 {
0085 public:
0086 InterpolationData(double x, double y, double z, double px, double py, double pz, double weight)
0087 : m_x(x)
0088 , m_y(y)
0089 , m_z(z)
0090 , m_px(px)
0091 , m_py(py)
0092 , m_pz(pz)
0093 , m_weight(weight)
0094 {
0095 }
0096
0097 double r() const
0098 {
0099 return std::sqrt(square(m_x) + square(m_y));
0100 }
0101
0102 double x() const { return m_x; }
0103 double y() const { return m_y; }
0104 double z() const { return m_z; }
0105 double px() const { return m_px; }
0106 double py() const { return m_py; }
0107 double pz() const { return m_pz; }
0108 double weight() const { return m_weight; }
0109
0110 private:
0111 double m_x = 0;
0112 double m_y = 0;
0113 double m_z = 0;
0114 double m_px = 0;
0115 double m_py = 0;
0116 double m_pz = 0;
0117 double m_weight = 1;
0118 };
0119
0120 template <double (InterpolationData::*accessor)() const>
0121 double interpolate_r(const std::vector<InterpolationData>& hits, double r_extrap, double fallback)
0122 {
0123 double sw = 0;
0124 double swr = 0;
0125 double swr2 = 0;
0126 double swq = 0;
0127 double swrq = 0;
0128
0129 for (const auto& hit : hits)
0130 {
0131 const auto q = (hit.*accessor)();
0132 const auto r = hit.r();
0133 const auto weight = hit.weight();
0134 if (!std::isfinite(q) || !std::isfinite(r) || !std::isfinite(weight) || weight <= 0)
0135 {
0136 continue;
0137 }
0138
0139 sw += weight;
0140 swr += weight * r;
0141 swr2 += weight * square(r);
0142 swq += weight * q;
0143 swrq += weight * r * q;
0144 }
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 const auto denom = sw * swr2 - square(swr);
0158 const auto scale = std::max(std::abs(sw * swr2), square(swr));
0159 if (scale <= 0 || std::abs(denom) <= std::numeric_limits<double>::epsilon() * scale)
0160 {
0161 return fallback;
0162 }
0163
0164 const auto alpha = sw * swrq - swr * swq;
0165 const auto beta = swr2 * swq - swr * swrq;
0166 const auto value = (alpha * r_extrap + beta) / denom;
0167 return std::isfinite(value) ? value : fallback;
0168 }
0169 }
0170
0171 PHTruthTrackFitter::PHTruthTrackFitter(const std::string& name)
0172 : SubsysReco(name)
0173 {
0174 }
0175
0176 int PHTruthTrackFitter::InitRun(PHCompositeNode* topNode)
0177 {
0178 if (Verbosity() > 0)
0179 {
0180 std::cout << "PHTruthTrackFitter::InitRun - output track map: " << m_trackMapName << std::endl;
0181 }
0182
0183 if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK)
0184 {
0185 return Fun4AllReturnCodes::ABORTEVENT;
0186 }
0187
0188 if (getNodes(topNode) != Fun4AllReturnCodes::EVENT_OK)
0189 {
0190 return Fun4AllReturnCodes::ABORTEVENT;
0191 }
0192
0193 return Fun4AllReturnCodes::EVENT_OK;
0194 }
0195
0196 int PHTruthTrackFitter::process_event(PHCompositeNode* )
0197 {
0198 m_trackMap->Reset();
0199
0200 unsigned int skipped_tracks = 0;
0201 for (auto* seed : *m_seedMap)
0202 {
0203 if (!seed)
0204 {
0205 continue;
0206 }
0207
0208 auto* tpc_seed = getSeed(m_tpcSeeds, seed->get_tpc_seed_index());
0209 auto* silicon_seed = getSeed(m_siliconSeeds, seed->get_silicon_seed_index());
0210
0211 if (!tpc_seed && !silicon_seed)
0212 {
0213 ++skipped_tracks;
0214 continue;
0215 }
0216
0217 const auto truth_track_id = getTruthTrackId(seed, tpc_seed, silicon_seed);
0218 if (!valid_track_id(truth_track_id))
0219 {
0220 if (Verbosity() > 1)
0221 {
0222 std::cout << "PHTruthTrackFitter::process_event - could not determine truth id for seed" << std::endl;
0223 }
0224 ++skipped_tracks;
0225 continue;
0226 }
0227
0228 auto* g4particle = m_g4TruthInfo->GetParticle(truth_track_id);
0229 if (!g4particle)
0230 {
0231 if (Verbosity() > 1)
0232 {
0233 std::cout << "PHTruthTrackFitter::process_event - no PHG4Particle for track id "
0234 << truth_track_id << std::endl;
0235 }
0236 ++skipped_tracks;
0237 continue;
0238 }
0239
0240 const auto* g4vertex = m_g4TruthInfo->GetVtx(g4particle->get_vtx_id());
0241 if (!g4vertex)
0242 {
0243 if (Verbosity() > 1)
0244 {
0245 std::cout << "PHTruthTrackFitter::process_event - no PHG4VtxPoint for track id "
0246 << truth_track_id << std::endl;
0247 }
0248 ++skipped_tracks;
0249 continue;
0250 }
0251
0252 SvtxTrack_v4 track;
0253 track.set_tpc_seed(tpc_seed);
0254 track.set_silicon_seed(silicon_seed);
0255 track.set_crossing(getCrossing(tpc_seed, silicon_seed));
0256 track.set_vertex_id(g4particle->get_vtx_id());
0257 track.set_charge(getCharge(g4particle, tpc_seed, silicon_seed));
0258 track.set_chisq(0);
0259
0260 track.set_x(g4vertex->get_x());
0261 track.set_y(g4vertex->get_y());
0262 track.set_z(g4vertex->get_z());
0263 track.set_px(g4particle->get_px());
0264 track.set_py(g4particle->get_py());
0265 track.set_pz(g4particle->get_pz());
0266
0267 for (int i = 0; i < 6; ++i)
0268 {
0269 for (int j = i; j < 6; ++j)
0270 {
0271 track.set_error(i, j, 0);
0272 }
0273 }
0274 track.set_error(0, 0, square(m_positionError));
0275 track.set_error(1, 1, square(m_positionError));
0276 track.set_error(2, 2, square(m_zError));
0277
0278 unsigned int state_index = 1;
0279 for (const auto* track_seed : {silicon_seed, tpc_seed})
0280 {
0281 if (!track_seed)
0282 {
0283 continue;
0284 }
0285
0286 for (auto iter = track_seed->begin_cluster_keys(); iter != track_seed->end_cluster_keys(); ++iter)
0287 {
0288 if (addStateFromCluster(&track, *iter, truth_track_id, g4particle, g4vertex, state_index))
0289 {
0290 ++state_index;
0291 }
0292 }
0293 }
0294
0295 if (track.size_states() <= 1)
0296 {
0297 if (Verbosity() > 1)
0298 {
0299 std::cout << "PHTruthTrackFitter::process_event - no truth states for track id "
0300 << truth_track_id << std::endl;
0301 }
0302 ++skipped_tracks;
0303 continue;
0304 }
0305
0306 track.set_ndf(std::max<int>(0, 2 * static_cast<int>(track.size_states()) - 5));
0307
0308 const unsigned int track_id = m_trackMap->size();
0309 track.set_id(track_id);
0310 m_trackMap->insertWithKey(&track, track_id);
0311 }
0312
0313 if (Verbosity() > 0)
0314 {
0315 std::cout << "PHTruthTrackFitter::process_event - built " << m_trackMap->size()
0316 << " truth tracks, skipped " << skipped_tracks << std::endl;
0317 }
0318
0319 return Fun4AllReturnCodes::EVENT_OK;
0320 }
0321
0322 int PHTruthTrackFitter::End(PHCompositeNode* )
0323 {
0324 return Fun4AllReturnCodes::EVENT_OK;
0325 }
0326
0327 int PHTruthTrackFitter::createNodes(PHCompositeNode* topNode)
0328 {
0329 PHNodeIterator iter(topNode);
0330
0331 auto* dst_node = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
0332 if (!dst_node)
0333 {
0334 std::cerr << PHWHERE << "DST node is missing" << std::endl;
0335 return Fun4AllReturnCodes::ABORTEVENT;
0336 }
0337
0338 PHNodeIterator dst_iter(dst_node);
0339 auto* svtx_node = dynamic_cast<PHCompositeNode*>(dst_iter.findFirst("PHCompositeNode", "SVTX"));
0340 if (!svtx_node)
0341 {
0342 svtx_node = new PHCompositeNode("SVTX");
0343 dst_node->addNode(svtx_node);
0344 }
0345
0346 m_trackMap = findNode::getClass<SvtxTrackMap>(topNode, m_trackMapName);
0347 if (!m_trackMap)
0348 {
0349 m_trackMap = new SvtxTrackMap_v2;
0350 auto* track_node = new PHIODataNode<PHObject>(m_trackMap, m_trackMapName, "PHObject");
0351 svtx_node->addNode(track_node);
0352 }
0353
0354 return Fun4AllReturnCodes::EVENT_OK;
0355 }
0356
0357 int PHTruthTrackFitter::getNodes(PHCompositeNode* topNode)
0358 {
0359 m_seedMap = findNode::getClass<TrackSeedContainer>(topNode, m_svtxSeedMapName);
0360 if (!m_seedMap)
0361 {
0362 std::cout << PHWHERE << "No " << m_svtxSeedMapName << " on node tree. Bailing" << std::endl;
0363 return Fun4AllReturnCodes::ABORTEVENT;
0364 }
0365
0366 m_tpcSeeds = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
0367 if (!m_tpcSeeds)
0368 {
0369 std::cout << PHWHERE << "No TpcTrackSeedContainer on node tree. Bailing" << std::endl;
0370 return Fun4AllReturnCodes::ABORTEVENT;
0371 }
0372
0373 m_siliconSeeds = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
0374 if (!m_siliconSeeds)
0375 {
0376 std::cout << PHWHERE << "No SiliconTrackSeedContainer on node tree. Bailing" << std::endl;
0377 return Fun4AllReturnCodes::ABORTEVENT;
0378 }
0379
0380 m_clusterMap = findNode::getClass<TrkrClusterContainer>(topNode, m_clusterMapName);
0381 if (!m_clusterMap)
0382 {
0383 std::cout << PHWHERE << "No " << m_clusterMapName << " on node tree. Bailing" << std::endl;
0384 return Fun4AllReturnCodes::ABORTEVENT;
0385 }
0386
0387 m_clusterHitMap = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
0388 if (!m_clusterHitMap)
0389 {
0390 std::cout << PHWHERE << "No TRKR_CLUSTERHITASSOC on node tree. Bailing" << std::endl;
0391 return Fun4AllReturnCodes::ABORTEVENT;
0392 }
0393
0394 m_hitTruthAssoc = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
0395 if (!m_hitTruthAssoc)
0396 {
0397 std::cout << PHWHERE << "No TRKR_HITTRUTHASSOC on node tree. Bailing" << std::endl;
0398 return Fun4AllReturnCodes::ABORTEVENT;
0399 }
0400
0401 m_g4TruthInfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0402 if (!m_g4TruthInfo)
0403 {
0404 std::cout << PHWHERE << "No G4TruthInfo on node tree. Bailing" << std::endl;
0405 return Fun4AllReturnCodes::ABORTEVENT;
0406 }
0407
0408 m_g4HitsTpc = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_TPC");
0409 m_g4HitsIntt = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_INTT");
0410 m_g4HitsMvtx = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MVTX");
0411 m_g4HitsMicromegas = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MICROMEGAS");
0412
0413 m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0414 if (m_extrapolateToClusterRadius && !m_tGeometry)
0415 {
0416 std::cout << PHWHERE << "No ActsGeometry on node tree. Bailing" << std::endl;
0417 return Fun4AllReturnCodes::ABORTEVENT;
0418 }
0419
0420 return Fun4AllReturnCodes::EVENT_OK;
0421 }
0422
0423 TrackSeed* PHTruthTrackFitter::getSeed(TrackSeedContainer* container, unsigned int index) const
0424 {
0425 if (!container || index >= container->size())
0426 {
0427 return nullptr;
0428 }
0429
0430 return container->get(index);
0431 }
0432
0433 unsigned int PHTruthTrackFitter::getTruthTrackId(const TrackSeed* svtxSeed,
0434 const TrackSeed* tpcSeed,
0435 const TrackSeed* siliconSeed) const
0436 {
0437 auto truth_track_id = m_invalidTruthTrackId;
0438 for (const auto* seed : {svtxSeed, tpcSeed, siliconSeed})
0439 {
0440 if (!seed)
0441 {
0442 continue;
0443 }
0444
0445 const auto seed_truth_track_id = seed->get_truth_track_id();
0446 if (!valid_track_id(seed_truth_track_id))
0447 {
0448 continue;
0449 }
0450
0451 if (valid_track_id(truth_track_id) && seed_truth_track_id != truth_track_id)
0452 {
0453 if (Verbosity() > 0)
0454 {
0455 std::cout << "PHTruthTrackFitter::getTruthTrackId - inconsistent seed truth ids "
0456 << truth_track_id << " and " << seed_truth_track_id << std::endl;
0457 }
0458 return m_invalidTruthTrackId;
0459 }
0460
0461 truth_track_id = seed_truth_track_id;
0462 }
0463
0464 return truth_track_id;
0465 }
0466
0467 std::vector<const PHG4Hit*> PHTruthTrackFitter::getTruthHits(TrkrDefs::cluskey cluskey) const
0468 {
0469 std::vector<const PHG4Hit*> truth_hits;
0470 if (!m_clusterHitMap || !m_hitTruthAssoc)
0471 {
0472 return truth_hits;
0473 }
0474
0475 const auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey);
0476 const auto trkrid = TrkrDefs::getTrkrId(hitsetkey);
0477 const auto hitrange = m_clusterHitMap->getHits(cluskey);
0478
0479 std::set<PHG4HitDefs::keytype> used_g4hits;
0480 for (auto clushititer = hitrange.first; clushititer != hitrange.second; ++clushititer)
0481 {
0482 const auto hitkey = clushititer->second;
0483
0484 TrkrHitTruthAssoc::MMap temp_map;
0485 m_hitTruthAssoc->getG4Hits(hitsetkey, hitkey, temp_map);
0486
0487 for (const auto& hit_truth_iter : temp_map)
0488 {
0489 const auto g4hitkey = hit_truth_iter.second.second;
0490 if (!used_g4hits.insert(g4hitkey).second)
0491 {
0492 continue;
0493 }
0494
0495 const auto* g4hit = getG4Hit(trkrid, g4hitkey);
0496 if (g4hit)
0497 {
0498 truth_hits.push_back(g4hit);
0499 }
0500 }
0501 }
0502
0503 return truth_hits;
0504 }
0505
0506 const PHG4Hit* PHTruthTrackFitter::getG4Hit(unsigned int trkrid, PHG4HitDefs::keytype g4hitkey) const
0507 {
0508 PHG4HitContainer* container = nullptr;
0509 switch (trkrid)
0510 {
0511 case TrkrDefs::tpcId:
0512 container = m_g4HitsTpc;
0513 break;
0514 case TrkrDefs::inttId:
0515 container = m_g4HitsIntt;
0516 break;
0517 case TrkrDefs::mvtxId:
0518 container = m_g4HitsMvtx;
0519 break;
0520 case TrkrDefs::micromegasId:
0521 container = m_g4HitsMicromegas;
0522 break;
0523 default:
0524 break;
0525 }
0526
0527 return container ? container->findHit(g4hitkey) : nullptr;
0528 }
0529
0530 bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track,
0531 TrkrDefs::cluskey cluskey,
0532 unsigned int truthTrackId,
0533 const PHG4Particle* particle,
0534 const PHG4VtxPoint* vertex,
0535 unsigned int stateIndex) const
0536 {
0537 auto* cluster = m_clusterMap->findCluster(cluskey);
0538 if (!cluster)
0539 {
0540 return false;
0541 }
0542
0543 std::vector<InterpolationData> interpolation_hits;
0544 double weight_sum = 0;
0545 double x = 0;
0546 double y = 0;
0547 double z = 0;
0548 double px = 0;
0549 double py = 0;
0550 double pz = 0;
0551 double local_x = 0;
0552 double local_y = 0;
0553
0554 for (const auto* g4hit : getTruthHits(cluskey))
0555 {
0556 if (!g4hit || g4hit->get_trkid() != static_cast<int>(truthTrackId))
0557 {
0558 continue;
0559 }
0560
0561 const auto hit_x = average_or(g4hit->get_x(0), g4hit->get_x(1), std::numeric_limits<float>::quiet_NaN());
0562 const auto hit_y = average_or(g4hit->get_y(0), g4hit->get_y(1), std::numeric_limits<float>::quiet_NaN());
0563 const auto hit_z = average_or(g4hit->get_z(0), g4hit->get_z(1), std::numeric_limits<float>::quiet_NaN());
0564 if (!is_finite(hit_x) || !is_finite(hit_y) || !is_finite(hit_z))
0565 {
0566 continue;
0567 }
0568
0569 const auto hit_px = average_or(g4hit->get_px(0), g4hit->get_px(1), particle->get_px());
0570 const auto hit_py = average_or(g4hit->get_py(0), g4hit->get_py(1), particle->get_py());
0571 const auto hit_pz = average_or(g4hit->get_pz(0), g4hit->get_pz(1), particle->get_pz());
0572 const auto hit_local_x = average_or(g4hit->get_local_x(0), g4hit->get_local_x(1), 0);
0573 const auto hit_local_y = average_or(g4hit->get_local_y(0), g4hit->get_local_y(1), 0);
0574
0575 double weight = g4hit->get_edep();
0576 if (!std::isfinite(weight) || weight <= 0)
0577 {
0578 weight = 1;
0579 }
0580
0581 for (int endpoint = 0; endpoint < 2; ++endpoint)
0582 {
0583 const auto endpoint_x = g4hit->get_x(endpoint);
0584 const auto endpoint_y = g4hit->get_y(endpoint);
0585 const auto endpoint_z = g4hit->get_z(endpoint);
0586 if (!is_finite(endpoint_x) || !is_finite(endpoint_y) || !is_finite(endpoint_z))
0587 {
0588 continue;
0589 }
0590
0591 const auto endpoint_px = g4hit->get_px(endpoint);
0592 const auto endpoint_py = g4hit->get_py(endpoint);
0593 const auto endpoint_pz = g4hit->get_pz(endpoint);
0594
0595 interpolation_hits.emplace_back(endpoint_x,
0596 endpoint_y,
0597 endpoint_z,
0598 is_finite(endpoint_px) ? endpoint_px : particle->get_px(),
0599 is_finite(endpoint_py) ? endpoint_py : particle->get_py(),
0600 is_finite(endpoint_pz) ? endpoint_pz : particle->get_pz(),
0601 weight);
0602 }
0603
0604 weight_sum += weight;
0605 x += weight * hit_x;
0606 y += weight * hit_y;
0607 z += weight * hit_z;
0608 px += weight * hit_px;
0609 py += weight * hit_py;
0610 pz += weight * hit_pz;
0611 local_x += weight * hit_local_x;
0612 local_y += weight * hit_local_y;
0613 }
0614
0615 if (weight_sum <= 0)
0616 {
0617 return false;
0618 }
0619
0620 x /= weight_sum;
0621 y /= weight_sum;
0622 z /= weight_sum;
0623 px /= weight_sum;
0624 py /= weight_sum;
0625 pz /= weight_sum;
0626 local_x /= weight_sum;
0627 local_y /= weight_sum;
0628
0629 if (m_extrapolateToClusterRadius && !interpolation_hits.empty())
0630 {
0631 const auto cluster_radius = getClusterRadius(cluskey, cluster);
0632 if (std::isfinite(cluster_radius) && cluster_radius > 0)
0633 {
0634 x = interpolate_r<&InterpolationData::x>(interpolation_hits, cluster_radius, x);
0635 y = interpolate_r<&InterpolationData::y>(interpolation_hits, cluster_radius, y);
0636 z = interpolate_r<&InterpolationData::z>(interpolation_hits, cluster_radius, z);
0637 px = interpolate_r<&InterpolationData::px>(interpolation_hits, cluster_radius, px);
0638 py = interpolate_r<&InterpolationData::py>(interpolation_hits, cluster_radius, py);
0639 pz = interpolate_r<&InterpolationData::pz>(interpolation_hits, cluster_radius, pz);
0640 }
0641 else if (Verbosity() > 1)
0642 {
0643 std::cout << "PHTruthTrackFitter::addStateFromCluster - invalid cluster radius for cluster "
0644 << cluskey << ", using truth hit average" << std::endl;
0645 }
0646 }
0647
0648 float pathlength = getPathLength(vertex, x, y, z, stateIndex);
0649 while (track->count_states(pathlength) != 0)
0650 {
0651 pathlength += 1.e-3;
0652 }
0653
0654 SvtxTrackState_v3 state(pathlength);
0655 state.set_name("PHTruthTrackFitter");
0656 state.set_cluskey(cluskey);
0657 state.set_x(x);
0658 state.set_y(y);
0659 state.set_z(z);
0660 state.set_px(px);
0661 state.set_py(py);
0662 state.set_pz(pz);
0663 state.set_localX(local_x);
0664 state.set_localY(local_y);
0665
0666 for (int i = 0; i < 6; ++i)
0667 {
0668 for (int j = i; j < 6; ++j)
0669 {
0670 state.set_error(i, j, 0);
0671 }
0672 }
0673 state.set_error(0, 0, square(m_positionError));
0674 state.set_error(1, 1, square(m_positionError));
0675 state.set_error(2, 2, square(m_zError));
0676
0677 track->insert_state(&state);
0678 return true;
0679 }
0680
0681 float PHTruthTrackFitter::getClusterRadius(TrkrDefs::cluskey cluskey, TrkrCluster* cluster) const
0682 {
0683 if (!m_tGeometry || !cluster)
0684 {
0685 return std::numeric_limits<float>::quiet_NaN();
0686 }
0687
0688 const auto global = m_tGeometry->getGlobalPosition(cluskey, cluster);
0689 const auto radius = std::sqrt(square(global.x()) + square(global.y()));
0690 return std::isfinite(radius) ? radius : std::numeric_limits<float>::quiet_NaN();
0691 }
0692
0693 float PHTruthTrackFitter::getPathLength(const PHG4VtxPoint* vertex,
0694 float x, float y, float z,
0695 unsigned int stateIndex) const
0696 {
0697 if (vertex)
0698 {
0699 const auto dx = x - vertex->get_x();
0700 const auto dy = y - vertex->get_y();
0701 const auto dz = z - vertex->get_z();
0702 const auto pathlength = std::sqrt(square(dx) + square(dy) + square(dz));
0703 if (std::isfinite(pathlength) && pathlength > 0)
0704 {
0705 return pathlength;
0706 }
0707 }
0708
0709 return static_cast<float>(stateIndex);
0710 }
0711
0712 int PHTruthTrackFitter::getCharge(const PHG4Particle* particle,
0713 const TrackSeed* tpcSeed,
0714 const TrackSeed* siliconSeed) const
0715 {
0716 for (const auto* seed : {tpcSeed, siliconSeed})
0717 {
0718 if (!seed)
0719 {
0720 continue;
0721 }
0722
0723 const auto charge = seed->get_charge();
0724 if (std::abs(charge) == 1)
0725 {
0726 return charge;
0727 }
0728 }
0729
0730 const auto* pdg_particle = particle ? TDatabasePDG::Instance()->GetParticle(particle->get_pid()) : nullptr;
0731 if (pdg_particle && pdg_particle->Charge() < 0)
0732 {
0733 return -1;
0734 }
0735
0736 return 1;
0737 }
0738
0739 short int PHTruthTrackFitter::getCrossing(const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const
0740 {
0741 for (const auto* seed : {siliconSeed, tpcSeed})
0742 {
0743 if (!seed)
0744 {
0745 continue;
0746 }
0747
0748 const auto crossing = seed->get_crossing();
0749 if (crossing != std::numeric_limits<short int>::max())
0750 {
0751 return crossing;
0752 }
0753 }
0754
0755 return m_defaultCrossing;
0756 }