Back to home page

sPhenix code displayed by LXR

 
 

    


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

0001 /**
0002  * \file TpcDirectLaserReconstruction.cc
0003  * \brief performs the reconstruction of TPC direct laser tracks
0004  * \author Hugo Pereira Da Costa <hugo.pereira-da-costa@cea.fr>
0005  */
0006 
0007 #include "TpcDirectLaserReconstruction.h"
0008 
0009 #include "TpcSpaceChargeMatrixContainerv1.h"
0010 
0011 #include <g4detectors/PHG4TpcCylinderGeom.h>
0012 #include <g4detectors/PHG4TpcCylinderGeomContainer.h>
0013 
0014 #include <trackbase/ActsTrackingGeometry.h>
0015 #include <trackbase/TpcDefs.h>
0016 #include <trackbase/TrkrHitSet.h>
0017 #include <trackbase/TrkrHitSetContainer.h>
0018 #include <trackbase/TrkrHitv2.h>  // for TrkrHit
0019 #include <trackbase_historic/SvtxTrack.h>
0020 #include <trackbase_historic/SvtxTrackMap.h>
0021 #include <trackbase_historic/SvtxTrackState_v1.h>
0022 
0023 #include <fun4all/Fun4AllReturnCodes.h>
0024 
0025 #include <phool/getClass.h>
0026 
0027 #include <TFile.h>
0028 #include <TH1.h>
0029 #include <TH2.h>
0030 #include <TH3.h>
0031 #include <TNtuple.h>
0032 #include <TVector3.h>
0033 
0034 #include <boost/format.hpp>
0035 
0036 #include <cassert>
0037 
0038 namespace
0039 {
0040 
0041   //! range adaptor to be able to use range-based for loop
0042   template <class T>
0043   class range_adaptor
0044   {
0045    public:
0046     explicit range_adaptor(const T& range)
0047       : m_range(range)
0048     {
0049     }
0050     inline const typename T::first_type& begin() { return m_range.first; }
0051     inline const typename T::second_type& end() { return m_range.second; }
0052 
0053    private:
0054     T m_range;
0055   };
0056 
0057   //! convenience square method
0058   template <class T>
0059   inline constexpr T square(const T& x)
0060   {
0061     return x * x;
0062   }
0063 
0064   //! get radius from x and y
0065   template <class T>
0066   inline constexpr T get_r(const T& x, const T& y)
0067   {
0068     return std::sqrt(square(x) + square(y));
0069   }
0070 
0071   // calculate intersection between line and circle
0072   std::pair<double, double> line_circle_intersection(const TVector3& p, const TVector3& d, double radius)
0073   {
0074     std::pair<double, double> ret = std::make_pair(-1, -1);
0075 
0076     const double A = square(d.x()) + square(d.y());
0077     const double B = 2 * p.x() * d.x() + 2 * p.y() * d.y();
0078     const double C = square(p.x()) + square(p.y()) - square(radius);
0079     const double delta = square(B) - 4 * A * C;
0080     if (delta < 0)
0081     {
0082       return ret;
0083     }
0084 
0085     // we want 1 intersection
0086     const double tup = (-B + std::sqrt(delta)) / (2 * A);
0087     const double tdn = (-B - sqrt(delta)) / (2 * A);
0088     // std::cout << " tup " << tup << " tdn " << tdn << std::endl;
0089     ret = std::make_pair(tup, tdn);
0090 
0091     return ret;
0092 
0093     /*
0094     if( tup > 0 && tup < tdn)
0095       return tup;
0096     if(tdn > 0 && tdn < tup)
0097        return tdn;
0098 
0099     // no valid extrapolation
0100     return -1;
0101     */
0102   }
0103 
0104   /// TVector3 stream
0105   inline std::ostream& operator<<(std::ostream& out, const TVector3& vector)
0106   {
0107     out << "( " << vector.x() << ", " << vector.y() << ", " << vector.z() << ")";
0108     return out;
0109   }
0110 
0111   /// calculate delta_phi between -pi and pi
0112   template <class T>
0113   inline constexpr T delta_phi(const T& phi)
0114   {
0115     if (phi >= M_PI)
0116     {
0117       return phi - 2 * M_PI;
0118     }
0119     else if (phi < -M_PI)
0120     {
0121       return phi + 2 * M_PI;
0122     }
0123     else
0124     {
0125       return phi;
0126     }
0127   }
0128 
0129   // phi range
0130   static constexpr float m_phimin = 0;
0131   static constexpr float m_phimax = 2. * M_PI;
0132 
0133   // TODO: could try to get the r and z range from TPC geometry
0134   // r range
0135   static constexpr float m_rmin = 20;
0136   static constexpr float m_rmax = 78;
0137 
0138   // z range
0139   static constexpr float m_zmin = -105.5;
0140   static constexpr float m_zmax = 105.5;
0141 
0142 }  // namespace
0143 
0144 //_____________________________________________________________________
0145 TpcDirectLaserReconstruction::TpcDirectLaserReconstruction(const std::string& name)
0146   : SubsysReco(name)
0147   , PHParameterInterface(name)
0148   , m_matrix_container(new TpcSpaceChargeMatrixContainerv1)
0149 {
0150   InitializeParameters();
0151 }
0152 
0153 //_____________________________________________________________________
0154 int TpcDirectLaserReconstruction::Init(PHCompositeNode* /*unused*/)
0155 {
0156   m_total_hits = 0;
0157   m_matched_hits = 0;
0158   m_accepted_clusters = 0;
0159 
0160   if (m_savehistograms)
0161   {
0162     create_histograms();
0163   }
0164   return Fun4AllReturnCodes::EVENT_OK;
0165 }
0166 
0167 //_____________________________________________________________________
0168 int TpcDirectLaserReconstruction::InitRun(PHCompositeNode* /*unused*/)
0169 {
0170   UpdateParametersWithMacro();
0171   m_max_dca = get_double_param("directlaser_max_dca");
0172   m_max_drphi = get_double_param("directlaser_max_drphi");
0173   m_max_dz = get_double_param("directlaser_max_dz");
0174 
0175   // print
0176   if (Verbosity())
0177   {
0178     std::cout
0179         << "TpcDirectLaserReconstruction::InitRun\n"
0180         << " m_outputfile: " << m_outputfile << "\n"
0181         << " m_max_dca: " << m_max_dca << "\n"
0182         << " m_max_drphi: " << m_max_drphi << "\n"
0183         << " m_max_dz: " << m_max_dz << "\n"
0184         << std::endl;
0185 
0186     // also identify the matrix container
0187     m_matrix_container->identify();
0188   }
0189 
0190   return Fun4AllReturnCodes::EVENT_OK;
0191 }
0192 
0193 //_____________________________________________________________________
0194 int TpcDirectLaserReconstruction::process_event(PHCompositeNode* topNode)
0195 {
0196   // load nodes
0197   const auto res = load_nodes(topNode);
0198   if (res != Fun4AllReturnCodes::EVENT_OK)
0199   {
0200     return res;
0201   }
0202 
0203   process_tracks();
0204   return Fun4AllReturnCodes::EVENT_OK;
0205 }
0206 
0207 //_____________________________________________________________________
0208 int TpcDirectLaserReconstruction::End(PHCompositeNode* /*unused*/)
0209 {
0210   // save matrix container in output file
0211   if (m_matrix_container)
0212   {
0213     std::unique_ptr<TFile> outputfile(TFile::Open(m_outputfile.c_str(), "RECREATE"));
0214     outputfile->cd();
0215     m_matrix_container->Write("TpcSpaceChargeMatrixContainer");
0216   }
0217 
0218   // write evaluation histograms to output
0219   if (m_savehistograms && m_histogramfile)
0220   {
0221     m_histogramfile->cd();
0222     // for(const auto& o:std::initializer_list<TObject*>({ h_dca_layer, h_deltarphi_layer_south,h_deltarphi_layer_north, h_deltaz_layer, h_deltar_r,h_deltheta_delphi,h_deltheta_delphi_1,h_deltheta_delphi_2,h_deltheta_delphi_3,h_deltheta_delphi_4,h_deltheta_delphi_5,h_deltheta_delphi_6,h_deltheta_delphi_7,h_deltheta_delphi_8, h_entries,h_relangle_lasrangle,h_relangle_theta_lasrangle,h_relangle_phi_lasrangle,h_GEMs_hit,h_layers_hit,h_xy,h_xz,h_xy_pca,h_xz_pca,h_dca_path,h_zr,h_zr_pca, h_dz_z }))
0223 
0224     for (const auto& o : std::initializer_list<TObject*>({h_dca_layer, h_deltarphi_layer_south, h_deltarphi_layer_north, h_deltaz_layer, h_deltar_r, h_deltheta_delphi, h_deltheta_delphi_1, h_deltheta_delphi_2, h_deltheta_delphi_3, h_deltheta_delphi_4, h_deltheta_delphi_5, h_deltheta_delphi_6, h_deltheta_delphi_7, h_deltheta_delphi_8, h_entries, h_hits, h_hits_reco, h_adc, h_adc_reco, h_adc_sum, h_adc_sum_reco, h_adc_sum_ratio, h_adc_sum_ratio_true, h_adc_vs_DCA_true, h_adc_sum_ratio_lasrangle, h_num_sum, h_num_sum_reco, h_num_sum_ratio,
0225                                                           h_num_sum_ratio_true, h_adc_sum_ratio_true, h_adc_sum_ratio, h_num_sum_ratio_lasrangle, h_bright_hits_laser1, h_bright_hits_laser2, h_bright_hits_laser3, h_bright_hits_laser4, h_relangle_lasrangle,
0226                                                           h_relangle_theta_lasrangle, h_relangle_phi_lasrangle, h_GEMs_hit, h_layers_hit, h_xy, h_xz, h_xy_pca, h_xz_pca, h_dca_path, h_zr, h_zr_pca, h_dz_z}))
0227 
0228     {
0229       if (o)
0230       {
0231         o->Write();
0232       }
0233     }
0234     m_histogramfile->Close();
0235   }
0236 
0237   // add these back in later !!!
0238   //,h_assoc_hits
0239   // h_hits
0240   // h_bright_hits_laser1
0241   // h_bright_hits_laser2
0242   // h_bright_hits_laser3
0243   // h_bright_hits_laser4
0244   // h_origins
0245   // h_clusters
0246 
0247   // print counters
0248   std::cout << "TpcDirectLaserReconstruction::End - m_total_hits: " << m_total_hits << std::endl;
0249   std::cout << "TpcDirectLaserReconstruction::End - m_matched_hits: " << m_matched_hits << std::endl;
0250   std::cout << "TpcDirectLaserReconstruction::End - m_accepted_clusters: " << m_accepted_clusters << std::endl;
0251   std::cout << "TpcDirectLaserReconstruction::End - fraction cluster/hits: " << m_accepted_clusters / m_total_hits << std::endl;
0252 
0253   return Fun4AllReturnCodes::EVENT_OK;
0254 }
0255 
0256 //___________________________________________________________________________
0257 void TpcDirectLaserReconstruction::SetDefaultParameters()
0258 {
0259   // DCA cut, to decide whether a cluster should be associated to a given laser track or not (set to 5 - Charles 10/24/23)
0260   set_default_double_param("directlaser_max_dca", 1.0);
0261 
0262   //   // residual cuts, used to decide if a given cluster is used to fill SC reconstruction matrices
0263   //   set_default_double_param( "directlaser_max_drphi", 0.5 );
0264   //   set_default_double_param( "directlaser_max_dz", 0.5 );
0265 
0266   set_default_double_param("directlaser_max_drphi", 2.);
0267   set_default_double_param("directlaser_max_dz", 2.);
0268 }
0269 
0270 //_____________________________________________________________________
0271 void TpcDirectLaserReconstruction::set_grid_dimensions(int phibins, int rbins, int zbins)
0272 {
0273   m_matrix_container->set_grid_dimensions(phibins, rbins, zbins);
0274 }
0275 
0276 //_____________________________________________________________________
0277 int TpcDirectLaserReconstruction::load_nodes(PHCompositeNode* topNode)
0278 {
0279   m_geom_container = findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
0280   assert(m_geom_container);
0281 
0282   // acts geometry
0283   m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0284   assert(m_tGeometry);
0285 
0286   // tracks
0287   m_track_map = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
0288   assert(m_track_map);
0289 
0290   // get node containing the digitized hits
0291   m_hit_map = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
0292   assert(m_hit_map);
0293 
0294   return Fun4AllReturnCodes::EVENT_OK;
0295 }
0296 
0297 //_____________________________________________________________________
0298 void TpcDirectLaserReconstruction::create_histograms()
0299 {
0300   std::cout << "TpcDirectLaserReconstruction::makeHistograms - writing evaluation histograms to: " << m_histogramfilename << std::endl;
0301   m_histogramfile.reset(new TFile(m_histogramfilename.c_str(), "RECREATE"));
0302   m_histogramfile->cd();
0303 
0304   // residuals vs layers
0305   h_dca_layer = new TH2F("dca_layer", ";radius; DCA (cm)", 78, 0, 78, 500, 0, 20);
0306   h_deltarphi_layer_north = new TH2F("deltarphi_layer_north", ";radius; r.#Delta#phi_{track-cluster} (cm)", 78, 0, 78, 2000, -5, 5);
0307   h_deltarphi_layer_south = new TH2F("deltarphi_layer_south", ";radius; r.#Delta#phi_{track-cluster} (cm)", 78, 0, 78, 2000, -5, 5);
0308   h_deltaz_layer = new TH2F("deltaz_layer", ";radius; #Deltaz_{track-cluster} (cm)", 78, 0, 78, 2000, -20, 20);
0309   h_deltar_r = new TH2F("deltar_r", ";radius;#Deltar_{track-cluster} (cm)", 78, 0, 78, 2000, -3, 3);
0310 
0311   h_xy = new TH2F("h_xy", " x vs y", 320, -80, 80, 320, -80, 80);
0312   h_xz = new TH2F("h_xz", " x vs z", 320, -80, 80, 440, -110, 110);
0313   h_xy_pca = new TH2F("h_xy_pca", " x vs y pca", 320, -80, 80, 320, -80, 80);
0314   h_xz_pca = new TH2F("h_xz_pca", " x vs z pca", 320, -80, 80, 440, -110, 110);
0315   h_dca_path = new TH2F("h_dca_path", " dca vs pathlength", 440, 0, 110, 100, 0, 20);
0316   h_zr = new TH2F("h_zr", " z vs r", 440, -110, 110, 1000, 28, 80);
0317   h_zr->GetXaxis()->SetTitle("z");
0318   h_zr->GetYaxis()->SetTitle("rad");
0319   h_zr_pca = new TH2F("h_zr_pca", " z vs r pca", 440, -110, 110, 1000, 28, 80);
0320   h_dz_z = new TH2F("h_dz_z", " dz vs z", 440, -110, 110, 1000, -20, 20);
0321 
0322   h_hits = new TNtuple("hits", "raw hits", "x:y:z:adc");
0323   h_hits_reco = new TNtuple("hits_reco", "raw hits", "x:y:z:adc");
0324 
0325   h_adc = new TH1F("adc", "pedestal subtracted ADC spectra of ALL lasers (MCTRUTH direction)", 1063, -19.5, 1042.5);
0326   h_adc->SetXTitle("ADC - PEDESTAL [ADU]");
0327 
0328   h_adc_reco = new TH1F("adc_reco", "pedestal subtracted ADC spectra of ALL lasers (RECO DIRECTION)", 1063, -19.5, 1042.5);
0329   h_adc_reco->SetXTitle("ADC - PEDESTAL [ADU]");
0330 
0331   h_adc_sum = new TH1F("adc_sum", "non-pedestal subtracted sum of ADC for each laser (MCTRUTH DIRECTION)", 1600, -0.5, 159999.5);
0332   h_adc_sum->SetXTitle("#Sigma ADC [ADU]");
0333 
0334   h_adc_sum_reco = new TH1F("adc_sum_reco", "non-pedestal subtracted sum of ADC for each laser (RECO DIRECTION)", 1600, -0.5, 159999.5);
0335   h_adc_sum_reco->SetXTitle("#Sigma ADC [ADU]");
0336 
0337   h_num_sum = new TH1F("num_sum", "sum of hits for each laser (MCTRUTH DIRECTION)", 1600, -0.5, 7999.5);
0338   h_num_sum->SetXTitle("#Sigma N_{hits}^{laser X} [arb. units]");
0339 
0340   h_num_sum_reco = new TH1F("num_sum_reco", "sum of hits for each laser (RECO DIRECTION)", 1600, -0.5, 7999.5);
0341   h_num_sum_reco->SetXTitle("#Sigma N_{hits}^{laser X} [arb. units]");
0342 
0343   h_adc_sum_ratio = new TH1F("adc_sum_ratio", "RATIO of non-pedestal subtracted sum of ADC for each laser (RECO DIRECTION/MCTRUTH DIRECTION)", 120, -0.5, 5.5);
0344   h_adc_sum_ratio->SetXTitle("#frac{#Sigma^{RECO} ADC}{#Sigma^{MCTRUTH} ADC}  [arb. units]");
0345 
0346   h_adc_sum_ratio_true = new TH1F("adc_sum_ratio_true", "RATIO of non-pedestal subtracted sum of ADC for each laser (MCTRUTH DIRECTION/ALL )", 120, -0.5, 5.5);
0347   h_adc_sum_ratio_true->SetXTitle("#frac{#Sigma^{MCTRUTH} ADC}{#Sigma^{ALL} ADC}  [arb. units]");
0348 
0349   h_num_sum_ratio = new TH1F("num_sum_ratio", "RATIO of number of hits associated to each laser (RECO DIRECTION/MCTRUTH DIRECTION)", 120, -0.5, 5.5);
0350   h_num_sum_ratio->SetXTitle("#frac{#Sigma^{RECO} N_{hits}^{laser X}}{#Sigma^{MCTRUTH} N_{hits}^{laser X}}  [arb. units]");
0351 
0352   h_num_sum_ratio_true = new TH1F("num_sum_ratio_true", "RATIO of number of hits associated to each laser (MCTRUTH DIRECTION/ALL )", 120, -0.5, 5.5);
0353   h_num_sum_ratio_true->SetXTitle("#frac{#Sigma^{MCTRUTH} N_{hits}^{laser X}}{#Sigma^{ALL} N_{hits}^{laser X}}  [arb. units]");
0354 
0355   h_adc_vs_DCA_true = new TH2F("adc_vs_DCA_true", "PEDESTAL SUBTRACTED ADC vs DCA for ALL HITS from ALL LASERS", 100, 0, 100, 1024, -0.5, 1023.5);
0356   h_adc_vs_DCA_true->SetXTitle("DCA [mm]");
0357   h_adc_vs_DCA_true->SetYTitle("ADC - PEDESTAL [ADU]");
0358 
0359   h_adc_sum_ratio_lasrangle = new TH2F("adc_sum_ratio_lasrangle", "RATIO of non-pedestal subtracted sum of ADC for LASER 1 ONLY (RECO DIRECTION/MCTRUTH DIRECTION)", 91, -0.5, 90.5, 361, -0.5, 360.5);
0360   h_adc_sum_ratio_lasrangle->SetXTitle("#theta_{laser} (deg.)");
0361   h_adc_sum_ratio_lasrangle->SetYTitle("#phi_{laser} (deg.)");
0362 
0363   h_num_sum_ratio_lasrangle = new TH2F("num_sum_ratio_lasrangle", "RATIO of sum of hits for LASER 1 ONLY (RECO DIRECTION/MCTRUTH DIRECTION)", 91, -0.5, 90.5, 361, -0.5, 360.5);
0364   h_num_sum_ratio_lasrangle->SetXTitle("#theta_{laser} (deg.)");
0365   h_num_sum_ratio_lasrangle->SetYTitle("#phi_{laser} (deg.)");
0366 
0367   h_bright_hits_laser1 = new TNtuple("bright_hits_laser1", "bright hits relative to laser 1", "x:y:z:deltheta:delphi");
0368   h_bright_hits_laser2 = new TNtuple("bright_hits_laser2", "bright hits relative to laser 2", "x:y:z:deltheta:delphi");
0369   h_bright_hits_laser3 = new TNtuple("bright_hits_laser3", "bright hits relative to laser 3", "x:y:z:deltheta:delphi");
0370   h_bright_hits_laser4 = new TNtuple("bright_hits_laser4", "bright hits relative to laser 4", "x:y:z:deltheta:delphi");
0371 
0372   // h_assoc_hits = new TNtuple("assoc_hits","hits associated with tracks (dca cut)","x:y:z");
0373   // h_clusters = new TNtuple("clusters","associated clusters","x:y:z");
0374   // h_origins = new TNtuple("origins","track origins","x:y:z");
0375 
0376   // h_relangle_lasrangle = new TH2F("relangle_lasrangle","Difference in pointing angle from laser and relative angle histogram for ALL lasers",51,-25.5,25.5,51,-25.5,25.5);
0377   h_relangle_lasrangle = new TH2F("relangle_lasrangle", "Difference in pointing angle from laser and relative angle histogram for ALL lasers", 102, -25.5, 25.5, 102, -25.5, 25.5);
0378   h_relangle_lasrangle->SetXTitle("#delta#theta (deg.)");
0379   h_relangle_lasrangle->SetYTitle("#delta#phi (deg.)");
0380 
0381   h_relangle_theta_lasrangle = new TH2F("relangle_theta_lasrangle", "#delta#theta from laser and relative angle histogram for LASER 1 ONLY, ", 91, -0.5, 90.5, 361, -0.5, 360.5);
0382   h_relangle_theta_lasrangle->SetXTitle("#theta_{laser} (deg.)");
0383   h_relangle_theta_lasrangle->SetYTitle("#phi_{laser} (deg.)");
0384 
0385   h_relangle_phi_lasrangle = new TH2F("relangle_phi_lasrangle", "#delta#phi from laser and relative angle histogram for LASER 1 ONLY", 91, -0.5, 90.5, 361, -0.5, 360.5);
0386   h_relangle_phi_lasrangle->SetXTitle("#theta_{laser} (deg.)");
0387   h_relangle_phi_lasrangle->SetYTitle("#phi_{laser} (deg.)");
0388 
0389   h_deltheta_delphi = new TH2F("deltheta_delphi", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and ALL laser start points", 181, -0.5, 180.5, 361, -0.5, 360.5);
0390   h_deltheta_delphi->SetXTitle("#Delta#theta");
0391   h_deltheta_delphi->SetYTitle("#Delta#phi");
0392 
0393   h_deltheta_delphi_1 = new TH2F("deltheta_delphi_1", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 1 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0394   h_deltheta_delphi_1->SetXTitle("#Delta#theta");
0395   h_deltheta_delphi_1->SetYTitle("#Delta#phi");
0396 
0397   h_deltheta_delphi_2 = new TH2F("deltheta_delphi_2", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 2 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0398   h_deltheta_delphi_2->SetXTitle("#Delta#theta");
0399   h_deltheta_delphi_2->SetYTitle("#Delta#phi");
0400 
0401   h_deltheta_delphi_3 = new TH2F("deltheta_delphi_3", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 3 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0402   h_deltheta_delphi_3->SetXTitle("#Delta#theta");
0403   h_deltheta_delphi_3->SetYTitle("#Delta#phi");
0404 
0405   h_deltheta_delphi_4 = new TH2F("deltheta_delphi_4", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 4 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0406   h_deltheta_delphi_4->SetXTitle("#Delta#theta");
0407   h_deltheta_delphi_4->SetYTitle("#Delta#phi");
0408 
0409   h_deltheta_delphi_5 = new TH2F("deltheta_delphi_5", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 5 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0410   h_deltheta_delphi_5->SetXTitle("#Delta#theta");
0411   h_deltheta_delphi_5->SetYTitle("#Delta#phi");
0412 
0413   h_deltheta_delphi_6 = new TH2F("deltheta_delphi_6", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 6 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0414   h_deltheta_delphi_6->SetXTitle("#Delta#theta");
0415   h_deltheta_delphi_6->SetYTitle("#Delta#phi");
0416 
0417   h_deltheta_delphi_7 = new TH2F("deltheta_delphi_7", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 7 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0418   h_deltheta_delphi_7->SetXTitle("#Delta#theta");
0419   h_deltheta_delphi_7->SetYTitle("#Delta#phi");
0420 
0421   h_deltheta_delphi_8 = new TH2F("deltheta_delphi_8", "#Delta#theta, #Delta#phi for separation b/w TPC volume hits and LASER 8 only", 181, -0.5, 180.5, 361, -0.5, 360.5);
0422   h_deltheta_delphi_8->SetXTitle("#Delta#theta");
0423   h_deltheta_delphi_8->SetYTitle("#Delta#phi");
0424 
0425   h_GEMs_hit = new TH1F("GEMS_hit", "Number of Unique GEM Modules hit for each laser", 8, 0, 8);
0426   h_layers_hit = new TH1F("layers_hit", "Number of Unique Layers hit for each laser", 8, 8, 8);
0427 
0428   std::string GEM_bin_label;
0429   for (int GEMhistiter = 0; GEMhistiter < 8; GEMhistiter++)
0430   {  // (pos z) laser 1 {0,60}, laser 2 {60,0}, laser 3 {0,-60}, laser 4 {-60,0}, (neg z) laser 5 {0,60}, laser 2 {60,0}, laser 3 {0,-60}, laser 4 {-60,0}
0431 //    sprintf(GEM_bin_label, "laser %i", GEMhistiter + 1);
0432     GEM_bin_label = (boost::format("laser %i") %(GEMhistiter + 1)).str();
0433     h_GEMs_hit->GetXaxis()->SetBinLabel(GEMhistiter + 1, GEM_bin_label.c_str());
0434     h_layers_hit->GetXaxis()->SetBinLabel(GEMhistiter + 1, GEM_bin_label.c_str());
0435   }
0436   h_GEMs_hit->SetYTitle("Number of Unique GEM Modules Hit");
0437   h_layers_hit->SetYTitle("Number of Unique Layers Hit");
0438 
0439   // entries vs cell grid
0440   /* histogram dimension and axis limits must match that of TpcSpaceChargeMatrixContainer */
0441   if (m_matrix_container)
0442   {
0443     int phibins = 0;
0444     int rbins = 0;
0445     int zbins = 0;
0446     m_matrix_container->get_grid_dimensions(phibins, rbins, zbins);
0447     h_entries = new TH3F("entries", ";#phi;r (cm);z (cm)", phibins, m_phimin, m_phimax, rbins, m_rmin, m_rmax, zbins, m_zmin, m_zmax);
0448   }
0449 }
0450 
0451 //_____________________________________________________________________
0452 void TpcDirectLaserReconstruction::process_tracks()
0453 {
0454   if (!(m_track_map && m_hit_map))
0455   {
0456     return;
0457   }
0458 
0459   // loop over tracks and process
0460   for (auto& iter : *m_track_map)
0461   {
0462     process_track(iter.second);
0463   }
0464 }
0465 
0466 //_____________________________________________________________________
0467 void TpcDirectLaserReconstruction::process_track(SvtxTrack* track)
0468 {
0469   std::multimap<unsigned int, std::pair<float, TVector3>> cluspos_map;
0470   std::set<unsigned int> layer_bin_set;
0471 
0472   // get track parameters
0473   const TVector3 origin(track->get_x(), track->get_y(), track->get_z());
0474   const TVector3 direction(track->get_px(), track->get_py(), track->get_pz());
0475   TVector3 direction2(track->get_px(), track->get_py(), track->get_pz());
0476 
0477   /*
0478     if(h_origins)
0479     {
0480       h_origins->Fill(track->get_x(), track->get_y(), track->get_z());
0481     }
0482   */
0483   const unsigned int trkid = track->get_id();
0484 
0485   const float theta_orig = origin.Theta();
0486   const float phi_orig = origin.Phi();
0487 
0488   float theta_trk = direction.Theta();
0489   direction2.RotateZ(-phi_orig);
0490   float phi_trk = direction2.Phi();
0491 
0492   if (theta_trk > M_PI / 2.)
0493   {
0494     theta_trk = M_PI - theta_trk;
0495   }
0496 
0497   // if(  phi_trk < 0) phi_trk*=-1;
0498 
0499   while (phi_trk < m_phimin)
0500   {
0501     phi_trk += 2. * M_PI;
0502   }
0503   while (phi_trk >= m_phimax)
0504   {
0505     phi_trk -= 2. * M_PI;
0506   }
0507 
0508   // const double xo = track->get_x();
0509   // const double yo = track->get_y();
0510   // const double zo = track->get_z();
0511 
0512   // if( phi_orig < 0 )phi_orig += 2.*M_PI;
0513 
0514   if (track->get_id() > 3)
0515   {
0516     phi_trk = (2 * M_PI) - phi_trk;
0517   }
0518 
0519   // if( Verbosity() )
0520   //{
0521   std::cout << "----------  processing track " << track->get_id() << std::endl;
0522   std::cout << "TpcDirectLaserReconstruction::process_track - position: " << origin << " direction: " << direction << std::endl;
0523   std::cout << "Position Orientation - Theta: " << theta_orig * (180. / M_PI) << ", Phi: " << phi_orig * (180. / M_PI) << std::endl;
0524   std::cout << "Track Angle Direction - Theta: " << theta_trk * (180. / M_PI) << ", Phi: " << phi_trk * (180. / M_PI) << std::endl;
0525   //}
0526 
0527   int GEM_Mod_Arr[72] = {0};
0528 
0529   // loop over hits
0530   TrkrHitSetContainer::ConstRange hitsetrange = m_hit_map->getHitSets(TrkrDefs::TrkrId::tpcId);
0531 
0532   float max_adc = 0.;
0533   float sum_adc_truth = 0;
0534   float sum_adc_truth_all = 0;
0535 
0536   float sum_n_hits_truth = 0;
0537   float sum_n_hits_truth_all = 0;
0538 
0539   for (auto hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr)
0540   {
0541     const TrkrDefs::hitsetkey& hitsetkey = hitsetitr->first;
0542     const int side = TpcDefs::getSide(hitsetkey);
0543 
0544     auto hitset = hitsetitr->second;
0545     const unsigned int layer = TrkrDefs::getLayer(hitsetkey);
0546     const auto layergeom = m_geom_container->GetLayerCellGeom(layer);
0547     const auto layer_center_radius = layergeom->get_radius();
0548 
0549     // maximum drift time.
0550     /* it is needed to calculate a given hit position from its drift time */
0551     const double AdcClockPeriod = layergeom->get_zstep();  // ns
0552     const unsigned short NTBins = (unsigned short) layergeom->get_zbins();
0553     const float tdriftmax = AdcClockPeriod * NTBins / 2.0;
0554 
0555     // get corresponding hits
0556     TrkrHitSet::ConstRange hitrangei = hitset->getHits();
0557 
0558     for (auto hitr = hitrangei.first; hitr != hitrangei.second; ++hitr)
0559     {
0560       ++m_total_hits;
0561       sum_n_hits_truth_all++;
0562 
0563       const unsigned short phibin = TpcDefs::getPad(hitr->first);
0564       const unsigned short zbin = TpcDefs::getTBin(hitr->first);
0565 
0566       const double phi = layergeom->get_phicenter(phibin, side);
0567       const double x = layer_center_radius * cos(phi);
0568       const double y = layer_center_radius * sin(phi);
0569 
0570       const double zdriftlength = layergeom->get_zcenter(zbin) * m_tGeometry->get_drift_velocity();
0571       double z = tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength;
0572       if (side == 0)
0573       {
0574         z *= -1;
0575       }
0576 
0577       const TVector3 global(x, y, z);
0578 
0579       float adc = (hitr->second->getAdc()) - m_pedestal;
0580       float adc_unsub = (hitr->second->getAdc());
0581       sum_adc_truth_all += adc_unsub;
0582       /*
0583               if(h_hits && trkid == 0)
0584                 {
0585                   h_hits->Fill(x,y,z,adc);
0586                 }
0587       */
0588       if (adc > max_adc)
0589       {
0590         max_adc = adc;
0591       }
0592 
0593       // calculate dca
0594       // origin is track origin, direction is track direction
0595       bool sameside = sameSign(global.z(), origin.z());
0596       const TVector3 oc(global.x() - origin.x(), global.y() - origin.y(), global.z() - origin.z());  // vector from track origin to cluster
0597       auto t = direction.Dot(oc) / square(direction.Mag());
0598       auto om = direction * t;  // vector from track origin to PCA
0599       const auto dca = (oc - om).Mag();
0600 
0601       if (sameside)
0602       {
0603         h_adc_vs_DCA_true->Fill(dca, adc);
0604       }
0605 
0606       // rotate displacement vector by the rotation of the coordinates:
0607       // oc2.RotateY(-theta_orig * trkzdir); //undoing rotation in PHG4TpcDirectLaser
0608 
0609       // global2.RotateZ(-phi_orig);
0610       // origin2.RotateZ(-phi_orig);
0611 
0612       TVector3 oc2(global.x() - origin.x(), global.y() - origin.y(), global.z() - origin.z());  // vector from track origin to cluster
0613       // const double xt = x-xo;
0614       // const double yt = y-yo;
0615       // const double zt = z-zo;
0616       oc2.RotateZ(-phi_orig);
0617 
0618       // auto theta1 = origin.Theta()*(180./M_PI);
0619       // auto theta2 = global.Theta()*(180./M_PI);
0620 
0621       // auto phi1 = origin.Phi()*(180./M_PI);
0622       // auto phi2 = global.Phi()*(180./M_PI);
0623 
0624       // float deltheta = GetRelTheta( origin.x() , origin.y(), origin.z(), global.x() , global.y() , global.z() , origin.Theta(), origin.Phi()) *(180./M_PI);
0625       // float delphi = GetRelPhi(origin.x() , origin.y() , global.x() , global.y() , origin.Phi()) *(180./M_PI);
0626 
0627       float deltheta = oc2.Theta();
0628       float delphi = oc2.Phi();
0629 
0630       if (deltheta > M_PI / 2.)
0631       {
0632         deltheta = M_PI - deltheta;
0633       }
0634 
0635       while (delphi < m_phimin)
0636       {
0637         delphi += 2. * M_PI;
0638       }
0639       while (delphi >= m_phimax)
0640       {
0641         delphi -= 2. * M_PI;
0642       }
0643 
0644       if (track->get_id() > 3)
0645       {
0646         delphi = (2 * M_PI) - delphi;
0647       }
0648 
0649       // if (delphi < 0) delphi*=-1;
0650 
0651       deltheta *= (180. / M_PI);
0652       delphi *= (180. / M_PI);
0653 
0654       /*
0655               if( trkid < 4)
0656               {
0657                 deltheta = 180 - theta2;
0658                 if ( trkid == 1) delphi = fabs(phi2 - phi);
0659                 else delphi = phi2 - phi1;
0660               }
0661               else
0662               {
0663                 deltheta = theta2;
0664                 if (trkid == 7 ) delphi = 360. - fabs(phi2 - phi1);
0665                 else delphi = fabs(phi2 - phi1);
0666               }
0667       */
0668 
0669       // relative angle histogram - only fill for hits in the same side as origin
0670 
0671       if (sameside)
0672       {
0673         // std::cout<<"Trk ID = "<<trkid<<std::endl;
0674 
0675         h_deltheta_delphi->Fill(deltheta, delphi);
0676 
0677         if (track->get_id() == 0)  // only fill for 1 laser !!!
0678         {
0679           // std::cout<<"Trk ID = "<<trkid<<std::endl;
0680           h_deltheta_delphi_1->Fill(deltheta, delphi);
0681           /*
0682                       //if( h_bright_hits && deltheta > 80 && deltheta < 95 && delphi > 130 && delphi < 150)
0683                       //filling bright_hits for theta = 75, phi = 80 (simple debugging only - to be removed)
0684                       if( h_bright_hits_laser1 )
0685                       {
0686                         h_bright_hits_laser1->Fill(x,y,z,deltheta,delphi);
0687                       }
0688           */
0689         }
0690         if (trkid == 1)  // only fill for 1 laser !!!
0691         {
0692           h_deltheta_delphi_2->Fill(deltheta, delphi);
0693           /*
0694                       if( h_bright_hits_laser2 )
0695                       {
0696                         h_bright_hits_laser2->Fill(x,y,z,deltheta,delphi);
0697                       }
0698           */
0699         }
0700         if (trkid == 2)  // only fill for 1 laser !!!
0701         {
0702           h_deltheta_delphi_3->Fill(deltheta, delphi);
0703           /*
0704                       if( h_bright_hits_laser3 )
0705                       {
0706                         h_bright_hits_laser3->Fill(x,y,z,deltheta,delphi);
0707                       }
0708           */
0709         }
0710         if (trkid == 3)  // only fill for 1 laser !!!
0711         {
0712           h_deltheta_delphi_4->Fill(deltheta, delphi);
0713           /*
0714                       if( h_bright_hits_laser4 )
0715                       {
0716                         h_bright_hits_laser4->Fill(x,y,z,deltheta,delphi);
0717                       }
0718           */
0719         }
0720         if (trkid == 4)  // only fill for 1 laser !!!
0721         {
0722           h_deltheta_delphi_5->Fill(deltheta, delphi);
0723         }
0724         if (trkid == 5)  // only fill for 1 laser !!!
0725         {
0726           h_deltheta_delphi_6->Fill(deltheta, delphi);
0727         }
0728         if (trkid == 6)  // only fill for 1 laser !!!
0729         {
0730           h_deltheta_delphi_7->Fill(deltheta, delphi);
0731         }
0732         if (trkid == 7)  // only fill for 1 laser !!!
0733         {
0734           h_deltheta_delphi_8->Fill(deltheta, delphi);
0735         }
0736       }
0737 
0738       // do not associate if dca is too large
0739       if (dca > m_max_dca)
0740       {
0741         continue;
0742       }
0743 
0744       if (sameside)
0745       {
0746         sum_n_hits_truth++;
0747         h_adc->Fill(adc);
0748         sum_adc_truth += adc_unsub;
0749       }  // increment truth BUT ONLY for hits on the same side as origin CHARLES 10.31.23
0750 
0751       ++m_matched_hits;
0752       /*
0753               if(h_assoc_hits){
0754                 h_assoc_hits->Fill( x,y,z);
0755               }
0756       */
0757       // for locating the associated hits
0758       float r2 = std::sqrt((x * x) + (y * y));
0759       float phi3 = phi;
0760       float z2 = z;
0761       while (phi3 < m_phimin)
0762       {
0763         phi3 += 2. * M_PI;
0764       }
0765       while (phi3 >= m_phimax)
0766       {
0767         phi3 -= 2. * M_PI;
0768       }
0769 
0770       const int locateid = Locate(r2, phi3, z2);  // find where the cluster is
0771 
0772       if (z2 > m_zmin || z2 < m_zmax)
0773       {
0774         GEM_Mod_Arr[locateid - 1]++;  // the array ath the cluster location - counts the number of clusters in each array, (IFF its in the volume !!!)
0775       }
0776 
0777       // bin hits by layer
0778       const auto cluspos_pair = std::make_pair(adc, global);
0779       cluspos_map.insert(std::make_pair(layer, cluspos_pair));
0780       layer_bin_set.insert(layer);
0781     }  // end looping over hits
0782   }    // end looping over hitset
0783 
0784   h_adc_sum->Fill(sum_adc_truth);
0785   h_num_sum->Fill(sum_n_hits_truth);
0786 
0787   if (sum_adc_truth_all > 0)  // you MUST have hits in this to take ratio
0788   {
0789     h_adc_sum_ratio_true->Fill(sum_adc_truth / sum_adc_truth_all);  // for a hits associated with the same laser fire take the ratio
0790   }
0791 
0792   if (sum_n_hits_truth_all > 0)  // you MUST have hits in this to take ratio
0793   {
0794     h_num_sum_ratio_true->Fill(sum_n_hits_truth / sum_n_hits_truth_all);  // for a hits associated with the same laser fire take the ratio
0795   }
0796 
0797   int maxbin;
0798   int deltheta_max, delphi_max, dummy_z;
0799 
0800   float theta_reco = 0;
0801   float phi_reco = 0;
0802 
0803   float direction_reco;
0804   if (trkid < 4)
0805   {
0806     direction_reco = -1;
0807   }  // first four lasers are on positive z readout plane, and shoot towards negative z
0808   else
0809   {
0810     direction_reco = 1;
0811   }  // next four lasers are on negative z readout plane and shoot towards positive z
0812 
0813   TVector3 dir(0, 0, direction_reco);  // unit vector starts out pointing along z axis
0814 
0815   if ((trkid == 0 && h_deltheta_delphi_1->GetEntries() > 0) && max_adc > 10)
0816   {
0817     h_deltheta_delphi_1->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0818     h_deltheta_delphi_1->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0819 
0820     maxbin = h_deltheta_delphi_1->GetMaximumBin();
0821 
0822     h_deltheta_delphi_1->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0823 
0824     std::cout << "Laser # " << (trkid + 1) << " naieve deltheta max: " << h_deltheta_delphi_1->GetXaxis()->GetBinCenter(deltheta_max) << ", naieve delphi max: " << h_deltheta_delphi_1->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0825 
0826     h_relangle_lasrangle->Fill(h_deltheta_delphi_1->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_1->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0827 
0828     h_relangle_theta_lasrangle->Fill(theta_trk * (180. / M_PI), phi_trk * (180. / M_PI), h_deltheta_delphi_1->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)));
0829     h_relangle_phi_lasrangle->Fill(theta_trk * (180. / M_PI), phi_trk * (180. / M_PI), h_deltheta_delphi_1->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0830 
0831     theta_reco = h_deltheta_delphi_1->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0832     phi_reco = h_deltheta_delphi_1->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0833   }
0834 
0835   else if ((trkid == 1 && h_deltheta_delphi_2->GetEntries() > 0) && max_adc > 10)
0836   {
0837     h_deltheta_delphi_2->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0838     h_deltheta_delphi_2->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0839 
0840     maxbin = h_deltheta_delphi_2->GetMaximumBin();
0841 
0842     h_deltheta_delphi_2->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0843 
0844     std::cout << "Laser # " << (trkid + 1) << " naieve deltheta max: " << h_deltheta_delphi_2->GetXaxis()->GetBinCenter(deltheta_max) << ", naive delphi max: " << h_deltheta_delphi_2->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0845 
0846     h_relangle_lasrangle->Fill(h_deltheta_delphi_2->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_2->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0847 
0848     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_2->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0849     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_2->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0850 
0851     theta_reco = h_deltheta_delphi_2->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0852     phi_reco = h_deltheta_delphi_2->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0853   }
0854 
0855   else if ((trkid == 2 && h_deltheta_delphi_3->GetEntries() > 0) && max_adc > 10)
0856   {
0857     h_deltheta_delphi_3->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0858     h_deltheta_delphi_3->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0859 
0860     maxbin = h_deltheta_delphi_3->GetMaximumBin();
0861 
0862     h_deltheta_delphi_3->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0863 
0864     std::cout << "Laser # " << (trkid + 1) << " naieve deltheta max: " << h_deltheta_delphi_3->GetXaxis()->GetBinCenter(deltheta_max) << ", naive delphi max: " << h_deltheta_delphi_3->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0865 
0866     h_relangle_lasrangle->Fill(h_deltheta_delphi_3->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_3->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0867 
0868     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_3->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0869     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_3->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0870 
0871     theta_reco = h_deltheta_delphi_3->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0872     phi_reco = h_deltheta_delphi_3->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0873   }
0874 
0875   else if ((trkid == 3 && h_deltheta_delphi_4->GetEntries() > 0) && max_adc > 10)
0876   {
0877     h_deltheta_delphi_4->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0878     h_deltheta_delphi_4->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0879 
0880     maxbin = h_deltheta_delphi_4->GetMaximumBin();
0881 
0882     h_deltheta_delphi_4->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0883 
0884     std::cout << "Laser # " << (trkid + 1) << " naieve deltheta max: " << h_deltheta_delphi_4->GetXaxis()->GetBinCenter(deltheta_max) << ", naieve delphi max: " << h_deltheta_delphi_4->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0885 
0886     h_relangle_lasrangle->Fill(h_deltheta_delphi_4->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_4->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0887 
0888     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_4->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0889     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_4->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0890 
0891     theta_reco = h_deltheta_delphi_4->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0892     phi_reco = h_deltheta_delphi_4->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0893   }
0894 
0895   else if ((trkid == 4 && h_deltheta_delphi_5->GetEntries() > 0) && max_adc > 10)
0896   {
0897     h_deltheta_delphi_5->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0898     h_deltheta_delphi_5->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0899 
0900     maxbin = h_deltheta_delphi_5->GetMaximumBin();
0901 
0902     h_deltheta_delphi_5->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0903 
0904     std::cout << "Laser # " << (trkid + 1) << " deltheta max: " << h_deltheta_delphi_5->GetXaxis()->GetBinCenter(deltheta_max) << ", delphi max: " << h_deltheta_delphi_5->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0905 
0906     h_relangle_lasrangle->Fill(h_deltheta_delphi_5->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_5->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0907 
0908     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_5->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0909     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_5->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0910 
0911     theta_reco = h_deltheta_delphi_5->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0912     phi_reco = h_deltheta_delphi_5->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0913   }
0914 
0915   else if ((trkid == 5 && h_deltheta_delphi_6->GetEntries() > 0) && max_adc > 10)
0916   {
0917     h_deltheta_delphi_6->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0918     h_deltheta_delphi_6->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0919 
0920     maxbin = h_deltheta_delphi_6->GetMaximumBin();
0921 
0922     h_deltheta_delphi_6->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0923 
0924     std::cout << "Laser # " << (trkid + 1) << " deltheta max: " << h_deltheta_delphi_6->GetXaxis()->GetBinCenter(deltheta_max) << ", delphi max: " << h_deltheta_delphi_6->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0925 
0926     h_relangle_lasrangle->Fill(h_deltheta_delphi_6->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_6->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0927 
0928     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_6->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0929     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_6->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0930 
0931     theta_reco = h_deltheta_delphi_6->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0932     phi_reco = h_deltheta_delphi_6->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0933   }
0934 
0935   else if ((trkid == 6 && h_deltheta_delphi_7->GetEntries() > 0) && max_adc > 10)
0936   {
0937     h_deltheta_delphi_7->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0938     h_deltheta_delphi_7->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0939 
0940     maxbin = h_deltheta_delphi_7->GetMaximumBin();
0941 
0942     h_deltheta_delphi_7->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0943 
0944     std::cout << "Laser # " << (trkid + 1) << " deltheta max: " << h_deltheta_delphi_7->GetXaxis()->GetBinCenter(deltheta_max) << ", delphi max: " << h_deltheta_delphi_7->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0945 
0946     h_relangle_lasrangle->Fill(h_deltheta_delphi_7->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_7->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0947 
0948     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_7->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0949     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_7->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0950 
0951     theta_reco = h_deltheta_delphi_7->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0952     phi_reco = h_deltheta_delphi_7->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0953   }
0954 
0955   else if ((trkid == 7 && h_deltheta_delphi_8->GetEntries() > 0) && max_adc > 10)
0956   {
0957     h_deltheta_delphi_8->GetXaxis()->SetRangeUser(-5 + (theta_trk * (180. / M_PI)), 5 + (theta_trk * (180. / M_PI)));
0958     h_deltheta_delphi_8->GetYaxis()->SetRangeUser(-5 + (phi_trk * (180. / M_PI)), 5 + (phi_trk * (180. / M_PI)));
0959 
0960     maxbin = h_deltheta_delphi_8->GetMaximumBin();
0961 
0962     h_deltheta_delphi_8->GetBinXYZ(maxbin, deltheta_max, delphi_max, dummy_z);
0963 
0964     std::cout << "Laser # " << (trkid + 1) << " deltheta max: " << h_deltheta_delphi_8->GetXaxis()->GetBinCenter(deltheta_max) << ", delphi max: " << h_deltheta_delphi_8->GetYaxis()->GetBinCenter(delphi_max) << std::endl;
0965 
0966     h_relangle_lasrangle->Fill(h_deltheta_delphi_8->GetXaxis()->GetBinCenter(deltheta_max) - (theta_trk * (180. / M_PI)), h_deltheta_delphi_8->GetYaxis()->GetBinCenter(delphi_max) - (phi_trk * (180. / M_PI)));
0967 
0968     // h_relangle_theta_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_8->GetXaxis()->GetBinCenter(deltheta_max)-(theta_trk*(180./M_PI)) );
0969     // h_relangle_phi_lasrangle->Fill(theta_trk*(180./M_PI),phi_trk*(180./M_PI),h_deltheta_delphi_8->GetYaxis()->GetBinCenter(delphi_max)-(phi_trk*(180./M_PI)) );
0970 
0971     theta_reco = h_deltheta_delphi_8->GetXaxis()->GetBinCenter(deltheta_max) * (M_PI / 180);  // convert to radians
0972     phi_reco = h_deltheta_delphi_8->GetYaxis()->GetBinCenter(delphi_max) * (M_PI / 180);      // convert to radians
0973   }
0974 
0975   // Determining Vector for reconstructed laser direction
0976   dir.RotateY(theta_reco * direction_reco);
0977   if (direction_reco == -1)
0978   {
0979     dir.RotateZ(phi_reco);  // if +z facing -z
0980   }
0981   else
0982   {
0983     dir.RotateZ(-phi_reco);  // if -z facting +z
0984   }
0985   dir.RotateZ(phi_orig);  // rotate by the laser coordinate
0986 
0987   //////    print out the reconstructed track direction ////////////////////////////////////////////
0988 
0989   TVector3 direction2_reco(dir.Px(), dir.Py(), dir.Pz());
0990 
0991   float theta_trk_reco = dir.Theta();
0992   direction2_reco.RotateZ(-phi_orig);
0993   float phi_trk_reco = direction2_reco.Phi();
0994 
0995   if (theta_trk_reco > M_PI / 2.)
0996   {
0997     theta_trk_reco = M_PI - theta_trk_reco;
0998   }
0999 
1000   // if(  phi_trk < 0) phi_trk*=-1;
1001 
1002   while (phi_trk_reco < m_phimin)
1003   {
1004     phi_trk_reco += 2. * M_PI;
1005   }
1006   while (phi_trk_reco >= m_phimax)
1007   {
1008     phi_trk_reco -= 2. * M_PI;
1009   }
1010 
1011   // const double xo = track->get_x();
1012   // const double yo = track->get_y();
1013   // const double zo = track->get_z();
1014 
1015   // if( phi_orig < 0 )phi_orig += 2.*M_PI;
1016 
1017   if (track->get_id() > 3)
1018   {
1019     phi_trk_reco = (2 * M_PI) - phi_trk_reco;
1020   }
1021 
1022   std::cout << "RECONSTRUCTED Track Angle Direction - Theta: " << theta_trk_reco * (180. / M_PI) << ", Phi: " << phi_trk_reco * (180. / M_PI) << std::endl;
1023 
1024   ////////////////////////////////////////////////
1025 
1026   // now loop over hits AGAIN and get ADC spectrum
1027 
1028   float sum_adc_reco = 0;
1029   float sum_n_hits_reco = 0;
1030 
1031   for (auto hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; ++hitsetitr)
1032   {
1033     const TrkrDefs::hitsetkey& hitsetkey_2 = hitsetitr->first;
1034     const int side_2 = TpcDefs::getSide(hitsetkey_2);
1035 
1036     auto hitset_2 = hitsetitr->second;
1037     const unsigned int layer_2 = TrkrDefs::getLayer(hitsetkey_2);
1038     const auto layergeom_2 = m_geom_container->GetLayerCellGeom(layer_2);
1039     const auto layer_center_radius_2 = layergeom_2->get_radius();
1040 
1041     // maximum drift time.
1042     /* it is needed to calculate a given hit position from its drift time */
1043     static constexpr double AdcClockPeriod_2 = 53.0;  // ns
1044     const unsigned short NTBins_2 = (unsigned short) layergeom_2->get_zbins();
1045     const float tdriftmax_2 = AdcClockPeriod_2 * NTBins_2 / 2.0;
1046 
1047     // get corresponding hits
1048     TrkrHitSet::ConstRange hitrangei_2 = hitset_2->getHits();
1049 
1050     for (auto hitr = hitrangei_2.first; hitr != hitrangei_2.second; ++hitr)
1051     {
1052       const unsigned short phibin_2 = TpcDefs::getPad(hitr->first);
1053       const unsigned short zbin_2 = TpcDefs::getTBin(hitr->first);
1054 
1055       const double phi_2 = layergeom_2->get_phicenter(phibin_2, side_2);
1056       const double x_2 = layer_center_radius_2 * cos(phi_2);
1057       const double y_2 = layer_center_radius_2 * sin(phi_2);
1058 
1059       const double zdriftlength_2 = layergeom_2->get_zcenter(zbin_2) * m_tGeometry->get_drift_velocity();
1060       double z_2 = tdriftmax_2 * m_tGeometry->get_drift_velocity() - zdriftlength_2;
1061       if (side_2 == 0)
1062       {
1063         z_2 *= -1;
1064       }
1065 
1066       const TVector3 global_2(x_2, y_2, z_2);
1067 
1068       bool sameside_reco = sameSign(global_2.z(), origin.z());
1069 
1070       float adc_2 = (hitr->second->getAdc()) - m_pedestal;
1071       float adc_2_unsub = (hitr->second->getAdc());
1072 
1073       // calculate dca
1074       // origin is track origin, direction is track direction
1075       const TVector3 oc_2(global_2.x() - origin.x(), global_2.y() - origin.y(), global_2.z() - origin.z());  // vector from track origin to cluster
1076       auto t_2 = dir.Dot(oc_2) / square(dir.Mag());
1077       auto om_2 = dir * t_2;  // vector from track origin to PCA
1078       const auto dca_2 = (oc_2 - om_2).Mag();
1079 
1080       if (dca_2 > m_max_dca)
1081       {
1082         continue;  // do not record if hit is outside DCA, proceed to next hit
1083       }
1084       if (sameside_reco)
1085       {
1086         sum_n_hits_reco++;
1087         h_adc_reco->Fill(adc_2);
1088         sum_adc_reco += adc_2_unsub;
1089       }  // increment reco but only if hits are on the same side
1090       /*
1091               if(h_hits_reco && trkid == 0)
1092               {
1093                   h_hits_reco->Fill(x_2,y_2,z_2,adc_2);
1094               }
1095       */
1096     }  // end loop over hits again
1097   }    // end loop over hitset again
1098 
1099   h_adc_sum_reco->Fill(sum_adc_reco);
1100   h_num_sum_reco->Fill(sum_n_hits_reco);
1101 
1102   if (sum_adc_truth > 0)  // you MUST have hits in this to take ratio
1103   {
1104     h_adc_sum_ratio->Fill(sum_adc_reco / sum_adc_truth);  // for a hits associated with the same laser fire take the ratio
1105     if (trkid == 0)                                       // for laser 1 only, show me WHERE we are messing up reconstruction
1106     {
1107       h_adc_sum_ratio_lasrangle->Fill(theta_trk * (180. / M_PI), phi_trk * (180. / M_PI), (sum_adc_reco / sum_adc_truth));
1108     }
1109   }
1110 
1111   if (sum_n_hits_truth > 0)  // you MUST have hits in this to take ratio
1112   {
1113     h_num_sum_ratio->Fill(sum_n_hits_reco / sum_n_hits_truth);  // for a hits associated with the same laser fire take the ratio
1114     if (trkid == 0)                                             // for laser 1 only, show me WHERE we are messing up reconstruction
1115     {
1116       h_num_sum_ratio_lasrangle->Fill(theta_trk * (180. / M_PI), phi_trk * (180. / M_PI), (sum_n_hits_reco / sum_n_hits_truth));
1117     }
1118   }
1119 
1120   for (int GEMS_iter : GEM_Mod_Arr)
1121   {
1122     if (GEMS_iter > 0)
1123     {  // laser 0
1124       h_GEMs_hit->Fill(trkid + 0.5);
1125     }
1126   }
1127 
1128   h_deltheta_delphi_1->Reset("ICESM");
1129   h_deltheta_delphi_2->Reset("ICESM");
1130   h_deltheta_delphi_3->Reset("ICESM");
1131   h_deltheta_delphi_4->Reset("ICESM");
1132   h_deltheta_delphi_5->Reset("ICESM");
1133   h_deltheta_delphi_6->Reset("ICESM");
1134   h_deltheta_delphi_7->Reset("ICESM");
1135   h_deltheta_delphi_8->Reset("ICESM");
1136 
1137   // We will bring this back here when we fix the clustering
1138   // int GEM_Mod_Arr[72] = {0};
1139 
1140   // we have all of the residuals for this track added to the map, binned by layer
1141   // now we calculate the centroid of the clusters in each bin
1142 
1143   for (auto layer : layer_bin_set)
1144   {
1145     PHG4TpcCylinderGeom* layergeom = m_geom_container->GetLayerCellGeom(layer);
1146     const auto layer_center_radius = layergeom->get_radius();
1147     const auto layer_inner_radius = layer_center_radius - layergeom->get_thickness() / 2.0;
1148     const auto layer_outer_radius = layer_center_radius + layergeom->get_thickness() / 2.0;
1149 
1150     h_layers_hit->Fill(trkid + 0.5);
1151 
1152     // does track pass completely through this layer? If not do not use the hits
1153     auto tupdn = line_circle_intersection(origin, direction, layer_outer_radius);
1154     if (tupdn.first <= 0 && tupdn.second <= 0)
1155     {
1156       std::cout << " punt:  layer " << layer << " layer outer radius " << layer_outer_radius << " tup " << tupdn.first << " tdn " << tupdn.second << std::endl;
1157       continue;
1158     }
1159     double layer_entry = tupdn.first;
1160     if (tupdn.second >= 0 && tupdn.second < tupdn.first)
1161     {
1162       layer_entry = tupdn.second;
1163     }
1164 
1165     tupdn = line_circle_intersection(origin, direction, layer_inner_radius);
1166     if (tupdn.first <= 0 && tupdn.second <= 0)
1167     {
1168       std::cout << " punt:  layer " << layer << " layer inner radius " << layer_inner_radius << " tup " << tupdn.first << " tdn " << tupdn.second << std::endl;
1169       continue;
1170     }
1171     double layer_exit = tupdn.first;
1172     if (tupdn.second > 0 && tupdn.second < tupdn.first)
1173     {
1174       layer_exit = tupdn.second;
1175     }
1176     if (Verbosity() > 2)
1177     {
1178       std::cout << " layer " << layer << " layer entry " << layer_entry << " layer exit " << layer_exit << std::endl;
1179     }
1180 
1181     // calculate track intersection with layer center
1182     tupdn = line_circle_intersection(origin, direction, layer_center_radius);
1183     double tup = tupdn.first;
1184     double tdn = tupdn.second;
1185     // take 1 one if there are two intersections
1186     double t = tup;
1187     if (tdn > 0 && tdn < tup)
1188     {
1189       t = tdn;
1190     }
1191     if (t < 0)
1192     {
1193       std::cout << " punt:  layer " << layer << " layer center radius " << layer_center_radius << " t " << t << " tup " << tupdn.first << " tdn " << tupdn.second << std::endl;
1194       continue;
1195     }
1196 
1197     // get position of layer center on track
1198     auto om = direction * t;
1199 
1200     // get vector pointing to the track intersection with layer center
1201     const auto projection = origin + om;
1202 
1203     double zmax = -999.;
1204     double zmin = 999.;
1205 
1206     auto bin_residual = cluspos_map.equal_range(layer);
1207 
1208     TVector3 clus_centroid(0, 0, 0);
1209     float wt = 0;
1210     for (auto mit = bin_residual.first; mit != bin_residual.second; ++mit)
1211     {
1212       float adc = (float) mit->second.first;
1213       TVector3 cluspos = mit->second.second;
1214 
1215       if (fabs(cluspos.z() - projection.z()) > m_max_zrange)
1216       {
1217         continue;  // to reject clusters from possible second traverse of layer
1218       }
1219 
1220       if (Verbosity() > 2)
1221       {
1222         std::cout << "  layer " << layer << " adc " << adc << std::endl;
1223         std::cout << "            cluspos " << cluspos.x() << "  " << cluspos.y() << "  " << cluspos.z()
1224                   << " clus radius " << sqrt(square(cluspos.x()) + square(cluspos.y())) << std::endl;
1225       }
1226 
1227       clus_centroid += cluspos * adc;
1228       wt += adc;
1229 
1230       if (cluspos.z() < zmin)
1231       {
1232         zmin = cluspos.z();
1233       }
1234       if (cluspos.z() > zmax)
1235       {
1236         zmax = cluspos.z();
1237       }
1238     }
1239 
1240     clus_centroid.SetX(clus_centroid.x() / wt);
1241     clus_centroid.SetY(clus_centroid.y() / wt);
1242     clus_centroid.SetZ(clus_centroid.z() / wt);
1243 
1244     double zrange = zmax - zmin;
1245     if (zrange > m_max_zrange)
1246     {
1247       std::cout << "    exceeded  max zrange:  zrange " << zrange << " max zrange " << m_max_zrange << std::endl;
1248       continue;
1249     }
1250 
1251     // get the distance of the cluster centroid to the track-layer intersection point
1252 
1253     const TVector3 oc(clus_centroid.x() - origin.x(), clus_centroid.y() - origin.y(), clus_centroid.z() - origin.z());  // vector from track origin to cluster
1254 
1255     const auto dca = (oc - om).Mag();
1256 
1257     // path length
1258     const auto pathlength = om.Mag();
1259 
1260     // Correct cluster z for the track transit time using the pathlength
1261     double ns_per_cm = 1e9 / 3e10;
1262     double dt = pathlength * ns_per_cm;
1263     double transit_dz = dt * m_tGeometry->get_drift_velocity();
1264     if (origin.z() > 0)
1265     {
1266       clus_centroid.SetZ(clus_centroid.z() + transit_dz);
1267     }
1268     else
1269     {
1270       clus_centroid.SetZ(clus_centroid.z() - transit_dz);
1271     }
1272 
1273     if (Verbosity() > 0)
1274     {
1275       std::cout << "  layer " << layer << " radius " << layer_center_radius << " wt " << wt << " t " << t << " dca " << dca
1276                 << " pathlength " << pathlength << " transit_dz " << transit_dz << std::endl;
1277       std::cout << "      clus_centroid " << clus_centroid.x() << "  " << clus_centroid.y() << "  " << clus_centroid.z() << " zrange " << zrange << std::endl;
1278       std::cout << "      projection " << projection.x() << "  " << projection.y() << "  " << projection.z() << " dz " << clus_centroid.z() - projection.z() << std::endl;
1279     }
1280 
1281     // create relevant state vector and assign to track
1282     SvtxTrackState_v1 state(pathlength);
1283     state.set_x(projection.x());
1284     state.set_y(projection.y());
1285     state.set_z(projection.z());
1286 
1287     state.set_px(direction.x());
1288     state.set_py(direction.y());
1289     state.set_pz(direction.z());
1290     track->insert_state(&state);
1291 
1292     // also associate cluster to track
1293     // track->insert_cluster_key( key );
1294 
1295     // cluster r, phi and z
1296     const auto cluster_r = get_r(clus_centroid.x(), clus_centroid.y());
1297     const auto cluster_phi = std::atan2(clus_centroid.y(), clus_centroid.x());
1298     const auto cluster_z = clus_centroid.z();
1299 
1300     // We will bring this back when we fix clustering !!
1301     /*
1302     float r2 = cluster_r;
1303     float phi2 = cluster_phi;
1304     float z2 = cluster_z;
1305     while( phi2 < m_phimin ) phi2 += 2.*M_PI;
1306     while( phi2 >= m_phimax ) phi2 -= 2.*M_PI;
1307 
1308     const int locateid = Locate(r2 , phi2 , z2); //find where the cluster is
1309 
1310     if( z2 > m_zmin || z2 < m_zmax ) GEM_Mod_Arr[locateid-1]++; // the array ath the cluster location - counts the number of clusters in each array, (IFF its in the volume !!!)
1311     */
1312 
1313     // cluster errors
1314     const auto cluster_rphi_error = 0.015;
1315     const auto cluster_z_error = 0.075;
1316 
1317     // track position
1318     const auto track_phi = std::atan2(projection.y(), projection.x());
1319     const auto track_z = projection.z();
1320 
1321     // track angles
1322     const auto cosphi(std::cos(track_phi));
1323     const auto sinphi(std::sin(track_phi));
1324     const auto track_pphi = -state.get_px() * sinphi + state.get_py() * cosphi;
1325     const auto track_pr = state.get_px() * cosphi + state.get_py() * sinphi;
1326     const auto track_pz = state.get_pz();
1327     const auto talpha = -track_pphi / track_pr;
1328     const auto tbeta = -track_pz / track_pr;
1329 
1330     // sanity check
1331     if (std::isnan(talpha))
1332     {
1333       std::cout << "TpcDirectLaserReconstruction::process_track - talpha is nan" << std::endl;
1334       continue;
1335     }
1336 
1337     if (std::isnan(tbeta))
1338     {
1339       std::cout << "TpcDirectLaserReconstruction::process_track - tbeta is nan" << std::endl;
1340       continue;
1341     }
1342 
1343     // residuals
1344     const auto drp = cluster_r * delta_phi(cluster_phi - track_phi);
1345     const auto dz = cluster_z - track_z;
1346 
1347     // sanity checks
1348     if (std::isnan(drp))
1349     {
1350       std::cout << "TpcDirectLaserReconstruction::process_track - drp is nan" << std::endl;
1351       continue;
1352     }
1353 
1354     if (std::isnan(dz))
1355     {
1356       std::cout << "TpcDirectLaserReconstruction::process_track - dz is nan" << std::endl;
1357       continue;
1358     }
1359 
1360     if (m_savehistograms)
1361     {
1362       const float r = get_r(projection.x(), projection.y());
1363       const float dr = cluster_r - r;
1364       if (h_dca_layer)
1365       {
1366         h_dca_layer->Fill(r, dca);
1367       }
1368       if (h_deltarphi_layer_south && clus_centroid.z() < 0)
1369       {
1370         h_deltarphi_layer_south->Fill(r, drp);
1371       }
1372       if (h_deltarphi_layer_north && clus_centroid.z() > 0)
1373       {
1374         h_deltarphi_layer_north->Fill(r, drp);
1375       }
1376       if (h_deltaz_layer)
1377       {
1378         h_deltaz_layer->Fill(r, dz);
1379       }
1380       if (h_deltar_r)
1381       {
1382         h_deltar_r->Fill(r, dr);
1383       }
1384       if (h_entries)
1385       {
1386         auto phi = cluster_phi;
1387         while (phi < m_phimin)
1388         {
1389           phi += 2. * M_PI;
1390         }
1391         while (phi >= m_phimax)
1392         {
1393           phi -= 2. * M_PI;
1394         }
1395         h_entries->Fill(phi, cluster_r, cluster_z);
1396       }
1397       if (h_xy)
1398       {
1399         h_xy->Fill(clus_centroid.x(), clus_centroid.y());
1400       }
1401       if (h_xz)
1402       {
1403         h_xz->Fill(clus_centroid.x(), clus_centroid.z());
1404       }
1405       if (h_xy_pca)
1406       {
1407         h_xy_pca->Fill(projection.x(), projection.y());
1408       }
1409       if (h_xz_pca)
1410       {
1411         h_xz_pca->Fill(projection.x(), projection.z());
1412       }
1413       if (h_dca_path)
1414       {
1415         h_dca_path->Fill(pathlength, dca);
1416       }
1417       if (h_zr)
1418       {
1419         h_zr->Fill(clus_centroid.z(), cluster_r);
1420       }
1421       if (h_zr_pca)
1422       {
1423         h_zr_pca->Fill(projection.z(), r);
1424       }
1425       if (h_dz_z)
1426       {
1427         h_dz_z->Fill(projection.z(), clus_centroid.z() - projection.z());
1428       }
1429       // if(h_clusters)h_clusters->Fill(clus_centroid.x(),clus_centroid.y(),clus_centroid.z());
1430     }
1431 
1432     //       // check against limits
1433     //       if( std::abs( drp ) > m_max_drphi ) continue;
1434     //       if( std::abs( dz ) > m_max_dz ) continue;
1435 
1436     // residual errors squared
1437     const auto erp = square(cluster_rphi_error);
1438     const auto ez = square(cluster_z_error);
1439 
1440     // sanity check
1441     if (std::isnan(erp))
1442     {
1443       std::cout << "TpcDirectLaserReconstruction::process_track - erp is nan" << std::endl;
1444       continue;
1445     }
1446 
1447     if (std::isnan(ez))
1448     {
1449       std::cout << "TpcDirectLaserReconstruction::process_track - ez is nan" << std::endl;
1450       continue;
1451     }
1452 
1453     // get cell
1454     const auto i = get_cell_index(clus_centroid);
1455     if (i < 0)
1456     {
1457       if (Verbosity())
1458       {
1459         std::cout << "TpcDirectLaserReconstruction::process_track - invalid cell index"
1460                   << " r: " << cluster_r
1461                   << " phi: " << cluster_phi
1462                   << " z: " << cluster_z
1463                   << std::endl;
1464       }
1465       continue;
1466     }
1467 
1468     // update matrices
1469     // see https://indico.bnl.gov/event/7440/contributions/43328/attachments/31334/49446/talk.pdf for details
1470     m_matrix_container->add_to_lhs(i, 0, 0, 1. / erp);
1471     m_matrix_container->add_to_lhs(i, 0, 1, 0);
1472     m_matrix_container->add_to_lhs(i, 0, 2, talpha / erp);
1473 
1474     m_matrix_container->add_to_lhs(i, 1, 0, 0);
1475     m_matrix_container->add_to_lhs(i, 1, 1, 1. / ez);
1476     m_matrix_container->add_to_lhs(i, 1, 2, tbeta / ez);
1477 
1478     m_matrix_container->add_to_lhs(i, 2, 0, talpha / erp);
1479     m_matrix_container->add_to_lhs(i, 2, 1, tbeta / ez);
1480     m_matrix_container->add_to_lhs(i, 2, 2, square(talpha) / erp + square(tbeta) / ez);
1481 
1482     m_matrix_container->add_to_rhs(i, 0, drp / erp);
1483     m_matrix_container->add_to_rhs(i, 1, dz / ez);
1484     m_matrix_container->add_to_rhs(i, 2, talpha * drp / erp + tbeta * dz / ez);
1485 
1486     // update entries in cell
1487     m_matrix_container->add_to_entries(i);
1488 
1489     // increment number of accepted clusters
1490     ++m_accepted_clusters;
1491   }
1492 
1493   // We will eventually bring this back when we fix clustering
1494   /*
1495     for(int GEMS_iter = 0; GEMS_iter < 72; GEMS_iter++)
1496     {
1497       if(GEM_Mod_Arr[GEMS_iter] > 0){  //laser 0
1498         h_GEMs_hit->Fill(trkid + 0.5);
1499       }
1500     }
1501   */
1502 }
1503 
1504 //_____________________________________________________________________
1505 int TpcDirectLaserReconstruction::get_cell_index(const TVector3& global) const
1506 {
1507   // get grid dimensions from matrix container
1508   int phibins = 0;
1509   int rbins = 0;
1510   int zbins = 0;
1511   m_matrix_container->get_grid_dimensions(phibins, rbins, zbins);
1512 
1513   // phi
1514   // bound check
1515   float phi = std::atan2(global.y(), global.x());
1516   while (phi < m_phimin)
1517   {
1518     phi += 2. * M_PI;
1519   }
1520   while (phi >= m_phimax)
1521   {
1522     phi -= 2. * M_PI;
1523   }
1524   int iphi = phibins * (phi - m_phimin) / (m_phimax - m_phimin);
1525 
1526   // radius
1527   const float r = get_r(global.x(), global.y());
1528   if (r < m_rmin || r >= m_rmax)
1529   {
1530     return -1;
1531   }
1532   int ir = rbins * (r - m_rmin) / (m_rmax - m_rmin);
1533 
1534   // z
1535   const float z = global.z();
1536   if (z < m_zmin || z >= m_zmax)
1537   {
1538     return -1;
1539   }
1540   int iz = zbins * (z - m_zmin) / (m_zmax - m_zmin);
1541 
1542   return m_matrix_container->get_cell_index(iphi, ir, iz);
1543 }
1544 //_____________________________________________________________________
1545 int TpcDirectLaserReconstruction::Locate(float r, float phi, float z)
1546 {
1547   ////////////////////////////////////////////////////////////////////////
1548   //          North Label Conventions                                  //
1549   ///////////////////////////////////////////////////////////////////////
1550   //   1 - 00_R1   16 - 05_R1   31 - 10_R1
1551   //   2 - 00_R2   17 - 05_R2   32 - 10_R2
1552   //   3 - 00_R3   18 - 05_R3   33 - 10_R3
1553   //   4 - 01_R1   19 - 06_R1   34 - 11_R1
1554   //   5 - 01_R2   20 - 06_R2   35 - 11_R2
1555   //   6 - 01_R3   21 - 06_R3   36 - 11_R3
1556   //   7 - 02_R1   22 - 07_R1
1557   //   8 - 02_R2   23 - 07_R2
1558   //   9 - 02_R3   24 - 07_R3
1559   //  10 - 03_R1   25 - 08_R1
1560   //  11 - 03_R2   26 - 08_R2
1561   //  12 - 03_R3   27 - 08_R3
1562   //  13 - 04_R1   28 - 09_R1
1563   //  14 - 04_R2   29 - 09_R2
1564   //  15 - 04_R3   30 - 09_R3
1565 
1566   ////////////////////////////////////////////////////////////////////////
1567   //          South Label Conventions                                   //
1568   ///////////////////////////////////////////////////////////////////////
1569   //  37 - 12_R1   52 - 17_R1   67 - 22_R1
1570   //  38 - 12_R2   53 - 17_R2   68 - 22_R2
1571   //  39 - 12_R3   54 - 17_R3   69 - 22_R3
1572   //  40 - 13_R1   55 - 18_R1   70 - 23_R1
1573   //  41 - 13_R2   56 - 18_R2   71 - 23_R2
1574   //  42 - 13_R3   57 - 18_R3   72 - 23_R3
1575   //  43 - 14_R1   58 - 19_R1
1576   //  44 - 14_R2   59 - 19_R2
1577   //  45 - 14_R3   60 - 19_R3
1578   //  46 - 15_R1   61 - 20_R1
1579   //  47 - 15_R2   62 - 20_R2
1580   //  48 - 15_R3   63 - 20_R3
1581   //  49 - 16_R1   64 - 21_R1
1582   //  50 - 16_R2   65 - 21_R2
1583   //  51 - 16_R3   66 - 21_R3
1584 
1585   int GEM_Mod_ID;  // integer from 1 to 72
1586 
1587   const float Angle_Bins[13] = {23 * M_PI / 12, 1 * M_PI / 12, 3 * M_PI / 12, 5 * M_PI / 12, 7 * M_PI / 12, 9 * M_PI / 12, 11 * M_PI / 12, 13 * M_PI / 12, 15 * M_PI / 12, 17 * M_PI / 12, 19 * M_PI / 12, 21 * M_PI / 12, 23 * M_PI / 12};  // 12 angle bins on each side
1588 
1589   const float r_bins[4] = {30, 46, 62, 78};  // 4 r bins
1590 
1591   int angle_id = 0;  // default to 0
1592   int r_id = 0;      // default to 0
1593   int side_id = 0;   // default to 0 (north side)
1594 
1595   for (int r_iter = 0; r_iter < 3; r_iter++)
1596   {
1597     if (r > r_bins[r_iter] && r < r_bins[r_iter + 1])
1598     {
1599       r_id = r_iter + 1;
1600       break;  // break out of the for loop if you found where the hit is in r
1601     }
1602   }
1603 
1604   for (int ang_iter = 0; ang_iter < 12; ang_iter++)
1605   {
1606     if (phi > Angle_Bins[ang_iter] && phi < Angle_Bins[ang_iter + 1])
1607     {
1608       angle_id = ang_iter;
1609       break;  // break out the for loop if you found where the hit is in phi
1610     }
1611   }
1612   if (z < 0)
1613   {
1614     side_id = 1;  //(south side)
1615   }
1616 
1617   return GEM_Mod_ID = (36 * side_id) + (3 * angle_id) + r_id;
1618 }
1619 
1620 float TpcDirectLaserReconstruction::GetRelPhi(float xorig, float yorig, float x, float y, float phiorig)
1621 {
1622   // getting the relative phi in the frame rotated to the ith laser origin
1623   //
1624   // inputs:
1625   //    xorig = x coordinate of ith laser origin
1626   //      yorig = y coordinate of ith laser origin
1627   //          x = x coordinate of arbitrary point in TPC volume
1628   //          y = y coordinate of arbitrary point in TPC volume
1629   //    phiorig = phi (from + x axis) of ith laser origin
1630   //
1631   // output:
1632   //     relphi = azimuthal displacement of arbitrary point in TPC volume from ith laser origin
1633 
1634   if (phiorig < 0)
1635   {
1636     phiorig += 2. * M_PI;
1637   }
1638   else if (phiorig > 2. * M_PI)
1639   {
1640     phiorig -= 2. * M_PI;
1641   }
1642 
1643   float dx = x - xorig;
1644   float dy = y - yorig;
1645   float relphi = atan2(dy, dx) - phiorig;
1646   if (relphi < 0)
1647   {
1648     relphi += 2. * M_PI;
1649   }
1650   else if (relphi > 2. * M_PI)
1651   {
1652     relphi -= 2. * M_PI;
1653   }
1654 
1655   return relphi;
1656 }
1657 
1658 float TpcDirectLaserReconstruction::GetRelTheta(float xorig, float yorig, float zorig, float x, float y, float z, float thetaorig, float phiorig)
1659 {
1660   // getting the relative theta in the frame rotated to the ith laser origin
1661   //
1662   // inputs:
1663   //    xorig = x coordinate of ith laser origin
1664   //      yorig = y coordinate of ith laser origin
1665   //      zorig = z cooridante of ith laser origin
1666   //          x = x coordinate of arbitrary point in TPC volume
1667   //          y = y coordinate of arbitrary point in TPC volume
1668   //          z = z coordinate of arbitrary point in TPC volume
1669   //  thetaorig = theta (from + y axis?) of ithe laser origin
1670   //    phiorig = phi (from + x axis) of ith laser origin
1671   //
1672   // output:
1673   //     reltheta = polar displacement of arbitrary point in TPC volume from ith laser origin
1674 
1675   if (phiorig < 0)
1676   {
1677     phiorig += 2. * M_PI;
1678   }
1679   else if (phiorig > 2. * M_PI)
1680   {
1681     phiorig -= 2. * M_PI;
1682   }
1683 
1684   if (thetaorig < 0)
1685   {
1686     thetaorig += 2. * M_PI;
1687   }
1688   else if (thetaorig > 2. * M_PI)
1689   {
1690     thetaorig -= 2. * M_PI;
1691   }
1692 
1693   float dx = x - xorig;
1694   float dy = y - yorig;
1695   float dz = z - zorig;
1696   float r = sqrt(dx * dx + dy * dy + dz * dz);
1697 
1698   float cos_beta = (dx * cos(phiorig) + dy * sin(phiorig)) / r;
1699   float sin_beta = dz / r;
1700 
1701   float reltheta = acos(cos_beta * cos(thetaorig) + sin_beta * sin(thetaorig)) - M_PI / 2.;
1702   if (reltheta < 0)
1703   {
1704     reltheta += 2. * M_PI;
1705   }
1706   else if (reltheta > 2. * M_PI)
1707   {
1708     reltheta -= 2. * M_PI;
1709   }
1710 
1711   return reltheta;
1712 }
1713 
1714 bool TpcDirectLaserReconstruction::sameSign(float num1, float num2)
1715 {
1716   return (num1 >= 0 && num2 >= 0) || (num1 < 0 && num2 < 0);
1717 }