File indexing completed on 2025-08-06 08:18:29
0001
0002 #include "PHCosmicTrackMerger.h"
0003
0004 #include <trackbase/ActsGeometry.h>
0005 #include <trackbase/TrackFitUtils.h>
0006 #include <trackbase/TrkrClusterContainer.h>
0007
0008 #include <trackbase_historic/TrackSeedContainer.h>
0009
0010 #include <fun4all/Fun4AllReturnCodes.h>
0011
0012 #include <phool/PHCompositeNode.h>
0013 #include <phool/getClass.h>
0014
0015 #include <cmath>
0016 #include <limits>
0017
0018 namespace
0019 {
0020 template <class T>
0021 inline constexpr T square(T &x)
0022 {
0023 return x * x;
0024 }
0025 template <class T>
0026 inline constexpr T r(T &x, T &y)
0027 {
0028 return std::sqrt(square(x) + square(y));
0029 }
0030
0031 }
0032
0033 PHCosmicTrackMerger::PHCosmicTrackMerger(const std::string &name)
0034 : SubsysReco(name)
0035 {
0036 }
0037
0038
0039 PHCosmicTrackMerger::~PHCosmicTrackMerger() = default;
0040
0041
0042 int PHCosmicTrackMerger::Init(PHCompositeNode * )
0043 {
0044 return Fun4AllReturnCodes::EVENT_OK;
0045 }
0046
0047
0048 int PHCosmicTrackMerger::InitRun(PHCompositeNode *topNode)
0049 {
0050 m_seeds = findNode::getClass<TrackSeedContainer>(topNode, "SvtxTrackSeedContainer");
0051 if (!m_seeds)
0052 {
0053 std::cout << PHWHERE << "No track seed container, cannot continue" << std::endl;
0054 return Fun4AllReturnCodes::ABORTRUN;
0055 }
0056
0057 m_siliconSeeds = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
0058 m_tpcSeeds = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
0059 if (!m_siliconSeeds or !m_tpcSeeds)
0060 {
0061 std::cout << PHWHERE << "Missing seed container, exiting." << std::endl;
0062 return Fun4AllReturnCodes::ABORTRUN;
0063 }
0064
0065 m_geometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0066 if (!m_geometry)
0067 {
0068 std::cout << PHWHERE << "no acts geometry, can't continue" << std::endl;
0069 return Fun4AllReturnCodes::ABORTRUN;
0070 }
0071
0072 m_clusterMap = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0073 if (!m_clusterMap)
0074 {
0075 std::cout << PHWHERE << "no cluster map, can't continue" << std::endl;
0076 return Fun4AllReturnCodes::ABORTRUN;
0077 }
0078
0079 return Fun4AllReturnCodes::EVENT_OK;
0080 }
0081
0082
0083 int PHCosmicTrackMerger::process_event(PHCompositeNode * )
0084 {
0085 if (Verbosity() > 3)
0086 {
0087 std::cout << "Seed container size " << m_seeds->size() << std::endl;
0088 }
0089
0090 for (auto tr1it = m_seeds->begin(); tr1it != m_seeds->end();
0091 ++tr1it)
0092 {
0093 auto track1 = *tr1it;
0094 if (!track1)
0095 {
0096 continue;
0097 }
0098 unsigned int tpcid1 = track1->get_tpc_seed_index();
0099 unsigned int siid1 = track1->get_silicon_seed_index();
0100 auto tpcseed1 = m_tpcSeeds->get(tpcid1);
0101 auto silseed1 = m_siliconSeeds->get(siid1);
0102
0103 for (auto tr2it = tr1it; tr2it != m_seeds->end();
0104 ++tr2it)
0105 {
0106
0107 TrackFitUtils::position_vector_t tr1_rz_pts, tr1_xy_pts;
0108 auto globTr1 = getGlobalPositions(tpcseed1);
0109 for (auto &pos : globTr1.second)
0110 {
0111 float clusr = r(pos.x(), pos.y());
0112 if (pos.y() < 0)
0113 {
0114 clusr *= -1;
0115 }
0116 tr1_rz_pts.push_back(std::make_pair(pos.z(), clusr));
0117 tr1_xy_pts.push_back(std::make_pair(pos.x(), pos.y()));
0118 }
0119
0120 float tr1xyslope = std::numeric_limits<float>::quiet_NaN();
0121 if (m_zeroField)
0122 {
0123 auto xyTr1Params = TrackFitUtils::line_fit(tr1_xy_pts);
0124 tr1xyslope = std::get<0>(xyTr1Params);
0125 }
0126 else
0127 {
0128
0129 auto xyTr1Params = TrackFitUtils::circle_fit_by_taubin(tr1_xy_pts);
0130 tr1xyslope = std::get<0>(xyTr1Params);
0131 }
0132
0133 auto rzTr1Params = TrackFitUtils::line_fit(tr1_rz_pts);
0134 float tr1rzslope = std::get<0>(rzTr1Params);
0135
0136
0137 if (std::fabs(tr1rzslope) < 0.005)
0138 {
0139 m_seeds->erase(m_seeds->index(tr1it));
0140 break;
0141 }
0142 if (tr1it == tr2it)
0143 {
0144 continue;
0145 }
0146
0147 auto track2 = *tr2it;
0148 if (!track2)
0149 {
0150 continue;
0151 }
0152
0153 unsigned int tpcid2 = track2->get_tpc_seed_index();
0154 unsigned int siid2 = track2->get_silicon_seed_index();
0155 auto tpcseed2 = m_tpcSeeds->get(tpcid2);
0156 auto silseed2 = m_siliconSeeds->get(siid2);
0157
0158 TrackFitUtils::position_vector_t tr2_rz_pts, tr2_xy_pts;
0159 auto globTr2 = getGlobalPositions(tpcseed2);
0160
0161 for (auto &pos : globTr2.second)
0162 {
0163 float clusr = r(pos.x(), pos.y());
0164 if (pos.y() < 0)
0165 {
0166 clusr *= -1;
0167 }
0168 tr2_rz_pts.push_back(std::make_pair(pos.z(), clusr));
0169 tr2_xy_pts.push_back(std::make_pair(pos.x(), pos.y()));
0170 }
0171
0172 float tr2xyslope = std::numeric_limits<float>::quiet_NaN();
0173 if (m_zeroField)
0174 {
0175 auto xyTr2Params = TrackFitUtils::line_fit(tr2_xy_pts);
0176 tr2xyslope = std::get<0>(xyTr2Params);
0177 }
0178 else
0179 {
0180
0181 auto xyTr2Params = TrackFitUtils::circle_fit_by_taubin(tr2_xy_pts);
0182 tr2xyslope = std::get<0>(xyTr2Params);
0183 }
0184
0185 auto rzTr2Params = TrackFitUtils::line_fit(tr2_rz_pts);
0186
0187
0188 float tr2rzslope = std::get<0>(rzTr2Params);
0189
0190 std::vector<TrkrDefs::cluskey> ckeyUnion;
0191 std::set_intersection(globTr1.first.begin(), globTr1.first.end(),
0192 globTr2.first.begin(), globTr2.first.end(), std::back_inserter(ckeyUnion));
0193
0194 if (
0195
0196 (ckeyUnion.size() > 10) or
0197 (m_zeroField and std::fabs(tr1xyslope - tr2xyslope) < 0.5 and std::fabs(tr1rzslope - tr2rzslope * -1) < 0.5) or
0198 (!m_zeroField and std::fabs(tr1xyslope - tr2xyslope) < 0.03 and (std::fabs(tr1rzslope - tr2rzslope * -1) < 1)))
0199 {
0200 if (Verbosity() > 3)
0201 {
0202 std::cout << "Combining tr" << m_seeds->index(tr1it) << " with sil/tpc " << tpcid1
0203 << ", " << siid1 << " with tr "
0204 << m_seeds->index(tr2it) << " with sil/tpc " << tpcid2 << ", "
0205 << siid2 << " with slopes "
0206 << tr1xyslope << ", " << tr2xyslope << ", "
0207 << tr1rzslope << ", " << tr2rzslope << " and ckey union "
0208 << ckeyUnion.size() << std::endl;
0209 }
0210
0211 for (auto &key : globTr2.first)
0212 {
0213 globTr1.first.push_back(key);
0214 }
0215 for (auto &pos : globTr2.second)
0216 {
0217 globTr1.second.push_back(pos);
0218 }
0219
0220 addKeys(tpcseed1, tpcseed2);
0221 if (silseed1 && silseed2)
0222 {
0223 addKeys(silseed1, silseed2);
0224 }
0225
0226 m_seeds->erase(m_seeds->index(tr2it));
0227 }
0228 }
0229
0230
0231
0232 if (m_removeOutliers)
0233 {
0234 if (m_iter == 1)
0235 {
0236 getBestClustersPerLayer(tpcseed1);
0237 if (silseed1)
0238 {
0239 getBestClustersPerLayer(silseed1);
0240 }
0241 }
0242
0243 removeOutliers(tpcseed1);
0244 if (silseed1)
0245 {
0246 removeOutliers(silseed1);
0247 }
0248 }
0249 }
0250 if (Verbosity() > 3)
0251 {
0252 std::cout << "Seed container size to finish " << m_seeds->size() << std::endl;
0253 for (auto &seed : *m_seeds)
0254 {
0255 if (seed)
0256 {
0257 seed->identify();
0258 std::cout << std::endl;
0259 unsigned int tpcid1 = seed->get_tpc_seed_index();
0260 unsigned int siid1 = seed->get_silicon_seed_index();
0261 auto tpcseed1 = m_tpcSeeds->get(tpcid1);
0262 auto silseed1 = m_siliconSeeds->get(siid1);
0263 tpcseed1->identify();
0264 if (silseed1)
0265 {
0266 silseed1->identify();
0267 }
0268 }
0269 else
0270 {
0271 std::cout << "nullptr seed was removed" << std::endl;
0272 }
0273 }
0274 }
0275 return Fun4AllReturnCodes::EVENT_OK;
0276 }
0277
0278 void PHCosmicTrackMerger::getBestClustersPerLayer(TrackSeed *seed)
0279 {
0280 TrackFitUtils::position_vector_t tr_rz_pts, tr_xy_pts;
0281
0282 auto glob = getGlobalPositions(seed);
0283
0284 for (const auto &pos : glob.second)
0285 {
0286 float clusr = r(pos.x(), pos.y());
0287 if (pos.y() < 0)
0288 {
0289 clusr *= -1;
0290 }
0291
0292 if (std::fabs(clusr) > 80.)
0293 {
0294 continue;
0295 }
0296 tr_rz_pts.push_back(std::make_pair(pos.z(), clusr));
0297 tr_xy_pts.push_back(std::make_pair(pos.x(), pos.y()));
0298 }
0299
0300 auto xyParams = TrackFitUtils::line_fit(tr_xy_pts);
0301 auto rzParams = TrackFitUtils::line_fit(tr_rz_pts);
0302 std::map<int, std::pair<float, float>> bestLayerDcasxy, bestLayerDcasrz;
0303 std::map<int, std::pair<TrkrDefs::cluskey, TrkrDefs::cluskey>> bestLayerCluskeys;
0304 for (int i = 0; i < 57; i++)
0305 {
0306 bestLayerDcasrz.insert(std::make_pair(i, std::make_pair(std::numeric_limits<float>::max(), std::numeric_limits<float>::max())));
0307 bestLayerDcasxy.insert(std::make_pair(i, std::make_pair(std::numeric_limits<float>::max(), std::numeric_limits<float>::max())));
0308 bestLayerCluskeys.insert(std::make_pair(i, std::make_pair(0, 0)));
0309 }
0310
0311 std::vector<TrkrDefs::cluskey> tpotClus;
0312 for (unsigned int i = 0; i < glob.first.size(); i++)
0313 {
0314 auto &pos = glob.second[i];
0315 float clusr = r(pos.x(), pos.y());
0316 if (pos.y() < 0)
0317 {
0318 clusr *= -1;
0319 }
0320
0321 float perpxyslope = -1. / std::get<0>(xyParams);
0322 float perpxyint = pos.y() - perpxyslope * pos.x();
0323 float perprzslope = -1. / std::get<0>(rzParams);
0324 float perprzint = clusr - perprzslope * pos.z();
0325
0326 float pcax = (perpxyint - std::get<1>(xyParams)) / (std::get<0>(xyParams) - perpxyslope);
0327 float pcay = std::get<0>(xyParams) * pcax + std::get<1>(xyParams);
0328
0329 float pcaz = (perprzint - std::get<1>(rzParams)) / (std::get<0>(rzParams) - perprzslope);
0330 float pcar = std::get<0>(rzParams) * pcaz + std::get<1>(rzParams);
0331 float dcax = pcax - pos.x();
0332 float dcay = pcay - pos.y();
0333 float dcar = pcar - clusr;
0334 float dcaz = pcaz - pos.z();
0335 float dcaxy = std::sqrt(square(dcax) + square(dcay));
0336 float dcarz = std::sqrt(square(dcar) + square(dcaz));
0337 auto trkid = TrkrDefs::getTrkrId(glob.first[i]);
0338 auto layer = TrkrDefs::getLayer(glob.first[i]);
0339
0340 if (layer == 4)
0341 {
0342 layer = 3;
0343 }
0344 if (layer == 6)
0345 {
0346 layer = 5;
0347 }
0348 float dcaxydiff1 = std::fabs(dcaxy - bestLayerDcasxy.find(layer)->second.first);
0349 float dcaxydiff2 = std::fabs(dcaxy - bestLayerDcasxy.find(layer)->second.second);
0350 if (trkid == TrkrDefs::TrkrId::mvtxId || trkid == TrkrDefs::TrkrId::tpcId)
0351 {
0352 if (dcaxydiff1 > dcaxydiff2)
0353 {
0354 if (dcaxy < bestLayerDcasxy.find(layer)->second.first &&
0355 dcarz < bestLayerDcasrz.find(layer)->second.first)
0356 {
0357 bestLayerDcasxy.find(layer)->second.first = dcaxy;
0358 bestLayerDcasrz.find(layer)->second.first = dcarz;
0359 bestLayerCluskeys.find(layer)->second.first = glob.first[i];
0360 }
0361 }
0362 else
0363 {
0364 if (dcaxy < bestLayerDcasxy.find(layer)->second.second &&
0365 dcarz < bestLayerDcasrz.find(layer)->second.second)
0366 {
0367 bestLayerDcasxy.find(layer)->second.second = dcaxy;
0368 bestLayerDcasrz.find(layer)->second.second = dcarz;
0369 bestLayerCluskeys.find(layer)->second.second = glob.first[i];
0370 }
0371 }
0372 }
0373 else if (trkid == TrkrDefs::TrkrId::inttId)
0374 {
0375 if (dcaxydiff1 > dcaxydiff2)
0376 {
0377 if (dcaxy < bestLayerDcasxy.find(layer)->second.first)
0378 {
0379 bestLayerDcasxy.find(layer)->second.first = dcaxy;
0380 bestLayerDcasrz.find(layer)->second.first = dcarz;
0381 bestLayerCluskeys.find(layer)->second.first = glob.first[i];
0382 }
0383 }
0384 else
0385 {
0386 if (dcaxy < bestLayerDcasxy.find(layer)->second.second)
0387 {
0388 bestLayerDcasxy.find(layer)->second.second = dcaxy;
0389 bestLayerDcasrz.find(layer)->second.second = dcarz;
0390 bestLayerCluskeys.find(layer)->second.second = glob.first[i];
0391 }
0392 }
0393 }
0394 else if (trkid == TrkrDefs::TrkrId::micromegasId)
0395 {
0396
0397 tpotClus.emplace_back(glob.first[i]);
0398 }
0399 }
0400 seed->identify();
0401
0402 seed->clear_cluster_keys();
0403 for (auto &[layer, keypair] : bestLayerCluskeys)
0404 {
0405 for (auto &key : {keypair.first, keypair.second})
0406 {
0407 if (key > 0)
0408 {
0409 seed->insert_cluster_key(key);
0410 }
0411 }
0412 }
0413 for (auto &key : tpotClus)
0414 {
0415 seed->insert_cluster_key(key);
0416 }
0417 }
0418 void PHCosmicTrackMerger::removeOutliers(TrackSeed *seed)
0419 {
0420 TrackFitUtils::position_vector_t tr_rz_pts, tr_xy_pts;
0421 auto glob = getGlobalPositions(seed);
0422 for (const auto &pos : glob.second)
0423 {
0424 float clusr = r(pos.x(), pos.y());
0425 if (pos.y() < 0)
0426 {
0427 clusr *= -1;
0428 }
0429
0430 if (std::fabs(clusr) > 80.)
0431 {
0432 continue;
0433 }
0434 tr_rz_pts.push_back(std::make_pair(pos.z(), clusr));
0435 tr_xy_pts.push_back(std::make_pair(pos.x(), pos.y()));
0436 }
0437
0438 auto xyParams = TrackFitUtils::line_fit(tr_xy_pts);
0439 auto rzParams = TrackFitUtils::line_fit(tr_rz_pts);
0440
0441 for (unsigned int i = 0; i < glob.first.size(); i++)
0442 {
0443 auto &pos = glob.second[i];
0444 float clusr = r(pos.x(), pos.y());
0445 if (pos.y() < 0)
0446 {
0447 clusr *= -1;
0448 }
0449
0450 if (std::fabs(clusr) > 80.)
0451 {
0452 continue;
0453 }
0454 float perpxyslope = -1. / std::get<0>(xyParams);
0455 float perpxyint = pos.y() - perpxyslope * pos.x();
0456 float perprzslope = -1. / std::get<0>(rzParams);
0457 float perprzint = clusr - perprzslope * pos.z();
0458
0459 float pcax = (perpxyint - std::get<1>(xyParams)) / (std::get<0>(xyParams) - perpxyslope);
0460 float pcay = std::get<0>(xyParams) * pcax + std::get<1>(xyParams);
0461
0462 float pcaz = (perprzint - std::get<1>(rzParams)) / (std::get<0>(rzParams) - perprzslope);
0463 float pcar = std::get<0>(rzParams) * pcaz + std::get<1>(rzParams);
0464 float dcax = pcax - pos.x();
0465 float dcay = pcay - pos.y();
0466 float dcar = pcar - clusr;
0467 float dcaz = pcaz - pos.z();
0468 float dcaxy = std::sqrt(square(dcax) + square(dcay));
0469 float dcarz = std::sqrt(square(dcar) + square(dcaz));
0470
0471
0472 if (dcaxy > m_dcaxycut ||
0473 (dcarz > m_dcarzcut && (r(pos.x(), pos.y()) > 20)))
0474 {
0475 if (Verbosity() > 2)
0476 {
0477 std::cout << "Erasing ckey " << glob.first[i] << " with position " << pos.transpose() << std::endl;
0478 }
0479 seed->erase_cluster_key(glob.first[i]);
0480 }
0481 }
0482 }
0483 void PHCosmicTrackMerger::addKeys(TrackSeed *toAddTo, TrackSeed *toAdd)
0484 {
0485 for (auto it = toAdd->begin_cluster_keys(); it != toAdd->end_cluster_keys();
0486 ++it)
0487 {
0488 if (Verbosity() > 3)
0489 {
0490 auto clus = m_clusterMap->findCluster(*it);
0491 auto glob = m_geometry->getGlobalPosition(*it, clus);
0492 std::cout << "adding " << *it << " with pos " << glob.transpose() << std::endl;
0493 }
0494 toAddTo->insert_cluster_key(*it);
0495 }
0496 }
0497 PHCosmicTrackMerger::KeyPosMap
0498 PHCosmicTrackMerger::getGlobalPositions(TrackSeed *seed)
0499 {
0500 KeyPosMap glob;
0501 std::vector<TrkrDefs::cluskey> ckeys;
0502 std::vector<Acts::Vector3> positions;
0503 for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys();
0504 ++it)
0505 {
0506 auto key = *it;
0507 auto clus = m_clusterMap->findCluster(key);
0508 ckeys.push_back(key);
0509 positions.push_back(m_geometry->getGlobalPosition(key, clus));
0510 }
0511 glob.first = ckeys;
0512 glob.second = positions;
0513 return glob;
0514 }
0515
0516 int PHCosmicTrackMerger::End(PHCompositeNode * )
0517 {
0518 return Fun4AllReturnCodes::EVENT_OK;
0519 }