Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-15 07:41:26

0001 #include <cmath>
0002 #include <fstream>
0003 #include <iostream>
0004 #include <string>
0005 #include <vector>
0006 #include <utility>
0007 #include <algorithm>
0008 #include <limits>
0009 #include "TLorentzVector.h"
0010 
0011 #include "ROOT/RDataFrame.hxx"
0012 #include <TH1D.h>
0013 #include <TH2D.h>
0014 #include <TRandom3.h>
0015 #include <TFile.h>
0016 #include <TChain.h>
0017 #include <TTree.h>
0018 #include <TMath.h>
0019 #include <TVector3.h>
0020 #include <TCanvas.h>
0021 #include <unordered_map> 
0022 #include <unordered_set>
0023 #include <TLorentzVector.h>  
0024 #include <TStyle.h>
0025 #include <TLine.h>
0026 #include <TLegend.h>
0027 #include <TGraphErrors.h>
0028 #include <TMultiGraph.h>   
0029 
0030 #include "TROOT.h"
0031 #include "TRandom.h"
0032 #include "TH3.h"
0033 
0034 #include "DD4hep/Detector.h"
0035 #include "DDRec/CellIDPositionConverter.h"
0036 #include "DD4hep/Volumes.h"
0037 #include "DD4hep/Objects.h"
0038 #include "DD4hep/Shapes.h"
0039 #include <DD4hep/Detector.h>
0040 #include <DD4hep/VolumeManager.h>
0041 #include <DD4hep/Printout.h>
0042 #include <TGeoBBox.h>
0043 #include <TGeoMatrix.h>
0044 
0045 #include "podio/Frame.h"
0046 #include "podio/CollectionBase.h"
0047 #include "podio/ROOTReader.h"
0048 #include "podio/CollectionIDTable.h"
0049 #include "podio/ObjectID.h"
0050 
0051 #include "edm4hep/MCParticleCollection.h"
0052 #include "edm4hep/MCParticle.h"
0053 
0054 #include "edm4hep/SimCalorimeterHitCollection.h"
0055 #include "edm4hep/SimCalorimeterHit.h"
0056 
0057 #include "edm4hep/CalorimeterHit.h"
0058 #include "edm4hep/CalorimeterHitCollection.h"
0059 
0060 #include "edm4eic/ClusterCollection.h"
0061 #include "edm4eic/Cluster.h"
0062 #include "edm4eic/ClusterData.h"
0063 
0064 #include "edm4eic/CalorimeterHit.h"
0065 #include "edm4eic/CalorimeterHitCollection.h"
0066 
0067 #include "edm4eic/InclusiveKinematicsCollection.h"
0068 #include "edm4eic/InclusiveKinematics.h"
0069 #include "edm4hep/utils/kinematics.h"
0070 #include "edm4hep/utils/vector_utils.h"
0071 #include "edm4eic/vector_utils_legacy.h"
0072 
0073 #include "edm4eic/Track.h"
0074 #include "edm4eic/TrackSegment.h"
0075 #include "edm4eic/TrackPoint.h"
0076 #include "edm4eic/TrackParameters.h"
0077 #include "edm4eic/TrackSegmentCollection.h"
0078 
0079 #include "edm4eic/ReconstructedParticleCollection.h"
0080 #include "edm4eic/ReconstructedParticle.h"
0081 
0082 #include "edm4eic/MCRecoCalorimeterHitAssociationCollection.h"
0083 #include "edm4eic/MCRecoCalorimeterHitAssociation.h"
0084 #include "edm4eic/MCRecoParticleAssociationCollection.h"
0085 #include "edm4eic/MCRecoParticleAssociation.h"
0086 
0087 using namespace std;
0088 using namespace ROOT;
0089 using namespace TMath;
0090 using namespace edm4hep;
0091 
0092 dd4hep::Detector* det = NULL;
0093 
0094 constexpr double ETA_MIN = -4.14, ETA_MAX = -1.16;
0095 
0096 inline bool inNHCal(double eta) {return (eta >= ETA_MIN && eta <= ETA_MAX);}
0097 
0098 inline string addPrefixAfterSlash(const string& path,
0099                                        const string& prefix) {
0100     const auto slash = path.find_last_of('/');
0101     if (slash == string::npos)
0102         return prefix + path;
0103     return path.substr(0, slash + 1) + prefix + path.substr(slash + 1);
0104 }
0105 
0106 void MakeLogBins(double *array, int nbins, double binLo, double binHi)
0107 {
0108     double logMin = log10(binLo);
0109     double logMax = log10(binHi);
0110     double binWidth = (logMax - logMin) / nbins;
0111 
0112     for (int i = 0; i <= nbins; ++i) {
0113         array[i] = pow(10, logMin + i * binWidth);
0114     }
0115 }
0116 
0117 TLine* makeLine(double x1, double y1, double x2, double y2) {
0118     TLine* l = new TLine(x1, y1, x2, y2);
0119     l->SetLineColor(kRed);
0120     l->SetLineStyle(2);
0121     l->SetLineWidth(2);
0122     l->Draw("same");
0123     return l;
0124 }
0125 
0126 static TGraph* makeEffGraph_B(TH1D* h_sel, TH1D* h_all,
0127                               const char* name,
0128                               int minAll = 2,
0129                               bool logx = false)
0130 {
0131     if (!h_sel || !h_all) return nullptr;
0132 
0133     std::unique_ptr<TH1D> h_eff((TH1D*)h_sel->Clone(Form("tmp_%s", name ? name : "eff")));
0134     h_eff->SetDirectory(nullptr);
0135     h_eff->Sumw2();
0136     h_eff->Divide(h_sel, h_all, 1.0, 1.0, "B");
0137 
0138     const int nb = h_all->GetNbinsX();
0139 
0140     std::unique_ptr<TGraphAsymmErrors> g_log;
0141     std::unique_ptr<TGraphErrors>      g_lin;
0142 
0143     if (logx) g_log = std::make_unique<TGraphAsymmErrors>();
0144     else      g_lin = std::make_unique<TGraphErrors>();
0145 
0146     int ip = 0;
0147     for (int b = 1; b <= nb; ++b) {
0148         const double all = h_all->GetBinContent(b);
0149         if (all < minAll) continue;
0150 
0151         const double xl = h_all->GetXaxis()->GetBinLowEdge(b);
0152         const double xh = h_all->GetXaxis()->GetBinUpEdge(b);
0153 
0154         const double y  = 100.0 * h_eff->GetBinContent(b);
0155         const double ey = 100.0 * h_eff->GetBinError(b);
0156 
0157         if (logx) {
0158             if (xl <= 0.0 || xh <= 0.0) continue; 
0159             const double x  = sqrt(xl * xh);
0160             const double exl = x - xl;
0161             const double exh = xh - x;
0162 
0163             g_log->SetPoint(ip, x, y);
0164             g_log->SetPointError(ip, exl, exh, ey, ey);
0165         } else {
0166             const double x  = h_all->GetBinCenter(b);
0167             const double ex = 0.5 * (xh - xl);
0168 
0169             g_lin->SetPoint(ip, x, y);
0170             g_lin->SetPointError(ip, ex, ey);
0171         }
0172         ++ip;
0173     }
0174 
0175     TGraph* g = logx ? (TGraph*)g_log.release() : (TGraph*)g_lin.release();
0176     g->SetName(Form("g_%s", name ? name : "eff"));
0177     return g;
0178 }
0179 
0180 inline void drawEffPanel(TH1D* h_all,
0181                          TH1D* const h_in[3],
0182                          const char* title,
0183                          const char* xlabel,
0184                          bool logx)
0185 {
0186     gPad->SetGrid();
0187     if (logx) gPad->SetLogx();
0188 
0189     auto* mg = new TMultiGraph();
0190     auto* leg = new TLegend(0.63, 0.7, 0.88, 0.88);
0191     leg->SetBorderSize(0);
0192     leg->SetFillStyle(0);
0193     leg->SetTextSize(0.04);
0194 
0195     Color_t colors[3]  = {kBlue, kRed, kBlack};
0196     Style_t markers[3] = {20, 21, 22};
0197 
0198     int added = 0;
0199 
0200     for (int i = 0; i < 3; ++i) {
0201         if (!h_all || !h_in[i]) continue;
0202         auto* g = makeEffGraph_B(h_in[i], h_all, Form("eff_%d", i), 2, logx);
0203         if (!g || g->GetN() == 0) continue;
0204 
0205         g->SetMarkerColor(colors[i]);
0206         g->SetMarkerStyle(markers[i]);
0207         g->SetMarkerSize(1.0);
0208         g->SetLineColor(kBlack);
0209 
0210         mg->Add(g, "PE");
0211         leg->AddEntry(g, Form("%d mu-in nHCAL", i), "p");
0212         ++added;
0213     }
0214 
0215     if (h_all && h_in[0] && h_in[1] && h_in[2]) {
0216         std::unique_ptr<TH1D> h_sum((TH1D*)h_in[0]->Clone("h_sum"));
0217         h_sum->SetDirectory(nullptr);
0218         h_sum->Add(h_in[1]);
0219         h_sum->Add(h_in[2]);
0220 
0221         auto* gsum = makeEffGraph_B(h_sum.get(), h_all, "eff_sum", 2, logx);
0222         if (gsum && gsum->GetN() > 0) {
0223             gsum->SetMarkerStyle(25);
0224             gsum->SetMarkerColor(kMagenta + 1);
0225             gsum->SetFillColor(kMagenta + 1);
0226             gsum->SetLineColor(kBlack);
0227             gsum->SetMarkerSize(1.0);
0228 
0229             mg->Add(gsum, "PE");
0230             leg->AddEntry(gsum, "All eligible", "p");
0231             ++added;
0232         }
0233     }
0234 
0235     mg->SetTitle(Form("%s;%s;geom. acc. [%%]", title ? title : "", xlabel ? xlabel : ""));
0236     mg->Draw("A");
0237 
0238     gPad->Update();
0239     if (mg->GetHistogram()) {
0240         double ymax = mg->GetHistogram()->GetMaximum();
0241         mg->GetHistogram()->SetMaximum(ymax * 1.35); 
0242     }
0243     gPad->Modified();
0244     gPad->Update();
0245 
0246     if (logx) {
0247         auto* ax = mg->GetXaxis();
0248         if (ax) {
0249             double xmin = ax->GetXmin(), xmax = ax->GetXmax();
0250             if (xmin <= 0) xmin = 1e-12;
0251             mg->GetXaxis()->SetLimits(xmin, xmax);
0252         }
0253     }
0254 
0255     leg->Draw();
0256 }
0257 
0258 inline double hypot2(double a, double b){ return sqrt(a*a + b*b); }
0259 inline int sgnD(double v){ return (v>0) - (v<0); }
0260 
0261 inline pair<double,double>
0262 trackXYatZ_fromTwoStates(double x1,double y1,double z1,
0263                          double x2,double y2,double z2,
0264                          double zTarget)
0265 {
0266     constexpr double EPSZ = 1e-12;
0267 
0268     const double dz = z2 - z1;
0269     if (abs(dz) < EPSZ) {
0270         const double d1 = abs(zTarget - z1);
0271         const double d2 = abs(zTarget - z2);
0272         if (d1 < d2) return {x1, y1};
0273         if (d2 < d1) return {x2, y2};
0274         return {0.5*(x1+x2), 0.5*(y1+y2)};
0275     }
0276 
0277     const double t = (zTarget - z1) / dz;
0278     const double x = x1 + t * (x2 - x1);
0279     const double y = y1 + t * (y2 - y1);
0280     return {x, y};
0281 }
0282 
0283 inline pair<double,double>
0284 trackXYatZ(const TVector3& A, const TVector3& B, double zTarget){
0285     return trackXYatZ_fromTwoStates(
0286         A.x(), A.y(), A.z(), B.x(), B.y(), B.z(),
0287         zTarget
0288     );
0289 }
0290 
0291 
0292 int pion_rejection_analysis(const string& filename, string outname_pdf, string outname_png, TString compact_file) {
0293 
0294     gStyle->SetOptStat(0);
0295     podio::ROOTReader reader;
0296     reader.openFile(filename);
0297     unsigned nEvents = reader.getEntries("events");
0298     cout << "Number of events: " << nEvents << endl;
0299 
0300     det = &(dd4hep::Detector::getInstance());
0301     det->fromCompact(compact_file.Data());
0302 
0303     double thickness_plastic_cm = 2.4;
0304     try {
0305         thickness_plastic_cm = det->constantAsDouble("HcalEndcapNPolystyreneThickness");
0306     } catch (...) {
0307         cerr << "[WARN] Using default plastic thickness = " << thickness_plastic_cm << " cm\n";
0308     }
0309 
0310     constexpr int NBINS = 60; 
0311 
0312     constexpr double Q2_MIN = 1e-2;
0313     constexpr double Q2_MAX = 1.0;
0314     constexpr double X_MIN = 1e-6;
0315     constexpr double X_MAX = 1e-3;
0316     constexpr double Y_MIN = 0.0;
0317     constexpr double Y_MAX = 1.0;
0318     constexpr double W_MIN = 0.0;
0319     constexpr double W_MAX = 160.0;
0320 
0321     constexpr int    Z_NBINS = 100;
0322     constexpr double Z_MIN_MM = -4500.0;
0323     constexpr double Z_MAX_MM = -3600.0;
0324 
0325     constexpr int    DXY_NBINS  = 120;
0326     constexpr double DXY_MIN_MM = -1000.0; 
0327     constexpr double DXY_MAX_MM =  1000.0;
0328 
0329     constexpr int    DR_NBINS  = 120;
0330     constexpr double DR_MIN_MM = 0.0;   
0331     constexpr double DR_MAX_MM = 400.0; 
0332 
0333     constexpr double P_MIN_GEV = 0.0;  
0334     constexpr double P_MAX_GEV = 25.0;   
0335     constexpr int    P_NBINS  = 50;
0336 
0337     constexpr double E_MIN_GEV = 2e-2;
0338     constexpr double E_MAX_GEV = 10.0;
0339 
0340     constexpr int    SIZE = 3;
0341     constexpr double MIP_ENERGY_GEV = 0.002; 
0342     constexpr double E_CUTS[SIZE] = {1.5, 1.7, 2.0}; 
0343     constexpr double E_THRESH = E_CUTS[2]; 
0344     constexpr double LAYER_PROC[SIZE] = {0.6, 0.7, 0.8};
0345 
0346     double DR_CUTS_CM[SIZE] = {7.0, 10.0, 13.0};
0347     double DR_THRESH_MM = 10*DR_CUTS_CM[2];
0348     int LAYER_MAX = 10;
0349     int LAYER_CUTS[SIZE] = {5, 6, 7}; 
0350     int LAYER_THRESH = LAYER_CUTS[0];
0351 
0352     vector<double> Xbins(NBINS+1), Q2bins(NBINS+1), Ebins(NBINS+1);
0353     MakeLogBins(Q2bins.data(), NBINS, Q2_MIN, Q2_MAX);
0354     MakeLogBins(Xbins.data(), NBINS, X_MIN, X_MAX);
0355     MakeLogBins(Ebins.data(), NBINS, E_MIN_GEV, E_MAX_GEV);
0356 
0357     gStyle->SetTitleSize(0.06, "XYZ");
0358     gStyle->SetLabelSize(0.06, "XYZ");
0359     gStyle->SetPadLeftMargin(0.15);
0360     gStyle->SetPadRightMargin(0.15);
0361     gStyle->SetPadBottomMargin(0.15);
0362     gStyle->SetPadTopMargin(0.10);
0363     gROOT->ForceStyle();
0364 
0365     TH2D* hEtaPt = new TH2D("hEtaPt", "Pion #eta vs p_{T};#eta;p_{T} [GeV]", 100, -6., 6., 100, 0., 7.);
0366 
0367     TH1D* hZ_proj = new TH1D("hZ_proj", "Pion track projections in nHCal; z [mm]; N_{proj}", NBINS, Z_MIN_MM, Z_MAX_MM);
0368 
0369     TH1D* hZ_hits = new TH1D("hZ_hits", "Reconstructed hit z in nHCal; z [mm]; N_{hits}", NBINS, Z_MIN_MM, Z_MAX_MM);
0370     
0371     TH3D* hDxDyZ_layer = new TH3D("hDxDyZ_layer","3D residuals (rec - proj): dx, dy vs z; dx [mm]; dy [mm]; z [mm]", NBINS, DXY_MIN_MM, DXY_MAX_MM, NBINS, DXY_MIN_MM, DXY_MAX_MM, NBINS, Z_MIN_MM, Z_MAX_MM); 
0372     
0373     TH2D* hDxDy_all = new TH2D("hDxDy_all",
0374                            "Residuals (rec - proj): dx vs dy (all layers); dx [mm]; dy [mm]",
0375                            DXY_NBINS, DXY_MIN_MM, DXY_MAX_MM, DXY_NBINS, DXY_MIN_MM, DXY_MAX_MM);
0376     
0377     TH2D* hDrZ_layer = new TH2D("hDrZ_layer","Radial residual (rec - proj) vs z; dr [mm]; z [mm]", NBINS, DR_MIN_MM, DR_MAX_MM, NBINS, Z_MIN_MM, Z_MAX_MM); 
0378     
0379     TH1D* hDr_all = new TH1D("hDr_all",
0380                          "Radial residual dr = #sqrt{dx^{2}+dy^{2}} (all layers); dr [mm]; N",
0381                          DR_NBINS, DR_MIN_MM, DR_MAX_MM);
0382 
0383     TH2D* hE_z = new TH2D("hE_z", "Reconstructed hit energy vs layer z; z_{layer} [mm]; E [GeV]", NBINS, Z_MIN_MM, Z_MAX_MM, NBINS, Ebins.data());
0384 
0385     TH2D* hEsum_z = new TH2D("hEsum_z", "Layer energy sum vs z (reconstructed); z_{layer} [mm]; E_{sum} [GeV]",
0386                             NBINS, Z_MIN_MM, Z_MAX_MM, NBINS, Ebins.data());
0387 
0388     TH1D* hE = new TH1D("hE", "Reconstructed hit energy; E [GeV]; N_{hits}", 10000, 0.0, 1.0);
0389 
0390     TH1D* hEsum = new TH1D("hEsum", "Layer energy sum (reconstructed); E_{sum} [GeV]; N_{energy}", 10000, 0.0, 1.0);
0391 
0392     TH1D* hP_all_pion = new TH1D("hP_all_pion", "MC pion momentum (pions in nHCal acceptance); p_{MC} [GeV]; N_{pions}", P_NBINS, P_MIN_GEV, P_MAX_GEV);
0393 
0394     TH1D* hP_pass_dr[3] = {
0395         new TH1D(Form("hP_pass_dr%.1fcm",DR_CUTS_CM[0]),  Form("Accepted (dr<%.1fcm);  p_{MC} [GeV]; N",DR_CUTS_CM[0]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0396         new TH1D(Form("hP_pass_dr%.1fcm",DR_CUTS_CM[1]),  Form("Accepted (dr<%.1fcm);  p_{MC} [GeV]; N",DR_CUTS_CM[1]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0397         new TH1D(Form("hP_pass_dr%.1fcm",DR_CUTS_CM[2]),  Form("Accepted (dr<%.1fcm);  p_{MC} [GeV]; N",DR_CUTS_CM[2]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0398     };
0399 
0400     TH1D* hP_pass_ECut[3] = {
0401         new TH1D(Form("hP_pass_E< %.1f MIP", E_CUTS[0]), Form("Accepted (E< %.1f MIP); p_{MC} [GeV]; N",E_CUTS[0]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0402         new TH1D(Form("hP_pass_E< %.1f MIP", E_CUTS[1]), Form("Accepted (E< %.1f MIP); p_{MC} [GeV]; N",E_CUTS[1]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0403         new TH1D(Form("hP_pass_E< %.1f MIP", E_CUTS[2]), Form("Accepted (E< %.1f MIP); p_{MC} [GeV]; N",E_CUTS[2]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0404     };
0405 
0406     TH1D* hP_pass_LayerCut[3] = {
0407         new TH1D(Form("hP_pass_Layer< %d layers", LAYER_CUTS[0]), Form("Accepted (Layer < %d layers); p_{MC} [GeV]; N",LAYER_CUTS[0]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0408         new TH1D(Form("hP_pass_Layer< %d layers", LAYER_CUTS[1]), Form("Accepted (Layer < %d layers); p_{MC} [GeV]; N",LAYER_CUTS[1]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0409         new TH1D(Form("hP_pass_Layer< %d layers", LAYER_CUTS[2]), Form("Accepted (Layer < %d layers); p_{MC} [GeV]; N",LAYER_CUTS[2]), P_NBINS, P_MIN_GEV, P_MAX_GEV),
0410     };
0411 
0412     for (unsigned ev = 0; ev < nEvents; ev++) {
0413         auto frameData = reader.readNextEntry(podio::Category::Event);
0414         if (!frameData) continue;
0415         podio::Frame frame(std::move(frameData));
0416 
0417         auto getCol = [&](const std::string& name) -> const podio::CollectionBase* {
0418             return frame.get(name);
0419         };
0420 
0421         const auto* mcColPtr    = dynamic_cast<const edm4hep::MCParticleCollection*>(getCol("MCParticles"));
0422         const auto* recPartsPtr = dynamic_cast<const edm4eic::ReconstructedParticleCollection*>(getCol("ReconstructedParticles"));
0423         const auto* projSegsPtr = dynamic_cast<const edm4eic::TrackSegmentCollection*>(getCol("CalorimeterTrackProjections"));
0424         const auto* hcalRecPtr  = dynamic_cast<const edm4eic::CalorimeterHitCollection*>(getCol("HcalEndcapNRecHits"));
0425         const auto* assocColPtr = dynamic_cast<const edm4eic::MCRecoParticleAssociationCollection*>(getCol("ReconstructedParticleAssociations"));
0426 
0427         if (!mcColPtr || !recPartsPtr || !projSegsPtr || !hcalRecPtr || !assocColPtr) continue;
0428 
0429         const auto& mcCol    = *mcColPtr;
0430         const auto& recParts = *recPartsPtr;
0431         const auto& projSegs = *projSegsPtr;
0432         const auto& hcalRec  = *hcalRecPtr;
0433         const auto& assocCol = *assocColPtr;
0434 
0435         vector<edm4hep::MCParticle> vPions;
0436         vector<TLorentzVector> vLorentzPions;
0437         for (const auto& p : mcCol) {
0438             if (p.getPDG() != -211 || p.getGeneratorStatus() == 0) continue;
0439             vPions.push_back(p); 
0440             TLorentzVector v(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy());
0441             vLorentzPions.push_back(v); 
0442             hEtaPt->Fill(v.Eta(), v.Pt());
0443             if(inNHCal(v.Eta())) {hP_all_pion->Fill(v.P());}
0444         }
0445 
0446         vector<edm4eic::ReconstructedParticle> matchedRecos;
0447         auto find_associated_reco = [&](const edm4hep::MCParticle& mc)->void {
0448             try {
0449                 if (!assocCol.isValid() || assocCol.empty()) return;
0450                 
0451                 const uint32_t mc_idx = mc.getObjectID().index;
0452                 
0453                 for (const auto& assoc : assocCol) {
0454                     if (assoc.getSimID() == mc_idx) {
0455                         uint32_t ridx = assoc.getRecID();
0456                         if (!recParts.isValid() || ridx >= recParts.size()) continue;
0457                         auto reco = recParts.at(ridx);
0458                         if (reco.isAvailable()) {
0459                             matchedRecos.push_back(reco);
0460                         }
0461                     }
0462                 }
0463             } catch (...) {}
0464         };
0465 
0466         if (!assocCol.isValid() || assocCol.empty()) continue;
0467         for(const auto&  p: vPions) if (p.getPDG() == -211) find_associated_reco(p);
0468 
0469         if (!recParts.isValid() || !projSegs.isValid() || !hcalRec.isValid() || recParts.empty() || projSegs.empty() || hcalRec.empty()) continue;
0470         
0471         set<int> uniqueCentersZ10;
0472         map<double, double> layerData;
0473         for (const auto& hit : hcalRec) {    
0474             double z = hit.getPosition().z;
0475             double zBin = round(z);
0476             
0477             int z10 = lround(z * 10.0);
0478             uniqueCentersZ10.insert(z10);
0479             
0480             layerData[zBin] += hit.getEnergy(); 
0481             hZ_hits->Fill(z);                
0482             hE_z->Fill(z, hit.getEnergy()); 
0483             hE->Fill(hit.getEnergy());
0484         }
0485 
0486         vector<double> layerCentersZ;
0487         layerCentersZ.reserve(uniqueCentersZ10.size());
0488         for (int z10 : uniqueCentersZ10) layerCentersZ.push_back(z10 / 10.0);
0489         if(layerCentersZ.size() > LAYER_MAX) LAYER_MAX = layerCentersZ.size();
0490 
0491         for(size_t n = 0; n < SIZE; n++) LAYER_CUTS[n] = static_cast<int>(LAYER_MAX*LAYER_PROC[n]);
0492         LAYER_THRESH = LAYER_CUTS[0];
0493 
0494         for (const auto& [zValue, sumEnergy] : layerData) {hEsum_z->Fill(zValue, sumEnergy); hEsum->Fill(sumEnergy);}
0495 
0496         vector<edm4eic::Track> allTracks;
0497         for (const auto& R : matchedRecos) {
0498             for (const auto& tr : R.getTracks()) {
0499                 if (tr.isAvailable()) allTracks.push_back(tr);
0500             }
0501         }
0502         vector<edm4eic::TrackSegment> segsTagged;
0503         for (const auto& seg : projSegs) {
0504             auto linkedTr = seg.getTrack();
0505             if (!linkedTr.isAvailable()) continue;
0506             for (const auto& TT : allTracks) {
0507                 if (linkedTr.getObjectID() == TT.getObjectID()) {
0508                     segsTagged.push_back(seg);
0509                     break;
0510                 }
0511             }
0512         }
0513 
0514         for (size_t s = 0; s < segsTagged.size(); ++s) {
0515 
0516             vector<double> segMinDistance(LAYER_MAX, std::numeric_limits<double>::infinity());
0517             vector<double> segHitEnergy(LAYER_MAX, std::numeric_limits<double>::quiet_NaN());
0518             vector<int> count_DrCuts(SIZE, 0);
0519             vector<int> count_ECuts(SIZE, 0);
0520 
0521             TVector3 A{}, B{};
0522             bool haveA = false, haveB = false;
0523 
0524             auto points = segsTagged[s].getPoints();
0525 
0526             for (const auto& pt : points) {
0527                 if (pt.system != 113) continue;
0528                 hZ_proj->Fill(pt.position.z);
0529                 if (!haveA) {
0530                     A.SetXYZ(pt.position.x, pt.position.y, pt.position.z);
0531                     haveA = true;
0532                 } else if (!haveB) {
0533                     B.SetXYZ(pt.position.x, pt.position.y, pt.position.z);
0534                     haveB = true;
0535                     break;
0536                 }
0537             }
0538 
0539             if (!haveA || !haveB) {continue;}
0540 
0541             for (size_t i = 0; i < LAYER_MAX; ++i) {
0542                 double best_dr_in_layer = 1e10;
0543                 double best_E_in_layer;
0544                 double partLayerEnergySum = 0;
0545                 double ratio_HitPartLayerEnergy = 0;
0546                 dd4hep::DDSegmentation::CellID best_cid_in_layer;
0547 
0548                 double zc = layerCentersZ[i];
0549                 auto [X, Y] = trackXYatZ(A, B, zc);
0550 
0551                 for (const auto& hit : hcalRec) {
0552                     const auto& hp = hit.getPosition();
0553 
0554                     if (fabs(hp.z - zc) > 5.0 /*mm*/) continue;
0555 
0556                     const double dx = X - hp.x;
0557                     const double dy = Y - hp.y;
0558                     const double dr = sqrt(dx*dx + dy*dy);
0559                     if(dr < 30*10 /*mm*/) partLayerEnergySum += hit.getEnergy();
0560 
0561                     hDxDyZ_layer->Fill(dx, dy, hp.z);
0562                     hDxDy_all->Fill(dx, dy);
0563                     hDrZ_layer->Fill(dr, hp.z);
0564                     hDr_all->Fill(dr);
0565 
0566                     if (dr < best_dr_in_layer) {
0567                         best_dr_in_layer = dr;
0568                         best_E_in_layer  = hit.getEnergy();
0569                     }
0570                 }
0571 
0572                 if (best_dr_in_layer < DR_THRESH_MM) {
0573                     segMinDistance[i] = best_dr_in_layer;
0574                     segHitEnergy[i]   = best_E_in_layer;
0575                 }
0576                 ratio_HitPartLayerEnergy += segHitEnergy[i]/partLayerEnergySum;
0577                 if (std::isnan(ratio_HitPartLayerEnergy) || fabs(ratio_HitPartLayerEnergy - 1) >= 0.2) continue; 
0578                 for(size_t j = 0; j < SIZE; ++j){
0579                     if (segMinDistance[i] < DR_CUTS_CM[j] * 10 /*mm*/){++count_DrCuts[j];}
0580                     if (segHitEnergy[i] < (E_CUTS[j] * MIP_ENERGY_GEV * thickness_plastic_cm * 100)){++count_ECuts[j];}
0581                 }
0582             }
0583             for (int j = 0; j < SIZE; ++j){
0584                 if (count_DrCuts[j] > LAYER_THRESH) hP_pass_dr[j]->Fill(vLorentzPions[s].P());
0585                 if (count_ECuts[j] > LAYER_THRESH) hP_pass_ECut[j]->Fill(vLorentzPions[s].P());
0586                 if (count_DrCuts[SIZE-1] > LAYER_CUTS[j]) hP_pass_LayerCut[j]->Fill(vLorentzPions[s].P());
0587             }
0588         }   
0589     }
0590 
0591     TCanvas* c = new TCanvas("c", "Pion analysis", 1600, 1000);
0592     c->Divide(2,2);
0593 
0594     c->cd(1); hEtaPt->Draw("COLZ");
0595   
0596     c->SaveAs(outname_pdf.c_str());
0597     c->SaveAs(outname_png.c_str());
0598 
0599     TCanvas* c_hitTrack = new TCanvas("c_hitTrack", "Pion hit and track analysis", 1600, 1000);
0600     c_hitTrack->Divide(2,2);                                                                 
0601     c_hitTrack->cd(1); gPad->SetGrid(); hZ_proj->Draw();                                     
0602     c_hitTrack->cd(2); gPad->SetGrid(); hZ_hits->Draw();
0603     c_hitTrack->SaveAs(addPrefixAfterSlash(outname_png, "hitTrack_").c_str());              
0604     c_hitTrack->SaveAs(addPrefixAfterSlash(outname_pdf, "hitTrack_").c_str()); 
0605 
0606     TCanvas* c_hitTrackDistance = new TCanvas("c_hitTrackDistance", "Pion hit-track distance analysis", 1600, 1000);
0607     c_hitTrackDistance->Divide(2,2); 
0608     c_hitTrackDistance->cd(1); gPad->SetGrid(); hDxDyZ_layer->Draw("COLZ");     
0609     c_hitTrackDistance->cd(2); gPad->SetGrid(); hDxDy_all->Draw("COLZ"); 
0610     c_hitTrackDistance->cd(3); gPad->SetGrid(); hDrZ_layer->Draw("COLZ");                             
0611     c_hitTrackDistance->cd(4); gPad->SetGrid(); hDr_all->Draw("COLZ");
0612     c_hitTrackDistance->SaveAs(addPrefixAfterSlash(outname_png, "hitTrackDistance_").c_str());              
0613     c_hitTrackDistance->SaveAs(addPrefixAfterSlash(outname_pdf, "hitTrackDistance_").c_str()); 
0614 
0615     TCanvas* c_Eff = new TCanvas("c_Eff", "Pion efficiency analysis", 1600, 1000);
0616     c_Eff->Divide(2,2);                        
0617     c_Eff->cd(1); gPad->SetGrid(); hP_all_pion->SetLineColor(kBlack); hP_all_pion->Draw();  
0618     c_Eff->cd(2); gPad->SetGrid();                                                       
0619     TH1D* hEff_dr[3]; 
0620     for (int idr=0; idr<3; ++idr) { 
0621         hEff_dr[idr] = (TH1D*)hP_pass_dr[idr]->Clone( 
0622             Form("hEff_dr%.1fcm", DR_CUTS_CM[idr]) 
0623         ); 
0624         hEff_dr[idr]->SetDirectory(nullptr);
0625         hEff_dr[idr]->SetTitle(Form("Efficiency vs p_{MC} (Layers > %d); p_{MC} [GeV]; efficiency", LAYER_THRESH)); 
0626         hEff_dr[idr]->Divide(hP_pass_dr[idr], hP_all_pion, 1, 1, "B");
0627     } 
0628 
0629     hEff_dr[0]->SetLineColor(kBlue); hEff_dr[0]->SetMinimum(0.0); hEff_dr[0]->SetMaximum(0.3); 
0630     hEff_dr[1]->SetLineColor(kRed);   
0631     hEff_dr[2]->SetLineColor(kGreen+2); 
0632 
0633     hEff_dr[0]->Draw("HIST E");            
0634     hEff_dr[1]->Draw("HIST E SAME");       
0635     hEff_dr[2]->Draw("HIST E SAME");       
0636     { auto leg_dr = new TLegend(0.60,0.70,0.88,0.88);
0637         for(int idr=0; idr<3; ++idr)
0638         {leg_dr->AddEntry(hEff_dr[idr],Form("dr < %.1f cm", DR_CUTS_CM[idr]),"l");} 
0639         leg_dr->Draw(); 
0640     }  
0641                                                                    
0642     c_Eff->cd(3); gPad->SetGrid();                                                        
0643     TH1D* hEff_E[3]; 
0644     for (int ie=0; ie<3; ++ie) { 
0645         hEff_E[ie] = (TH1D*)hP_pass_ECut[ie]->Clone( 
0646             Form("hEff_E%.1fcm", E_CUTS[ie]) 
0647         ); 
0648         hEff_E[ie]->SetDirectory(nullptr);
0649         hEff_E[ie]->SetTitle(Form("Efficiency vs p_{MC} (Layers > %d, dr < %.1f cm); p_{MC} [GeV]; efficiency",LAYER_THRESH, DR_THRESH_MM/10)); 
0650         hEff_E[ie]->Divide(hP_pass_ECut[ie], hP_all_pion, 1, 1, "B");
0651     } 
0652 
0653     hEff_E[0]->SetLineColor(kBlue); hEff_E[0]->SetMinimum(0.0); hEff_E[0]->SetMaximum(0.3); 
0654     hEff_E[1]->SetLineColor(kRed);   
0655     hEff_E[2]->SetLineColor(kGreen+2); 
0656 
0657     hEff_E[0]->Draw("HIST E");            
0658     hEff_E[1]->Draw("HIST E SAME");       
0659     hEff_E[2]->Draw("HIST E SAME");       
0660     { auto leg_E = new TLegend(0.60,0.70,0.88,0.88);
0661         for(int ie=0; ie<3; ++ie)
0662         {leg_E->AddEntry(hEff_E[ie],Form("E < %.1f MIP", E_CUTS[ie]),"l");}  
0663         leg_E->Draw(); 
0664     }
0665     
0666     c_Eff->cd(4); gPad->SetGrid();
0667     TH1D* hEff_Layer[3]; 
0668     for (int il=0; il<3; ++il) { 
0669         hEff_Layer[il] = (TH1D*)hP_pass_LayerCut[il]->Clone( 
0670             Form("hEff_Layer%d", LAYER_CUTS[il]) 
0671         ); 
0672         hEff_Layer[il]->SetDirectory(nullptr);
0673         hEff_Layer[il]->SetTitle(Form("Efficiency vs p_{MC} (dr < %.1f cm); p_{MC} [GeV]; efficiency", DR_THRESH_MM/10)); 
0674         hEff_Layer[il]->Divide(hP_pass_LayerCut[il], hP_all_pion, 1, 1, "B");
0675     } 
0676 
0677     hEff_Layer[0]->SetLineColor(kBlue); hEff_Layer[0]->SetMinimum(0.0); hEff_Layer[0]->SetMaximum(0.3); 
0678     hEff_Layer[1]->SetLineColor(kRed);   
0679     hEff_Layer[2]->SetLineColor(kGreen+2); 
0680 
0681     hEff_Layer[0]->Draw("HIST E");            
0682     hEff_Layer[1]->Draw("HIST E SAME");       
0683     hEff_Layer[2]->Draw("HIST E SAME");       
0684     { auto leg_Layer = new TLegend(0.60,0.70,0.88,0.88);
0685         for(int il=0; il<3; ++il)
0686         {leg_Layer->AddEntry(hEff_Layer[il],Form("L > %d Layers", LAYER_CUTS[il]),"l");}  
0687         leg_Layer->Draw(); 
0688     }  
0689     c_Eff->SaveAs(addPrefixAfterSlash(outname_png, "matching_efficiency_").c_str());              
0690     c_Eff->SaveAs(addPrefixAfterSlash(outname_pdf, "matching_efficiency_").c_str()); 
0691     
0692     TCanvas* c_hEnergy = new TCanvas("c_hEnergy", "Pion hit energy analysis", 1600, 1000);
0693     c_hEnergy->Divide(2,2); 
0694 
0695     c_hEnergy->cd(1); gPad->SetGrid(); gPad->SetLogy(); hE_z->GetYaxis()->SetMoreLogLabels(); hE_z->Draw("COLZ");
0696     TProfile* pE_z = hE_z->ProfileX("pE_z"); pE_z->SetLineWidth(3); pE_z->SetLineColor(kRed); pE_z->SetMarkerColor(kRed);
0697                     pE_z->SetDirectory(nullptr); pE_z->Draw("SAME");
0698 
0699     const double Ecut_GeV = MIP_ENERGY_GEV * thickness_plastic_cm * 100;
0700     TLine* cut = new TLine(hE_z->GetXaxis()->GetXmin(), Ecut_GeV, hE_z->GetXaxis()->GetXmax(), Ecut_GeV);
0701                 cut->SetLineColor(kRed+1); cut->SetLineStyle(2); cut->SetLineWidth(2);
0702                 cut->Draw("SAME"); 
0703     auto* leg = new TLegend(0.58, 0.75, 0.84, 0.88); leg->SetTextSize(0.04);leg->AddEntry(cut, Form("E_{cut} = %.3f GeV", Ecut_GeV), "l"); 
0704                 leg->Draw();    
0705 
0706     c_hEnergy->cd(2); gPad->SetGrid(); gPad->SetLogy(); hEsum_z->GetYaxis()->SetMoreLogLabels(); hEsum_z->Draw("COLZ");
0707     TProfile* pEsum_z = hEsum_z->ProfileX("pEsum_z"); pEsum_z->SetLineWidth(3); pEsum_z->SetLineColor(kRed); pEsum_z->SetMarkerColor(kRed);
0708                     pEsum_z->SetDirectory(nullptr); pEsum_z->Draw("SAME"); 
0709     c_hEnergy->cd(3); gPad->SetGrid(); hE->Draw();
0710     c_hEnergy->cd(4); gPad->SetGrid(); hEsum->Draw();
0711     
0712     c_hEnergy->SaveAs(addPrefixAfterSlash(outname_png, "hit_energy_").c_str());              
0713     c_hEnergy->SaveAs(addPrefixAfterSlash(outname_pdf, "hit_energy_").c_str()); 
0714 
0715     delete c;
0716     delete c_hitTrack;
0717     delete c_hitTrackDistance;
0718     delete c_Eff;
0719     delete c_hEnergy;
0720 
0721     return 0;
0722 }