Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:20:59

0001 /*!
0002  *  \file       PHActsTrkFitter.C
0003  *  \brief      Refit SvtxTracks with PHActs.
0004  *  \details    Refit SvtxTracks with PHActs.
0005  *  \author         Tony Frawley <afrawley@fsu.edu>
0006  */
0007 
0008 
0009 #include "PHActsTrkFitter.h"
0010 
0011 #include "ActsPropagator.h"
0012 #include "MakeSourceLinks.h"
0013 
0014 #include <tpc/TpcDistortionCorrectionContainer.h>
0015 
0016 /// Tracking includes
0017 #include <trackbase/Calibrator.h>
0018 #include <trackbase/ClusterErrorPara.h>
0019 #include <trackbase/InttDefs.h>
0020 #include <trackbase/MvtxDefs.h>
0021 #include <trackbase/TpcDefs.h>
0022 #include <trackbase/TrkrCluster.h>
0023 #include <trackbase/TrkrClusterContainer.h>
0024 
0025 #include <trackbase_historic/ActsTransformations.h>
0026 #include <trackbase_historic/SvtxAlignmentStateMap_v1.h>
0027 #include <trackbase_historic/SvtxTrackMap_v2.h>
0028 //#include <trackbase_historic/SvtxTrackState_v1.h>
0029 #include <trackbase_historic/SvtxTrackState_v3.h>
0030 #include <trackbase_historic/SvtxTrack_v4.h>
0031 #include <trackbase_historic/TrackSeed.h>
0032 #include <trackbase_historic/TrackSeedContainer.h>
0033 #include <trackbase_historic/TrackSeedHelper.h>
0034 
0035 #include <g4detectors/PHG4TpcGeomContainer.h>
0036 
0037 #include <micromegas/MicromegasDefs.h>
0038 
0039 #include <ffamodules/CDBInterface.h>
0040 
0041 #include <fun4all/Fun4AllReturnCodes.h>
0042 
0043 #include <phool/PHCompositeNode.h>
0044 #include <phool/PHDataNode.h>
0045 #include <phool/PHNode.h>
0046 #include <phool/PHNodeIterator.h>
0047 #include <phool/PHObject.h>
0048 #include <phool/PHTimer.h>
0049 #include <phool/getClass.h>
0050 #include <phool/phool.h>
0051 
0052 #include <Acts/EventData/MultiTrajectory.hpp>
0053 #include <Acts/EventData/MultiTrajectoryHelpers.hpp>
0054 #include <Acts/EventData/SourceLink.hpp>
0055 #include <Acts/EventData/TrackParameters.hpp>
0056 #include <Acts/Surfaces/PerigeeSurface.hpp>
0057 #include <Acts/Surfaces/Surface.hpp>
0058 #include <Acts/TrackFitting/GainMatrixSmoother.hpp>
0059 #include <Acts/TrackFitting/GainMatrixUpdater.hpp>
0060 
0061 #include <cmath>
0062 #include <filesystem>
0063 #include <iostream>
0064 #include <vector>
0065 
0066 namespace
0067 {
0068   // check vector validity
0069   inline bool is_valid(const Acts::Vector3& vec)
0070   {
0071     return !(std::isnan(vec.x()) || std::isnan(vec.y()) || std::isnan(vec.z()));
0072   }
0073   template <class T>
0074   inline T square(const T& x)
0075   {
0076     return x * x;
0077   }
0078 }  // namespace
0079 
0080 #include <trackbase/alignmentTransformationContainer.h>
0081 #include <Eigen/Dense>
0082 #include <Eigen/Geometry>
0083 
0084 PHActsTrkFitter::PHActsTrkFitter(const std::string& name)
0085   : SubsysReco(name)
0086 {
0087 }
0088 
0089 int PHActsTrkFitter::InitRun(PHCompositeNode* topNode)
0090 {
0091   if (Verbosity() > 1)
0092   {
0093     std::cout << "Setup PHActsTrkFitter" << std::endl;
0094   }
0095 
0096   if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK)
0097   {
0098     return Fun4AllReturnCodes::ABORTEVENT;
0099   }
0100 
0101   if (getNodes(topNode) != Fun4AllReturnCodes::EVENT_OK)
0102   {
0103     return Fun4AllReturnCodes::ABORTEVENT;
0104   }
0105 
0106   // configure alignStates
0107   m_alignStates.loadNodes(topNode);
0108   m_alignStates.verbosity(Verbosity());
0109   m_alignStates.fieldMap(m_fieldMap);
0110 
0111   // detect const field
0112   std::istringstream stringline(m_fieldMap);
0113   stringline >> fieldstrength;
0114   if (!stringline.fail())  // it is a float
0115   {
0116     m_ConstField = true;
0117   }
0118 
0119   auto level = Acts::Logging::FATAL;
0120   if (Verbosity() > 5)
0121   {
0122     level = Acts::Logging::VERBOSE;
0123   }
0124 
0125   m_fitCfg.fit = ActsTrackFittingAlgorithm::makeKalmanFitterFunction(
0126       m_tGeometry->geometry().tGeometry,
0127       m_tGeometry->geometry().magField,
0128       true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("Kalman", level));
0129 
0130   m_fitCfg.dFit = ActsTrackFittingAlgorithm::makeDirectedKalmanFitterFunction(
0131       m_tGeometry->geometry().tGeometry,
0132       m_tGeometry->geometry().magField);
0133 
0134   MaterialSurfaceSelector selector;
0135   if (m_fitSiliconMMs || m_directNavigation)
0136   {
0137     m_tGeometry->geometry().tGeometry->visitSurfaces(selector,false);
0138     //std::cout<<"selector.surfaces.size() "<<selector.surfaces.size()<<std::endl;
0139     m_materialSurfaces = selector.surfaces;
0140   }
0141 
0142   m_outlierFinder.verbosity = Verbosity();
0143   std::map<long unsigned int, float> chi2Cuts;
0144   chi2Cuts.insert(std::make_pair(10, 4));
0145   chi2Cuts.insert(std::make_pair(12, 4));
0146   chi2Cuts.insert(std::make_pair(14, 9));
0147   chi2Cuts.insert(std::make_pair(16, 4));
0148   m_outlierFinder.chi2Cuts = chi2Cuts;
0149   if (m_useOutlierFinder)
0150   {
0151     m_outlierFinder.m_tGeometry = m_tGeometry;
0152     m_fitCfg.fit->outlierFinder(m_outlierFinder);
0153   }
0154 
0155   if (m_timeAnalysis)
0156   {
0157     m_timeFile = new TFile(std::string(Name() + ".root").c_str(),
0158                            "RECREATE");
0159     h_eventTime = new TH1F("h_eventTime", ";time [ms]",
0160                            100000, 0, 10000);
0161     h_fitTime = new TH2F("h_fitTime", ";p_{T} [GeV];time [ms]",
0162                          80, 0, 40, 100000, 0, 1000);
0163     h_updateTime = new TH1F("h_updateTime", ";time [ms]",
0164                             100000, 0, 1000);
0165 
0166     h_rotTime = new TH1F("h_rotTime", ";time [ms]",
0167                          100000, 0, 1000);
0168     h_stateTime = new TH1F("h_stateTime", ";time [ms]",
0169                            100000, 0, 1000);
0170   }
0171 
0172   if (m_actsEvaluator)
0173   {
0174     m_evaluator = std::make_unique<ActsEvaluator>(m_evalname);
0175     m_evaluator->Init(topNode);
0176     if(m_actsEvaluator && !m_simActsEvaluator)
0177     {
0178       m_evaluator->isData();
0179     }
0180     m_evaluator->verbosity(Verbosity());
0181   }
0182 
0183   _tpccellgeo = findNode::getClass<PHG4TpcGeomContainer>(topNode, "TPCGEOMCONTAINER");
0184   if (!_tpccellgeo)
0185     {
0186       std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl;
0187       return Fun4AllReturnCodes::ABORTRUN;
0188     }
0189 
0190   if (Verbosity() > 1)
0191   {
0192     std::cout << "Finish PHActsTrkFitter Setup" << std::endl;
0193   }
0194 
0195   return Fun4AllReturnCodes::EVENT_OK;
0196 }
0197 
0198 int PHActsTrkFitter::process_event(PHCompositeNode* topNode)
0199 {
0200   PHTimer eventTimer("eventTimer");
0201   eventTimer.stop();
0202   eventTimer.restart();
0203   m_nBadFits = 0;
0204   m_event++;
0205 
0206   auto logLevel = Acts::Logging::FATAL;
0207 
0208   if (m_actsEvaluator)
0209   {
0210     m_evaluator->next_event(topNode);
0211   }
0212 
0213   if (Verbosity() > 1)
0214   {
0215     std::cout << PHWHERE << "Events processed: " << m_event << std::endl;
0216     std::cout << "Start PHActsTrkFitter::process_event" << std::endl;
0217     if (Verbosity() > 4)
0218     {
0219       logLevel = Acts::Logging::VERBOSE;
0220     }
0221   }
0222 
0223   // in case the track map already exist in the file, we want to replace it
0224   m_trackMap->Reset();
0225 
0226   loopTracks(logLevel);
0227 
0228   eventTimer.stop();
0229   auto eventTime = eventTimer.get_accumulated_time();
0230 
0231   if (Verbosity() > 1)
0232   {
0233     std::cout << "PHActsTrkFitter total event time "
0234               << eventTime << std::endl;
0235   }
0236 
0237   if (m_timeAnalysis)
0238   {
0239     h_eventTime->Fill(eventTime);
0240   }
0241 
0242   if (Verbosity() > 1)
0243   {
0244     std::cout << "PHActsTrkFitter::process_event finished"
0245               << std::endl;
0246   }
0247 
0248   // put this in the output file
0249   if (Verbosity() > 0)
0250   {
0251     std::cout << "The Acts track fitter had " << m_nBadFits
0252               << " fits return an error" << std::endl;
0253     std::cout << " seed map size " << m_seedMap->size() << std::endl;
0254 
0255     std::cout << " SvtxTrackMap size is now " << m_trackMap->size()
0256               << std::endl;
0257   }
0258 
0259   return Fun4AllReturnCodes::EVENT_OK;
0260 }
0261 
0262 int PHActsTrkFitter::ResetEvent(PHCompositeNode* /*topNode*/)
0263 {
0264   if (Verbosity() > 1)
0265   {
0266     std::cout << "Reset PHActsTrkFitter" << std::endl;
0267   }
0268 
0269   return Fun4AllReturnCodes::EVENT_OK;
0270 }
0271 
0272 int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/)
0273 {
0274   if (m_timeAnalysis)
0275   {
0276     m_timeFile->cd();
0277     h_fitTime->Write();
0278     h_eventTime->Write();
0279     h_rotTime->Write();
0280     h_stateTime->Write();
0281     h_updateTime->Write();
0282     m_timeFile->Write();
0283     m_timeFile->Close();
0284   }
0285 
0286   if (m_actsEvaluator)
0287   {
0288     m_evaluator->End();
0289   }
0290   if(m_useOutlierFinder)
0291   {
0292     m_outlierFinder.Write();
0293   }
0294   if (Verbosity() > 0)
0295   {
0296     std::cout << "Finished PHActsTrkFitter" << std::endl;
0297   }
0298   return Fun4AllReturnCodes::EVENT_OK;
0299 }
0300 
0301 void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel)
0302 {
0303   auto logger = Acts::getDefaultLogger("PHActsTrkFitter", logLevel);
0304 
0305   for (auto track : *m_seedMap)
0306   {
0307     if (!track)
0308     {
0309       continue;
0310     }
0311 
0312     unsigned int tpcid = track->get_tpc_seed_index();
0313     unsigned int siid = track->get_silicon_seed_index();
0314 
0315     // capture the input crossing value, and set crossing parameters
0316     //==============================
0317     short silicon_crossing =  SHRT_MAX;
0318     auto siseed = m_siliconSeeds->get(siid);
0319     if(siseed)
0320       {
0321     silicon_crossing = siseed->get_crossing();
0322       }
0323     short crossing = silicon_crossing;
0324     short int crossing_estimate = crossing;
0325 
0326     if(m_enable_crossing_estimate)
0327       {
0328     crossing_estimate = track->get_crossing_estimate();  // geometric crossing estimate from matcher
0329      }
0330     //===============================
0331 
0332 
0333     // must have silicon seed with valid crossing if we are doing a SC calibration fit
0334     if (m_fitSiliconMMs)
0335       {
0336     if( (siid == std::numeric_limits<unsigned int>::max()) || (silicon_crossing == SHRT_MAX))
0337       {
0338         continue;
0339       }
0340       }
0341 
0342     // do not skip TPC only tracks, just set crossing to the nominal zero
0343     if(!siseed)
0344       {
0345     crossing = 0;
0346       }
0347 
0348     if (Verbosity() > 1)
0349     {
0350       if(siseed)
0351     {
0352       std::cout << "tpc and si id " << tpcid << ", " << siid << " silicon_crossing " << silicon_crossing
0353             << " crossing " << crossing << " crossing estimate " << crossing_estimate << std::endl;
0354     }
0355     }
0356 
0357     auto tpcseed = m_tpcSeeds->get(tpcid);
0358 
0359     /// Need to also check that the tpc seed wasn't removed by the ghost finder
0360     if (!tpcseed)
0361     {
0362       std::cout << "no tpc seed" << std::endl;
0363       continue;
0364     }
0365 
0366     if (Verbosity() > 0)
0367     {
0368       if (siseed)
0369       {
0370         const auto si_position = TrackSeedHelper::get_xyz(siseed);
0371         const auto tpc_position = TrackSeedHelper::get_xyz(tpcseed);
0372         std::cout << "    silicon seed position is (x,y,z) = " << si_position.x() << "  " << si_position.y() << "  " << si_position.z() << std::endl;
0373         std::cout << "    tpc seed position is (x,y,z) = " << tpc_position.x() << "  " << tpc_position.y() << "  " << tpc_position.z() << std::endl;
0374       }
0375     }
0376 
0377     PHTimer trackTimer("TrackTimer");
0378     trackTimer.stop();
0379     trackTimer.restart();
0380 
0381     if (Verbosity() > 1 && siseed)
0382     {
0383       std::cout << " m_pp_mode " << m_pp_mode << " m_enable_crossing_estimate " << m_enable_crossing_estimate
0384         << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl;
0385     }
0386 
0387     short int this_crossing = crossing;
0388     bool use_estimate = false;
0389     short int nvary = 0;
0390     std::vector<float> chisq_ndf;
0391     std::vector<SvtxTrack_v4> svtx_vec;
0392 
0393     if(m_pp_mode)
0394       {
0395     if (m_enable_crossing_estimate && crossing == SHRT_MAX)
0396       {
0397         // this only happens if there is a silicon seed but no assigned INTT crossing, and only in pp_mode
0398         // If there is no INTT crossing, start with the crossing_estimate value, vary up and down, fit, and choose the best chisq/ndf
0399         use_estimate = true;
0400         nvary = max_bunch_search;
0401         if (Verbosity() > 1)
0402           {
0403         std::cout << " No INTT crossing: use crossing_estimate " << crossing_estimate << " with nvary " << nvary << std::endl;
0404           }
0405       }
0406     else
0407       {
0408         // use INTT crossing
0409         crossing_estimate = crossing;
0410       }
0411       }
0412     else
0413       {
0414     // non pp mode, we want only crossing zero, veto others
0415     if(siseed && silicon_crossing != 0)
0416       {
0417         crossing = 0;
0418         //continue;
0419       }
0420     crossing_estimate = crossing;
0421       }
0422 
0423     // Fit this track assuming either:
0424     //    crossing = INTT value, if it exists (uses nvary = 0)
0425     //    crossing = crossing_estimate +/- max_bunch_search, if no INTT value exists and m_enable_crossing_estimate flag is set.
0426 
0427     for (short int ivary = -nvary; ivary <= nvary; ++ivary)
0428     {
0429       this_crossing = crossing_estimate + ivary;
0430 
0431       if (Verbosity() > 1)
0432       {
0433         std::cout << "   nvary " << nvary << " trial fit with ivary " << ivary << " this_crossing = " << this_crossing << std::endl;
0434       }
0435 
0436       ActsTrackFittingAlgorithm::MeasurementContainer measurements;
0437 
0438       SourceLinkVec sourceLinks;
0439 
0440       MakeSourceLinks makeSourceLinks;
0441       makeSourceLinks.initialize(_tpccellgeo);
0442       makeSourceLinks.setVerbosity(Verbosity());
0443       makeSourceLinks.set_pp_mode(m_pp_mode);
0444       for(const auto& layer : m_ignoreLayer)
0445       {
0446         makeSourceLinks.ignoreLayer(layer);
0447       }
0448       // loop over modifiedTransformSet and replace transient elements modified for the previous track with the default transforms
0449       // does nothing if m_transient_id_set is empty
0450       makeSourceLinks.resetTransientTransformMap(
0451         m_alignmentTransformationMapTransient,
0452         m_transient_id_set,
0453         m_tGeometry);
0454 
0455       if (m_use_clustermover)
0456       {
0457         // make source links using cluster mover after making distortion correction
0458         if (siseed && !m_ignoreSilicon)
0459         {
0460           // silicon source links
0461           sourceLinks = makeSourceLinks.getSourceLinksClusterMover(
0462             siseed,
0463             measurements,
0464             m_clusterContainer,
0465             m_tGeometry,
0466             m_globalPositionWrapper,
0467             this_crossing);
0468         }
0469 
0470         // tpc source links
0471         const auto tpcSourceLinks = makeSourceLinks.getSourceLinksClusterMover(
0472           tpcseed,
0473           measurements,
0474           m_clusterContainer,
0475           m_tGeometry,
0476           m_globalPositionWrapper,
0477           this_crossing);
0478 
0479         // add tpc sourcelinks to silicon source links
0480         sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end());
0481 
0482       } else {
0483 
0484         // make source links using transient transforms for distortion corrections
0485         if(Verbosity() > 1)
0486         { std::cout << "Calling getSourceLinks for si seed, siid " << siid << " and tpcid " << tpcid << std::endl; }
0487 
0488         if (siseed && !m_ignoreSilicon)
0489         {
0490           // silicon source links
0491           sourceLinks = makeSourceLinks.getSourceLinks(
0492             siseed,
0493             measurements,
0494             m_clusterContainer,
0495             m_tGeometry,
0496             m_globalPositionWrapper,
0497             m_alignmentTransformationMapTransient,
0498             m_transient_id_set,
0499             this_crossing);
0500         }
0501 
0502         if(Verbosity() > 1)
0503         { std::cout << "Calling getSourceLinks for tpc seed, siid " << siid << " and tpcid " << tpcid << std::endl; }
0504 
0505         // tpc source links
0506         const auto tpcSourceLinks = makeSourceLinks.getSourceLinks(
0507           tpcseed,
0508           measurements,
0509           m_clusterContainer,
0510           m_tGeometry,
0511           m_globalPositionWrapper,
0512           m_alignmentTransformationMapTransient,
0513           m_transient_id_set,
0514           this_crossing);
0515 
0516         // add tpc sourcelinks to silicon source links
0517         sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end());
0518       }
0519 
0520       // copy transient map for this track into transient geoContext
0521       m_transient_geocontext = m_alignmentTransformationMapTransient;
0522 
0523       // position comes from the silicon seed, unless there is no silicon seed
0524       Acts::Vector3 position(0, 0, 0);
0525       if (siseed)
0526       {
0527         position = TrackSeedHelper::get_xyz(siseed)*Acts::UnitConstants::cm;
0528       }
0529       if(!siseed || !is_valid(position) || m_ignoreSilicon)
0530       {
0531         position = TrackSeedHelper::get_xyz(tpcseed)*Acts::UnitConstants::cm;
0532       }
0533       if (!is_valid(position))
0534       {
0535        if(Verbosity() > 4)
0536         {
0537           std::cout << "Invalid position of " << position.transpose() << std::endl;
0538         }
0539         continue;
0540       }
0541 
0542       if (sourceLinks.empty())
0543       {
0544         continue;
0545       }
0546 
0547       /// If using directed navigation, collect surface list to navigate
0548       SurfacePtrVec surfaces_tmp;
0549       SurfacePtrVec surfaces;
0550       if (m_fitSiliconMMs || m_directNavigation)
0551       {
0552         sourceLinks = getSurfaceVector(sourceLinks, surfaces_tmp);
0553 
0554         // skip if there is no surfaces
0555         if (surfaces_tmp.empty())
0556         {
0557           continue;
0558         }
0559 
0560         for (const auto& surface_apr : m_materialSurfaces)
0561         {
0562           if(m_forceSiOnlyFit)
0563           {
0564             if(surface_apr->geometryId().volume() >12)
0565             {
0566               continue;
0567             }
0568           }
0569           bool pop_flag = false;
0570           if(surface_apr->geometryId().approach() == 1)
0571           {
0572             surfaces.push_back(surface_apr);
0573           }
0574           else
0575           {
0576             pop_flag = true;
0577             for (const auto& surface_sns: surfaces_tmp)
0578             {
0579               if (surface_apr->geometryId().volume() == surface_sns->geometryId().volume())
0580               {
0581                 if ( surface_apr->geometryId().layer()==surface_sns->geometryId().layer())
0582                 {
0583                   pop_flag = false;
0584                   surfaces.push_back(surface_sns);
0585                 }
0586               }
0587             }
0588             if (!pop_flag)
0589             {
0590               surfaces.push_back(surface_apr);
0591             }
0592             else
0593             {
0594               surfaces.pop_back();
0595               pop_flag = false;
0596             }
0597             if (surface_apr->geometryId().volume() == 12&& surface_apr->geometryId().layer()==8)
0598             {
0599               for (const auto& surface_sns: surfaces_tmp)
0600               {
0601                 if (14 == surface_sns->geometryId().volume())
0602                 {
0603                   surfaces.push_back(surface_sns);
0604                 }
0605               }
0606             }
0607           }
0608         }
0609         checkSurfaceVec(surfaces);
0610         if (Verbosity() > 1)
0611         {
0612           for (const auto& surf : surfaces)
0613           {
0614             std::cout << "Surface vector : " << surf->geometryId() << std::endl;
0615           }
0616         }
0617 
0618         if (m_fitSiliconMMs)
0619         {
0620           // make sure micromegas are in the tracks, if required
0621           if (m_useMicromegas &&
0622             std::none_of(surfaces.begin(), surfaces.end(), [this](const auto& surface)
0623           { return m_tGeometry->maps().isMicromegasSurface(surface); }))
0624         {
0625           continue;
0626         }
0627       }
0628     }
0629 
0630       float px = std::numeric_limits<float>::quiet_NaN();
0631       float py = std::numeric_limits<float>::quiet_NaN();
0632       float pz = std::numeric_limits<float>::quiet_NaN();
0633 
0634       // get phi and theta from the silicon seed, momentum from the TPC seed
0635       float seedphi = 0;
0636       float seedtheta = 0;
0637       float seedeta = 0;
0638       if(siseed)
0639       {
0640         seedphi = siseed->get_phi();
0641         seedtheta = siseed->get_theta();
0642         seedeta = siseed->get_eta();
0643       }
0644       else
0645       {
0646         seedphi = tpcseed->get_phi();
0647         seedtheta = tpcseed->get_theta();
0648         seedeta = tpcseed->get_eta();
0649       }
0650 
0651       float seedpt = tpcseed->get_pt();
0652 
0653       if (m_ConstField)
0654       {
0655         float pt = fabs(1. / tpcseed->get_qOverR()) * (0.3 / 100) * fieldstrength;
0656         float phi = seedphi;
0657         float eta = seedeta;
0658         float theta = seedtheta;
0659         px = pt * std::cos(phi);
0660         py = pt * std::sin(phi);
0661         pz = pt * std::cosh(eta) * std::cos(theta);
0662       } else {
0663         px = seedpt * std::cos(seedphi);
0664         py = seedpt * std::sin(seedphi);
0665         pz = seedpt * std::cosh(seedeta) * std::cos(seedtheta);
0666       }
0667 
0668       Acts::Vector3 momentum(px, py, pz);
0669       if (!is_valid(momentum))
0670       {
0671         if(Verbosity() > 4)
0672         {
0673           std::cout << "Invalid momentum of " << momentum.transpose() << std::endl;
0674         }
0675         continue;
0676       }
0677 
0678       auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>( position);
0679 
0680       Acts::Vector4 actsFourPos(position(0), position(1), position(2), 10 * Acts::UnitConstants::ns);
0681       Acts::BoundSquareMatrix cov = setDefaultCovariance();
0682 
0683       int charge = tpcseed->get_charge();
0684 
0685       /// Reset the track seed with the dummy covariance
0686       auto seed = ActsTrackFittingAlgorithm::TrackParameters::create(
0687                       pSurface,
0688                       m_transient_geocontext,
0689                       actsFourPos,
0690                       momentum,
0691                       charge / momentum.norm(),
0692                       cov,
0693                       Acts::ParticleHypothesis::pion())
0694                       .value();
0695 
0696       if (Verbosity() > 2)
0697       {
0698         printTrackSeed(seed);
0699       }
0700 
0701       /// Set host of propagator options for Acts to do e.g. material integration
0702       Acts::PropagatorPlainOptions ppPlainOptions;
0703 
0704       auto calibptr = std::make_unique<Calibrator>();
0705       CalibratorAdapter calibrator{*calibptr, measurements};
0706 
0707       auto magcontext = m_tGeometry->geometry().magFieldContext;
0708       auto calibcontext = m_tGeometry->geometry().calibContext;
0709 
0710       ActsTrackFittingAlgorithm::GeneralFitterOptions
0711           kfOptions{
0712               m_transient_geocontext,
0713               magcontext,
0714               calibcontext,
0715               pSurface.get(),
0716               ppPlainOptions};
0717 
0718       PHTimer fitTimer("FitTimer");
0719       fitTimer.stop();
0720       fitTimer.restart();
0721 
0722       auto trackContainer = std::make_shared<Acts::VectorTrackContainer>();
0723       auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>();
0724       ActsTrackFittingAlgorithm::TrackContainer tracks(trackContainer, trackStateContainer);
0725 
0726       if(Verbosity() > 1)
0727       {  std::cout << "Calling fitTrack for track with siid " << siid << " tpcid " << tpcid << " crossing " << crossing << std::endl; }
0728 
0729       auto result = fitTrack(sourceLinks, seed, kfOptions, surfaces, calibrator, tracks);
0730       fitTimer.stop();
0731 
0732       if (Verbosity() > 1)
0733       {
0734         const auto fitTime = fitTimer.get_accumulated_time();
0735         std::cout << "PHActsTrkFitter Acts fit time " << fitTime << std::endl;
0736       }
0737 
0738       /// Check that the track fit result did not return an error
0739       if (result.ok())
0740       {
0741         if (use_estimate)  // trial variation case
0742         {
0743           // this is a trial variation of the crossing estimate for this track
0744           // Capture the chisq/ndf so we can choose the best one after all trials
0745 
0746           SvtxTrack_v4 newTrack;
0747           newTrack.set_tpc_seed(tpcseed);
0748           newTrack.set_crossing(this_crossing);
0749           newTrack.set_silicon_seed(siseed);
0750 
0751           if (getTrackFitResult(result, track, &newTrack, tracks, measurements))
0752           {
0753             float chi2ndf = newTrack.get_quality();
0754             chisq_ndf.push_back(chi2ndf);
0755             svtx_vec.push_back(newTrack);
0756             if (Verbosity() > 1)
0757             {
0758               std::cout << "   tpcid " << tpcid << " siid " << siid << " ivary " << ivary << " this_crossing " << this_crossing << " chi2ndf " << chi2ndf << std::endl;
0759             }
0760           }
0761 
0762           if (ivary != nvary)
0763           {
0764             if(Verbosity() > 3)
0765             {
0766               std::cout << "Skipping track fit for trial variation" << std::endl;
0767             }
0768             continue;
0769           }
0770 
0771           // if we are here this is the last crossing iteration, evaluate the results
0772           if (Verbosity() > 1)
0773           {
0774             std::cout << "Finished with trial fits, chisq_ndf size is " << chisq_ndf.size() << " chisq_ndf values are:" << std::endl;
0775           }
0776           float best_chisq = 1000.0;
0777           short int best_ivary = 0;
0778           for (unsigned int i = 0; i < chisq_ndf.size(); ++i)
0779           {
0780             if (chisq_ndf[i] < best_chisq)
0781             {
0782               best_chisq = chisq_ndf[i];
0783               best_ivary = i;
0784             }
0785             if (Verbosity() > 1)
0786             {
0787               std::cout << "  trial " << i << " chisq_ndf " << chisq_ndf[i] << " best_chisq " << best_chisq << " best_ivary " << best_ivary << std::endl;
0788             }
0789           }
0790           unsigned int trid = m_trackMap->size();
0791           svtx_vec[best_ivary].set_id(trid);
0792 
0793           m_trackMap->insertWithKey(&svtx_vec[best_ivary], trid);
0794         }
0795         else  // case where INTT crossing is known
0796         {
0797           SvtxTrack_v4 newTrack;
0798           newTrack.set_tpc_seed(tpcseed);
0799           newTrack.set_crossing(this_crossing);
0800           newTrack.set_silicon_seed(siseed);
0801 
0802           if (m_fitSiliconMMs)
0803           {
0804             unsigned int trid = m_directedTrackMap->size();
0805             newTrack.set_id(trid);
0806 
0807             if (getTrackFitResult(result, track, &newTrack, tracks, measurements))
0808             {
0809 
0810               // insert in dedicated map
0811               m_directedTrackMap->insertWithKey(&newTrack, trid);
0812             }
0813 
0814           }  // end insert track for SC calib fit
0815           else
0816           {
0817             unsigned int trid = m_trackMap->size();
0818             newTrack.set_id(trid);
0819 
0820             if (getTrackFitResult(result, track, &newTrack, tracks, measurements))
0821             {
0822               m_trackMap->insertWithKey(&newTrack, trid);
0823             }
0824           }  // end insert track for normal fit
0825         }    // end case where INTT crossing is known
0826 
0827 
0828 
0829 
0830       }
0831       else if (!m_fitSiliconMMs)
0832       {
0833         /// Track fit failed, get rid of the track from the map
0834         m_nBadFits++;
0835         if (Verbosity() > 1)
0836         {
0837           std::cout << "Track fit failed for track " << m_seedMap->find(track)
0838                     << " with Acts error message "
0839                     << result.error() << ", " << result.error().message()
0840                     << std::endl;
0841         }
0842       }  // end fit failed case
0843     }    // end ivary loop
0844 
0845     trackTimer.stop();
0846     auto trackTime = trackTimer.get_accumulated_time();
0847 
0848     if (Verbosity() > 1)
0849     {
0850       std::cout << "PHActsTrkFitter total single track time " << trackTime << std::endl;
0851     }
0852   }
0853 
0854   return;
0855 }
0856 
0857 bool PHActsTrkFitter::getTrackFitResult(
0858   const FitResult& fitOutput,
0859   TrackSeed* seed, SvtxTrack* track,
0860   const ActsTrackFittingAlgorithm::TrackContainer& tracks,
0861   const ActsTrackFittingAlgorithm::MeasurementContainer& measurements)
0862 {
0863   /// Make a trajectory state for storage, which conforms to Acts track fit
0864   /// analysis tool
0865   std::vector<Acts::MultiTrajectoryTraits::IndexType> trackTips;
0866   trackTips.reserve(1);
0867   const auto& outtrack = fitOutput.value();
0868   if (outtrack.hasReferenceSurface())
0869   {
0870     trackTips.emplace_back(outtrack.tipIndex());
0871     Trajectory::IndexedParameters indexedParams;
0872 
0873     // retrieve track parameters from fit result
0874     Acts::BoundTrackParameters parameters = ActsExamples::TrackParameters(outtrack.referenceSurface().getSharedPtr(),
0875       outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis());
0876 
0877     indexedParams.emplace(
0878       outtrack.tipIndex(),
0879       ActsExamples::TrackParameters{outtrack.referenceSurface().getSharedPtr(),
0880       outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()});
0881 
0882     if (Verbosity() > 2)
0883     {
0884       std::cout << "Fitted parameters for track" << std::endl;
0885       std::cout << " position : " << outtrack.referenceSurface().localToGlobal(m_transient_geocontext, Acts::Vector2(outtrack.loc0(), outtrack.loc1()), Acts::Vector3(1, 1, 1)).transpose()
0886 
0887                 << std::endl;
0888       int otcharge = outtrack.qOverP() > 0 ? 1 : -1;
0889       std::cout << "charge: " << otcharge << std::endl;
0890       std::cout << " momentum : " << outtrack.momentum().transpose()
0891                 << std::endl;
0892       std::cout << "For trackTip == " << outtrack.tipIndex() << std::endl;
0893     }
0894 
0895     /// Get position, momentum from the Acts output. Update the values of
0896     /// the proto track
0897     PHTimer updateTrackTimer("UpdateTrackTimer");
0898     updateTrackTimer.stop();
0899     updateTrackTimer.restart();
0900     updateSvtxTrack(trackTips, indexedParams, tracks, track);
0901 
0902     if (m_commissioning)
0903     {
0904       if (track->get_silicon_seed() && track->get_tpc_seed())
0905       {
0906         m_alignStates.fillAlignmentStateMap(tracks, trackTips,
0907                                             track, measurements);
0908       }
0909     }
0910 
0911     updateTrackTimer.stop();
0912     auto updateTime = updateTrackTimer.get_accumulated_time();
0913 
0914     if (Verbosity() > 1)
0915     {
0916       std::cout << "PHActsTrkFitter update SvtxTrack time "
0917                 << updateTime << std::endl;
0918     }
0919 
0920     if (m_timeAnalysis)
0921     {
0922       h_updateTime->Fill(updateTime);
0923     }
0924 
0925     Trajectory trajectory(tracks.trackStateContainer(),
0926                           trackTips, indexedParams);
0927 
0928     if (m_actsEvaluator)
0929     {
0930       m_evaluator->evaluateTrackFit(tracks, trackTips, indexedParams, track,
0931                                     seed, measurements);
0932     }
0933 
0934     return true;
0935   }
0936 
0937   return false;
0938 }
0939 
0940 //__________________________________________________________________________________
0941 ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack(
0942     const std::vector<Acts::SourceLink>& sourceLinks,
0943     const ActsTrackFittingAlgorithm::TrackParameters& seed,
0944     const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions,
0945     const SurfacePtrVec& surfSequence,
0946     const CalibratorAdapter& calibrator,
0947     ActsTrackFittingAlgorithm::TrackContainer& tracks)
0948 {
0949   // use direct fit for silicon MM gits or direct navigation
0950   if (m_fitSiliconMMs || m_directNavigation)
0951   { return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, calibrator, tracks); }
0952 
0953   // use full fit in all other cases
0954   return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, calibrator, tracks);
0955 }
0956 
0957 //__________________________________________________________________________________
0958 SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, SurfacePtrVec& surfaces) const
0959 {
0960   SourceLinkVec siliconMMSls;
0961 
0962   //   if(Verbosity() > 1)
0963   //     std::cout << "Sorting " << sourceLinks.size() << " SLs" << std::endl;
0964 
0965   for (const auto& sl : sourceLinks)
0966   {
0967     const ActsSourceLink asl = sl.get<ActsSourceLink>();
0968     if (Verbosity() > 1)
0969     {
0970       std::cout << "SL available on : " << asl.geometryId() << std::endl;
0971     }
0972 
0973     const auto* const surf = m_tGeometry->geometry().tGeometry->findSurface(asl.geometryId());
0974     if (m_fitSiliconMMs)
0975     {
0976       // skip TPC surfaces
0977       if (m_tGeometry->maps().isTpcSurface(surf))
0978       {
0979         continue;
0980       }
0981 
0982       // also skip micromegas surfaces if not used
0983       if (m_tGeometry->maps().isMicromegasSurface(surf) && !m_useMicromegas)
0984       {
0985         continue;
0986       }
0987     }
0988 
0989     if(m_forceSiOnlyFit)
0990     {
0991       if(m_tGeometry->maps().isMicromegasSurface(surf)||m_tGeometry->maps().isTpcSurface(surf))
0992       {
0993         continue;
0994       }
0995     }
0996 
0997     // update vectors
0998     siliconMMSls.push_back(sl);
0999     surfaces.push_back(surf);
1000   }
1001 
1002   if (Verbosity() > 10)
1003   {
1004     for (const auto& surf : surfaces)
1005     {
1006       std::cout << "Surface vector : " << surf->geometryId() << std::endl;
1007     }
1008   }
1009 
1010   return siliconMMSls;
1011 }
1012 
1013 void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const
1014 {
1015   for (unsigned int i = 0; i < surfaces.size() - 1; i++)
1016   {
1017     const auto& surface = surfaces.at(i);
1018     const auto thisVolume = surface->geometryId().volume();
1019     const auto thisLayer = surface->geometryId().layer();
1020 
1021     const auto nextSurface = surfaces.at(i + 1);
1022     const auto nextVolume = nextSurface->geometryId().volume();
1023     const auto nextLayer = nextSurface->geometryId().layer();
1024 
1025     /// Implement a check to ensure surfaces are sorted
1026     if (nextVolume == thisVolume)
1027     {
1028       if (nextLayer < thisLayer)
1029       {
1030         std::cout
1031             << "PHActsTrkFitter::checkSurfaceVec - "
1032             << "Surface not in order... removing surface"
1033             << surface->geometryId() << std::endl;
1034 
1035         surfaces.erase(surfaces.begin() + i);
1036 
1037         /// Subtract one so we don't skip a surface
1038         --i;
1039         continue;
1040       }
1041     }
1042     else
1043     {
1044       if (nextVolume < thisVolume)
1045       {
1046         std::cout
1047             << "PHActsTrkFitter::checkSurfaceVec - "
1048             << "Volume not in order... removing surface"
1049             << surface->geometryId() << std::endl;
1050 
1051         surfaces.erase(surfaces.begin() + i);
1052 
1053         /// Subtract one so we don't skip a surface
1054         --i;
1055         continue;
1056       }
1057     }
1058   }
1059 }
1060 
1061 void PHActsTrkFitter::updateSvtxTrack(
1062   const std::vector<Acts::MultiTrajectoryTraits::IndexType>& tips,
1063   const Trajectory::IndexedParameters& paramsMap,
1064   const ActsTrackFittingAlgorithm::TrackContainer& tracks,
1065   SvtxTrack* track)
1066 {
1067   const auto& mj = tracks.trackStateContainer();
1068 
1069   /// only one track tip in the track fit Trajectory
1070   const auto& trackTip = tips.front();
1071 
1072   if (Verbosity() > 2)
1073   {
1074     std::cout << "Identify (proto) track before updating with acts results " << std::endl;
1075     track->identify();
1076   }
1077 
1078   if (!m_fitSiliconMMs && !m_forceSiOnlyFit)
1079   {
1080     track->clear_states();
1081   }
1082 
1083   // create a state at pathlength = 0.0
1084   // This state holds the track parameters, which will be updated below
1085   float pathlength = 0.0;
1086   //  SvtxTrackState_v1 out(pathlength);
1087   SvtxTrackState_v3 out(pathlength);
1088   out.set_localX(0.0);
1089   out.set_localY(0.0);
1090   out.set_x(0.0);
1091   out.set_y(0.0);
1092   out.set_z(0.0);
1093   track->insert_state(&out);
1094 
1095   auto trajState =
1096       Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip);
1097 
1098   const auto& params = paramsMap.find(trackTip)->second;
1099 
1100   /// Acts default unit is mm. So convert to cm
1101   track->set_x(params.position(m_transient_geocontext)(0) / Acts::UnitConstants::cm);
1102   track->set_y(params.position(m_transient_geocontext)(1) / Acts::UnitConstants::cm);
1103   track->set_z(params.position(m_transient_geocontext)(2) / Acts::UnitConstants::cm);
1104 
1105   track->set_px(params.momentum()(0));
1106   track->set_py(params.momentum()(1));
1107   track->set_pz(params.momentum()(2));
1108 
1109   track->set_charge(params.charge());
1110   track->set_chisq(trajState.chi2Sum);
1111   track->set_ndf(trajState.NDF);
1112 
1113   ActsTransformations transformer;
1114   transformer.setVerbosity(Verbosity());
1115 
1116   if (params.covariance())
1117   {
1118     auto rotatedCov = transformer.rotateActsCovToSvtxTrack(params);
1119 
1120     for (int i = 0; i < 6; i++)
1121     {
1122       for (int j = 0; j < 6; j++)
1123       {
1124         track->set_error(i, j, rotatedCov(i, j));
1125       }
1126     }
1127   }
1128 
1129   // Also need to update the state list and cluster ID list for all measurements associated with the acts track
1130   // loop over acts track states, copy over to SvtxTrackStates, and add to SvtxTrack
1131   PHTimer trackStateTimer("TrackStateTimer");
1132   trackStateTimer.stop();
1133   trackStateTimer.restart();
1134 
1135   if (m_fillSvtxTrackStates)
1136   { transformer.fillSvtxTrackStates(mj, trackTip, track, m_transient_geocontext); }
1137 
1138   // in using silicon mm fit also extrapolate track parameters to all TPC surfaces with clusters
1139   // get all tpc clusters
1140   auto* seed = track->get_tpc_seed();
1141   if( m_fitSiliconMMs && seed )
1142   {
1143 
1144     // acts propagator
1145     ActsPropagator propagator(m_tGeometry);
1146 
1147     // loop over cluster keys associated to TPC seed
1148     for( auto key_iter = seed->begin_cluster_keys(); key_iter != seed->end_cluster_keys(); ++key_iter )
1149     {
1150       const auto& cluskey = *key_iter;
1151 
1152       // make sure cluster is from TPC
1153       const auto detId = TrkrDefs::getTrkrId(cluskey);
1154       if (detId != TrkrDefs::tpcId)
1155       { continue; }
1156 
1157       // get layer, propagate
1158       const auto layer = TrkrDefs::getLayer(cluskey);
1159       auto result = propagator.propagateTrack(params, layer);
1160       if( !result.ok() ) { continue; }
1161 
1162       // get path length and extrapolated parameters
1163       auto& [pathLength, trackStateParams] = result.value();
1164       pathLength /= Acts::UnitConstants::cm;
1165 
1166       // create track state and add to track
1167       transformer.addTrackState(track, cluskey, pathLength, trackStateParams, m_transient_geocontext);
1168     }
1169   }
1170 
1171   trackStateTimer.stop();
1172   auto stateTime = trackStateTimer.get_accumulated_time();
1173 
1174   if (Verbosity() > 1)
1175   {
1176     std::cout << "PHActsTrkFitter update SvtxTrackStates time "
1177               << stateTime << std::endl;
1178   }
1179 
1180   if (m_timeAnalysis)
1181   {
1182     h_stateTime->Fill(stateTime);
1183   }
1184 
1185   if (Verbosity() > 2)
1186   {
1187     std::cout << " Identify fitted track after updating track states:"
1188               << std::endl;
1189     track->identify();
1190   }
1191 
1192   return;
1193 }
1194 
1195 Acts::BoundSquareMatrix PHActsTrkFitter::setDefaultCovariance() const
1196 {
1197   Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero();
1198 
1199   /// Acts cares about the track covariance as it helps the KF
1200   /// know whether or not to trust the initial track seed or not.
1201   /// We reset it here to some loose values as it helps Acts improve
1202   /// the fitting.
1203   /// If the covariance is too loose, it won't be able to propagate,
1204   /// but if it is too tight, it will just "believe" the track seed over
1205   /// the hit data
1206 
1207   /// If we are using distortions, then we need to blow up the covariance
1208   /// a bit since the seed was created with distorted TPC clusters
1209   if (m_fitSiliconMMs)
1210   {
1211     cov << 1000 * Acts::UnitConstants::um, 0., 0., 0., 0., 0.,
1212         0., 1000 * Acts::UnitConstants::um, 0., 0., 0., 0.,
1213         0., 0., 0.1, 0., 0., 0.,
1214         0., 0., 0., 0.1, 0., 0.,
1215         0., 0., 0., 0., 0.005, 0.,
1216         0., 0., 0., 0., 0., 1.;
1217   }
1218   else
1219   {
1220     // cppcheck-suppress duplicateAssignExpression
1221     double sigmaD0 = 50 * Acts::UnitConstants::um;
1222     double sigmaZ0 = 50 * Acts::UnitConstants::um;
1223     // cppcheck-suppress duplicateAssignExpression
1224     double sigmaPhi = 1. * Acts::UnitConstants::degree;
1225     double sigmaTheta = 1. * Acts::UnitConstants::degree;
1226     double sigmaT = 1. * Acts::UnitConstants::ns;
1227 
1228     cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = sigmaD0 * sigmaD0;
1229     cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = sigmaZ0 * sigmaZ0;
1230     cov(Acts::eBoundTime, Acts::eBoundTime) = sigmaT * sigmaT;
1231     cov(Acts::eBoundPhi, Acts::eBoundPhi) = sigmaPhi * sigmaPhi;
1232     cov(Acts::eBoundTheta, Acts::eBoundTheta) = sigmaTheta * sigmaTheta;
1233     /// Acts takes this value very seriously - tuned to be in a "sweet spot"
1234     //    cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 0.0001;
1235     cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = 0.025;
1236   }
1237 
1238   return cov;
1239 }
1240 
1241 void PHActsTrkFitter::printTrackSeed(const ActsTrackFittingAlgorithm::TrackParameters& seed) const
1242 {
1243   std::cout
1244       << PHWHERE
1245       << " Processing proto track:"
1246       << std::endl;
1247 
1248   std::cout
1249       << "position: " << seed.position(m_transient_geocontext).transpose()
1250       << std::endl
1251       << "momentum: " << seed.momentum().transpose()
1252       << std::endl;
1253 
1254   std::cout << "charge : " << seed.charge() << std::endl;
1255   std::cout << "absolutemom : " << seed.absoluteMomentum() << std::endl;
1256 }
1257 
1258 int PHActsTrkFitter::createNodes(PHCompositeNode* topNode)
1259 {
1260   PHNodeIterator iter(topNode);
1261 
1262   PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
1263 
1264   if (!dstNode)
1265   {
1266     std::cerr << "DST node is missing, quitting" << std::endl;
1267     throw std::runtime_error("Failed to find DST node in PHActsTrkFitter::createNodes");
1268   }
1269 
1270   PHNodeIterator dstIter(topNode);
1271   PHCompositeNode* svtxNode = dynamic_cast<PHCompositeNode*>(dstIter.findFirst("PHCompositeNode", "SVTX"));
1272 
1273   if (!svtxNode)
1274   {
1275     svtxNode = new PHCompositeNode("SVTX");
1276     dstNode->addNode(svtxNode);
1277   }
1278 
1279   if (m_fitSiliconMMs)
1280   {
1281     m_directedTrackMap = findNode::getClass<SvtxTrackMap>(topNode,
1282                                                           "SvtxSiliconMMTrackMap");
1283     if (!m_directedTrackMap)
1284     {
1285       /// Copy this trackmap, then use it for the rest of processing
1286       m_directedTrackMap = new SvtxTrackMap_v2;
1287 
1288       PHIODataNode<PHObject>* trackNode =
1289           new PHIODataNode<PHObject>(m_directedTrackMap, "SvtxSiliconMMTrackMap", "PHObject");
1290       svtxNode->addNode(trackNode);
1291     }
1292   }
1293 
1294   m_trackMap = findNode::getClass<SvtxTrackMap>(topNode, _track_map_name);
1295 
1296   if (!m_trackMap)
1297   {
1298     m_trackMap = new SvtxTrackMap_v2;
1299     PHIODataNode<PHObject>* node = new PHIODataNode<PHObject>(m_trackMap, _track_map_name, "PHObject");
1300     svtxNode->addNode(node);
1301   }
1302 
1303   m_alignmentStateMap = findNode::getClass<SvtxAlignmentStateMap>(topNode, _svtx_alignment_state_map_name);
1304   if (!m_alignmentStateMap)
1305   {
1306     m_alignmentStateMap = new SvtxAlignmentStateMap_v1;
1307     auto node = new PHDataNode<SvtxAlignmentStateMap>(m_alignmentStateMap, _svtx_alignment_state_map_name, "PHObject");
1308     svtxNode->addNode(node);
1309   }
1310 
1311   return Fun4AllReturnCodes::EVENT_OK;
1312 }
1313 
1314 int PHActsTrkFitter::getNodes(PHCompositeNode* topNode)
1315 {
1316   m_alignmentTransformationMap = findNode::getClass<alignmentTransformationContainer>(topNode, "alignmentTransformationContainer");
1317   if (!m_alignmentTransformationMap)
1318   {
1319     std::cout << PHWHERE << "alignmentTransformationContainer not on node tree. Bailing"
1320               << std::endl;
1321     return Fun4AllReturnCodes::ABORTEVENT;
1322   }
1323 
1324   m_alignmentTransformationMapTransient = findNode::getClass<alignmentTransformationContainer>(topNode, "alignmentTransformationContainerTransient");
1325   if (!m_alignmentTransformationMapTransient)
1326   {
1327     std::cout << PHWHERE << "alignmentTransformationContainerTransient not on node tree. Bailing"
1328               << std::endl;
1329     return Fun4AllReturnCodes::ABORTEVENT;
1330   }
1331 
1332   // tpc seeds
1333   m_tpcSeeds = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
1334   if (!m_tpcSeeds)
1335   {
1336     std::cout << PHWHERE << "TpcTrackSeedContainer not on node tree. Bailing"
1337               << std::endl;
1338     return Fun4AllReturnCodes::ABORTEVENT;
1339   }
1340 
1341   // silicon seeds
1342   m_siliconSeeds = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
1343   if (!m_siliconSeeds)
1344   {
1345     std::cout << PHWHERE << "SiliconTrackSeedContainer not on node tree. Bailing"
1346               << std::endl;
1347     return Fun4AllReturnCodes::ABORTEVENT;
1348   }
1349 
1350   // clusters
1351   m_clusterContainer = findNode::getClass<TrkrClusterContainer>(topNode, m_clusterContainerName);
1352   if (!m_clusterContainer)
1353   {
1354     std::cout << PHWHERE
1355               << "No trkr cluster container, exiting." << std::endl;
1356     return Fun4AllReturnCodes::ABORTEVENT;
1357   }
1358 
1359   // acts geometry
1360   m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
1361   if (!m_tGeometry)
1362   {
1363     std::cout << "ActsGeometry not on node tree. Exiting."
1364               << std::endl;
1365 
1366     return Fun4AllReturnCodes::ABORTEVENT;
1367   }
1368 
1369   // track seeds
1370   m_seedMap = findNode::getClass<TrackSeedContainer>(topNode, _svtx_seed_map_name);
1371   if (!m_seedMap)
1372   {
1373     std::cout << "No Svtx seed map on node tree. Exiting."
1374               << std::endl;
1375     return Fun4AllReturnCodes::ABORTEVENT;
1376   }
1377 
1378   // tpc global position wrapper
1379   m_globalPositionWrapper.loadNodes(topNode);
1380   m_globalPositionWrapper.set_suppressCrossing(true);
1381 
1382   return Fun4AllReturnCodes::EVENT_OK;
1383 }