Back to home page

sPhenix code displayed by LXR

 
 

    


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 }  // namespace
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 * /*unused*/)
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 * /*unused*/)
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       //! update track 1 in case more clusters have been added
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         //! If field on, treat the circle radius as "slope"
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       //! Check if the rz slope is close to 0 corresponding to an chain of clusters
0136       //! from an ion tail
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         //! If field on, treat the circle radius as "slope"
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       // float tr2xyint = std::get<1>(xyTr2Params);
0187       // float tr2rzint = std::get<1>(rzTr2Params);
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           //! check on common cluskeys
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         //! erase track 2
0226         m_seeds->erase(m_seeds->index(tr2it));
0227       }
0228     }
0229 
0230     //! remove any obvious outlier clusters from the track that were mistakenly
0231     //! picked up by the seeder
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     // skip tpot clusters, as they are always bad in 1D due to 1D resolution
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     //! combine layers 3/4 and 5/6 since they are half layers
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       //! add all tpot clusters, since they are 1d
0397       tpotClus.emplace_back(glob.first[i]);
0398     }
0399   }
0400   seed->identify();
0401   // now erase all cluskeys and fill with the new set of cluskeys
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     // skip tpot clusters, as they are always bad in 1D due to 1D resolution
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     // skip tpot clusters, as they are always bad in 1D due to 1D resolution
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     //! exclude silicon from DCAz cut
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 * /*unused*/)
0517 {
0518   return Fun4AllReturnCodes::EVENT_OK;
0519 }