Back to home page

sPhenix code displayed by LXR

 
 

    


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

0001 #include "PHTpcResiduals.h"
0002 #include "TpcSpaceChargeMatrixContainerv2.h"
0003 
0004 #include <trackbase/ActsGeometry.h>
0005 #include <trackbase/ActsSurfaceMaps.h>
0006 #include <trackbase/ActsTrackingGeometry.h>
0007 #include <trackbase/TrkrCluster.h>
0008 #include <trackbase/TrkrClusterContainer.h>
0009 
0010 #include <trackbase_historic/SvtxTrack.h>
0011 #include <trackbase_historic/SvtxTrackMap.h>
0012 #include <trackbase_historic/SvtxTrackState.h>
0013 #include <trackbase_historic/TrackSeed.h>
0014 
0015 #include <micromegas/MicromegasDefs.h>
0016 
0017 #include <fun4all/Fun4AllReturnCodes.h>
0018 
0019 #include <phool/PHCompositeNode.h>
0020 #include <phool/getClass.h>
0021 #include <phool/phool.h>
0022 
0023 #include <Acts/Definitions/TrackParametrization.hpp>
0024 #include <Acts/Definitions/Units.hpp>
0025 #include <Acts/EventData/GenericBoundTrackParameters.hpp>
0026 #include <Acts/EventData/ParticleHypothesis.hpp>
0027 #include <Acts/Surfaces/PerigeeSurface.hpp>
0028 #include <Acts/Surfaces/Surface.hpp>
0029 #include <Acts/Utilities/Result.hpp>
0030 
0031 #include <TFile.h>
0032 #include <TH1.h>
0033 
0034 #include <cassert>
0035 #include <iostream>
0036 #include <limits>
0037 
0038 namespace
0039 {
0040 
0041   // square
0042   template <class T>
0043   constexpr T square(const T& x)
0044   {
0045     return x * x;
0046   }
0047 
0048   // radius
0049   template <class T>
0050   T get_r(const T& x, const T& y)
0051   {
0052     return std::sqrt(square(x) + square(y));
0053   }
0054 
0055   template <class T>
0056   constexpr T deltaPhi(const T& phi)
0057   {
0058     if (phi > M_PI)
0059     {
0060       return phi - 2. * M_PI;
0061     }
0062     if (phi <= -M_PI)
0063     {
0064       return phi + 2. * M_PI;
0065     }
0066 
0067     return phi;
0068   }
0069 
0070   /// get sector median angle associated to a given index
0071   /** this assumes that sector 0 is centered on phi=0, then numbered along increasing phi */
0072   constexpr double get_sector_phi(int isec)
0073   {
0074     return isec * M_PI / 6;
0075   }
0076 
0077   // specify bins for which one will save histograms
0078   const std::vector<float> phi_rec = {get_sector_phi(9)};
0079   const std::vector<float> z_rec = {5.};
0080 
0081   //! get cluster keys from a given track
0082   std::vector<TrkrDefs::cluskey> get_cluster_keys(SvtxTrack* track)
0083   {
0084     std::vector<TrkrDefs::cluskey> out;
0085     for (const auto& seed : {track->get_silicon_seed(), track->get_tpc_seed()})
0086     {
0087       if (seed)
0088       {
0089         std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out));
0090       }
0091     }
0092     return out;
0093   }
0094 
0095   std::vector<TrkrDefs::cluskey> get_state_keys(SvtxTrack* track)
0096   {
0097     std::vector<TrkrDefs::cluskey> out;
0098     for (auto state_iter = track->begin_states();
0099          state_iter != track->end_states();
0100          ++state_iter)
0101     {
0102       SvtxTrackState* tstate = state_iter->second;
0103       auto stateckey = tstate->get_cluskey();
0104       out.push_back(stateckey);
0105     }
0106     return out;
0107   }
0108 
0109   /// return number of clusters of a given type that belong to a tracks
0110   template <int type>
0111   int count_clusters(const std::vector<TrkrDefs::cluskey>& keys)
0112   {
0113     return std::count_if(keys.begin(), keys.end(),
0114                          [](const TrkrDefs::cluskey& key)
0115                          { return TrkrDefs::getTrkrId(key) == type; });
0116   }
0117 
0118   /// streamer
0119   std::ostream& operator<<(std::ostream& out, const Acts::Vector3& v)
0120   {
0121     out << "(" << v.x() << "," << v.y() << "," << v.z() << ")";
0122     return out;
0123   }
0124 
0125 }  // namespace
0126 
0127 //___________________________________________________________________________________
0128 PHTpcResiduals::PHTpcResiduals(const std::string& name)
0129   : SubsysReco(name)
0130   , m_matrix_container(new TpcSpaceChargeMatrixContainerv2)
0131 {
0132 }
0133 
0134 //___________________________________________________________________________________
0135 int PHTpcResiduals::Init(PHCompositeNode* /*topNode*/)
0136 {
0137   // configuration printout
0138   std::cout << "PHTpcResiduals::Init - m_maxTAlpha: " << m_maxTAlpha << std::endl;
0139   std::cout << "PHTpcResiduals::Init - m_maxTBeta: " << m_maxTBeta << std::endl;
0140   std::cout << "PHTpcResiduals::Init - m_maxResidualDrphi: " << m_maxResidualDrphi << " cm" << std::endl;
0141   std::cout << "PHTpcResiduals::Init - m_maxResidualDz: " << m_maxResidualDz << " cm" << std::endl;
0142   std::cout << "PHTpcResiduals::Init - m_minRPhiErr: " << m_minRPhiErr << " cm" << std::endl;
0143   std::cout << "PHTpcResiduals::Init - m_minZErr: " << m_minZErr << " cm" << std::endl;
0144   std::cout << "PHTpcResiduals::Init - m_minPt: " << m_minPt << " GeV/c" << std::endl;
0145   std::cout << "PHTpcResiduals::Init - m_requireCrossing: " << m_requireCrossing << std::endl;
0146 
0147   // reset counters
0148   m_total_tracks = 0;
0149   m_accepted_tracks = 0;
0150 
0151   m_total_clusters = 0;
0152   m_accepted_clusters = 0;
0153 
0154   return Fun4AllReturnCodes::EVENT_OK;
0155 }
0156 
0157 //___________________________________________________________________________________
0158 int PHTpcResiduals::InitRun(PHCompositeNode* topNode)
0159 {
0160   if (getNodes(topNode) != Fun4AllReturnCodes::EVENT_OK)
0161   {
0162     return Fun4AllReturnCodes::ABORTEVENT;
0163   }
0164 
0165   if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK)
0166   {
0167     return Fun4AllReturnCodes::ABORTEVENT;
0168   }
0169   m_zMax = m_tGeometry->get_max_driftlength() + m_tGeometry->get_CM_halfwidth();
0170   m_zMin = -m_zMax;
0171   return Fun4AllReturnCodes::EVENT_OK;
0172 }
0173 
0174 //___________________________________________________________________________________
0175 int PHTpcResiduals::process_event(PHCompositeNode* topNode)
0176 {
0177   const auto returnVal = processTracks(topNode);
0178   ++m_event;
0179 
0180   return returnVal;
0181 }
0182 
0183 //___________________________________________________________________________________
0184 int PHTpcResiduals::End(PHCompositeNode* /*topNode*/)
0185 {
0186   std::cout << "PHTpcResiduals::End - writing matrices to " << m_outputfile << std::endl;
0187 
0188   // save matrix container in output file
0189   if (m_matrix_container)
0190   {
0191     std::unique_ptr<TFile> outputfile(TFile::Open(m_outputfile.c_str(), "RECREATE"));
0192     outputfile->cd();
0193     m_matrix_container->Write("TpcSpaceChargeMatrixContainer");
0194   }
0195 
0196   // print counters
0197   std::cout
0198       << "PHTpcResiduals::End -"
0199       << " track statistics total: " << m_total_tracks
0200       << " accepted: " << m_accepted_tracks
0201       << " fraction: " << 100. * m_accepted_tracks / m_total_tracks << "%"
0202       << std::endl;
0203 
0204   std::cout
0205       << "PHTpcResiduals::End -"
0206       << " cluster statistics total: " << m_total_clusters
0207       << " accepted: " << m_accepted_clusters << " fraction: "
0208       << 100. * m_accepted_clusters / m_total_clusters << "%"
0209       << std::endl;
0210 
0211   return Fun4AllReturnCodes::EVENT_OK;
0212 }
0213 
0214 //___________________________________________________________________________________
0215 int PHTpcResiduals::processTracks(PHCompositeNode* /*topNode*/)
0216 {
0217   if (Verbosity())
0218   {
0219     std::cout << "PHTpcResiduals::processTracks - proto track size " << m_trackMap->size() << std::endl;
0220   }
0221 
0222   for (const auto& [trackKey, track] : *m_trackMap)
0223   {
0224     if (Verbosity() > 1)
0225     {
0226       std::cout << "PHTpcResiduals::processTracks - Processing track key " << trackKey << std::endl;
0227     }
0228 
0229     ++m_total_tracks;
0230     if (checkTrack(track))
0231     {
0232       ++m_accepted_tracks;
0233       processTrack(track);
0234     }
0235   }
0236 
0237   return Fun4AllReturnCodes::EVENT_OK;
0238 }
0239 
0240 //___________________________________________________________________________________
0241 bool PHTpcResiduals::checkTrack(SvtxTrack* track) const
0242 {
0243   if (Verbosity() > 2)
0244   {
0245     std::cout << "PHTpcResiduals::checkTrack - pt: " << track->get_pt() << std::endl;
0246   }
0247 
0248   if (m_requireCrossing && track->get_crossing() != 0)
0249   {
0250     return false;
0251   }
0252 
0253   if (track->get_pt() < m_minPt)
0254   {
0255     return false;
0256   }
0257 
0258   // ignore tracks with too few mvtx, intt and micromegas hits
0259   const auto cluster_keys(get_cluster_keys(track));
0260   if (count_clusters<TrkrDefs::mvtxId>(cluster_keys) < 3)
0261   {
0262     return false;
0263   }
0264   if (count_clusters<TrkrDefs::inttId>(cluster_keys) < 2)
0265   {
0266     return false;
0267   }
0268   if (count_clusters<TrkrDefs::tpcId>(cluster_keys) < 35)
0269   {
0270     return false;
0271   }
0272   //  if (m_useMicromegas && count_clusters<TrkrDefs::micromegasId>(cluster_keys) < 2)
0273   //  {
0274   //    return false;
0275   //  }
0276 
0277   const auto state_keys(get_state_keys(track));
0278   if (count_clusters<TrkrDefs::mvtxId>(state_keys) < 3)
0279   {
0280     return false;
0281   }
0282   if (count_clusters<TrkrDefs::inttId>(state_keys) < 2)
0283   {
0284     return false;
0285   }
0286   //  if (m_useMicromegas && count_clusters<TrkrDefs::micromegasId>(state_keys) < 2)
0287   //  {
0288   //    return false;
0289   //  }
0290 
0291   if (m_useMicromegas && checkTPOTResidual(track) == false)
0292   {
0293     return false;
0294   }
0295 
0296   return true;
0297 }
0298 
0299 //___________________________________________________________________________________
0300 bool PHTpcResiduals::checkTPOTResidual(SvtxTrack* track) const
0301 {
0302   bool flag = true;
0303 
0304   int nTPOTcluster = 0;
0305   int nTPOTstate = 0;
0306   int TPOTtileID = -1;
0307   for (const auto& cluskey : get_cluster_keys(track))
0308   {
0309     // make sure cluster is from TPOT
0310     const auto detId = TrkrDefs::getTrkrId(cluskey);
0311     if (detId != TrkrDefs::micromegasId)
0312     {
0313       continue;
0314     }
0315     TPOTtileID = MicromegasDefs::getTileId(cluskey);
0316     nTPOTcluster++;
0317 
0318     auto* const cluster = m_clusterContainer->findCluster(cluskey);
0319 
0320     SvtxTrackState* state = nullptr;
0321 
0322     // the track states from the Acts fit are fitted to fully corrected clusters, and are on the surface
0323     for (auto state_iter = track->begin_states();
0324          state_iter != track->end_states();
0325          ++state_iter)
0326     {
0327       SvtxTrackState* tstate = state_iter->second;
0328       auto stateckey = tstate->get_cluskey();
0329       if (stateckey == cluskey)
0330       {
0331         state = tstate;
0332         break;
0333       }
0334     }
0335 
0336     const auto layer = TrkrDefs::getLayer(cluskey);
0337 
0338     if (!state)
0339     {
0340       if (Verbosity() > 1)
0341       {
0342         std::cout << "   no state for cluster " << cluskey << "  in layer " << layer << std::endl;
0343       }
0344       continue;
0345     }
0346     nTPOTstate++;
0347 
0348     const auto crossing = track->get_crossing();
0349     assert(crossing != std::numeric_limits<short>::max());
0350 
0351     // calculate residuals with respect to cluster
0352     // Get all the relevant information for residual calculation
0353     const auto globClusPos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(cluskey, cluster, crossing);
0354     const double clusR = get_r(globClusPos(0), globClusPos(1));
0355     const double clusPhi = std::atan2(globClusPos(1), globClusPos(0));
0356     const double clusZ = globClusPos(2);
0357 
0358     const double globStateX = state->get_x();
0359     const double globStateY = state->get_y();
0360     const double globStateZ = state->get_z();
0361     const double globStatePx = state->get_px();
0362     const double globStatePy = state->get_py();
0363     const double globStatePz = state->get_pz();
0364 
0365     const double trackR = std::sqrt(square(globStateX) + square(globStateY));
0366 
0367     const double dr = clusR - trackR;
0368     const double trackDrDt = (globStateX * globStatePx + globStateY * globStatePy) / trackR;
0369     const double trackDxDr = globStatePx / trackDrDt;
0370     const double trackDyDr = globStatePy / trackDrDt;
0371     const double trackDzDr = globStatePz / trackDrDt;
0372 
0373     const double trackX = globStateX + dr * trackDxDr;
0374     const double trackY = globStateY + dr * trackDyDr;
0375     const double trackZ = globStateZ + dr * trackDzDr;
0376     const double trackPhi = std::atan2(trackY, trackX);
0377 
0378     // Calculate residuals
0379     // need to be calculated in local coordinates in the future
0380     const double drphi = clusR * deltaPhi(clusPhi - trackPhi);
0381     if (std::isnan(drphi))
0382     {
0383       continue;
0384     }
0385 
0386     const double dz = clusZ - trackZ;
0387     if (std::isnan(dz))
0388     {
0389       continue;
0390     }
0391 
0392     if (Verbosity() > 3)
0393     {
0394       std::cout << "PHTpcResiduals::checkTPOTResidual -"
0395                 << " drphi: " << drphi
0396                 << " dz: " << dz
0397                 << std::endl;
0398     }
0399 
0400     // check rphi residual for layer 55
0401     if (layer == 55 && std::fabs(drphi) > 0.1)
0402     {
0403       flag = false;
0404       break;
0405     }
0406 
0407     // check z residual for layer 56
0408     if (layer == 56 && std::fabs(dz) > 1)
0409     {
0410       flag = false;
0411       break;
0412     }
0413   }
0414 
0415   if (flag)
0416   {
0417     // SCOZ has a half dead tile
0418     // only require one TPOT cluster/state from SCOP
0419     if (TPOTtileID == 0)
0420     {
0421       if (nTPOTcluster < 1 || nTPOTstate < 1)
0422       {
0423         flag = false;
0424       }
0425     }
0426     else if (TPOTtileID > 0)
0427     {
0428       if (nTPOTcluster < 2 || nTPOTstate < 2)
0429       {
0430         flag = false;
0431       }
0432     }
0433     else if (TPOTtileID < 0)
0434     {
0435       flag = false;
0436     }
0437   }
0438 
0439   return flag;
0440 }
0441 
0442 //_____________________________________________________________________________________________
0443 void PHTpcResiduals::processTrack(SvtxTrack* track)
0444 {
0445   if (Verbosity() > 1)
0446   {
0447     std::cout << "PHTpcResiduals::processTrack -"
0448               << " track momentum: " << track->get_p()
0449               << " position: " << Acts::Vector3(track->get_x(), track->get_y(), track->get_z())
0450               << std::endl;
0451   }
0452 
0453   // store crossing. It is used in calculating cluster's global position
0454   const auto crossing = track->get_crossing();
0455   assert(crossing != std::numeric_limits<short>::max());
0456 
0457   for (const auto& cluskey : get_cluster_keys(track))
0458   {
0459     // increment counter
0460     ++m_total_clusters;
0461 
0462     // make sure cluster is from TPC
0463     const auto detId = TrkrDefs::getTrkrId(cluskey);
0464     if (detId != TrkrDefs::tpcId)
0465     {
0466       continue;
0467     }
0468 
0469     // find matching track state
0470     const auto stateiter = std::find_if( track->begin_states(), track->end_states(), [&cluskey]( const auto& state_pair )
0471       { return state_pair.second->get_cluskey() == cluskey; } );
0472 
0473     // check if found
0474     if( stateiter ==  track->end_states() ) { continue; }
0475 
0476     // get extrapolated track state, convert to sPHENIX and add to track
0477     const auto& [pathLength, state] = *stateiter;
0478 
0479     // calculate residuals with respect to cluster
0480     auto* const cluster = m_clusterContainer->findCluster(cluskey);
0481     const auto globClusPos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(cluskey, cluster, crossing);
0482     const double clusR = get_r(globClusPos(0), globClusPos(1));
0483     const double clusPhi = std::atan2(globClusPos(1), globClusPos(0));
0484     const double clusZ = globClusPos(2);
0485 
0486     // cluster errors
0487     const double clusRPhiErr = cluster->getRPhiError();
0488     const double clusZErr = cluster->getZError();
0489     if (Verbosity() > 3)
0490     {
0491       std::cout << "PHTpcResiduals::processTrack -"
0492                 << " cluskey: " << cluskey
0493                 << " clusR: " << clusR
0494                 << " clusPhi: " << clusPhi << "+/-" << clusRPhiErr
0495                 << " clusZ: " << clusZ << "+/-" << clusZErr
0496                 << std::endl;
0497     }
0498 
0499     // position
0500     const double globStateX = state->get_x();
0501     const double globStateY = state->get_y();
0502     const double globStateZ = state->get_z();
0503     const auto trackR = std::sqrt(square(globStateX) + square(globStateY));
0504 
0505     // momentum
0506     const double globalStateMomX = state->get_px();
0507     const double globalStateMomY = state->get_py();
0508     const double globalStateMomZ = state->get_pz();
0509 
0510     // errors
0511     const double trackRPhiErr = state->get_rphi_error();
0512     const double trackZErr = state->get_z_error();
0513 
0514     const double dr = clusR - trackR;
0515     const double trackDrDt = (globStateX * globalStateMomX + globStateY * globalStateMomY) / trackR;
0516     const double trackDxDr = globalStateMomX / trackDrDt;
0517     const double trackDyDr = globalStateMomY / trackDrDt;
0518     const double trackDzDr = globalStateMomZ / trackDrDt;
0519 
0520     const double trackX = globStateX + dr * trackDxDr;
0521     const double trackY = globStateY + dr * trackDyDr;
0522     const double trackZ = globStateZ + dr * trackDzDr;
0523     const double trackPhi = std::atan2(trackY, trackX);
0524 
0525     if (Verbosity() > 2)
0526     {
0527       std::cout << "PHTpcResiduals::processTrack -"
0528                 << " trackR: " << trackR
0529                 << " dr: " << dr
0530                 << " trackDrDt: " << trackDrDt
0531                 << " trackDxDr: " << trackDxDr
0532                 << " trackDyDr: " << trackDyDr
0533                 << " trackDzDr: " << trackDzDr
0534                 << " trackPhi: " << trackPhi << "+/-" << trackRPhiErr
0535                 << " track position: (" << trackX << ", " << trackY << ", " << trackZ << ")"
0536                 << std::endl;
0537     }
0538 
0539     const double erp = square(clusRPhiErr) + square(trackRPhiErr);
0540     if (std::isnan(erp))
0541     {
0542       continue;
0543     }
0544 
0545     const double ez = square(clusZErr) + square(trackZErr);
0546     if (std::isnan(ez))
0547     {
0548       continue;
0549     }
0550 
0551     // Calculate residuals
0552     const double drphi = clusR * deltaPhi(clusPhi - trackPhi);
0553     if (std::isnan(drphi))
0554     {
0555       continue;
0556     }
0557 
0558     const double dz = clusZ - trackZ;
0559     if (std::isnan(dz))
0560     {
0561       continue;
0562     }
0563 
0564     if (Verbosity() > 3)
0565     {
0566       std::cout << "PHTpcResiduals::processTrack -"
0567                 << " drphi: " << drphi
0568                 << " dz: " << dz
0569                 << " erp: " << erp
0570                 << " ez: " << ez
0571                 << std::endl;
0572     }
0573 
0574     // check rphi and z error
0575     if (std::sqrt(erp) < m_minRPhiErr)
0576     {
0577       continue;
0578     }
0579 
0580     if (std::sqrt(ez) < m_minZErr)
0581     {
0582       continue;
0583     }
0584 
0585     const double trackPPhi = -globalStateMomX*std::sin(trackPhi) + globalStateMomY*std::cos(trackPhi);
0586     const double trackPR = globalStateMomX*std::cos(trackPhi) + globalStateMomY*std::sin(trackPhi);
0587     const double trackPZ = globalStateMomZ;
0588 
0589     const double trackAlpha = -trackPPhi / trackPR;
0590     if (std::isnan(trackAlpha))
0591     {
0592       continue;
0593     }
0594 
0595     const double trackBeta = -trackPZ / trackPR;
0596     if (std::isnan(trackBeta))
0597     {
0598       continue;
0599     }
0600 
0601     if (Verbosity() > 3)
0602     {
0603       std::cout
0604           << "PHTpcResiduals::processTrack -"
0605           << " trackPPhi: " << trackPPhi
0606           << " trackPR: " << trackPR
0607           << " trackPZ: " << trackPZ
0608           << " trackAlpha: " << trackAlpha
0609           << " trackBeta: " << trackBeta
0610           << std::endl;
0611     }
0612 
0613     // get cell index
0614     const auto index = getCell(globClusPos);
0615 
0616     if (Verbosity() > 3)
0617     {
0618       std::cout << "Bin index found is " << index << std::endl;
0619     }
0620 
0621     if (index < 0)
0622     {
0623       continue;
0624     }
0625 
0626     if (Verbosity() > 3)
0627     {
0628       std::cout << "PHTpcResiduals::processTrack - layer: " << (int) TrkrDefs::getLayer(cluskey) << std::endl;
0629       std::cout << "PHTpcResiduals::processTrack -"
0630                 << " cluster: (" << clusR << ", " << clusR * clusPhi << ", " << clusZ << ")"
0631                 << " (" << clusRPhiErr << ", " << clusZErr << ")"
0632                 << std::endl;
0633 
0634       std::cout << "PHTpcResiduals::processTrack -"
0635                 << " track: (" << trackR << ", " << clusR * trackPhi << ", " << trackZ << ")"
0636                 << " (" << trackAlpha << ", " << trackBeta << ")"
0637                 << " (" << trackRPhiErr << ", " << trackZErr << ")"
0638                 << std::endl;
0639       std::cout << std::endl;
0640     }
0641 
0642     // check track angles and residuals agains cuts
0643     if (std::abs(trackAlpha) > m_maxTAlpha || std::abs(drphi) > m_maxResidualDrphi)
0644     {
0645       continue;
0646     }
0647 
0648     if (std::abs(trackBeta) > m_maxTBeta || std::abs(dz) > m_maxResidualDz)
0649     {
0650       continue;
0651     }
0652 
0653     // Fill distortion matrices
0654     m_matrix_container->add_to_lhs(index, 0, 0, square(clusR) / erp);
0655     m_matrix_container->add_to_lhs(index, 0, 1, 0);
0656     m_matrix_container->add_to_lhs(index, 0, 2, clusR * trackAlpha / erp);
0657 
0658     m_matrix_container->add_to_lhs(index, 1, 0, 0);
0659     m_matrix_container->add_to_lhs(index, 1, 1, 1. / ez);
0660     m_matrix_container->add_to_lhs(index, 1, 2, trackBeta / ez);
0661 
0662     m_matrix_container->add_to_lhs(index, 2, 0, clusR * trackAlpha / erp);
0663     m_matrix_container->add_to_lhs(index, 2, 1, trackBeta / ez);
0664     m_matrix_container->add_to_lhs(index, 2, 2, square(trackAlpha) / erp + square(trackBeta) / ez);
0665 
0666     m_matrix_container->add_to_rhs(index, 0, clusR * drphi / erp);
0667     m_matrix_container->add_to_rhs(index, 1, dz / ez);
0668     m_matrix_container->add_to_rhs(index, 2, trackAlpha * drphi / erp + trackBeta * dz / ez);
0669 
0670     // also update rphi reduced matrices
0671     m_matrix_container->add_to_lhs_rphi(index, 0, 0, square(clusR) / erp);
0672     m_matrix_container->add_to_lhs_rphi(index, 0, 1, clusR * trackAlpha / erp);
0673     m_matrix_container->add_to_lhs_rphi(index, 1, 0, clusR * trackAlpha / erp);
0674     m_matrix_container->add_to_lhs_rphi(index, 1, 1, square(trackAlpha) / erp);
0675 
0676     m_matrix_container->add_to_rhs_rphi(index, 0, clusR * drphi / erp);
0677     m_matrix_container->add_to_rhs_rphi(index, 1, trackAlpha * drphi / erp);
0678 
0679     // also update z reduced matrices
0680     m_matrix_container->add_to_lhs_z(index, 0, 0, 1. / ez);
0681     m_matrix_container->add_to_lhs_z(index, 0, 1, trackBeta / ez);
0682     m_matrix_container->add_to_lhs_z(index, 1, 0, trackBeta / ez);
0683     m_matrix_container->add_to_lhs_z(index, 1, 1, square(trackBeta) / ez);
0684 
0685     m_matrix_container->add_to_rhs_z(index, 0, dz / ez);
0686     m_matrix_container->add_to_rhs_z(index, 1, trackBeta * dz / ez);
0687 
0688     // update entries in cell
0689     m_matrix_container->add_to_entries(index);
0690 
0691     // increment number of accepted clusters
0692     ++m_accepted_clusters;
0693   }
0694 }
0695 
0696 //_______________________________________________________________________________
0697 int PHTpcResiduals::getCell(const Acts::Vector3& loc)
0698 {
0699   // get grid dimensions from matrix container
0700   int phibins = 0;
0701   int rbins = 0;
0702   int zbins = 0;
0703   m_matrix_container->get_grid_dimensions(phibins, rbins, zbins);
0704 
0705   // phi
0706   float phi = std::atan2(loc(1), loc(0));
0707   while (phi < m_phiMin)
0708   {
0709     phi += 2. * M_PI;
0710   }
0711   while (phi >= m_phiMax)
0712   {
0713     phi -= 2. * M_PI;
0714   }
0715   const int iphi = phibins * (phi - m_phiMin) / (m_phiMax - m_phiMin);
0716 
0717   // r
0718   const auto r = get_r(loc(0), loc(1));
0719   if (r < m_rMin || r >= m_rMax)
0720   {
0721     return -1;
0722   }
0723   const int ir = rbins * (r - m_rMin) / (m_rMax - m_rMin);
0724 
0725   // z
0726   const auto z = loc(2);
0727   if (z < m_zMin || z >= m_zMax)
0728   {
0729     return -1;
0730   }
0731   const int iz = zbins * (z - m_zMin) / (m_zMax - m_zMin);
0732 
0733   // get index from matrix container
0734   return m_matrix_container->get_cell_index(iphi, ir, iz);
0735 }
0736 
0737 //_______________________________________________________________________________
0738 int PHTpcResiduals::createNodes(PHCompositeNode* /*topNode*/)
0739 {
0740   return Fun4AllReturnCodes::EVENT_OK;
0741 }
0742 
0743 //_______________________________________________________________________________
0744 int PHTpcResiduals::getNodes(PHCompositeNode* topNode)
0745 {
0746   // clusters
0747   m_clusterContainer = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0748   if (!m_clusterContainer)
0749   {
0750     std::cout << PHWHERE << "No TRKR_CLUSTER node on node tree. Exiting." << std::endl;
0751     return Fun4AllReturnCodes::ABORTEVENT;
0752   }
0753 
0754   // geometry
0755   m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0756   if (!m_tGeometry)
0757   {
0758     std::cout << "ActsTrackingGeometry not on node tree. Exiting." << std::endl;
0759     return Fun4AllReturnCodes::ABORTEVENT;
0760   }
0761 
0762   // tracks
0763   m_trackMap = findNode::getClass<SvtxTrackMap>(topNode, m_trackmapname);
0764   if (!m_trackMap)
0765   {
0766     std::cout << PHWHERE << " " << m_trackmapname << " not on node tree. Exiting." << std::endl;
0767     return Fun4AllReturnCodes::ABORTEVENT;
0768   }
0769 
0770   // tpc global position wrapper
0771   m_globalPositionWrapper.loadNodes(topNode);
0772   if (m_disable_module_edge_corr)
0773   {
0774     m_globalPositionWrapper.set_enable_module_edge_corr(false);
0775   }
0776   if (m_disable_static_corr)
0777   {
0778     m_globalPositionWrapper.set_enable_static_corr(false);
0779   }
0780   if (m_disable_average_corr)
0781   {
0782     m_globalPositionWrapper.set_enable_average_corr(false);
0783   }
0784   if (m_disable_fluctuation_corr)
0785   {
0786     m_globalPositionWrapper.set_enable_fluctuation_corr(false);
0787   }
0788 
0789   return Fun4AllReturnCodes::EVENT_OK;
0790 }
0791 
0792 //____________________________________________________________________________
0793 void PHTpcResiduals::setGridDimensions(const int phiBins, const int rBins, const int zBins)
0794 {
0795   m_matrix_container->set_grid_dimensions(phiBins, rBins, zBins);
0796 }