Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:13:39

0001 //____________________________________________________________________________..
0002 //
0003 // This is a template for a Fun4All SubsysReco module with all methods from the
0004 // $OFFLINE_MAIN/include/fun4all/SubsysReco.h baseclass
0005 // You do not have to implement all of them, you can just remove unused methods
0006 // here and in InttZVertexFinderTrapezoidal.h.
0007 //
0008 // InttZVertexFinderTrapezoidal(const std::string &name = "InttZVertexFinderTrapezoidal")
0009 // everything is keyed to InttZVertexFinderTrapezoidal, duplicate names do work but it makes
0010 // e.g. finding culprits in logs difficult or getting a pointer to the module
0011 // from the command line
0012 //
0013 // InttZVertexFinderTrapezoidal::~InttZVertexFinderTrapezoidal()
0014 // this is called when the Fun4AllServer is deleted at the end of running. Be
0015 // mindful what you delete - you do loose ownership of object you put on the node tree
0016 //
0017 // int InttZVertexFinderTrapezoidal::Init(PHCompositeNode *topNode)
0018 // This method is called when the module is registered with the Fun4AllServer. You
0019 // can create historgrams here or put objects on the node tree but be aware that
0020 // modules which haven't been registered yet did not put antyhing on the node tree
0021 //
0022 // int InttZVertexFinderTrapezoidal::InitRun(PHCompositeNode *topNode)
0023 // This method is called when the first event is read (or generated). At
0024 // this point the run number is known (which is mainly interesting for raw data
0025 // processing). Also all objects are on the node tree in case your module's action
0026 // depends on what else is around. Last chance to put nodes under the DST Node
0027 // We mix events during readback if branches are added after the first event
0028 //
0029 // int InttZVertexFinderTrapezoidal::process_event(PHCompositeNode *topNode)
0030 // called for every event. Return codes trigger actions, you find them in
0031 // $OFFLINE_MAIN/include/fun4all/Fun4AllReturnCodes.h
0032 //   everything is good:
0033 //     return Fun4AllReturnCodes::EVENT_OK
0034 //   abort event reconstruction, clear everything and process next event:
0035 //     return Fun4AllReturnCodes::ABORT_EVENT; 
0036 //   proceed but do not save this event in output (needs output manager setting):
0037 //     return Fun4AllReturnCodes::DISCARD_EVENT; 
0038 //   abort processing:
0039 //     return Fun4AllReturnCodes::ABORT_RUN
0040 // all other integers will lead to an error and abort of processing
0041 //
0042 // int InttZVertexFinderTrapezoidal::ResetEvent(PHCompositeNode *topNode)
0043 // If you have internal data structures (arrays, stl containers) which needs clearing
0044 // after each event, this is the place to do that. The nodes under the DST node are cleared
0045 // by the framework
0046 //
0047 // int InttZVertexFinderTrapezoidal::EndRun(const int runnumber)
0048 // This method is called at the end of a run when an event from a new run is
0049 // encountered. Useful when analyzing multiple runs (raw data). Also called at
0050 // the end of processing (before the End() method)
0051 //
0052 // int InttZVertexFinderTrapezoidal::End(PHCompositeNode *topNode)
0053 // This is called at the end of processing. It needs to be called by the macro
0054 // by Fun4AllServer::End(), so do not forget this in your macro
0055 //
0056 // int InttZVertexFinderTrapezoidal::Reset(PHCompositeNode *topNode)
0057 // not really used - it is called before the dtor is called
0058 //
0059 // void InttZVertexFinderTrapezoidal::Print(const std::string &what) const
0060 // Called from the command line - useful to print information when you need it
0061 //
0062 //____________________________________________________________________________..
0063 
0064 #include "InttZVertexFinderTrapezoidal.h"
0065 
0066 //____________________________________________________________________________..
0067 InttZVertexFinderTrapezoidal::InttZVertexFinderTrapezoidal(
0068   const std::string &name,
0069   std::pair<double, double> vertexXYIncm_in, // note : cm
0070   bool IsFieldOn_in,
0071   bool IsDCACutApplied_in,
0072   std::pair<std::pair<double,double>,std::pair<double,double>> DeltaPhiCutInDegree_in, // note : in degree
0073   std::pair<std::pair<double,double>,std::pair<double,double>> DCAcutIncm_in, // note : in cm
0074   int ClusAdcCut_in,
0075   int ClusPhiSizeCut_in,
0076   bool PrintRecoDetails_in
0077 ):
0078   SubsysReco(name),
0079   vertexXYIncm(vertexXYIncm_in),
0080   IsFieldOn(IsFieldOn_in),
0081   IsDCACutApplied(IsDCACutApplied_in),
0082   DeltaPhiCutInDegree(DeltaPhiCutInDegree_in),
0083   DCAcutIncm(DCAcutIncm_in),
0084   ClusAdcCut(ClusAdcCut_in),
0085   ClusPhiSizeCut(ClusPhiSizeCut_in),
0086   PrintRecoDetails(PrintRecoDetails_in)
0087   // m_vertexXYInmm(std::make_pair(vertexXYIncm.first*10., vertexXYIncm.second*10.)),
0088   // m_DCAcutInmm(std::make_pair(std::make_pair(DCAcutIncm.first.first*10., DCAcutIncm.first.second*10.), std::make_pair(DCAcutIncm.second.first*10., DCAcutIncm.second.second*10.)))
0089 {
0090   std::cout << "InttZVertexFinderTrapezoidal::InttZVertexFinderTrapezoidal(const std::string &name) Calling ctor" << std::endl;
0091 
0092     evt_possible_z = new TH1D("","evt_possible_z",50, evt_possible_z_range.first, evt_possible_z_range.second);
0093     evt_possible_z -> SetLineWidth(1);
0094     evt_possible_z -> GetXaxis() -> SetTitle("Z [cm]");
0095     evt_possible_z -> GetYaxis() -> SetTitle("Entry");
0096 
0097 
0098     line_breakdown_hist = new TH1D("", "line_breakdown_hist", 2*zvtx_hist_Nbins+1, -1*(fine_bin_width*zvtx_hist_Nbins + fine_bin_width/2.), fine_bin_width*zvtx_hist_Nbins + fine_bin_width/2.);
0099     line_breakdown_hist -> SetLineWidth(1);
0100     line_breakdown_hist -> GetXaxis() -> SetTitle("Z [cm]");
0101     line_breakdown_hist -> GetYaxis() -> SetTitle("Entries [A.U.]");
0102     line_breakdown_hist -> GetXaxis() -> SetNdivisions(705);
0103 
0104     combination_zvtx_range_shape = new TH1D(
0105         "",
0106         "",
0107         line_breakdown_hist -> GetNbinsX(),
0108         line_breakdown_hist -> GetXaxis() -> GetXmin(),
0109         line_breakdown_hist -> GetXaxis() -> GetXmax()
0110     );
0111 
0112     temp_sPH_inner_nocolumn_vec.clear();
0113     temp_sPH_outer_nocolumn_vec.clear();
0114 
0115     gaus_fit = new TF1("gaus_fit",gaus_func,evt_possible_z_range.first,evt_possible_z_range.second,4);
0116     gaus_fit -> SetLineColor(2);
0117     gaus_fit -> SetLineWidth(1);
0118     gaus_fit -> SetNpx(1000);
0119 
0120     gaus_fit_vec.clear();
0121     for (int i = 0; i < number_of_gaus; i++) 
0122     {
0123         gaus_fit_vec.push_back(new TF1("gaus_fit_vec",gaus_func,evt_possible_z_range.first,evt_possible_z_range.second,4));
0124         gaus_fit_vec[i] -> SetLineColor(TColor::GetColor(color_code[i].c_str()));
0125         gaus_fit_vec[i] -> SetLineWidth(1);
0126         gaus_fit_vec[i] -> SetNpx(1000);
0127     }
0128 
0129     
0130 
0131 }
0132 
0133 //____________________________________________________________________________..
0134 InttZVertexFinderTrapezoidal::~InttZVertexFinderTrapezoidal()
0135 {
0136   std::cout << "InttZVertexFinderTrapezoidal::~InttZVertexFinderTrapezoidal() Calling dtor" << std::endl;
0137 }
0138 
0139 //____________________________________________________________________________..
0140 int InttZVertexFinderTrapezoidal::Init(PHCompositeNode *topNode)
0141 {
0142   std::cout << "InttZVertexFinderTrapezoidal::Init(PHCompositeNode *topNode) Initializing" << std::endl;
0143   return Fun4AllReturnCodes::EVENT_OK;
0144 }
0145 
0146 //____________________________________________________________________________..
0147 int InttZVertexFinderTrapezoidal::InitRun(PHCompositeNode *topNode)
0148 {
0149   std::cout << "InttZVertexFinderTrapezoidal::InitRun(PHCompositeNode *topNode) Initializing for Run XXX" << std::endl;
0150 
0151   if (createNodes(topNode) == Fun4AllReturnCodes::ABORTEVENT)
0152   {
0153     std::cout << PHWHERE << "Could not create nodes. Exiting." << std::endl;
0154     return Fun4AllReturnCodes::ABORTEVENT;
0155   }
0156 
0157   return Fun4AllReturnCodes::EVENT_OK;
0158 }
0159 
0160 int InttZVertexFinderTrapezoidal::PrepareClusterVec(PHCompositeNode *topNode)
0161 {
0162   // std::cout << "InttZVertexFinderTrapezoidal::PrepareClusterVec(PHCompositeNode *topNode) Preparing Cluster Vector" << std::endl;
0163 
0164   ActsGeometry* tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0165   if (!tGeometry)
0166   {
0167     std::cout << PHWHERE << "No ActsGeometry on node tree. Bailing." << std::endl;
0168     return Fun4AllReturnCodes::ABORTEVENT;
0169   }
0170 
0171   TrkrClusterContainer* clusterMap =
0172       findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0173   if (!clusterMap)
0174   {
0175     std::cout << PHWHERE << "TrkrClusterContainer node is missing." << std::endl;
0176     return Fun4AllReturnCodes::ABORTEVENT;
0177   }
0178 
0179 
0180   for (unsigned int inttlayer = 0; inttlayer < 4; inttlayer++)
0181   {
0182     std::vector<clu_info>* p_temp_sPH_nocolumn_vec =
0183         (inttlayer < 2) ? (&temp_sPH_inner_nocolumn_vec)
0184                         : (&temp_sPH_outer_nocolumn_vec);
0185 
0186     for (const auto& hitsetkey : clusterMap->getHitSetKeys(TrkrDefs::TrkrId::inttId, inttlayer + 3))
0187     {
0188       auto range = clusterMap->getClusters(hitsetkey);
0189 
0190       for (auto clusIter = range.first; clusIter != range.second; ++clusIter)
0191       {
0192         NClusAll += 1;
0193         NClusAllInner += (inttlayer < 2) ? 1 : 0;
0194 
0195         const auto cluskey = clusIter->first;
0196         const auto cluster = clusIter->second;
0197 
0198         const auto globalPos = tGeometry->getGlobalPosition(cluskey, cluster);
0199         double clu_x = globalPos(0);  //note: unit in cm
0200         double clu_y = globalPos(1);  //note: unit in cm
0201         double clu_z = globalPos(2);  //note: unit in cm
0202 
0203         // double clu_phi = (clu_y < 0) ? atan2(clu_y, clu_x) * (180. / M_PI) + 360
0204         //                              : atan2(clu_y, clu_x) * (180. / M_PI);
0205 
0206         // double clu_radius = sqrt(pow(clu_x, 2) + pow(clu_y, 2));
0207 
0208         // int size = cluster->getSize();
0209         int phisize = cluster->getPhiSize();
0210         int adc = cluster->getAdc();
0211         int sensorZID = InttDefs::getLadderZId(cluskey);
0212 
0213         if (adc <= ClusAdcCut || phisize > ClusPhiSizeCut) {continue;}
0214 
0215         p_temp_sPH_nocolumn_vec->push_back({
0216           clu_x,
0217           clu_y,
0218           clu_z,
0219           adc,
0220           phisize,
0221           sensorZID
0222         });
0223       }
0224     }
0225   }
0226 
0227 
0228   return Fun4AllReturnCodes::EVENT_OK;
0229 }
0230 
0231 int InttZVertexFinderTrapezoidal::PrepareINTTvtxZ()
0232 {
0233   for (int inner_i = 0; inner_i < int(temp_sPH_inner_nocolumn_vec.size()); inner_i++) {
0234       double Clus_InnerPhi_Offset = (temp_sPH_inner_nocolumn_vec[inner_i].y - vertexXYIncm.second < 0) ? atan2(temp_sPH_inner_nocolumn_vec[inner_i].y - vertexXYIncm.second, temp_sPH_inner_nocolumn_vec[inner_i].x - vertexXYIncm.first) * (180./TMath::Pi()) + 360 : atan2(temp_sPH_inner_nocolumn_vec[inner_i].y - vertexXYIncm.second, temp_sPH_inner_nocolumn_vec[inner_i].x - vertexXYIncm.first) * (180./TMath::Pi());
0235       inner_clu_phi_map[ int(Clus_InnerPhi_Offset) ].push_back({false,temp_sPH_inner_nocolumn_vec[inner_i]});
0236   }
0237   for (int outer_i = 0; outer_i < int(temp_sPH_outer_nocolumn_vec.size()); outer_i++) {
0238       double Clus_OuterPhi_Offset = (temp_sPH_outer_nocolumn_vec[outer_i].y - vertexXYIncm.second < 0) ? atan2(temp_sPH_outer_nocolumn_vec[outer_i].y - vertexXYIncm.second, temp_sPH_outer_nocolumn_vec[outer_i].x - vertexXYIncm.first) * (180./TMath::Pi()) + 360 : atan2(temp_sPH_outer_nocolumn_vec[outer_i].y - vertexXYIncm.second, temp_sPH_outer_nocolumn_vec[outer_i].x - vertexXYIncm.first) * (180./TMath::Pi());
0239       outer_clu_phi_map[ int(Clus_OuterPhi_Offset) ].push_back({false,temp_sPH_outer_nocolumn_vec[outer_i]});
0240   }
0241 
0242   // note : prepare good tracklet
0243   for (int inner_phi_i = 0; inner_phi_i < 360; inner_phi_i++) // note : each phi cell (1 degree)
0244   {
0245       // note : N cluster in this phi cell
0246       for (int inner_phi_clu_i = 0; inner_phi_clu_i < int(inner_clu_phi_map[inner_phi_i].size()); inner_phi_clu_i++)
0247       {
0248           if (inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].first == true) {continue;}
0249 
0250           double Clus_InnerPhi_Offset = (inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.y - vertexXYIncm.second < 0) ? atan2(inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.y - vertexXYIncm.second, inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.x - vertexXYIncm.first) * (180./TMath::Pi()) + 360 : atan2(inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.y - vertexXYIncm.second, inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.x - vertexXYIncm.first) * (180./TMath::Pi());
0251 
0252           // todo: change the outer phi scan range
0253           // note : the outer phi index, -1, 0, 1
0254           // note : the outer phi index, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 for the scan test
0255           for (int scan_i = -5; scan_i < 6; scan_i++)
0256           {
0257               int true_scan_i = ((inner_phi_i + scan_i) < 0) ? 360 + (inner_phi_i + scan_i) : ((inner_phi_i + scan_i) > 359) ? (inner_phi_i + scan_i)-360 : inner_phi_i + scan_i;
0258 
0259               // note : N clusters in that outer phi cell
0260               for (int outer_phi_clu_i = 0; outer_phi_clu_i < int(outer_clu_phi_map[true_scan_i].size()); outer_phi_clu_i++)
0261               {
0262                   if (outer_clu_phi_map[true_scan_i][outer_phi_clu_i].first == true) {continue;}
0263 
0264                   double Clus_OuterPhi_Offset = (outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.y - vertexXYIncm.second < 0) ? atan2(outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.y - vertexXYIncm.second, outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.x - vertexXYIncm.first) * (180./TMath::Pi()) + 360 : atan2(outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.y - vertexXYIncm.second, outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.x - vertexXYIncm.first) * (180./TMath::Pi());
0265                   double delta_phi = get_delta_phi(Clus_InnerPhi_Offset, Clus_OuterPhi_Offset);
0266                   
0267                   double delta_phi_correct = delta_phi; // note : this is for the further correction, potentially 
0268 
0269                   // note : ----------------------------------------------------------------------------------------------------------------------------------
0270                   // note : delta phi cut
0271                   if (!IsFieldOn){ // note : field off
0272                     if (delta_phi_correct <= DeltaPhiCutInDegree.first.first || delta_phi_correct >= DeltaPhiCutInDegree.first.second) {continue;}
0273                   }
0274                   // note : field ON
0275                   else{
0276                     if (
0277                           (delta_phi_correct > DeltaPhiCutInDegree.first.first && delta_phi_correct < DeltaPhiCutInDegree.first.second) == false && 
0278                           (delta_phi_correct > DeltaPhiCutInDegree.second.first && delta_phi_correct < DeltaPhiCutInDegree.second.second) == false
0279                        ) 
0280                        {continue;}
0281                   }
0282 
0283                   double DCA_sign = calculateAngleBetweenVectors(
0284                       outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.x, outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.y,
0285                       inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.x, inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.y,
0286                       vertexXYIncm.first, vertexXYIncm.second
0287                   );   
0288 
0289                   // note : ----------------------------------------------------------------------------------------------------------------------------------
0290                   // note : DCA cut
0291                   if (IsDCACutApplied)
0292                   {
0293                     if (!IsFieldOn){ // note : field off
0294                       if (DCA_sign <= DCAcutIncm.first.first || DCA_sign >= DCAcutIncm.first.second) {continue;}
0295                     }
0296                     else{
0297                       if (
0298                           (DCA_sign > DCAcutIncm.first.first && DCA_sign < DCAcutIncm.first.second) == false && 
0299                           (DCA_sign > DCAcutIncm.second.first && DCA_sign < DCAcutIncm.second.second) == false
0300                        ) 
0301                        {continue;}
0302                     }
0303                   }
0304 
0305                   // note : ----------------------------------------------------------------------------------------------------------------------------------
0306                   // note : good proto-tracklet
0307                   std::pair<double,double> z_range_info = Get_possible_zvtx( 
0308                       0., // get_radius(vertexXYIncm.first,vertexXYIncm.second), 
0309                       {
0310                         get_radius(inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.x - vertexXYIncm.first, inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.y - vertexXYIncm.second), 
0311                         inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.z,
0312                         double(inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.sensorZID)
0313                       }, // note : unsign radius
0314                       
0315                       {
0316                         get_radius(outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.x - vertexXYIncm.first, outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.y - vertexXYIncm.second), 
0317                         outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.z,
0318                         double(outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.sensorZID)
0319                       }  // note : unsign radius
0320                   );
0321 
0322                   // note : ----------------------------------------------------------------------------------------------------------------------------------
0323                   // note : check the coverage
0324                   if (evt_possible_z_range.first < z_range_info.first && z_range_info.first < evt_possible_z_range.second) {
0325                       evt_possible_z -> Fill(z_range_info.first);
0326 
0327                       // note : fill the line_breakdown histogram as well as a vector for the width determination
0328                       trapezoidal_line_breakdown( 
0329                           line_breakdown_hist, 
0330                           
0331                           // note : inner_r and inner_z
0332                           get_radius(inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.x - vertexXYIncm.first, inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.y - vertexXYIncm.second), 
0333                           inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.z,
0334                           inner_clu_phi_map[inner_phi_i][inner_phi_clu_i].second.sensorZID,
0335 
0336                           // note : outer_r and outer_z
0337                           get_radius(outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.x - vertexXYIncm.first, outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.y - vertexXYIncm.second), 
0338                           outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.z,
0339                           outer_clu_phi_map[true_scan_i][outer_phi_clu_i].second.sensorZID
0340                       );
0341                   }
0342                   
0343               }
0344           } // note : end of outer clu loop
0345       } 
0346 
0347   } // note : end of inner clu loop
0348 
0349   // todo : some of the events have the special behavior which is having the high entry in the both edges
0350   // note : prepare the vertex Z by INTT
0351   for (int bin_i = 0; bin_i < line_breakdown_hist->GetNbinsX(); bin_i++){
0352       if (line_breakdown_hist -> GetBinCenter(bin_i+1) < edge_rejection.first || line_breakdown_hist -> GetBinCenter(bin_i+1) > edge_rejection.second){
0353           line_breakdown_hist -> SetBinContent(bin_i+1,0);
0354       }
0355   }
0356 
0357   // note : no good proto-tracklet
0358   if (line_breakdown_hist->Integral(-1,-1) == 0) {
0359     return Fun4AllReturnCodes::EVENT_OK;
0360   }
0361 
0362   std::vector<double> N_group_info = find_Ngroup(evt_possible_z);
0363 
0364 
0365   std::vector<double> N_group_info_detail = find_Ngroup(line_breakdown_hist);
0366   double Half_N_group_half_width = fabs(N_group_info_detail[3] - N_group_info_detail[2]) / 2.;
0367   double line_breakdown_hist_max_content = line_breakdown_hist -> GetBinContent( line_breakdown_hist -> GetMaximumBin() );
0368   double line_breakdown_hist_max_center = line_breakdown_hist -> GetBinCenter( line_breakdown_hist -> GetMaximumBin() );
0369   
0370   // note : first fit is for the width, so apply the constraints on the Gaussian offset
0371   gaus_fit -> SetParameters(line_breakdown_hist_max_content, line_breakdown_hist_max_center, Half_N_group_half_width, 0);
0372   gaus_fit -> SetParLimits(0,0,100000);  // note : size 
0373   gaus_fit -> SetParLimits(2,0.5,1000);   // note : Width
0374   gaus_fit -> SetParLimits(3,0,10000);   // note : offset
0375   // todo : the width fit range is 60% of the peak width, // todo : try to use single gaus to fit the distribution
0376   double width_fit_range_l = line_breakdown_hist_max_center - Half_N_group_half_width * 0.6;
0377   double width_fit_range_r = line_breakdown_hist_max_center + Half_N_group_half_width * 0.6;
0378   line_breakdown_hist -> Fit(gaus_fit, "NQ", "", width_fit_range_l, width_fit_range_r); 
0379   
0380   // std::cout<<"evnet_i: "<<", width fitting, SetParameters: "<<line_breakdown_hist_max_content<<" "<<line_breakdown_hist_max_center<<" "<<Half_N_group_half_width<<std::endl;
0381   // std::cout<<"evnet_i: "<<", width fitting, FitRange: "<<width_fit_range_l<<" "<<width_fit_range_r<<std::endl;
0382   // std::cout<<"evnet_i: "<<", width fitting, result: "<<gaus_fit -> GetParameter(0)<<" "<<gaus_fit -> GetParameter(1)<<" "<<gaus_fit -> GetParameter(2)<<" "<<gaus_fit -> GetParameter(3)<<std::endl;
0383   
0384 
0385   for (int fit_i = 0; fit_i < int(gaus_fit_vec.size()); fit_i++) // note : special_tag, uses a vector of gaus fit to determine the vertex Z
0386   {
0387       gaus_fit_vec[fit_i] -> SetParameters(line_breakdown_hist_max_content, line_breakdown_hist_max_center, Half_N_group_half_width, 0);
0388       gaus_fit_vec[fit_i] -> SetParLimits(0,0,100000);  // note : size 
0389       gaus_fit_vec[fit_i] -> SetParLimits(2,0.5,1000);   // note : Width
0390       gaus_fit_vec[fit_i] -> SetParLimits(3,-200,10000);   // note : offset
0391       double N_width_ratio = 0.2 + 0.15 * fit_i;
0392       double mean_fit_range_l = line_breakdown_hist_max_center - Half_N_group_half_width * N_width_ratio;
0393       double mean_fit_range_r = line_breakdown_hist_max_center + Half_N_group_half_width * N_width_ratio;
0394 
0395       line_breakdown_hist -> Fit(gaus_fit_vec[fit_i], "NQ", "", mean_fit_range_l, mean_fit_range_r);
0396       gaus_fit_vec[fit_i] -> SetRange(mean_fit_range_l, mean_fit_range_r);
0397 
0398       fit_mean_mean_vec.push_back(gaus_fit_vec[fit_i] -> GetParameter(1));
0399       fit_mean_reducedChi2_vec.push_back(gaus_fit_vec[fit_i] -> GetChisquare() / double(gaus_fit_vec[fit_i] -> GetNDF()));
0400       fit_mean_width_vec.push_back(fabs(gaus_fit_vec[fit_i] -> GetParameter(2)));
0401   }
0402 
0403   INTTvtxZ = vector_average(fit_mean_mean_vec);
0404   INTTvtxZError = vector_stddev(fit_mean_mean_vec);
0405 
0406   NgroupTrapezoidal = N_group_info_detail[0];
0407   NgroupCoarse = N_group_info[0];
0408   TrapezoidalFitWidth = gaus_fit -> GetParameter(2);
0409   TrapezoidalFWHM = (fabs(N_group_info_detail[3] - N_group_info_detail[2]) / 2.);
0410 
0411   // for (int hist_i = 0; hist_i < line_breakdown_hist->GetNbinsX(); hist_i++){
0412   //     // std::cout<<"("<<hist_i+1<<", "<<line_breakdown_hist->GetBinContent(hist_i+1)<<"), ";
0413   //     std::cout<<"{"<<hist_i+1<<", "<<line_breakdown_hist->GetBinContent(hist_i+1)<<"}, "<<std::endl;
0414   // }
0415   // std::cout<<std::endl;
0416 
0417   return Fun4AllReturnCodes::EVENT_OK;
0418 }
0419 
0420 double InttZVertexFinderTrapezoidal::get_radius(double x, double y)
0421 {
0422     return sqrt(pow(x,2)+pow(y,2));
0423 }
0424 
0425 double InttZVertexFinderTrapezoidal::get_delta_phi(double angle_1, double angle_2)
0426 {
0427     std::vector<double> vec_abs = {std::fabs(angle_1 - angle_2), std::fabs(angle_1 - angle_2 + 360), std::fabs(angle_1 - angle_2 - 360)};
0428     std::vector<double> vec = {(angle_1 - angle_2), (angle_1 - angle_2 + 360), (angle_1 - angle_2 - 360)};
0429     return vec[std::distance(vec_abs.begin(), std::min_element(vec_abs.begin(),vec_abs.end()))];
0430 }
0431 
0432 double InttZVertexFinderTrapezoidal::calculateAngleBetweenVectors(double x1, double y1, double x2, double y2, double targetX, double targetY) {
0433     // Calculate the vectors vector_1 (point_1 to point_2) and vector_2 (point_1 to target)
0434     double vector1X = x2 - x1;
0435     double vector1Y = y2 - y1;
0436 
0437     double vector2X = targetX - x1;
0438     double vector2Y = targetY - y1;
0439 
0440     // Calculate the cross product of vector_1 and vector_2 (z-component)
0441     double crossProduct = vector1X * vector2Y - vector1Y * vector2X;
0442     
0443     // cout<<" crossProduct : "<<crossProduct<<endl;
0444 
0445     // Calculate the magnitudes of vector_1 and vector_2
0446     double magnitude1 = std::sqrt(vector1X * vector1X + vector1Y * vector1Y);
0447     double magnitude2 = std::sqrt(vector2X * vector2X + vector2Y * vector2Y);
0448 
0449     // Calculate the angle in radians using the inverse tangent of the cross product and dot product
0450     double dotProduct = vector1X * vector2X + vector1Y * vector2Y;
0451 
0452     double angleInRadians = std::atan2(std::abs(crossProduct), dotProduct);
0453     // Convert the angle from radians to degrees and return it
0454     double angleInDegrees __attribute__((unused)) = angleInRadians * 180.0 / M_PI;
0455     
0456     double angleInRadians_new = std::asin( crossProduct/(magnitude1*magnitude2) );
0457     double angleInDegrees_new __attribute__((unused)) = angleInRadians_new * 180.0 / M_PI;
0458     
0459     // cout<<"angle : "<<angleInDegrees_new<<endl;
0460 
0461     double DCA_distance = sin(angleInRadians_new) * magnitude2;
0462 
0463     return DCA_distance;
0464 }
0465 
0466 double InttZVertexFinderTrapezoidal::Get_extrapolation(double given_y, double p0x, double p0y, double p1x, double p1y) // note : x : z, y : r
0467 {
0468     if ( fabs(p0x - p1x) < 0.000001 ){ // note : the line is vertical (if z is along the x axis)
0469         return p0x;
0470     }
0471     else {
0472         double slope = (p1y - p0y) / (p1x - p0x);
0473         double yIntercept = p0y - slope * p0x;
0474         double xCoordinate = (given_y - yIntercept) / slope;
0475         return xCoordinate;
0476     }
0477 }
0478 
0479 std::pair<double,double> InttZVertexFinderTrapezoidal::Get_possible_zvtx(double rvtx, std::vector<double> p0, std::vector<double> p1) // note : inner p0, outer p1, vector {r,z, zid}, -> {y,x}
0480 {
0481     std::vector<double> p0_z_edge = { ( p0[2] == typeA_sensorZID[0] || p0[2] == typeA_sensorZID[1] ) ? p0[1] - typeA_sensor_half_length_incm : p0[1] - typeB_sensor_half_length_incm, ( p0[2] == typeA_sensorZID[0] || p0[2] == typeA_sensorZID[1] ) ? p0[1] + typeA_sensor_half_length_incm : p0[1] + typeB_sensor_half_length_incm}; // note : vector {left edge, right edge}
0482     std::vector<double> p1_z_edge = { ( p1[2] == typeA_sensorZID[0] || p1[2] == typeA_sensorZID[1] ) ? p1[1] - typeA_sensor_half_length_incm : p1[1] - typeB_sensor_half_length_incm, ( p1[2] == typeA_sensorZID[0] || p1[2] == typeA_sensorZID[1] ) ? p1[1] + typeA_sensor_half_length_incm : p1[1] + typeB_sensor_half_length_incm}; // note : vector {left edge, right edge}
0483 
0484     double edge_first  = Get_extrapolation(rvtx,p0_z_edge[0],p0[0],p1_z_edge[1],p1[0]);
0485     double edge_second = Get_extrapolation(rvtx,p0_z_edge[1],p0[0],p1_z_edge[0],p1[0]);
0486 
0487     double mid_point = (edge_first + edge_second) / 2.;
0488     double possible_width = fabs(edge_first - edge_second) / 2.;
0489 
0490     return {mid_point, possible_width}; // note : first : mid point, second : width
0491 
0492 }
0493 
0494 void InttZVertexFinderTrapezoidal::line_breakdown(TH1D* hist_in, std::pair<double,double> line_range)
0495 { 
0496     int first_bin = int((line_range.first  - hist_in->GetXaxis()->GetXmin()) /  hist_in->GetBinWidth(1)) + 1;
0497     int last_bin  = int((line_range.second - hist_in->GetXaxis()->GetXmin()) /  hist_in->GetBinWidth(1)) + 1;
0498     
0499     if (first_bin < 1) {first_bin = 0;}
0500     else if (first_bin > hist_in -> GetNbinsX()) {first_bin = hist_in -> GetNbinsX() + 1;}
0501 
0502     if (last_bin < 1) {last_bin = 0;}
0503     else if (last_bin > hist_in -> GetNbinsX()) {last_bin = hist_in -> GetNbinsX() + 1;}
0504 
0505     // double fill_weight = 1./fabs(line_range.second - line_range.first); // note : the entry is weitghted by the width of the line, by Akiba san's suggestion // special_tag cancel
0506     double fill_weight = 1.; // note : the weight is 1, it's for testing the trapezoidal method // special_tag
0507 
0508     // cout<<"Digitize the bin : "<<first_bin<<" "<<last_bin<<endl;
0509 
0510     // note : if first:last = (0:0) or (N+1:N+1) -> the subtraction of them euqals to zero.
0511     for (int i = 0; i < (last_bin - first_bin) + 1; i++){
0512         hist_in -> SetBinContent(first_bin + i,  hist_in -> GetBinContent(first_bin + i) + fill_weight ); // note : special_tag
0513         // line_breakdown_vec.push_back(hist_in -> GetBinCenter(first_bin + i));
0514     }
0515 
0516 }
0517 
0518 // note : for each combination
0519 // note : corrected inner_r and outer_r
0520 void InttZVertexFinderTrapezoidal::trapezoidal_line_breakdown(TH1D * hist_in, double inner_r, double inner_z, int inner_zid, double outer_r, double outer_z, int outer_zid)
0521 {
0522     combination_zvtx_range_shape -> Reset("ICESM");
0523 
0524     std::vector<double> inner_edge = { ( inner_zid == typeA_sensorZID[0] || inner_zid == typeA_sensorZID[1] ) ? inner_z - typeA_sensor_half_length_incm : inner_z - typeB_sensor_half_length_incm, ( inner_zid == typeA_sensorZID[0] || inner_zid == typeA_sensorZID[1] ) ? inner_z + typeA_sensor_half_length_incm : inner_z + typeB_sensor_half_length_incm}; // note : vector {left edge, right edge}
0525     std::vector<double> outer_edge = { ( outer_zid == typeA_sensorZID[0] || outer_zid == typeA_sensorZID[1] ) ? outer_z - typeA_sensor_half_length_incm : outer_z - typeB_sensor_half_length_incm, ( outer_zid == typeA_sensorZID[0] || outer_zid == typeA_sensorZID[1] ) ? outer_z + typeA_sensor_half_length_incm : outer_z + typeB_sensor_half_length_incm}; // note : vector {left edge, right edge}
0526 
0527     for (int possible_i = 0; possible_i < 2001; possible_i++) // todo : the segmentation of the strip
0528     {
0529         // double random_inner_z = rand_gen -> Uniform(inner_edge[0], inner_edge[1]);
0530         double random_inner_z = inner_edge[0] + ((inner_edge[1] - inner_edge[0]) / 2000.) * possible_i; 
0531         double edge_first  = Get_extrapolation(0, random_inner_z, inner_r, outer_edge[1], outer_r);
0532         double edge_second = Get_extrapolation(0, random_inner_z, inner_r, outer_edge[0], outer_r);
0533 
0534         double mid_point = (edge_first + edge_second) / 2.;
0535         double possible_width = fabs(edge_first - edge_second) / 2.;
0536 
0537         line_breakdown(combination_zvtx_range_shape, {mid_point - possible_width, mid_point + possible_width});
0538     }
0539 
0540     combination_zvtx_range_shape -> Scale(1./ combination_zvtx_range_shape -> Integral(-1,-1));
0541 
0542     for (int bin_i = 1; bin_i <= combination_zvtx_range_shape -> GetNbinsX(); bin_i++)
0543     {
0544         hist_in -> SetBinContent(bin_i, hist_in -> GetBinContent(bin_i) + combination_zvtx_range_shape -> GetBinContent(bin_i));
0545     }
0546 }
0547 
0548 std::vector<double> InttZVertexFinderTrapezoidal::find_Ngroup(TH1D * hist_in)
0549 {
0550     double Highest_bin_Content  = hist_in -> GetBinContent(hist_in -> GetMaximumBin());
0551     double Highest_bin_Center   = hist_in -> GetBinCenter(hist_in -> GetMaximumBin());
0552 
0553     int group_Nbin = 0;
0554     int peak_group_ID = -9999;
0555     double group_entry = 0;
0556     double peak_group_ratio;
0557     std::vector<int> group_Nbin_vec; group_Nbin_vec.clear();
0558     std::vector<double> group_entry_vec; group_entry_vec.clear();
0559     std::vector<double> group_widthL_vec; group_widthL_vec.clear();
0560     std::vector<double> group_widthR_vec; group_widthR_vec.clear();
0561 
0562     for (int i = 0; i < hist_in -> GetNbinsX(); i++){
0563         // todo : the background rejection is here : Highest_bin_Content/2. for the time being
0564         double bin_content = ( hist_in -> GetBinContent(i+1) <= Highest_bin_Content/2.) ? 0. : ( hist_in -> GetBinContent(i+1) - Highest_bin_Content/2. );
0565 
0566         if (bin_content != 0){
0567             
0568             if (group_Nbin == 0) {
0569                 group_widthL_vec.push_back(hist_in -> GetBinCenter(i+1) - (hist_in -> GetBinWidth(i+1)/2.));
0570             }
0571 
0572             group_Nbin += 1; 
0573             group_entry += bin_content;
0574         }
0575         else if (bin_content == 0 && group_Nbin != 0){
0576             group_widthR_vec.push_back(hist_in -> GetBinCenter(i+1) - (hist_in -> GetBinWidth(i+1)/2.));
0577             group_Nbin_vec.push_back(group_Nbin);
0578             group_entry_vec.push_back(group_entry);
0579             group_Nbin = 0;
0580             group_entry = 0;
0581         }
0582     }
0583     if (group_Nbin != 0) {
0584         group_Nbin_vec.push_back(group_Nbin);
0585         group_entry_vec.push_back(group_entry);
0586         group_widthR_vec.push_back(hist_in -> GetXaxis()->GetXmax());
0587     } // note : the last group at the edge
0588 
0589     // note : find the peak group
0590     for (int i = 0; i < int(group_Nbin_vec.size()); i++){
0591         if (group_widthL_vec[i] < Highest_bin_Center && Highest_bin_Center < group_widthR_vec[i]){
0592             peak_group_ID = i;
0593             break;
0594         }
0595     }
0596     
0597     // note : On Nov 6, 2024, we no longer need to calculate the ratio of the peak group
0598     // double denominator = (accumulate( group_entry_vec.begin(), group_entry_vec.end(), 0.0 ));
0599     // denominator = (denominator <= 0) ? 1. : denominator;
0600     // peak_group_ratio = group_entry_vec[peak_group_ID] / denominator;
0601     peak_group_ratio = -999;
0602 
0603     double peak_group_left  = (double(group_Nbin_vec.size()) == 0) ? -999 : group_widthL_vec[peak_group_ID];
0604     double peak_group_right = (double(group_Nbin_vec.size()) == 0) ? 999  : group_widthR_vec[peak_group_ID];
0605 
0606     // for (int i = 0; i < group_Nbin_vec.size(); i++)
0607     // {
0608     //     cout<<" "<<endl;
0609     //     cout<<"group size : "<<group_Nbin_vec[i]<<endl;
0610     //     cout<<"group entry : "<<group_entry_vec[i]<<endl;
0611     //     cout<<group_widthL_vec[i]<<" "<<group_widthR_vec[i]<<endl;
0612     // }
0613 
0614     // cout<<" "<<endl;
0615     // cout<<"N group : "<<group_Nbin_vec.size()<<endl;
0616     // cout<<"Peak group ID : "<<peak_group_ID<<endl;
0617     // cout<<"peak group width : "<<group_widthL_vec[peak_group_ID]<<" "<<group_widthR_vec[peak_group_ID]<<endl;
0618     // cout<<"ratio : "<<peak_group_ratio<<endl;
0619     
0620     // note : {N_group, ratio (if two), peak widthL, peak widthR}
0621     return {double(group_Nbin_vec.size()), peak_group_ratio, peak_group_left, peak_group_right};
0622 }
0623 
0624 double  InttZVertexFinderTrapezoidal::vector_average (std::vector <double> input_vector) {
0625     return accumulate( input_vector.begin(), input_vector.end(), 0.0 ) / double(input_vector.size());
0626 }
0627 
0628 double InttZVertexFinderTrapezoidal::vector_stddev (std::vector <double> input_vector){
0629     
0630     double sum_subt = 0;
0631     double average  = accumulate( input_vector.begin(), input_vector.end(), 0.0 ) / double(input_vector.size());
0632     
0633     // cout<<"average is : "<<average<<endl;
0634 
0635     for (int i=0; i<int(input_vector.size()); i++){ sum_subt += pow((input_vector[i] - average),2); }
0636 
0637     //cout<<"sum_subt : "<<sum_subt<<endl;
0638     // cout<<"print from the function, average : "<<average<<" std : "<<stddev<<endl;
0639 
0640     return sqrt( sum_subt / double(input_vector.size()-1) );
0641 }   
0642 
0643 //____________________________________________________________________________..
0644 int InttZVertexFinderTrapezoidal::process_event(PHCompositeNode *topNode)
0645 {
0646   // std::cout << "InttZVertexFinderTrapezoidal::process_event(PHCompositeNode *topNode) Processing Event" << std::endl;
0647   
0648   temp_sPH_inner_nocolumn_vec.clear();
0649   temp_sPH_outer_nocolumn_vec.clear();
0650   evt_possible_z -> Reset("ICESM");
0651   line_breakdown_hist -> Reset("ICESM");
0652 
0653   INTTvtxZ = std::nan("");
0654   INTTvtxZError = std::nan("");
0655   NgroupTrapezoidal = std::nan("");
0656   NgroupCoarse = std::nan("");
0657   TrapezoidalFitWidth = std::nan("");
0658   TrapezoidalFWHM = std::nan("");
0659   NClusAll = 0;
0660   NClusAllInner = 0;
0661 
0662   inner_clu_phi_map.clear();
0663   outer_clu_phi_map.clear();
0664   inner_clu_phi_map = std::vector<std::vector<std::pair<bool,clu_info>>>(360);
0665   outer_clu_phi_map = std::vector<std::vector<std::pair<bool,clu_info>>>(360);
0666 
0667   fit_mean_mean_vec.clear();
0668   fit_mean_reducedChi2_vec.clear();
0669   fit_mean_width_vec.clear();
0670 
0671   PrepareClusterVec(topNode);
0672 
0673   if (temp_sPH_inner_nocolumn_vec.size() < 1 || temp_sPH_outer_nocolumn_vec.size() < 1) {return Fun4AllReturnCodes::EVENT_OK;}
0674 
0675   PrepareINTTvtxZ();
0676 
0677   inttzobj->INTTvtxZ = INTTvtxZ;
0678   inttzobj->INTTvtxZError = INTTvtxZError;
0679   inttzobj->NgroupTrapezoidal = NgroupTrapezoidal;
0680   inttzobj->NgroupCoarse = NgroupCoarse;
0681   inttzobj->TrapezoidalFitWidth = TrapezoidalFitWidth;
0682   inttzobj->TrapezoidalFWHM = TrapezoidalFWHM; 
0683   inttzobj->NClusAll = NClusAll;
0684   inttzobj->NClusAllInner = NClusAllInner;
0685 
0686   // note : print everything 
0687   if (PrintRecoDetails){
0688     std::cout<<"NClusGood: "<<temp_sPH_inner_nocolumn_vec.size() + temp_sPH_outer_nocolumn_vec.size()<<", INTTvtxZ : "<<INTTvtxZ<<" INTTvtxZError : "<<INTTvtxZError<<" NgroupTrapezoidal : "<<NgroupTrapezoidal<<" NgroupCoarse : "<<NgroupCoarse<<" TrapezoidalFitWidth : "<<TrapezoidalFitWidth<<" TrapezoidalFWHM : "<<TrapezoidalFWHM<<std::endl;
0689   }
0690   
0691   
0692   return Fun4AllReturnCodes::EVENT_OK;
0693 }
0694 
0695 //____________________________________________________________________________..
0696 int InttZVertexFinderTrapezoidal::ResetEvent(PHCompositeNode *topNode)
0697 {
0698   // std::cout << "InttZVertexFinderTrapezoidal::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << std::endl;
0699   return Fun4AllReturnCodes::EVENT_OK;
0700 }
0701 
0702 //____________________________________________________________________________..
0703 int InttZVertexFinderTrapezoidal::EndRun(const int runnumber)
0704 {
0705   std::cout << "InttZVertexFinderTrapezoidal::EndRun(const int runnumber) Ending Run for Run " << runnumber << std::endl;
0706   return Fun4AllReturnCodes::EVENT_OK;
0707 }
0708 
0709 //____________________________________________________________________________..
0710 int InttZVertexFinderTrapezoidal::End(PHCompositeNode *topNode)
0711 {
0712   std::cout << "InttZVertexFinderTrapezoidal::End(PHCompositeNode *topNode) This is the End..." << std::endl;
0713   return Fun4AllReturnCodes::EVENT_OK;
0714 }
0715 
0716 //____________________________________________________________________________..
0717 int InttZVertexFinderTrapezoidal::Reset(PHCompositeNode *topNode)
0718 {
0719  std::cout << "InttZVertexFinderTrapezoidal::Reset(PHCompositeNode *topNode) being Reset" << std::endl;
0720   return Fun4AllReturnCodes::EVENT_OK;
0721 }
0722 
0723 //____________________________________________________________________________..
0724 void InttZVertexFinderTrapezoidal::Print(const std::string &what) const
0725 {
0726   std::cout << "InttZVertexFinderTrapezoidal::Print(const std::string &what) const Printing info for " << what << std::endl;
0727 }
0728 
0729 
0730 int InttZVertexFinderTrapezoidal::createNodes(PHCompositeNode* topNode)
0731 {
0732   PHNodeIterator iter(topNode);
0733   PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
0734   if (!dstNode)
0735   {
0736     std::cout << PHWHERE << "DST Node missing doing nothing" << std::endl;
0737     return Fun4AllReturnCodes::ABORTEVENT;
0738   }
0739 
0740   // ---                                                                                                                                                     
0741   PHCompositeNode* inttNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "INTT"));
0742   if (!inttNode)
0743   {
0744     inttNode = new PHCompositeNode("INTT");
0745     dstNode->addNode(inttNode);
0746   }
0747 
0748   // m_inttvertexmap = findNode::getClass<InttVertexMap>(inttNode, "InttVertexMap");                                                                         
0749   if (true)
0750   {
0751     inttzobj = new INTTvtxZF4AObj();
0752     PHIODataNode<PHObject>* inttzobjNode = new PHIODataNode<PHObject>(inttzobj, "inttzobj", "PHObject");
0753     inttNode->addNode(inttzobjNode);
0754   }
0755 
0756   return Fun4AllReturnCodes::EVENT_OK;
0757 }