Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:21:45

0001 #include "g4evaltools.h"
0002 
0003 #include <mvtx/CylinderGeom_Mvtx.h>
0004 
0005 #include <intt/CylinderGeomIntt.h>
0006 
0007 #include <g4detectors/PHG4CylinderGeomContainer.h>
0008 #include <g4detectors/PHG4TpcGeom.h>
0009 #include <g4detectors/PHG4TpcGeomContainer.h>
0010 
0011 #include <g4tracking/EmbRecoMatchContainer.h>
0012 #include <g4tracking/TrkrTruthTrack.h>
0013 
0014 #include <trackbase_historic/SvtxTrack.h>
0015 #include <trackbase_historic/SvtxTrackMap.h>
0016 
0017 #include <trackbase/ActsGeometry.h>
0018 #include <trackbase/TrkrCluster.h>
0019 #include <trackbase/TrkrClusterContainer.h>
0020 
0021 #include <phool/PHCompositeNode.h>
0022 #include <phool/PHNode.h>  // for PHNode
0023 #include <phool/PHNodeIterator.h>
0024 #include <phool/PHObject.h>  // for PHObject
0025 #include <phool/getClass.h>
0026 #include <phool/phool.h>  // for PHWHERE
0027 
0028 #include <TFile.h>
0029 #include <TObjString.h>
0030 
0031 #include <cmath>
0032 #include <iostream>
0033 #include <numeric>  // for std::accumulate
0034 
0035 namespace G4Eval
0036 {
0037   std::vector<int> unmatchedSvtxTrkIds(EmbRecoMatchContainer* matches, SvtxTrackMap* m_SvtxTrackMap)
0038   {
0039     std::set<unsigned int> ids_matched{};
0040     for (auto trkid : matches->ids_RecoMatched())
0041     {
0042       ids_matched.insert(trkid);
0043     }
0044 
0045     std::set<int> ids_unmatched;
0046     for (auto& reco : *m_SvtxTrackMap)
0047     {
0048       auto trkid = reco.first;
0049       if (!ids_matched.contains(trkid))
0050       {
0051         ids_unmatched.insert(trkid);
0052       }
0053     }
0054     std::vector<int> ids_vec;
0055     ids_vec.reserve(ids_unmatched.size());
0056     for (auto id : ids_unmatched)
0057     {
0058       ids_vec.push_back((int) id);
0059     }
0060     std::sort(ids_vec.begin(), ids_vec.end());
0061     return ids_vec;
0062   }
0063 
0064   // function implementation mostly from
0065   // https://root-forum.cern.ch/t/is-it-possible-to-save-plain-text-in-a-root-file/27674/4
0066   // Note that there is also the code there to read it back from a TFile
0067   void write_StringToTFile(const std::string& msg_name, const std::string& msg)
0068   {
0069     // the string is either written to the current file, or to a new file
0070     // that is named f_outname
0071     TFile* s_current = gDirectory->GetFile();
0072     if (s_current == nullptr)
0073     {
0074       std::cout << PHWHERE << " Error no TFile open to which to wrote the "
0075                 << std::endl
0076                 << " TObjString mesaged." << std::endl;
0077       return;
0078     }
0079     TObjString obj(msg.c_str());
0080     s_current->WriteObject(&obj, msg_name.c_str());
0081     return;
0082   }
0083 
0084   // return the layer of the hit: 0:Mvtx 1:Intt 2:Tpc 3:Tpot
0085   int trklayer_0123(TrkrDefs::hitsetkey key)
0086   {
0087     auto layer = TrkrDefs::getLayer(key);
0088     if (layer < 3)
0089     {
0090       return 0;
0091     }
0092     if (layer < 7)
0093     {
0094       return 1;
0095     }
0096     if (layer < 55)
0097     {
0098       return 2;
0099     }
0100     return 3;
0101   }
0102 
0103   // Implementation of Cluster comparator
0104   TrkrClusterComparer::TrkrClusterComparer(float _nphi_widths, float _nz_widths)
0105     : m_nphi_widths{_nphi_widths}
0106     , m_nz_widths{_nz_widths} {};
0107   int TrkrClusterComparer::init(PHCompositeNode* topNode,
0108                                 const std::string& name_phg4_clusters,
0109                                 const std::string& name_reco_clusters)
0110   {
0111     // fill bin/pixel sizes
0112     // ------ MVTX data ------
0113     PHG4CylinderGeomContainer* geom_container_mvtx = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_MVTX");
0114     if (!geom_container_mvtx)
0115     {
0116       std::cout << PHWHERE << " Could not locate CYLINDERGEOM_MVTX " << std::endl;
0117       return Fun4AllReturnCodes::ABORTRUN;
0118     }
0119     for (int this_layer = 0; this_layer < 3; ++this_layer)
0120     {
0121       auto* layergeom = dynamic_cast<CylinderGeom_Mvtx*>(geom_container_mvtx->GetLayerGeom(this_layer));
0122       const double pitch = layergeom->get_pixel_x();
0123       const double length = layergeom->get_pixel_z();
0124       m_phistep[this_layer] = pitch;
0125       if (this_layer == 0)
0126       {
0127         m_zstep_mvtx = length;
0128       }
0129     }
0130 
0131     // ------ INTT data ------
0132     PHG4CylinderGeomContainer* geom_container_intt = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERGEOM_INTT");
0133     if (!geom_container_intt)
0134     {
0135       std::cout << PHWHERE << " Could not locate CYLINDERGEOM_INTT " << std::endl;
0136       return Fun4AllReturnCodes::ABORTRUN;
0137     }
0138     // get phi and Z steps for intt
0139     for (int this_layer = 3; this_layer < 7; ++this_layer)
0140     {
0141       CylinderGeomIntt* geom =
0142           dynamic_cast<CylinderGeomIntt*>(geom_container_intt->GetLayerGeom(this_layer));
0143       float pitch = geom->get_strip_y_spacing();
0144       m_phistep[this_layer] = pitch;
0145     }
0146 
0147     // ------ TPC data ------
0148     PHG4TpcGeomContainer* geom_tpc =
0149         findNode::getClass<PHG4TpcGeomContainer>(topNode, "TPCGEOMCONTAINER");
0150     if (!geom_tpc)
0151     {
0152       std::cout << PHWHERE << " Could not locate TPCGEOMCONTAINER, abort" << std::endl;
0153       return Fun4AllReturnCodes::ABORTRUN;
0154     }
0155 
0156     for (int this_layer = 7; this_layer < 55; ++this_layer)
0157     {
0158       PHG4TpcGeom* layergeom = geom_tpc->GetLayerCellGeom(this_layer);
0159       if (this_layer == 7)
0160       {
0161         m_zstep_tpc = layergeom->get_zstep();
0162       }
0163       m_phistep[this_layer] = layergeom->get_phistep();
0164     }
0165 
0166     m_TruthClusters =
0167         findNode::getClass<TrkrClusterContainer>(topNode, name_phg4_clusters);
0168     if (!m_TruthClusters)
0169     {
0170       std::cout << PHWHERE << " Could not locate " << name_phg4_clusters << " node" << std::endl;
0171       return Fun4AllReturnCodes::ABORTRUN;
0172     }
0173 
0174     m_RecoClusters =
0175         findNode::getClass<TrkrClusterContainer>(topNode, name_reco_clusters);
0176     if (!m_TruthClusters)
0177     {
0178       std::cout << PHWHERE << " Could not locate " << name_reco_clusters << " node" << std::endl;
0179       return Fun4AllReturnCodes::ABORTRUN;
0180     }
0181 
0182     m_ActsGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0183     if (!m_ActsGeometry)
0184     {
0185       std::cout << PHWHERE << " Could not locate ActsGeometry node" << std::endl;
0186       return Fun4AllReturnCodes::ABORTRUN;
0187     }
0188 
0189     return Fun4AllReturnCodes::EVENT_OK;
0190   }
0191 
0192   // ok return tuple<bool is_match, float stat,
0193   // float delta_phi (in pixels), float half_phi_width (in pixels),
0194   // float half_eta_width (in pixels)
0195   // float delta_z (in bins), flaot
0196   //
0197 
0198   std::pair<bool, float> TrkrClusterComparer::operator()(TrkrDefs::cluskey key_T, TrkrDefs::cluskey key_R)
0199   {
0200     // note: can use returned values, or just pull from these values
0201     layer = TrkrDefs::getLayer(key_T);
0202     if (layer > 55)
0203     {
0204       std::cout << " Error! Trying to compar cluster in layer > 55, "
0205                 << "which is not programmed yet!" << std::endl;
0206       return {false, 0.};
0207     }
0208 
0209     in_mvtx = (layer < 3);
0210     in_intt = (layer > 2 && layer < 7);
0211     in_tpc = (layer > 6 && layer < 55);
0212 
0213     float phi_step = m_phistep[layer];
0214     float z_step = in_mvtx ? m_zstep_mvtx : m_zstep_tpc;
0215 
0216     clus_T = m_TruthClusters->findCluster(key_T);
0217     clus_R = m_RecoClusters->findCluster(key_R);
0218 
0219     phi_T = clus_T->getPosition(0);
0220     phi_R = clus_R->getPosition(0);
0221     phisize_R = clus_R->getPhiSize() * m_nphi_widths;  // * phi_step;
0222     phisize_T = clus_T->getPhiSize() * m_nphi_widths;  // * phi_step; // only for user to get, if they want
0223 
0224     z_T = clus_T->getPosition(1);
0225     z_R = clus_R->getPosition(1);
0226 
0227     if (!in_intt)
0228     {
0229       zsize_R = clus_R->getZSize() * m_nz_widths;  // * z_step;
0230       zsize_T = clus_R->getZSize() * m_nz_widths;  // * z_step;
0231     }
0232 
0233     phi_delta = std::abs(phi_T - phi_R);
0234     while (phi_delta > M_PI)
0235     {
0236       phi_delta = fabs(phi_delta - 2 * M_PI);
0237     }
0238     phi_delta /= phi_step;
0239 
0240     z_delta = std::abs(z_T - z_R) / z_step;
0241 
0242     /* float phi_stat = (m_nphi_widths * phisize_R ); */
0243 
0244     float phi_stat = std::max(phisize_T, phisize_R);
0245     float fit_statistic = (phi_delta / phi_stat);
0246     is_match = (fit_statistic <= 1.);
0247 
0248     float z_stat = 0;
0249     if (!in_intt)
0250     {
0251       z_stat = std::max(zsize_T, zsize_R);
0252 
0253       is_match = is_match && (z_delta < z_stat);
0254       fit_statistic += z_delta / z_stat;
0255     }
0256     return {is_match, fit_statistic};
0257   }
0258 
0259   ClusLoc TrkrClusterComparer::clusloc_PHG4(
0260       std::pair<TrkrDefs::hitsetkey, TrkrDefs::cluskey> input)
0261   {
0262     auto* cluster = m_TruthClusters->findCluster(input.second);
0263     Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(input.second, cluster);
0264     return {TrkrDefs::getLayer(input.first), gloc,
0265             (int) cluster->getPhiSize(), (int) cluster->getZSize()};
0266   }
0267 
0268   ClusLoc TrkrClusterComparer::clusloc_SVTX(
0269       std::pair<TrkrDefs::hitsetkey, TrkrDefs::cluskey> input)
0270   {
0271     auto* cluster = m_RecoClusters->findCluster(input.second);
0272     Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(input.second, cluster);
0273     return {TrkrDefs::getLayer(input.first), gloc,
0274             (int) cluster->getPhiSize(), (int) cluster->getZSize()};
0275   }
0276 
0277   // Implementation of the iterable struct to get cluster keys from
0278   // a SvtxTrack. It is used like:
0279   // for (auto& cluskey : ClusKeyIter(svtx_track)) {
0280   //    ... // do things with cluster keys
0281   // }
0282   ClusKeyIter::ClusKeyIter(SvtxTrack* _track)
0283     : track{_track}
0284     , in_silicon{_track->get_silicon_seed() != nullptr}
0285     , has_tpc{_track->get_tpc_seed() != nullptr}
0286     , no_data{!in_silicon && !has_tpc}
0287   {
0288   }
0289 
0290   ClusKeyIter ClusKeyIter::begin() const
0291   {
0292     ClusKeyIter iter0{track};
0293     if (iter0.no_data)
0294     {
0295       return iter0;
0296     }
0297     if (iter0.in_silicon)
0298     {
0299       iter0.iter = track->get_silicon_seed()->begin_cluster_keys();
0300       iter0.iter_end_silicon = track->get_silicon_seed()->end_cluster_keys();
0301     }
0302     else if (has_tpc)
0303     {
0304       iter0.iter = track->get_tpc_seed()->begin_cluster_keys();
0305     }
0306     return iter0;
0307   }
0308 
0309   ClusKeyIter ClusKeyIter::end() const
0310   {
0311     ClusKeyIter iter0{track};
0312     if (iter0.no_data)
0313     {
0314       return iter0;
0315     }
0316     if (has_tpc)
0317     {
0318       iter0.iter = track->get_tpc_seed()->end_cluster_keys();
0319     }
0320     else if (in_silicon)
0321     {
0322       iter0.iter = track->get_silicon_seed()->end_cluster_keys();
0323     }
0324     return iter0;
0325   }
0326 
0327   void ClusKeyIter::operator++()
0328   {
0329     if (no_data)
0330     {
0331       return;
0332     }
0333     ++iter;
0334     if (in_silicon && has_tpc && iter == iter_end_silicon)
0335     {
0336       in_silicon = false;
0337       iter = track->get_tpc_seed()->begin_cluster_keys();
0338     }
0339   }
0340 
0341   bool ClusKeyIter::operator!=(const ClusKeyIter& rhs) const
0342   {
0343     if (no_data)
0344     {
0345       return false;
0346     }
0347     return iter != rhs.iter;
0348   }
0349 
0350   TrkrDefs::cluskey ClusKeyIter::operator*() const
0351   {
0352     return *iter;
0353   }
0354 
0355   TrkrClusterContainer* ClusCntr::get_PHG4_clusters()
0356   {
0357     if (comp == nullptr)
0358     {
0359       return nullptr;
0360     }
0361 
0362     return comp->m_TruthClusters;
0363   }
0364 
0365   TrkrClusterContainer* ClusCntr::get_SVTX_clusters()
0366   {
0367     if (comp == nullptr)
0368     {
0369       return nullptr;
0370     }
0371 
0372     return comp->m_RecoClusters;
0373   }
0374 
0375   std::array<int, 5> ClusCntr::cntclus(Vector& keys)
0376   {
0377     std::array<int, 5> cnt{0, 0, 0, 0, 0};
0378     for (auto& it : keys)
0379     {
0380       cnt[trklayer_0123(it.first)] += 1;
0381     }
0382     for (int i = 0; i < 4; ++i)
0383     {
0384       cnt[4] += cnt[i];
0385     }
0386     return cnt;
0387   }
0388 
0389   std::array<int, 5> ClusCntr::cnt_matchedclus(Vector& keys, std::vector<bool>& matches)
0390   {
0391     std::array<int, 5> cnt{0, 0, 0, 0, 0};
0392     if (keys.size() != matches.size())
0393     {
0394       std::cout << PHWHERE << " matching and key vector not the same size. "
0395                 << std::endl
0396                 << " run find_matches() first." << std::endl;
0397       return cnt;
0398     }
0399     for (unsigned int i = 0; i < keys.size(); ++i)
0400     {
0401       if (matches[i])
0402       {
0403         cnt[trklayer_0123(keys[i].first)] += 1;
0404       }
0405     }
0406     for (int i = 0; i < 4; ++i)
0407     {
0408       cnt[4] += cnt[i];
0409     }
0410     return cnt;
0411   }
0412 
0413   int ClusCntr::addClusKeys(SvtxTrack* track)
0414   {
0415     svtx_keys.clear();
0416     for (auto ckey : ClusKeyIter(track))
0417     {
0418       svtx_keys.emplace_back(TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey);
0419     }
0420     std::sort(svtx_keys.begin(), svtx_keys.end());
0421     return svtx_keys.size();
0422   }
0423 
0424   int ClusCntr::addClusKeys(TrkrTruthTrack* track)
0425   {
0426     phg4_keys.clear();
0427     for (auto ckey : track->getClusters())
0428     {
0429       phg4_keys.emplace_back(TrkrDefs::getHitSetKeyFromClusKey(ckey), ckey);
0430     }
0431     std::sort(phg4_keys.begin(), phg4_keys.end());
0432     return phg4_keys.size();
0433   }
0434 
0435   void ClusCntr::reset()
0436   {
0437     phg4_keys.clear();
0438     phg4_matches.clear();
0439     svtx_keys.clear();
0440     svtx_matches.clear();
0441   }
0442 
0443   std::array<int, 3> ClusCntr::find_matches()
0444   {
0445     if (comp == nullptr)
0446     {
0447       std::cout << PHWHERE
0448                 << " Won't compare tracks because of missing TrkrClusterComparer" << std::endl;
0449       return {0, 0, 0};
0450     }
0451     // find the matches between the svtx_keys and phg4_keys
0452     // also keep track of the sum of the comparison between then
0453 
0454     // ---------------------------------
0455     // set aliases for notation cleaness
0456     // use A for PHG4 and B for SVTX
0457     auto& vA = phg4_keys;
0458     auto& vB = svtx_keys;
0459 
0460     auto& matchesA = phg4_matches;
0461     auto& matchesB = svtx_matches;
0462 
0463     match_stat = 0.;
0464 
0465     // matches will say, cluster by cluster, which clusters are matched
0466     matchesA = std::vector<bool>(vA.size(), false);
0467     matchesB = std::vector<bool>(vB.size(), false);
0468 
0469     // user iterators to access the vectors
0470     auto iA0 = vA.begin();
0471     auto iA1 = vA.end();
0472 
0473     auto iB0 = vB.begin();
0474     auto iB1 = vB.end();
0475 
0476     auto iA = iA0;
0477     auto iB = iB0;
0478 
0479     int n_match{0};
0480 
0481     while (iA != iA1 && iB != iB1)
0482     {
0483       if (iA->first == iB->first)
0484       {
0485         auto hitset = iA->first;
0486 
0487         // must compare ALL sets of iA and iB with this same hitset
0488         auto sAend = iA + 1;  // search A end
0489         while (sAend != iA1 && sAend->first == hitset)
0490         {
0491           ++sAend;
0492         }
0493 
0494         auto sBend = iB + 1;  // search B end
0495         while (sBend != iB1 && sBend->first == hitset)
0496         {
0497           ++sBend;
0498         }
0499 
0500         for (auto A = iA; A != sAend; ++A)
0501         {
0502           for (auto B = iB; B != sBend; ++B)
0503           {
0504             auto comp_val = comp->operator()(A->second, B->second);
0505             if (comp_val.first)
0506             {
0507               matchesA[A - iA0] = true;
0508               matchesB[B - iB0] = true;
0509               match_stat += comp_val.second;
0510               ++n_match;
0511             }
0512           }
0513         }
0514         iA = sAend;
0515         iB = sBend;
0516       }
0517       else if (iA->first < iB->first)
0518       {
0519         ++iA;
0520       }
0521       else
0522       {
0523         ++iB;
0524       }
0525     }
0526     return {n_match, (int) phg4_keys.size(), (int) svtx_keys.size()};
0527   }
0528 
0529   std::array<int, 3> ClusCntr::find_matches(TrkrTruthTrack* g4_track, SvtxTrack* sv_track)
0530   {
0531     addClusKeys(sv_track);
0532     addClusKeys(g4_track);
0533     return find_matches();
0534   }
0535 
0536   int ClusCntr::phg4_n_matched()
0537   {
0538     return std::accumulate(phg4_matches.begin(), phg4_matches.end(), 0);
0539   }
0540 
0541   int ClusCntr::svtx_n_matched()
0542   {
0543     return std::accumulate(svtx_matches.begin(), svtx_matches.end(), 0);
0544   }
0545 
0546   std::vector<ClusLoc> ClusCntr::phg4_clusloc_all()
0547   {
0548     std::vector<ClusLoc> vec{};
0549     for (auto& cluspair : phg4_keys)
0550     {
0551       vec.push_back(comp->clusloc_PHG4(cluspair));
0552     }
0553     return vec;
0554   }
0555 
0556   std::vector<ClusLoc> ClusCntr::phg4_clusloc_unmatched()
0557   {
0558     std::vector<ClusLoc> vec{};
0559     auto cnt = phg4_keys.size();
0560     for (unsigned int i = 0; i < cnt; ++i)
0561     {
0562       if (!phg4_matches[i])
0563       {
0564         vec.push_back(comp->clusloc_PHG4(phg4_keys[i]));
0565       }
0566     }
0567     return vec;
0568   }
0569 
0570   std::vector<ClusLoc> ClusCntr::svtx_clusloc_all()
0571   {
0572     std::vector<ClusLoc> vec{};
0573     for (auto& cluspair : svtx_keys)
0574     {
0575       vec.push_back(comp->clusloc_SVTX(cluspair));
0576     }
0577     return vec;
0578   }
0579 
0580   std::vector<ClusLoc> ClusCntr::svtx_clusloc_unmatched()
0581   {
0582     std::vector<ClusLoc> vec{};
0583     auto cnt = svtx_keys.size();
0584     for (unsigned int i = 0; i < cnt; ++i)
0585     {
0586       if (!svtx_matches[i])
0587       {
0588         vec.push_back(comp->clusloc_SVTX(svtx_keys[i]));
0589       }
0590     }
0591     return vec;
0592   }
0593 
0594   std::vector<ClusLoc> ClusCntr::clusloc_matched()
0595   {
0596     std::vector<ClusLoc> vec{};
0597     auto cnt = phg4_keys.size();
0598     for (unsigned int i = 0; i < cnt; ++i)
0599     {
0600       if (phg4_matches[i])
0601       {
0602         vec.push_back(comp->clusloc_PHG4(phg4_keys[i]));
0603       }
0604     }
0605     return vec;
0606   }
0607 
0608   /* ClusCntr::layer_xyzLoc ClusCntr::xyzLoc(std::pair<TrkrDefs::hitsetkey,TrkrDefs::cluskey) { */
0609   /*   if (geom == nullptr) { */
0610   /*     std::cout << PHWHERE << " fatal: geom, type ActsGeometry*, must be set to call xyzLoc!" << std::endl; */
0611   /*     return {-1,{std::numeric_limits<float>::max(),std::numeric_limits<float>::max(),std::numeric_limits<float>::max()}}; */
0612   /*   } */
0613   /*   Eigen::Vector3d gloc =    m_ActsGeometry->getGlobalPosition(reco_ckey, cluster); */
0614   /* } */
0615 
0616 }  // namespace G4Eval