Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:18:30

0001 /*!
0002  *  \file       PHGenFitTrkFitter.C
0003  *  \brief      Refit SvtxTracks with PHGenFit.
0004  *  \details    Refit SvtxTracks with PHGenFit.
0005  *  \author     Haiwang Yu <yuhw@nmsu.edu>
0006  */
0007 
0008 #include "PHGenFitTrkFitter.h"
0009 
0010 #include <fun4all/Fun4AllReturnCodes.h>
0011 #include <fun4all/PHTFileServer.h>
0012 #include <fun4all/SubsysReco.h>  // for SubsysReco
0013 
0014 #include <g4detectors/PHG4CylinderGeom.h>  // for PHG4CylinderGeom
0015 #include <g4detectors/PHG4CylinderGeomContainer.h>
0016 
0017 #include <intt/CylinderGeomIntt.h>
0018 #include <intt/CylinderGeomInttHelper.h>
0019 
0020 #include <micromegas/CylinderGeomMicromegas.h>
0021 #include <micromegas/MicromegasDefs.h>
0022 
0023 #include <mvtx/CylinderGeom_Mvtx.h>
0024 #include <mvtx/CylinderGeom_MvtxHelper.h>
0025 
0026 #include <phfield/PHFieldUtility.h>
0027 
0028 #include <phgenfit/Fitter.h>
0029 #include <phgenfit/Measurement.h>  // for Measurement
0030 #include <phgenfit/PlanarMeasurement.h>
0031 #include <phgenfit/SpacepointMeasurement.h>
0032 #include <phgenfit/Track.h>
0033 
0034 #include <phgeom/PHGeomUtility.h>
0035 
0036 #include <phool/PHCompositeNode.h>
0037 #include <phool/PHIODataNode.h>
0038 #include <phool/PHNode.h>  // for PHNode
0039 #include <phool/PHNodeIterator.h>
0040 #include <phool/PHObject.h>  // for PHObject
0041 #include <phool/getClass.h>
0042 #include <phool/phool.h>
0043 
0044 #include <trackbase/ActsGeometry.h>
0045 #include <trackbase/InttDefs.h>
0046 #include <trackbase/MvtxDefs.h>
0047 #include <trackbase/TpcDefs.h>
0048 #include <trackbase/TrkrCluster.h>  // for TrkrCluster
0049 #include <trackbase/TrkrClusterContainer.h>
0050 #include <trackbase/TrkrDefs.h>
0051 
0052 #include <trackbase_historic/SvtxTrack.h>
0053 #include <trackbase_historic/SvtxTrackMap.h>
0054 #include <trackbase_historic/SvtxTrackMap_v2.h>
0055 #include <trackbase_historic/SvtxTrackState.h>  // for SvtxTrackState
0056 #include <trackbase_historic/SvtxTrackState_v2.h>
0057 #include <trackbase_historic/SvtxTrack_v4.h>
0058 #include <trackbase_historic/TrackSeed.h>
0059 #include <trackbase_historic/TrackSeedContainer.h>
0060 #include <trackbase_historic/TrackSeedHelper.h>
0061 
0062 #include <GenFit/AbsMeasurement.h>  // for AbsMeasurement
0063 #include <GenFit/Exception.h>       // for Exception
0064 #include <GenFit/KalmanFitterInfo.h>
0065 #include <GenFit/MeasuredStateOnPlane.h>
0066 #include <GenFit/RKTrackRep.h>
0067 #include <GenFit/Track.h>
0068 #include <GenFit/TrackPoint.h>  // for TrackPoint
0069 
0070 #include <TMatrixDSymfwd.h>  // for TMatrixDSym
0071 #include <TMatrixFfwd.h>     // for TMatrixF
0072 #include <TMatrixT.h>        // for TMatrixT, operator*
0073 #include <TMatrixTSym.h>     // for TMatrixTSym
0074 #include <TMatrixTUtils.h>   // for TMatrixTRow
0075 #include <TRotation.h>
0076 #include <TTree.h>
0077 #include <TVector3.h>
0078 #include <TVectorDfwd.h>  // for TVectorD
0079 #include <TVectorT.h>     // for TVectorT
0080 
0081 #include <cmath>  // for sqrt, NAN
0082 #include <iostream>
0083 #include <map>
0084 #include <memory>
0085 #include <utility>
0086 #include <vector>
0087 
0088 class PHField;
0089 class TGeoManager;
0090 namespace genfit
0091 {
0092   class AbsTrackRep;
0093 }
0094 
0095 #define LogDebug(exp) std::cout << "DEBUG: " << __FILE__ << ": " << __LINE__ << ": " << (exp) << std::endl
0096 #define LogError(exp) std::cout << "ERROR: " << __FILE__ << ": " << __LINE__ << ": " << (exp) << std::endl
0097 #define LogWarning(exp) std::cout << "WARNING: " << __FILE__ << ": " << __LINE__ << ": " << (exp) << std::endl
0098 
0099 using namespace std;
0100 
0101 //______________________________________________________
0102 namespace
0103 {
0104 
0105   // square
0106   template <class T>
0107   inline static constexpr T square(const T& x)
0108   {
0109     return x * x;
0110   }
0111 
0112   // square
0113   template <class T>
0114   inline static T get_r(const T& x, const T& y)
0115   {
0116     return std::sqrt( square(x)+square(y));
0117   }
0118 
0119   // convert gf state to SvtxTrackState_v2
0120   SvtxTrackState_v2 create_track_state(float pathlength, const genfit::MeasuredStateOnPlane* gf_state)
0121   {
0122     SvtxTrackState_v2 out(pathlength);
0123     out.set_x(gf_state->getPos().x());
0124     out.set_y(gf_state->getPos().y());
0125     out.set_z(gf_state->getPos().z());
0126 
0127     out.set_px(gf_state->getMom().x());
0128     out.set_py(gf_state->getMom().y());
0129     out.set_pz(gf_state->getMom().z());
0130 
0131     for (int i = 0; i < 6; i++)
0132     {
0133       for (int j = i; j < 6; j++)
0134       {
0135         out.set_error(i, j, gf_state->get6DCov()[i][j]);
0136       }
0137     }
0138 
0139     return out;
0140   }
0141 
0142   // get cluster keys from a given track
0143   std::vector<TrkrDefs::cluskey> get_cluster_keys(const SvtxTrack* track)
0144   {
0145     std::vector<TrkrDefs::cluskey> out;
0146     for (const auto& seed : {track->get_silicon_seed(), track->get_tpc_seed()})
0147     {
0148       if (seed)
0149       {
0150         std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out));
0151       }
0152     }
0153     return out;
0154   }
0155 
0156   [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector3& vector)
0157   {
0158     out << "(" << vector.x() << ", " << vector.y() << ", " << vector.z() << ")";
0159     return out;
0160   }
0161 
0162   TVector3 get_world_from_local_vect( ActsGeometry* geometry, Surface surface, const TVector3& local_vect )
0163   {
0164 
0165     // get global vector from local, using ACTS surface
0166     Acts::Vector3 local(
0167       local_vect.x()*Acts::UnitConstants::cm,
0168       local_vect.y()*Acts::UnitConstants::cm,
0169       local_vect.z()*Acts::UnitConstants::cm );
0170 
0171     // TODO: check signification of the last two parameters to referenceFrame.
0172     const Acts::Vector3 global = surface->referenceFrame(geometry->geometry().getGeoContext(), {0,0,0}, {0,0,0})*local;
0173     return TVector3(
0174       global.x()/Acts::UnitConstants::cm,
0175       global.y()/Acts::UnitConstants::cm,
0176       global.z()/Acts::UnitConstants::cm );
0177   }
0178 
0179 }  // namespace
0180 
0181 /*
0182  * Constructor
0183  */
0184 PHGenFitTrkFitter::PHGenFitTrkFitter(const string& name)
0185   : SubsysReco(name)
0186 {
0187 }
0188 
0189 /*
0190  * Init
0191  */
0192 int PHGenFitTrkFitter::Init(PHCompositeNode* /*topNode*/)
0193 {
0194   return Fun4AllReturnCodes::EVENT_OK;
0195 }
0196 
0197 /*
0198  * Init run
0199  */
0200 int PHGenFitTrkFitter::InitRun(PHCompositeNode* topNode)
0201 {
0202   CreateNodes(topNode);
0203 
0204   auto tgeo_manager = PHGeomUtility::GetTGeoManager(topNode);
0205   auto field = PHFieldUtility::GetFieldMapNode(nullptr, topNode);
0206 
0207   _fitter.reset(PHGenFit::Fitter::getInstance(tgeo_manager, field, _track_fitting_alg_name, "RKTrackRep", false));
0208   _fitter->set_verbosity(Verbosity());
0209 
0210   std::cout << "PHGenFitTrkFitter::InitRun - m_fit_silicon_mms: " << m_fit_silicon_mms << std::endl;
0211   std::cout << "PHGenFitTrkFitter::InitRun - m_use_micromegas: " << m_use_micromegas << std::endl;
0212 
0213   // print disabled layers
0214   // if( Verbosity() )
0215   {
0216     for (const auto& layer : _disabled_layers)
0217     {
0218       std::cout << PHWHERE << " Layer " << layer << " is disabled." << std::endl;
0219     }
0220   }
0221 
0222   return Fun4AllReturnCodes::EVENT_OK;
0223 }
0224 
0225 /*
0226  * process_event():
0227  *  Call user instructions for every event.
0228  *  This function contains the analysis structure.
0229  *
0230  */
0231 int PHGenFitTrkFitter::process_event(PHCompositeNode* topNode)
0232 {
0233   ++_event;
0234 
0235   if (Verbosity() > 1)
0236   {
0237     std::cout << PHWHERE << "Events processed: " << _event << std::endl;
0238   }
0239 
0240   // clear global position map
0241   GetNodes(topNode);
0242 
0243   // clear default track map, fill with seeds
0244   m_trackMap->Reset();
0245 
0246   unsigned int trackid = 0;
0247   for (const auto& track : *m_seedMap)
0248   {
0249     if (!track) continue;
0250 
0251     // get silicon seed and check
0252     const auto siid = track->get_silicon_seed_index();
0253     if (siid == std::numeric_limits<unsigned int>::max()) continue;
0254     const auto siseed = m_siliconSeeds->get(siid);
0255     if (!siseed) continue;
0256 
0257     // get crossing number and check
0258     const auto crossing = siseed->get_crossing();
0259     if (crossing == SHRT_MAX) continue;
0260 
0261     // get tpc seed and check
0262     const auto tpcid = track->get_tpc_seed_index();
0263     const auto tpcseed = m_tpcSeeds->get(tpcid);
0264     if (!tpcseed) continue;
0265 
0266     // build track
0267     auto svtxtrack = std::make_unique<SvtxTrack_v4>();
0268     svtxtrack->set_id(trackid++);
0269     svtxtrack->set_silicon_seed(siseed);
0270     svtxtrack->set_tpc_seed(tpcseed);
0271     svtxtrack->set_crossing(crossing);
0272 
0273     // track position comes from silicon seed
0274     const auto position = TrackSeedHelper::get_xyz(siseed);
0275     svtxtrack->set_x(position.x());
0276     svtxtrack->set_y(position.y());
0277     svtxtrack->set_z(position.z());
0278 
0279     // track momentum comes from tpc seed
0280     svtxtrack->set_charge(tpcseed->get_qOverR() > 0 ? 1 : -1);
0281     svtxtrack->set_px(tpcseed->get_px());
0282     svtxtrack->set_py(tpcseed->get_py());
0283     svtxtrack->set_pz(tpcseed->get_pz());
0284 
0285     // insert in map
0286     m_trackMap->insert(svtxtrack.get());
0287   }
0288 
0289   // stands for Refit_GenFit_Tracks
0290   vector<genfit::Track*> rf_gf_tracks;
0291   vector<std::shared_ptr<PHGenFit::Track> > rf_phgf_tracks;
0292 
0293   map<unsigned int, unsigned int> svtxtrack_genfittrack_map;
0294 
0295   for (const auto& [key, svtx_track] : *m_trackMap)
0296   {
0297     if (!svtx_track) continue;
0298 
0299     if (Verbosity() > 10)
0300     {
0301       cout << "   process SVTXTrack " << key << endl;
0302       svtx_track->identify();
0303     }
0304 
0305     if (!(svtx_track->get_pt() > _fit_min_pT)) continue;
0306 
0307     // This is the final track (re)fit. It does not include the collision vertex. If fit_primary_track is set, a refit including the vertex is done below.
0308     // rf_phgf_track stands for Refit_PHGenFit_Track
0309     const auto rf_phgf_track = ReFitTrack(topNode, svtx_track);
0310     if (rf_phgf_track)
0311     {
0312       svtxtrack_genfittrack_map[svtx_track->get_id()] = rf_phgf_tracks.size();
0313       rf_phgf_tracks.push_back(rf_phgf_track);
0314       if (rf_phgf_track->get_ndf() > _vertex_min_ndf)
0315       {
0316         rf_gf_tracks.push_back(rf_phgf_track->getGenFitTrack());
0317       }
0318 
0319       if (Verbosity() > 10) cout << "Done refitting input track" << svtx_track->get_id() << " or rf_phgf_track " << rf_phgf_tracks.size() << endl;
0320     }
0321     else if (Verbosity() >= 1)
0322     {
0323       cout << "failed refitting input track# " << key << endl;
0324     }
0325   }
0326 
0327   // Finds the refitted rf_phgf_track corresponding to each SvtxTrackMap entry
0328   // Converts it to an SvtxTrack in MakeSvtxTrack
0329   // MakeSvtxTrack takes a vertex that it gets from the map made in FillSvtxVertex
0330   // If the refit was succesful, the track on the node tree is replaced with the new one
0331   // If not, the track is erased from the node tree
0332   for (SvtxTrackMap::Iter iter = m_trackMap->begin(); iter != m_trackMap->end();)
0333   {
0334     std::shared_ptr<PHGenFit::Track> rf_phgf_track;
0335 
0336     // find the genfit track that corresponds to this one on the node tree
0337     unsigned int itrack = 0;
0338     if (svtxtrack_genfittrack_map.find(iter->second->get_id()) != svtxtrack_genfittrack_map.end())
0339     {
0340       itrack = svtxtrack_genfittrack_map[iter->second->get_id()];
0341       rf_phgf_track = rf_phgf_tracks[itrack];
0342     }
0343 
0344     if (rf_phgf_track)
0345     {
0346       const auto rf_track = MakeSvtxTrack(iter->second, rf_phgf_track);
0347       if (rf_track)
0348       {
0349         // replace track in map
0350         iter->second->CopyFrom(rf_track.get());
0351       }
0352       else
0353       {
0354         // converting track failed. erase track from map
0355         auto key = iter->first;
0356         ++iter;
0357         m_trackMap->erase(key);
0358         continue;
0359       }
0360     }
0361     else
0362     {
0363       // genfit track is invalid. erase track from map
0364       auto key = iter->first;
0365       ++iter;
0366       m_trackMap->erase(key);
0367       continue;
0368     }
0369 
0370     ++iter;
0371   }
0372 
0373   // clear genfit tracks
0374   rf_phgf_tracks.clear();
0375 
0376   return Fun4AllReturnCodes::EVENT_OK;
0377 }
0378 
0379 /*
0380  * End
0381  */
0382 int PHGenFitTrkFitter::End(PHCompositeNode* /*topNode*/)
0383 {
0384   return Fun4AllReturnCodes::EVENT_OK;
0385 }
0386 
0387 int PHGenFitTrkFitter::CreateNodes(PHCompositeNode* topNode)
0388 {
0389   // create nodes...
0390   PHNodeIterator iter(topNode);
0391 
0392   auto dstNode = static_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
0393   if (!dstNode)
0394   {
0395     cerr << PHWHERE << "DST Node missing, doing nothing." << endl;
0396     return Fun4AllReturnCodes::ABORTEVENT;
0397   }
0398   PHNodeIterator iter_dst(dstNode);
0399 
0400   // Create the SVTX node
0401   auto svtx_node = dynamic_cast<PHCompositeNode*>(iter_dst.findFirst("PHCompositeNode", "SVTX"));
0402   if (!svtx_node)
0403   {
0404     svtx_node = new PHCompositeNode("SVTX");
0405     dstNode->addNode(svtx_node);
0406     if (Verbosity())
0407     {
0408       cout << "SVTX node added" << endl;
0409     }
0410   }
0411 
0412   // default track map
0413   m_trackMap = findNode::getClass<SvtxTrackMap>(topNode, _trackMap_name);
0414   if (!m_trackMap)
0415   {
0416     m_trackMap = new SvtxTrackMap_v2;
0417     auto node = new PHIODataNode<PHObject>(m_trackMap, _trackMap_name, "PHObject");
0418     svtx_node->addNode(node);
0419   }
0420 
0421   return Fun4AllReturnCodes::EVENT_OK;
0422 }
0423 
0424 //______________________________________________________
0425 void PHGenFitTrkFitter::disable_layer(int layer, bool disabled)
0426 {
0427   if (disabled)
0428     _disabled_layers.insert(layer);
0429   else
0430     _disabled_layers.erase(layer);
0431 }
0432 
0433 //______________________________________________________
0434 void PHGenFitTrkFitter::set_disabled_layers(const std::set<int>& layers)
0435 {
0436   _disabled_layers = layers;
0437 }
0438 
0439 //______________________________________________________
0440 void PHGenFitTrkFitter::clear_disabled_layers()
0441 {
0442   _disabled_layers.clear();
0443 }
0444 
0445 //______________________________________________________
0446 const std::set<int>& PHGenFitTrkFitter::get_disabled_layers() const
0447 {
0448   return _disabled_layers;
0449 }
0450 
0451 //______________________________________________________
0452 void PHGenFitTrkFitter::set_fit_silicon_mms(bool value)
0453 {
0454   // store flags
0455   m_fit_silicon_mms = value;
0456 
0457   // disable/enable layers accordingly
0458   for (int layer = 7; layer < 23; ++layer)
0459   {
0460     disable_layer(layer, value);
0461   }
0462   for (int layer = 23; layer < 39; ++layer)
0463   {
0464     disable_layer(layer, value);
0465   }
0466   for (int layer = 39; layer < 55; ++layer)
0467   {
0468     disable_layer(layer, value);
0469   }
0470 }
0471 
0472 /*
0473  * GetNodes():
0474  *  Get all the all the required nodes off the node tree
0475  */
0476 int PHGenFitTrkFitter::GetNodes(PHCompositeNode* topNode)
0477 {
0478   // acts geometry
0479   m_tgeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0480   if (!m_tgeometry)
0481   {
0482     std::cout << "PHGenFitTrkFitter::GetNodes - No acts tracking geometry, can't proceed" << std::endl;
0483     return Fun4AllReturnCodes::ABORTEVENT;
0484   }
0485 
0486   // DST objects
0487   // clusters
0488   m_clustermap = findNode::getClass<TrkrClusterContainer>(topNode, "CORRECTED_TRKR_CLUSTER");
0489   if (m_clustermap)
0490   {
0491     if (_event < 2)
0492     {
0493       std::cout << "PHGenFitTrkFitter::GetNodes - Using CORRECTED_TRKR_CLUSTER node " << std::endl;
0494     }
0495   }
0496   else
0497   {
0498     if (_event < 2)
0499     {
0500       std::cout << "PHGenFitTrkFitter::GetNodes - CORRECTED_TRKR_CLUSTER node not found, using TRKR_CLUSTER" << std::endl;
0501     }
0502     m_clustermap = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0503   }
0504 
0505   if (!m_clustermap)
0506   {
0507     cout << PHWHERE << "PHGenFitTrkFitter::GetNodes - TRKR_CLUSTER node not found on node tree" << endl;
0508     return Fun4AllReturnCodes::ABORTEVENT;
0509   }
0510 
0511   // seeds
0512   m_seedMap = findNode::getClass<TrackSeedContainer>(topNode, _seedMap_name);
0513   if (!m_seedMap)
0514   {
0515     std::cout << "PHGenFitTrkFitter::GetNodes - No Svtx seed map on node tree. Exiting." << std::endl;
0516     return Fun4AllReturnCodes::ABORTEVENT;
0517   }
0518 
0519   m_tpcSeeds = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
0520   if (!m_tpcSeeds)
0521   {
0522     std::cout << "PHGenFitTrkFitter::GetNodes - TpcTrackSeedContainer not on node tree. Bailing"
0523               << std::endl;
0524     return Fun4AllReturnCodes::ABORTEVENT;
0525   }
0526 
0527   m_siliconSeeds = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
0528   if (!m_siliconSeeds)
0529   {
0530     std::cout << "PHGenFitTrkFitter::GetNodes - SiliconTrackSeedContainer not on node tree. Bailing"
0531               << std::endl;
0532     return Fun4AllReturnCodes::ABORTEVENT;
0533   }
0534 
0535   // Svtx Tracks
0536   m_trackMap = findNode::getClass<SvtxTrackMap>(topNode, _trackMap_name);
0537   if (!m_trackMap && _event < 2)
0538   {
0539     cout << "PHGenFitTrkFitter::GetNodes - SvtxTrackMap node not found on node tree" << endl;
0540     return Fun4AllReturnCodes::ABORTEVENT;
0541   }
0542 
0543   // global position wrapper
0544   m_globalPositionWrapper.loadNodes(topNode);
0545   if (m_disable_module_edge_corr) { m_globalPositionWrapper.set_enable_module_edge_corr(false); }
0546   if (m_disable_static_corr) { m_globalPositionWrapper.set_enable_static_corr(false); }
0547   if (m_disable_average_corr) { m_globalPositionWrapper.set_enable_average_corr(false); }
0548   if (m_disable_fluctuation_corr) { m_globalPositionWrapper.set_enable_fluctuation_corr(false); }
0549 
0550   return Fun4AllReturnCodes::EVENT_OK;
0551 }
0552 
0553 /*
0554  * fit track with SvtxTrack as input seed.
0555  * \param intrack Input SvtxTrack
0556  */
0557 std::shared_ptr<PHGenFit::Track> PHGenFitTrkFitter::ReFitTrack(PHCompositeNode* /*topNode*/, const SvtxTrack* intrack)
0558 {
0559   // std::shared_ptr<PHGenFit::Track> empty_track(nullptr);
0560   if (!intrack)
0561   {
0562     cerr << PHWHERE << " Input SvtxTrack is nullptr!" << endl;
0563     return nullptr;
0564   }
0565 
0566   // get crossing from track
0567   const auto crossing = intrack->get_crossing();
0568   assert(crossing != SHRT_MAX);
0569 
0570   // prepare seed
0571   TVector3 seed_mom(100, 0, 0);
0572   TVector3 seed_pos(0, 0, 0);
0573   TMatrixDSym seed_cov(6);
0574   for (int i = 0; i < 6; i++)
0575   {
0576     for (int j = 0; j < 6; j++)
0577     {
0578       seed_cov[i][j] = 100.;
0579     }
0580   }
0581 
0582   // Create measurements
0583   std::vector<PHGenFit::Measurement*> measurements;
0584 
0585   // sort clusters with radius before fitting
0586   if (Verbosity() > 10)
0587   {
0588     intrack->identify();
0589   }
0590   std::map<float, TrkrDefs::cluskey> m_r_cluster_id;
0591 
0592   unsigned int n_silicon_clusters = 0;
0593   unsigned int n_micromegas_clusters = 0;
0594 
0595   for (const auto& cluster_key : get_cluster_keys(intrack))
0596   {
0597     // count clusters
0598     switch (TrkrDefs::getTrkrId(cluster_key))
0599     {
0600     case TrkrDefs::mvtxId:
0601     case TrkrDefs::inttId:
0602       ++n_silicon_clusters;
0603       break;
0604 
0605     case TrkrDefs::micromegasId:
0606       ++n_micromegas_clusters;
0607       break;
0608 
0609     default:
0610       break;
0611     }
0612 
0613     const auto cluster = m_clustermap->findCluster(cluster_key);
0614     const auto globalPosition = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(cluster_key, cluster, crossing);
0615     const float r = get_r(globalPosition.x(), globalPosition.y());
0616     m_r_cluster_id.emplace(r, cluster_key);
0617     if (Verbosity() > 10)
0618     {
0619       const int layer_out = TrkrDefs::getLayer(cluster_key);
0620       cout << "    Layer " << layer_out << " cluster " << cluster_key << " radius " << r << endl;
0621     }
0622   }
0623 
0624   // discard track if not enough clusters when fitting with silicon + mm only
0625   if (m_fit_silicon_mms)
0626   {
0627     if (n_silicon_clusters == 0)
0628     {
0629       return nullptr;
0630     }
0631     if (m_use_micromegas && n_micromegas_clusters == 0)
0632     {
0633       return nullptr;
0634     }
0635   }
0636 
0637   for (const auto& [r, cluster_key] : m_r_cluster_id)
0638   {
0639     const int layer = TrkrDefs::getLayer(cluster_key);
0640 
0641     // skip disabled layers
0642     if (_disabled_layers.find(layer) != _disabled_layers.end())
0643     {
0644       continue;
0645     }
0646 
0647     auto cluster = m_clustermap->findCluster(cluster_key);
0648     if (!cluster)
0649     {
0650       LogError("No cluster Found!");
0651       continue;
0652     }
0653 
0654     const auto globalPosition_acts = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(cluster_key, cluster, crossing);
0655     const TVector3 pos(globalPosition_acts.x(), globalPosition_acts.y(), globalPosition_acts.z());
0656 
0657     const double cluster_rphi_error = cluster->getRPhiError();
0658     const double cluster_z_error = cluster->getZError();
0659 
0660     seed_mom.SetPhi(pos.Phi());
0661     seed_mom.SetTheta(pos.Theta());
0662 
0663     std::unique_ptr<PHGenFit::PlanarMeasurement> meas;
0664     switch (TrkrDefs::getTrkrId(cluster_key))
0665         {
0666         case TrkrDefs::mvtxId:
0667         {
0668           auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
0669           auto surface = m_tgeometry->maps().getSiliconSurface(hitsetkey);
0670         const auto u = get_world_from_local_vect(m_tgeometry, surface, {1, 0, 0});
0671         const auto v = get_world_from_local_vect(m_tgeometry, surface, {0, 1, 0});
0672           meas.reset( new PHGenFit::PlanarMeasurement(pos, u, v, cluster_rphi_error, cluster_z_error) );
0673 
0674           break;
0675         }
0676 
0677         case TrkrDefs::inttId:
0678         {
0679           auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
0680           auto surface = m_tgeometry->maps().getSiliconSurface(hitsetkey);
0681         const auto u = get_world_from_local_vect(m_tgeometry, surface, {1, 0, 0});
0682         const auto v = get_world_from_local_vect(m_tgeometry, surface, {0, 1, 0});
0683           meas.reset( new PHGenFit::PlanarMeasurement(pos, u, v, cluster_rphi_error, cluster_z_error) );
0684           break;
0685         }
0686 
0687         case TrkrDefs::micromegasId:
0688         {
0689 
0690           // get geometry
0691           /* a situation where micromegas clusters are found, but not the geometry, should not happen */
0692           auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
0693           auto surface = m_tgeometry->maps().getMMSurface(hitsetkey);
0694         const auto u = get_world_from_local_vect(m_tgeometry, surface, {1, 0, 0});
0695         const auto v = get_world_from_local_vect(m_tgeometry, surface, {0, 1, 0});
0696           meas.reset( new PHGenFit::PlanarMeasurement(pos, u, v, cluster_rphi_error, cluster_z_error) );
0697           break;
0698         }
0699 
0700         case TrkrDefs::tpcId:
0701         {
0702           // create measurement
0703           const TVector3 n(globalPosition_acts.x(), globalPosition_acts.y(), 0);
0704           meas.reset( new PHGenFit::PlanarMeasurement(pos, n, cluster_rphi_error, cluster_z_error) );
0705           break;
0706         }
0707 
0708     }
0709 
0710     // assign cluster key to measurement
0711     meas->set_cluster_key( cluster_key );
0712 
0713     // add to list
0714     measurements.push_back(meas.release());
0715   }
0716 
0717   /*!
0718    * mu+:   -13
0719    * mu-:   13
0720    * pi+:   211
0721    * pi-:   -211
0722    * e-:    11
0723    * e+:    -11
0724    */
0725   // TODO Add multiple TrackRep choices.
0726   // int pid = 211;
0727   auto rep = new genfit::RKTrackRep(_primary_pid_guess);
0728   std::shared_ptr<PHGenFit::Track> track(new PHGenFit::Track(rep, seed_pos, seed_mom, seed_cov));
0729 
0730   // TODO unsorted measurements, should use sorted ones?
0731   track->addMeasurements(measurements);
0732 
0733   /*!
0734    *  Fit the track
0735    *  ret code 0 means 0 error or good status
0736    */
0737 
0738   if (_fitter->processTrack(track.get(), false) != 0)
0739   {
0740     // if (Verbosity() >= 1)
0741     {
0742       LogWarning("Track fitting failed");
0743     }
0744     // delete track;
0745     return nullptr;
0746   }
0747 
0748   if (Verbosity() > 10)
0749     cout << " track->getChisq() " << track->get_chi2() << " get_ndf " << track->get_ndf()
0750          << " mom.X " << track->get_mom().X()
0751          << " mom.Y " << track->get_mom().Y()
0752          << " mom.Z " << track->get_mom().Z()
0753          << endl;
0754 
0755   return track;
0756 }
0757 
0758 /*
0759  * Make SvtxTrack from PHGenFit::Track and SvtxTrack
0760  */
0761 // SvtxTrack* PHGenFitTrkFitter::MakeSvtxTrack(const SvtxTrack* svtx_track,
0762 std::shared_ptr<SvtxTrack> PHGenFitTrkFitter::MakeSvtxTrack(const SvtxTrack* svtx_track, const std::shared_ptr<PHGenFit::Track>& phgf_track)
0763 {
0764   double chi2 = phgf_track->get_chi2();
0765   double ndf = phgf_track->get_ndf();
0766 
0767   TVector3 vertex_position(0, 0, 0);
0768   TMatrixF vertex_cov(3, 3);
0769   double dvr2 = 0;
0770   double dvz2 = 0;
0771 
0772   std::unique_ptr<genfit::MeasuredStateOnPlane> gf_state_beam_line_ca;
0773   try
0774   {
0775     gf_state_beam_line_ca.reset(phgf_track->extrapolateToLine(vertex_position, TVector3(0., 0., 1.)));
0776   }
0777   catch (...)
0778   {
0779     if (Verbosity() >= 2)
0780     {
0781       LogWarning("extrapolateToLine failed!");
0782     }
0783   }
0784   if (!gf_state_beam_line_ca)
0785   {
0786     return nullptr;
0787   }
0788 
0789   /*!
0790    *  1/p, u'/z', v'/z', u, v
0791    *  u is defined as momentum X beam line at POCA of the beam line
0792    *  v is alone the beam line
0793    *  so u is the dca2d direction
0794    */
0795 
0796   double u = gf_state_beam_line_ca->getState()[3];
0797   double v = gf_state_beam_line_ca->getState()[4];
0798 
0799   double du2 = gf_state_beam_line_ca->getCov()[3][3];
0800   double dv2 = gf_state_beam_line_ca->getCov()[4][4];
0801   // cout << PHWHERE << "        u " << u << " v " << v << " du2 " << du2 << " dv2 " << dv2 << " dvr2 " << dvr2 << endl;
0802   // delete gf_state_beam_line_ca;
0803 
0804   // create new track
0805   auto out_track = std::make_shared<SvtxTrack_v4>(*svtx_track);
0806 
0807   // clear states and insert empty one for vertex position
0808   out_track->clear_states();
0809   {
0810     /*
0811     insert first, dummy state, as done in constructor,
0812     so that the track state list is never empty. Note that insert_state, despite taking a pointer as argument,
0813     does not take ownership of the state
0814     */
0815     SvtxTrackState_v2 first(0.0);
0816     out_track->insert_state(&first);
0817   }
0818 
0819   out_track->set_dca2d(u);
0820   out_track->set_dca2d_error(sqrt(du2 + dvr2));
0821 
0822   std::unique_ptr<genfit::MeasuredStateOnPlane> gf_state_vertex_ca;
0823   try
0824   {
0825     gf_state_vertex_ca.reset(phgf_track->extrapolateToPoint(vertex_position));
0826   }
0827   catch (...)
0828   {
0829     if (Verbosity() >= 2)
0830     {
0831       LogWarning("extrapolateToPoint failed!");
0832     }
0833   }
0834   if (!gf_state_vertex_ca)
0835   {
0836     // delete out_track;
0837     return nullptr;
0838   }
0839 
0840   const auto mom = gf_state_vertex_ca->getMom();
0841   const auto pos = gf_state_vertex_ca->getPos();
0842   const auto cov = gf_state_vertex_ca->get6DCov();
0843 
0844   //    genfit::MeasuredStateOnPlane* gf_state_vertex_ca =
0845   //            phgf_track->extrapolateToLine(vertex_position,
0846   //                    TVector3(0., 0., 1.));
0847 
0848   u = gf_state_vertex_ca->getState()[3];
0849   v = gf_state_vertex_ca->getState()[4];
0850 
0851   du2 = gf_state_vertex_ca->getCov()[3][3];
0852   dv2 = gf_state_vertex_ca->getCov()[4][4];
0853 
0854   double dca3d = sqrt(square(u) + square(v));
0855   double dca3d_error = sqrt(du2 + dv2 + dvr2 + dvz2);
0856 
0857   out_track->set_dca(dca3d);
0858   out_track->set_dca_error(dca3d_error);
0859 
0860   //
0861   // in: X, Y, Z; out; r: n X Z, Z X r, Z
0862 
0863   float dca3d_xy = NAN;
0864   float dca3d_z = NAN;
0865   float dca3d_xy_error = NAN;
0866   float dca3d_z_error = NAN;
0867 
0868   try
0869   {
0870     TMatrixF pos_in(3, 1);
0871     TMatrixF cov_in(3, 3);
0872     TMatrixF pos_out(3, 1);
0873     TMatrixF cov_out(3, 3);
0874 
0875     TVectorD state6(6);      // pos(3), mom(3)
0876     TMatrixDSym cov6(6, 6);  //
0877 
0878     gf_state_vertex_ca->get6DStateCov(state6, cov6);
0879 
0880     TVector3 vn(state6[3], state6[4], state6[5]);
0881 
0882     // mean of two multivariate gaussians Pos - Vertex
0883     pos_in[0][0] = state6[0] - vertex_position.X();
0884     pos_in[1][0] = state6[1] - vertex_position.Y();
0885     pos_in[2][0] = state6[2] - vertex_position.Z();
0886 
0887     for (int i = 0; i < 3; ++i)
0888     {
0889       for (int j = 0; j < 3; ++j)
0890       {
0891         cov_in[i][j] = cov6[i][j] + vertex_cov[i][j];
0892       }
0893     }
0894 
0895     // vn is momentum vector, pos_in is position vector (of what?)
0896     pos_cov_XYZ_to_RZ(vn, pos_in, cov_in, pos_out, cov_out);
0897 
0898     if (Verbosity() > 30)
0899     {
0900       cout << " vn.X " << vn.X() << " vn.Y " << vn.Y() << " vn.Z " << vn.Z() << endl;
0901       cout << " pos_in.X " << pos_in[0][0] << " pos_in.Y " << pos_in[1][0] << " pos_in.Z " << pos_in[2][0] << endl;
0902       cout << " pos_out.X " << pos_out[0][0] << " pos_out.Y " << pos_out[1][0] << " pos_out.Z " << pos_out[2][0] << endl;
0903     }
0904 
0905     dca3d_xy = pos_out[0][0];
0906     dca3d_z = pos_out[2][0];
0907     dca3d_xy_error = sqrt(cov_out[0][0]);
0908     dca3d_z_error = sqrt(cov_out[2][2]);
0909 
0910 #ifdef _DEBUG_
0911     cout << __LINE__ << ": Vertex: ----------------" << endl;
0912     vertex_position.Print();
0913     vertex_cov.Print();
0914 
0915     cout << __LINE__ << ": State: ----------------" << endl;
0916     state6.Print();
0917     cov6.Print();
0918 
0919     cout << __LINE__ << ": Mean: ----------------" << endl;
0920     pos_in.Print();
0921     cout << "===>" << endl;
0922     pos_out.Print();
0923 
0924     cout << __LINE__ << ": Cov: ----------------" << endl;
0925     cov_in.Print();
0926     cout << "===>" << endl;
0927     cov_out.Print();
0928 
0929     cout << endl;
0930 #endif
0931   }
0932   catch (...)
0933   {
0934     if (Verbosity())
0935     {
0936       LogWarning("DCA calculationfailed!");
0937     }
0938   }
0939 
0940   out_track->set_dca3d_xy(dca3d_xy);
0941   out_track->set_dca3d_z(dca3d_z);
0942   out_track->set_dca3d_xy_error(dca3d_xy_error);
0943   out_track->set_dca3d_z_error(dca3d_z_error);
0944 
0945   // if(gf_state_vertex_ca) delete gf_state_vertex_ca;
0946 
0947   out_track->set_chisq(chi2);
0948   out_track->set_ndf(ndf);
0949   out_track->set_charge(phgf_track->get_charge());
0950 
0951   out_track->set_px(mom.Px());
0952   out_track->set_py(mom.Py());
0953   out_track->set_pz(mom.Pz());
0954 
0955   out_track->set_x(pos.X());
0956   out_track->set_y(pos.Y());
0957   out_track->set_z(pos.Z());
0958 
0959   for (int i = 0; i < 6; i++)
0960   {
0961     for (int j = i; j < 6; j++)
0962     {
0963       out_track->set_error(i, j, cov[i][j]);
0964     }
0965   }
0966 
0967 #ifdef _DEBUG_
0968   cout << __LINE__ << endl;
0969 #endif
0970 
0971   const auto gftrack = phgf_track->getGenFitTrack();
0972   const auto rep = gftrack->getCardinalRep();
0973   for (unsigned int id = 0; id < gftrack->getNumPointsWithMeasurement(); ++id)
0974   {
0975     genfit::TrackPoint* trpoint = gftrack->getPointWithMeasurementAndFitterInfo(id, gftrack->getCardinalRep());
0976 
0977     if (!trpoint)
0978     {
0979       if (Verbosity() > 1) LogWarning("!trpoint");
0980       continue;
0981     }
0982 
0983     auto kfi = static_cast<genfit::KalmanFitterInfo*>(trpoint->getFitterInfo(rep));
0984     if (!kfi)
0985     {
0986       if (Verbosity() > 1) LogWarning("!kfi");
0987       continue;
0988     }
0989 
0990     const genfit::MeasuredStateOnPlane* gf_state = nullptr;
0991     try
0992     {
0993       // this works because KalmanFitterInfo returns a const reference to internal object and not a temporary object
0994       gf_state = &kfi->getFittedState(true);
0995     }
0996     catch (...)
0997     {
0998       if (Verbosity() >= 1)
0999         LogWarning("Exrapolation failed!");
1000     }
1001     if (!gf_state)
1002     {
1003       if (Verbosity() >= 1)
1004         LogWarning("Exrapolation failed!");
1005       continue;
1006     }
1007     genfit::MeasuredStateOnPlane temp;
1008     float pathlength = -phgf_track->extrapolateToPoint(temp, vertex_position, id);
1009 
1010     // create new svtx state and add to track
1011     auto state = create_track_state(pathlength, gf_state);
1012 
1013     // get matching cluster key from phgf_track and assign to state
1014     state.set_cluskey(phgf_track->get_cluster_keys()[id]);
1015 
1016     out_track->insert_state(&state);
1017 
1018 #ifdef _DEBUG_
1019     cout
1020         << __LINE__
1021         << ": " << id
1022         << ": " << pathlength << " => "
1023         << sqrt(square(state->get_x()) + square(state->get_y()))
1024         << endl;
1025 #endif
1026   }
1027 
1028   // loop over clusters, check if layer is disabled, include extrapolated SvtxTrackState
1029   if (!_disabled_layers.empty())
1030   {
1031     // get crossing
1032     const auto crossing = svtx_track->get_crossing();
1033     assert(crossing != SHRT_MAX);
1034 
1035     unsigned int id_min = 0;
1036     for (const auto& cluster_key : get_cluster_keys(svtx_track))
1037     {
1038       const auto cluster = m_clustermap->findCluster(cluster_key);
1039       const auto layer = TrkrDefs::getLayer(cluster_key);
1040 
1041       // skip enabled layers
1042       if (_disabled_layers.find(layer) == _disabled_layers.end())
1043       {
1044         continue;
1045       }
1046 
1047       // get position
1048       const auto globalPosition = m_globalPositionWrapper.getGlobalPositionDistortionCorrected( cluster_key, cluster, crossing );
1049       const TVector3 pos_A(globalPosition.x(), globalPosition.y(), globalPosition.z() );
1050       const float r_cluster = std::sqrt( square(globalPosition.x()) + square(globalPosition.y()) );
1051 
1052       // loop over states
1053       /* find first state whose radius is larger than that of cluster if any */
1054       unsigned int id = id_min;
1055       for (; id < gftrack->getNumPointsWithMeasurement(); ++id)
1056       {
1057         auto trpoint = gftrack->getPointWithMeasurementAndFitterInfo(id, rep);
1058         if (!trpoint) continue;
1059 
1060         auto kfi = static_cast<genfit::KalmanFitterInfo*>(trpoint->getFitterInfo(rep));
1061         if (!kfi) continue;
1062 
1063         const genfit::MeasuredStateOnPlane* gf_state = nullptr;
1064         try
1065         {
1066           gf_state = &kfi->getFittedState(true);
1067         }
1068         catch (...)
1069         {
1070           if (Verbosity())
1071           {
1072             LogWarning("Failed to get kf fitted state");
1073           }
1074         }
1075 
1076         if (!gf_state) continue;
1077 
1078         float r_track = std::sqrt(square(gf_state->getPos().x()) + square(gf_state->getPos().y()));
1079         if (r_track > r_cluster) break;
1080       }
1081 
1082       // forward extrapolation
1083       genfit::MeasuredStateOnPlane gf_state;
1084       float pathlength = 0;
1085 
1086       // first point is previous, if valid
1087       if (id > 0) id_min = id - 1;
1088 
1089       // extrapolate forward
1090       try
1091       {
1092         auto trpoint = gftrack->getPointWithMeasurementAndFitterInfo(id_min, rep);
1093         if (!trpoint) continue;
1094 
1095         auto kfi = static_cast<genfit::KalmanFitterInfo*>(trpoint->getFitterInfo(rep));
1096         gf_state = *kfi->getForwardUpdate();
1097         pathlength = gf_state.extrapolateToPoint( pos_A );
1098         auto tmp = *kfi->getBackwardUpdate();
1099         pathlength -= tmp.extrapolateToPoint(vertex_position);
1100       }
1101       catch (...)
1102       {
1103         if (Verbosity())
1104         {
1105           std::cerr << PHWHERE << "Failed to forward extrapolate from id " << id_min << " to disabled layer " << layer << std::endl;
1106         }
1107         continue;
1108       }
1109 
1110       // also extrapolate backward from next state if any
1111       // and take the weighted average between both points
1112       if (id > 0 && id < gftrack->getNumPointsWithMeasurement())
1113         try
1114         {
1115           auto trpoint = gftrack->getPointWithMeasurementAndFitterInfo(id, rep);
1116           if (!trpoint) continue;
1117 
1118           auto kfi = static_cast<genfit::KalmanFitterInfo*>(trpoint->getFitterInfo(rep));
1119           genfit::KalmanFittedStateOnPlane gf_state_backward = *kfi->getBackwardUpdate();
1120           gf_state_backward.extrapolateToPlane(gf_state.getPlane());
1121           gf_state = genfit::calcAverageState(gf_state, gf_state_backward);
1122         }
1123         catch (...)
1124         {
1125           if (Verbosity())
1126           {
1127             std::cerr << PHWHERE << "Failed to backward extrapolate from id " << id << " to disabled layer " << layer << std::endl;
1128           }
1129           continue;
1130         }
1131 
1132       // create new svtx state and add to track
1133       auto state = create_track_state(pathlength, &gf_state);
1134       state.set_cluskey(cluster_key);
1135       out_track->insert_state(&state);
1136     }
1137   }
1138 
1139   // printout all track state
1140   if (Verbosity())
1141   {
1142     for (auto&& iter = out_track->begin_states(); iter != out_track->end_states(); ++iter)
1143     {
1144       const auto& [pathlength, state] = *iter;
1145       const auto r = std::sqrt(square(state->get_x()) + square(state->get_y()));
1146       const auto phi = std::atan2(state->get_y(), state->get_x());
1147       std::cout << "PHGenFitTrkFitter::MakeSvtxTrack -"
1148                 << " pathlength: " << pathlength
1149                 << " radius: " << r
1150                 << " phi: " << phi
1151                 << " z: " << state->get_z()
1152                 << std::endl;
1153     }
1154 
1155     std::cout << std::endl;
1156   }
1157   return out_track;
1158 }
1159 
1160 //______________________________________________________________________
1161 bool PHGenFitTrkFitter::pos_cov_XYZ_to_RZ(
1162     const TVector3& n, const TMatrixF& pos_in, const TMatrixF& cov_in,
1163     TMatrixF& pos_out, TMatrixF& cov_out) const
1164 {
1165   if (pos_in.GetNcols() != 1 || pos_in.GetNrows() != 3)
1166   {
1167     if (Verbosity())
1168     {
1169       LogWarning("pos_in.GetNcols() != 1 || pos_in.GetNrows() != 3");
1170     }
1171     return false;
1172   }
1173 
1174   if (cov_in.GetNcols() != 3 || cov_in.GetNrows() != 3)
1175   {
1176     if (Verbosity())
1177     {
1178       LogWarning("cov_in.GetNcols() != 3 || cov_in.GetNrows() != 3");
1179     }
1180     return false;
1181   }
1182 
1183   // produces a vector perpendicular to both the momentum vector and beam line - i.e. in the direction of the dca_xy
1184   // only the angle of r will be used, not the magnitude
1185   TVector3 r = n.Cross(TVector3(0., 0., 1.));
1186   if (r.Mag() < 0.00001)
1187   {
1188     if (Verbosity())
1189     {
1190       LogWarning("n is parallel to z");
1191     }
1192     return false;
1193   }
1194 
1195   // R: rotation from u,v,n to n X Z, nX(nXZ), n
1196   TMatrixF R(3, 3);
1197   TMatrixF R_T(3, 3);
1198 
1199   try
1200   {
1201     // rotate u along z to up
1202     float phi = -TMath::ATan2(r.Y(), r.X());
1203     R[0][0] = cos(phi);
1204     R[0][1] = -sin(phi);
1205     R[0][2] = 0;
1206     R[1][0] = sin(phi);
1207     R[1][1] = cos(phi);
1208     R[1][2] = 0;
1209     R[2][0] = 0;
1210     R[2][1] = 0;
1211     R[2][2] = 1;
1212 
1213     R_T.Transpose(R);
1214   }
1215   catch (...)
1216   {
1217     if (Verbosity())
1218     {
1219       LogWarning("Can't get rotation matrix");
1220     }
1221 
1222     return false;
1223   }
1224 
1225   pos_out.ResizeTo(3, 1);
1226   cov_out.ResizeTo(3, 3);
1227 
1228   pos_out = R * pos_in;
1229   cov_out = R * cov_in * R_T;
1230 
1231   return true;
1232 }