From 9928379499a4e813db484acab9b390716566d657 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Thu, 11 Sep 2025 17:08:28 -0400 Subject: [PATCH 1/9] new boost.h --- ElectronID/Boost.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 ElectronID/Boost.h diff --git a/ElectronID/Boost.h b/ElectronID/Boost.h new file mode 100644 index 0000000..321e6a2 --- /dev/null +++ b/ElectronID/Boost.h @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Wouter Deconinck, Barak Schmookler + +#pragma once + +#include +#include +#include +#include +#include +#include + +using ROOT::Math::PxPyPzEVector; + +namespace eicrecon { + +using ROOT::Math::LorentzRotation; + +inline LorentzRotation determine_boost(PxPyPzEVector ei, PxPyPzEVector pi) { + + using ROOT::Math::Boost; + using ROOT::Math::RotationX; + using ROOT::Math::RotationY; + + // Step 1: Find the needed boosts and rotations from the incoming lepton and hadron beams + // (note, this will give you a perfect boost, in principle you will not know the beam momenta exactly and should use an average) + + PxPyPzEVector eo = ei; + PxPyPzEVector po = pi; + + // Define the Boost to make beams back-to-back + const auto cmBoost = (ei + pi).BoostToCM(); + const Boost boost_to_cm(cmBoost); + + // Boost to COM frame + pi = boost_to_cm(pi); + ei = boost_to_cm(ei); + + // This will boost beams from a center of momentum frame back to (nearly) their original energies + PxPyPzEVector eh(0, 0, -1*sqrt(pow(eo.E(),2)-pow(eo.M(),2)), eo.E()); + PxPyPzEVector ph(0, 0, sqrt(pow(po.E(),2)-pow(po.M(),2)), po.E()); + + const auto hoBoost = (eh + ph).BoostToCM(); + const Boost boost_to_headon(-hoBoost); + + // Boost and rotate the incoming beams to find the proper rotations TLorentzVector + + // Rotate to head-on + RotationY rotAboutY(-1.0 * atan2(pi.Px(), pi.Pz())); // Rotate to remove x component of beams + RotationX rotAboutX(+1.0 * atan2(pi.Py(), pi.Pz())); // Rotate to remove y component of beams + + // final matrix: P' = [BtoH][RX][RY][BtoCM]P <-- Matrix multi. goes from R to L + LorentzRotation tf; + tf *= boost_to_headon; + tf *= rotAboutX; + tf *= rotAboutY; + tf *= boost_to_cm; + + return tf; +} + +inline PxPyPzEVector apply_boost(const LorentzRotation& tf, PxPyPzEVector part) { + + // Step 2: Apply boosts and rotations to any particle 4-vector + // (here too, choices will have to be made as to what the 4-vector is for reconstructed particles) + + // Boost and rotate particle 4-momenta into the headon frame + tf(part); + return part; +} + +} // namespace eicrecon From 969f4f373bbc80161b9903fd3838ad5562c08239 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Mon, 15 Sep 2025 16:39:09 -0400 Subject: [PATCH 2/9] added bench mark plots, more reconstruction methods --- ElectronID/Beam.h | 74 ++++++++ ElectronID/ElectronID.cc | 116 ++++++++++++ ElectronID/ElectronID.hh | 15 ++ ElectronID/InclusiveSkim.C | 351 ++++++++++++++++++++++++++++--------- ElectronID/InclusiveSkim.h | 62 ++++--- ElectronID/constants.h | 10 ++ ElectronID/draw_helper.h | 320 +++++++++++++++++++++++++++++++++ ElectronID/kinematics.cc | 159 +++++++++++++++++ ElectronID/kinematics.hh | 51 ++++++ ElectronID/reconMethod.hh | 43 +++++ 10 files changed, 1096 insertions(+), 105 deletions(-) create mode 100644 ElectronID/Beam.h create mode 100644 ElectronID/constants.h create mode 100644 ElectronID/draw_helper.h create mode 100644 ElectronID/kinematics.cc create mode 100644 ElectronID/kinematics.hh create mode 100644 ElectronID/reconMethod.hh diff --git a/ElectronID/Beam.h b/ElectronID/Beam.h new file mode 100644 index 0000000..5b754ba --- /dev/null +++ b/ElectronID/Beam.h @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Wouter Deconinck + +#pragma once + +#include +#include +#include +#include + +using ROOT::Math::PxPyPzEVector; + +namespace eicrecon { + +template auto find_first_with_pdg(const T* parts, const std::set& pdg) { + T c; + c.setSubsetCollection(); + for (const auto& p : *parts) { + if (pdg.count(p.getPDG()) > 0) { + c.push_back(p); + break; + } + } + return c; +} + +template +auto find_first_with_status_pdg(const T* parts, const std::set& status, + const std::set& pdg) { + T c; + c.setSubsetCollection(); + for (const auto& p : *parts) { + if (status.count(p.getGeneratorStatus()) > 0 && pdg.count(p.getPDG()) > 0) { + c.push_back(p); + break; + } + } + return c; +} + +inline auto find_first_beam_electron(const edm4hep::MCParticleCollection* mcparts) { + return find_first_with_status_pdg(mcparts, {4}, {11}); +} + +inline auto find_first_beam_hadron(const edm4hep::MCParticleCollection* mcparts) { + return find_first_with_status_pdg(mcparts, {4}, {2212, 2112}); +} + +inline auto find_first_scattered_electron(const edm4hep::MCParticleCollection* mcparts) { + return find_first_with_status_pdg(mcparts, {1}, {11}); +} + +inline auto find_first_scattered_electron(const edm4eic::ReconstructedParticleCollection* rcparts) { + return find_first_with_pdg(rcparts, {11}); +} + +template +PxPyPzEVector round_beam_four_momentum(const Vector3& p_in, const float mass, + const std::vector& pz_set, + const float crossing_angle = 0.0) { + PxPyPzEVector p_out; + for (const auto& pz : pz_set) { + if (fabs(p_in.z / pz - 1) < 0.1) { + p_out.SetPz(pz); + break; + } + } + p_out.SetPx(p_out.Pz() * sin(crossing_angle)); + p_out.SetPz(p_out.Pz() * cos(crossing_angle)); + p_out.SetE(std::hypot(p_out.Px(), p_out.Pz(), mass)); + return p_out; +} + +} // namespace eicrecon diff --git a/ElectronID/ElectronID.cc b/ElectronID/ElectronID.cc index 2b50165..1485526 100644 --- a/ElectronID/ElectronID.cc +++ b/ElectronID/ElectronID.cc @@ -6,6 +6,9 @@ #include +#include +using ROOT::Math::PxPyPzEVector; + ElectronID::ElectronID() { mEe = 10.; @@ -47,9 +50,77 @@ ElectronID::~ElectronID() { void ElectronID::SetEvent(const podio::Frame* event) { mEvent = event; + hfs_dpt.clear(); + hfs_dpz.clear(); + hfs_de.clear(); + hfs_theta.clear(); +} + +edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost) { + + edm4eic::ReconstructedParticleCollection meRecon; + meRecon->setSubsetCollection(); + edm4hep::MCParticleCollection meMiss; + meMiss->setSubsetCollection(); + + auto& rcparts = mEvent->get("ReconstructedParticles"); + + if ( use_mc ) + { + edm4hep::MCParticleCollection meMC = GetMCElectron(); + auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + + for(const auto& assoc : RecoMC) + { + if(assoc.getSim() != meMC[0] && assoc.getSim().getGeneratorStatus() == 1) + { + PxPyPzEVector v(assoc.getSim().getMomentum().x, assoc.getSim().getMomentum().y, assoc.getSim().getMomentum().z, assoc.getSim().getEnergy()); + PxPyPzEVector u(assoc.getRec().getMomentum().x, assoc.getRec().getMomentum().y, assoc.getRec().getMomentum().z, assoc.getRec().getEnergy()); + PxPyPzEVector c(assoc.getRec().getMomentum().x, assoc.getRec().getMomentum().y, assoc.getRec().getMomentum().z, GetCalorimeterEnergy(assoc.getRec())); + + hfs_dpt.push_back((u.Pt()-v.Pt())/v.Pt()); + hfs_dpz.push_back((u.Z()-v.Z())/v.Z()); + hfs_de.push_back((u.E()-v.E())/v.E()); + hfs_theta.push_back(v.Theta()*(180./M_PI)); + + v = boost(v); + u = boost(u); + c = boost(c); + + meRecon.push_back(assoc.getRec()); + } + } + } + else + { + for(const auto& mcp : rcparts) { + if ( mcp.getObjectID().index != object_id ) + meRecon.push_back(mcp); + } + } + + return meRecon; } +edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { + + edm4hep::MCParticleCollection mhMC; + mhMC->setSubsetCollection(); + + auto& mcparts = mEvent->get("MCParticles"); + + std::vector mc_hadronic; + edm4hep::MCParticleCollection meMC = GetMCElectron(); + + bool found_scattered_e = false; + for(const auto& mcp : mcparts) { + if (mcp.getGeneratorStatus() == 1 && mcp.getObjectID().index != meMC[0].getObjectID().index ) + mhMC.push_back(mcp); + } + + return mhMC; +} edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { @@ -215,4 +286,49 @@ double ElectronID::GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rc } +void ElectronID::GetBeam(LorentzRotation &boost, TLorentzVector &in_e, TLorentzVector &in_n) +{ + edm4hep::MCParticle mc_electron; + edm4hep::MCParticle mc_nucleon; + + auto& mcparts = mEvent->get("MCParticles"); + vector spec_protons; + + for(const auto& mcp : mcparts) + { + if ( mcp.getGeneratorStatus() == 4 ) + { + if ( mcp.getPDG() == ID_ELECTRON ) + mc_electron = mcp; + else + mc_nucleon = mcp; + } + } + + if ( !mc_electron.isAvailable() || !mc_nucleon.isAvailable() ) + return; + + in_e.SetPxPyPzE(mc_electron.getMomentum().x, mc_electron.getMomentum().y, mc_electron.getMomentum().z, mc_electron.getEnergy()); + in_n.SetPxPyPzE(mc_nucleon.getMomentum().x, mc_nucleon.getMomentum().y, mc_nucleon.getMomentum().z, mc_nucleon.getEnergy()); + + // get boost matrix -- redo every run because the proton / neutron has different mass .. but really this should not change per event .. to be changed + const PxPyPzEVector ei( + eicrecon::round_beam_four_momentum( + mc_electron.getMomentum(), + mc_electron.getMass(), + {-1*mEe}, + 0.0) + ); + + const PxPyPzEVector pi( + eicrecon::round_beam_four_momentum( + mc_nucleon.getMomentum(), + mc_nucleon.getMass(), + {mEh}, + -0.025) + ); + + boost = eicrecon::determine_boost(ei, pi); // Get boost to colinear frame + return; +} diff --git a/ElectronID/ElectronID.hh b/ElectronID/ElectronID.hh index ad5e047..b113022 100644 --- a/ElectronID/ElectronID.hh +++ b/ElectronID/ElectronID.hh @@ -6,6 +6,12 @@ #include "edm4eic/ReconstructedParticleCollection.h" #include "edm4hep/MCParticleCollection.h" +#include "constants.h" +#include "Beam.h" +#include "Boost.h" + +using ROOT::Math::LorentzRotation; + class ElectronID{ public: @@ -21,11 +27,20 @@ public: void SetEvent(const podio::Frame* event); + edm4eic::ReconstructedParticleCollection FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost); + edm4hep::MCParticleCollection GetMCHadronicFinalState(); edm4eic::ReconstructedParticleCollection FindScatteredElectron(); edm4eic::ReconstructedParticleCollection GetTruthReconElectron(); edm4hep::MCParticleCollection GetMCElectron(); edm4eic::ReconstructedParticle SelectHighestPT(const edm4eic::ReconstructedParticleCollection& rcparts); double GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rcp); + void GetBeam(LorentzRotation &boost, TLorentzVector &in_e, TLorentzVector &in_n); + + // for HFS QA + vector hfs_dpt; + vector hfs_dpz; + vector hfs_de; + vector hfs_theta; private: diff --git a/ElectronID/InclusiveSkim.C b/ElectronID/InclusiveSkim.C index 6788d41..d086614 100644 --- a/ElectronID/InclusiveSkim.C +++ b/ElectronID/InclusiveSkim.C @@ -6,7 +6,8 @@ #include "edm4eic/ClusterCollection.h" #include "edm4eic/MCRecoParticleAssociationCollection.h" #include "podio/Frame.h" -#include "podio/ROOTFrameReader.h" +// #include "podio/ROOTFrameReader.h" -- for simulation campaign before March 2023 with eic-shell 25.03.2 +#include "podio/ROOTReader.h" // ROOT headers #include "TTree.h" @@ -17,27 +18,48 @@ // Analysis headers #include "InclusiveSkim.h" -#include "ElectronID.cc" +#include "drawKinematics.C" void InclusiveSkim() { + // Set beam energy double Ee = 10.; double Eh = 100.; - vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; + // Set what electron ID to use + int eID_type = truthID; - auto reader = podio::ROOTFrameReader(); + // access local file + // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; + + // access remote file + vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; + + // auto reader = podio::ROOTFrameReader(); + auto reader = podio::ROOTReader(); reader.openFiles(inFiles); + // setup eid ElectronID* eFinder = new ElectronID(Ee, Eh); + // setup kinematic algorithms + algorithm.push_back(Kinematics("E_Method", 2)); // electron method + algorithm.push_back(Kinematics("JB_Method", 4)); // Jacquet-Blondel method + algorithm.push_back(Kinematics("DA_Method", 1)); // Double-Angle method + algorithm.push_back(Kinematics("Sig_Method", kOrange+1)); // Sigma method + algorithm.push_back(Kinematics("ESig_Method", kGreen+3)); // E-Sigma method + algorithm.push_back(Kinematics("MC", kGray)); // MC info + + // setup output file and histograms TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); CreateOutputTree(outFileName); + DefineHistograms(); - + // loop events for(size_t ev = 0; ev < reader.getEntries("events"); ev++) { - if(ev%1000==0) cout << "Event " << ev << "/" << reader.getEntries("events") << endl; + if(ev%1000==0) + cout << "Event " << ev << "/" << reader.getEntries("events") << endl; ResetVariables(); @@ -47,56 +69,230 @@ void InclusiveSkim() { edm4hep::MCParticleCollection e_mc = eFinder->GetMCElectron(); // Skip events without scattered MC electron - if(e_mc.size() == 0) continue; + if(e_mc.size() == 0) + continue; + + // Set boost and get incoming particles + TLorentzVector in_e; + TLorentzVector in_n; + LorentzRotation boost; + eFinder->GetBeam(boost, in_e, in_n); + in_e = boost(in_e); + in_n =boost(in_n); + + // Calculate kinematic variables using MC electron + TLorentzVector kprime; + kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, Me); + TLorentzVector true_e_lab = kprime; + kprime = boost(kprime); // boost back to head-on frame + + // Get momentum vector elements from MC electron + mc_p = edm4hep::utils::magnitude(e_mc[0].getMomentum()); + mc_eta = edm4hep::utils::eta(e_mc[0].getMomentum()); + mc_phi = edm4hep::utils::angleAzimuthal(e_mc[0].getMomentum()); + + // Don't have to boost if we are just calulcating x, Q2, y using e method because they are Lorentz invariant + // But since we boosted the outgoing ones earlier for later analysis, we need to boost the incoming ones as well + CalculateRealElectronKinematics(in_e, in_n, kprime, algorithm[MC]); + + if ( !pass_ke_cut(algorithm[MC]) ) + continue; + + // Set Range for plots + int Qrange = 0; + if ( algorithm[MC].Q2 > 1000 ) + Qrange = 3; + else if ( algorithm[MC].Q2 > 100 ) + Qrange = 2; + else if ( algorithm[MC].Q2 > 10 ) + Qrange = 1; + + // Find scattered electrons using mc association + auto e_truth = eFinder->GetTruthReconElectron(); - // Find scattered electrons + // Find scattered electrons using detector information auto e_candidates = eFinder->FindScatteredElectron(); edm4eic::ReconstructedParticle e_rec; - // If there are multiple candidates, - // select one with highest pT + + // If there are multiple candidates, select one with highest pT if(e_candidates.size() > 0) { positive_eID = 1; e_rec = eFinder->SelectHighestPT(e_candidates); } - // Get momentum vector elements from MC electron - mc_p = edm4hep::utils::magnitude(e_mc[0].getMomentum()); - mc_eta = edm4hep::utils::eta(e_mc[0].getMomentum()); - mc_phi = edm4hep::utils::angleAzimuthal(e_mc[0].getMomentum()); + // select which eID we are using + PxPyPzEVector scat_ele(0, 0, 0, -1); + if ( eID_type == truthID ) { + if(e_truth.size() < 1) + continue; + + scat_ele.SetPxPyPzE(e_truth[0].getMomentum().x, e_truth[0].getMomentum().y, e_truth[0].getMomentum().z, e_truth[0].getEnergy()); + } + else if ( eID_type == mcID ) { + scat_ele = true_e_lab; + } + else { + if(!positive_eID) + continue; - // Calculate kinematic variables using MC electron - TLorentzVector kprime; - kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, Me); - CalculateElectronKinematics(Ee, Eh, kprime, mc_xB, mc_Q2, mc_W, mc_y, mc_nu); + scat_ele.SetPxPyPzE(e_rec.getMomentum().x, e_rec.getMomentum().y, e_rec.getMomentum().z, e_rec.getEnergy()); + } - // If electron was identified, get vector elements - // and kinematic variables from reconstructed particle - if(positive_eID) { - track_p = edm4hep::utils::magnitude(e_rec.getMomentum()); - track_eta = edm4hep::utils::eta(e_rec.getMomentum()); - track_phi = edm4hep::utils::angleAzimuthal(e_rec.getMomentum()); + PxPyPzEVector rec_e_lab = scat_ele; + if( eID_type!=2 ) + { + // Calculate kinematics using track info only + kprime.SetXYZM(rec_e_lab.Px(), rec_e_lab.Py(), rec_e_lab.Pz(), Me); + TLorentzVector track_kprime = kprime; + h_dEt[Qrange]->Fill((track_kprime.E()-true_e_lab.E())/true_e_lab.E()); + h_dt[Qrange]->Fill((track_kprime.Theta()-true_e_lab.Theta())/true_e_lab.Theta()); + h_dp[Qrange]->Fill((track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); + h_tde[1]->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); + h_tdp->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); + h_pde->Fill(true_e_lab.Pt(), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); + h_pt->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.Pt()); + + // Calculate kinematics using track + cluster energy + TVector3 e3v = kprime.Vect(); - kprime.SetXYZM(e_rec.getMomentum().x, e_rec.getMomentum().y, e_rec.getMomentum().z, Me); - CalculateElectronKinematics(Ee, Eh, kprime, e_track_xB, e_track_Q2, e_track_W, e_track_y, e_track_nu); + double track_clust_E; + if ( eID_type == truthID ) + track_clust_E = eFinder->GetCalorimeterEnergy(e_truth[0]); + else if ( eID_type == mcID ) + track_clust_E = e_mc[0].getEnergy(); + else + track_clust_E = eFinder->GetCalorimeterEnergy(e_rec); - // Calculate kinematic variables with calorimeter energy - TVector3 e3v = kprime.Vect(); - double track_clust_E = eFinder->GetCalorimeterEnergy(e_rec); e3v.SetMag(track_clust_E); kprime.SetVectM(e3v, Me); - CalculateElectronKinematics(Ee, Eh, kprime, e_clust_xB, e_clust_Q2, e_clust_W, e_clust_y, e_clust_nu); - } + h_dEc[Qrange]->Fill((track_clust_E-true_e_lab.E())/true_e_lab.E()); + h_tde[0]->Fill(true_e_lab.Theta()*(180./M_PI), (track_clust_E-true_e_lab.E())/true_e_lab.E()); + h_ede->Fill(true_e_lab.E(), (track_clust_E-true_e_lab.E())/true_e_lab.E()); + h_et->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.E()); + + TLorentzVector calo_kprime = kprime; + // // cut example + // if ( algorithm[MC].Q2 > 100 ) + // scat_ele = calo_kprime; + } - outTree->Fill(); + scat_ele = boost(scat_ele); + float theta = scat_ele.Theta(); + float E = scat_ele.E(); + + // Find hadronic final state + double pxsum = 0; + double pysum = 0; + double pzsum = 0; + double Esum = 0; + + // MC and Rec data structure are different.. not sure how to not repeat code here + auto mc_hfsCollection = eFinder->GetMCHadronicFinalState(); + for (const auto p : mc_hfsCollection) { + // Lorentz vector in lab frame + PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); + // Boost to colinear frame + hf = boost(hf); + + pxsum += hf.Px(); + pysum += hf.Py(); + pzsum += hf.Pz(); + Esum += hf.E(); + } + double true_sigma_h = Esum - pzsum; + double true_pt_had = sqrt(pxsum*pxsum + pysum*pysum); + + pxsum = 0; + pysum = 0; + pzsum = 0; + Esum = 0; + + auto hfsCollection = eFinder->FindHadronicFinalState(eID_type, e_rec.getObjectID().index, boost); + for (const auto p : hfsCollection) { + // Lorentz vector in lab frame + // double track_clust_E = eFinder->GetCalorimeterEnergy(p); + // cout << "energy " << track_clust_E << " " << p.getEnergy() << " " << track_clust_E - p.getEnergy() << endl; + PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); + // PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, track_clust_E); + // Boost to colinear frame + hf = boost(hf); + + pxsum += hf.Px(); + pysum += hf.Py(); + pzsum += hf.Pz(); + Esum += hf.E(); + } + double sigma_h = Esum - pzsum; + double pt_had = sqrt(pxsum*pxsum + pysum*pysum); + + for ( int i = 0; i < eFinder->hfs_dpt.size(); i++ ) + { + h_hfs_dpt->Fill(eFinder->hfs_dpt[i]); + h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpt[i]); + } + + for ( int i = 0; i < eFinder->hfs_dpz.size(); i++ ) + { + h_hfs_dpz->Fill(eFinder->hfs_dpz[i]); + h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpz[i]); + } + + for ( int i = 0; i < eFinder->hfs_de.size(); i++ ) + { + h_hfs_de->Fill(eFinder->hfs_de[i]); + h_hfs_de_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_de[i]); + } + + if ( eID_type == mcID ) + { + sigma_h = true_sigma_h; + pt_had = true_pt_had; + } + + // Calculate kinematics + + // example cut + // if ( abs((scat_ele.E() - true_e_lab.E())/true_e_lab.E()) > 0.2 ) + // return; + + if ( E > 0 ) + algorithm[EL].save_variables(calc_elec_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + + if ( hfsCollection.size() != 0 ) + { + h_dhf[Qrange]->Fill((sigma_h-true_sigma_h)/true_sigma_h); + h_dpt[Qrange]->Fill((pt_had-true_pt_had)/true_pt_had); + + algorithm[JB].save_variables(calc_jb_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + + if ( E > 0 ) + { + algorithm[DA].save_variables(calc_da_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + algorithm[SIG].save_variables(calc_sig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + algorithm[ESIG].save_variables(calc_esig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + } + } + + algorithm[MC].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); + for ( int i = 0; i < algorithm.size()-1; i ++ ) + algorithm[i].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); + + + outTree->Fill(); } outFile->cd(); outTree->Write(outTree->GetName(), 2); -} + plot_energy_and_track(); + plot_kinematics_qa(); + + // outFile->Close(); + return; +} void CreateOutputTree(TString outFileName) { @@ -105,38 +301,32 @@ void CreateOutputTree(TString outFileName) { outTree->Branch("positive_eID", &positive_eID); + // Create branches for each algorithm + for ( int i = 0; i < algorithm.size(); i ++ ) + { + outTree->Branch(Form("%s_xB", algorithm[i].method_name.c_str()), &algorithm[i].xB); + outTree->Branch(Form("%s_Q2", algorithm[i].method_name.c_str()), &algorithm[i].Q2); + outTree->Branch(Form("%s_y", algorithm[i].method_name.c_str()), &algorithm[i].y); + outTree->Branch(Form("%s_nu", algorithm[i].method_name.c_str()), &algorithm[i].nu); + outTree->Branch(Form("%s_W2", algorithm[i].method_name.c_str()), &algorithm[i].W2); + } + outTree->Branch("mc_p", &mc_p); outTree->Branch("mc_eta", &mc_eta); outTree->Branch("mc_phi", &mc_phi); outTree->Branch("track_p", &track_p); - outTree->Branch("track_eta", &track_eta); - outTree->Branch("track_phi", &track_phi); - - outTree->Branch("mc_xB", &mc_xB); - outTree->Branch("mc_Q2", &mc_Q2); - outTree->Branch("mc_W", &mc_W); - outTree->Branch("mc_y", &mc_y); - outTree->Branch("mc_nu", &mc_nu); - - outTree->Branch("e_track_xB", &e_track_xB); - outTree->Branch("e_track_Q2", &e_track_Q2); - outTree->Branch("e_track_W", &e_track_W); - outTree->Branch("e_track_y", &e_track_y); - outTree->Branch("e_track_nu", &e_track_nu); - - outTree->Branch("e_clust_xB", &e_clust_xB); - outTree->Branch("e_clust_Q2", &e_clust_Q2); - outTree->Branch("e_clust_W", &e_clust_W); - outTree->Branch("e_clust_y", &e_clust_y); - outTree->Branch("e_clust_nu", &e_clust_nu); - + outTree->Branch("track_eta", &track_eta); + outTree->Branch("track_phi", &track_phi); } void ResetVariables() { positive_eID = 0; + for ( auto &v : algorithm ) + v.reset(); + mc_p = -999; mc_eta = -999; mc_phi = -999; @@ -144,41 +334,20 @@ void ResetVariables() { track_p = -999; track_eta = -999; track_phi = -999; - - mc_xB = -999; - mc_Q2 = -999; - mc_W = -999; - mc_y = -999; - mc_nu = -999; - e_track_xB = -999; - e_track_Q2 = -999; - e_track_W = -999; - e_track_y = -999; - e_track_nu = -999; - - e_clust_xB = -999; - e_clust_Q2 = -999; - e_clust_W = -999; - e_clust_y = -999; - e_clust_nu = -999; - - } -void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, float& xB, float& Q2, float& W, float& y, float& nu) { - - TLorentzVector ki; ki.SetXYZM(0., 0., -fEe, Me); - TLorentzVector P = GetHadronBeam(fEh); - TLorentzVector q = ki - kf; - Q2 = -(q.Dot(q)); - nu = (q.Dot(P))/Mp; - xB = Q2/(2.*Mp*nu); - y = (q.Dot(P))/(ki.Dot(P)); - W = sqrt(Mp*Mp + (2.*Mp*nu) - Q2); +// mc kinematics for comparison - use real incident particle kinematics +void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v) { + // input is boosted + TLorentzVector q = ki - kf; + v.Q2 = -(q.Dot(q)); + v.nu = (q.Dot(P))/Mp; + v.xB = v.Q2/(2.*Mp*v.nu); + v.y = (q.Dot(P))/(ki.Dot(P)); + v.W2 = (Mp*Mp + (2.*Mp*v.nu) - v.Q2); } - TLorentzVector GetHadronBeam(double fEh) { TLorentzVector hadron_beam; @@ -189,3 +358,17 @@ TLorentzVector GetHadronBeam(double fEh) { return hadron_beam; } + +bool pass_ke_cut(Kinematics v) +{ + if ( v.y <= 0.01 || v.y >= 0.95 ) + return false; + + if ( v.Q2 < 2 ) + return false; + + if ( v.W2 < 4 ) + return false; + + return true; +} \ No newline at end of file diff --git a/ElectronID/InclusiveSkim.h b/ElectronID/InclusiveSkim.h index 928b6ff..633fffd 100644 --- a/ElectronID/InclusiveSkim.h +++ b/ElectronID/InclusiveSkim.h @@ -1,3 +1,12 @@ +// Analysis headers +#include "ElectronID.cc" +#include "kinematics.cc" +#include "draw_helper.h" +#include "reconMethod.hh" +#include "constants.h" + +#pragma once + TFile* outFile = NULL; TTree* outTree = NULL; @@ -5,15 +14,45 @@ const double Me = 0.511e-3; // GeV const double Mp = 0.938272; // GeV const double crossing_angle = -0.025; // rad +// QA histograms +TH1F* h_dEc[4]; +TH1F* h_dEt[4]; +TH1F* h_dt[4]; +TH1F* h_dp[4]; +TH2F* h_tde[2]; +TH2F* h_tdp; +TH2F* h_pde; +TH2F* h_ede; +TH2F* h_pt; +TH2F* h_et; + +TH1F* h_dhf[4]; +TH1F* h_dpt[4]; + +TH1F* h_hfs_dpz; +TH1F* h_hfs_dpt; +TH1F* h_hfs_de; +TH2F* h_hfs_dpz_t; +TH2F* h_hfs_dpt_t; +TH2F* h_hfs_de_t; + +enum {EL, JB, DA, SIG, ESIG, MC}; +enum {reconID, truthID, mcID}; + void SetInputBranchAddresses(); void CreateOutputTree(TString outFileName); void ResetVariables(); -void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, float& xB, float& Q2, float& W, float& y, float& nu); +void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v); TLorentzVector GetHadronBeam(double fEh); +void DefineHistograms(); +void plot_kinematics_qa(); +void plot_energy_and_track(); +bool pass_ke_cut(Kinematics v); using namespace std; int positive_eID; +vector algorithm; float mc_p; float mc_eta; @@ -21,23 +60,4 @@ float mc_phi; float track_p; float track_eta; -float track_phi; - -float mc_xB; -float mc_Q2; -float mc_W; -float mc_y; -float mc_nu; - -float e_track_xB; -float e_track_Q2; -float e_track_W; -float e_track_y; -float e_track_nu; - -float e_clust_xB; -float e_clust_Q2; -float e_clust_W; -float e_clust_y; -float e_clust_nu; - +float track_phi; \ No newline at end of file diff --git a/ElectronID/constants.h b/ElectronID/constants.h new file mode 100644 index 0000000..b62f090 --- /dev/null +++ b/ElectronID/constants.h @@ -0,0 +1,10 @@ +// masses in GeV +#define MASS_ELECTRON 0.000511 +#define MASS_PROTON 0.93827 +#define MASS_NEUTRON 0.93957 +#define MASS_HELIUM3 2.8094 + +// PDG code +#define ID_ELECTRON 11 +#define ID_PROTON 2212 +#define ID_NEUTRON 2112 \ No newline at end of file diff --git a/ElectronID/draw_helper.h b/ElectronID/draw_helper.h new file mode 100644 index 0000000..adcc14e --- /dev/null +++ b/ElectronID/draw_helper.h @@ -0,0 +1,320 @@ +// Some plot formatting +// But should switch to standard ePIC format .. + +#pragma once + +// bin setting +const int n_x_bin = 25; +const int n_q_bin = 25; + +// axis range +double x_gen_min = 0; +double q_gen_max = 0; + +void BinLogX(TH1F* &h) // taken from https://root.cern.ch/root/roottalk/roottalk06/1213.html +{ + TAxis *axis = h->GetXaxis(); + int bins = axis->GetNbins(); + + Axis_t from = axis->GetXmin(); + Axis_t to = axis->GetXmax(); + Axis_t width = (to - from) / bins; + Axis_t *new_bins = new Axis_t[bins + 1]; + + for (int i = 0; i <= bins; i++) + new_bins[i] = pow(10, from + i * width); + + axis->Set(bins, new_bins); + delete[] new_bins; +} + +void BinLogX(TH2F* &h, int a) // taken from https://root.cern.ch/root/roottalk/roottalk06/1213.html +{ + TAxis *axis = a == 0 ? h->GetXaxis() : h->GetYaxis(); + int bins = axis->GetNbins(); + + Axis_t from = axis->GetXmin(); + Axis_t to = axis->GetXmax(); + Axis_t width = (to - from) / bins; + Axis_t *new_bins = new Axis_t[bins + 1]; + + for (int i = 0; i <= bins; i++) + new_bins[i] = pow(10, from + i * width); + + axis->Set(bins, new_bins); + delete[] new_bins; +} + +void BinLogXY(TH2F* &h) +{ + for ( int j = 0; j < 2; j ++ ) + { + BinLogX(h, j); + // TAxis *axis = j == 0 ? h->GetXaxis() : h->GetYaxis(); + + // int bins = axis->GetNbins(); + // Axis_t from = axis->GetXmin(); + // Axis_t to = axis->GetXmax(); + // Axis_t width = (to - from) / bins; + // Axis_t *new_bins = new Axis_t[bins + 1]; + + // for (int i = 0; i <= bins; i++) + // new_bins[i] = pow(10, from + i * width); + + // axis->Set(bins, new_bins); + + // delete[] new_bins; + } +} + +TH1F* BookTH1(std::string name, std::string title, double n_bins, double min, double max) +{ + TH1F* h = new TH1F(name.c_str(), title.c_str(), n_bins, min, max); + h->GetXaxis()->CenterTitle(); + h->GetYaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.5); + h->GetYaxis()->SetTitleOffset(1.5); + + BinLogX(h); + + return h; +} + +TH2F* BookTH2(std::string name, std::string title, double n_xbins, double xmin, double xmax, double n_ybins, double ymin, double ymax, int colorMap) +{ + TH2F* h = new TH2F(name.c_str(), title.c_str(), n_xbins, xmin, xmax, n_ybins, ymin, ymax); + h->GetXaxis()->CenterTitle(); + h->GetYaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.5); + h->GetYaxis()->SetTitleOffset(1.5); + + TExec *exDefault = new TExec("ex1","gStyle->SetPalette(kBird)"); + TExec *exUser = new TExec("ex1",Form("gStyle->SetPalette(%d)",colorMap)); + + if ( colorMap != 0 ) + h->GetListOfFunctions()->Add(exUser); + else + h->GetListOfFunctions()->Add(exDefault); + + BinLogXY(h); + + return h; +} + +TCanvas* BookCanvas(std::string name, std::string title, double width, double height) +{ + TCanvas* c = new TCanvas(name.c_str(), title.c_str(), width, height); + c->SetLeftMargin(0.13); + c->SetBottomMargin(0.13); + c->SetRightMargin(0.13); + + return c; +} + +void plot_2d_xq(std::string c_name, std::string c_title, double c_min, double c_max, TH2F* h_xq2, double x_gen_min, double q_gen_max) +{ + TCanvas* c_xq = BookCanvas(c_name, c_title, c_min, c_max); + c_xq->SetLogx(); + c_xq->SetLogy(); + // c_xq->SetLogz(); + h_xq2->SetStats(0); + h_xq2->GetXaxis()->SetRangeUser(x_gen_min, 1); + h_xq2->GetYaxis()->SetRangeUser(1,q_gen_max); + h_xq2->Draw("COLZ TEXT"); + + return; +} + +void format_graph(TGraph* g) +{ + // g->GetXaxis()->SetTitle("Q^{2} (GeV/c^{2})^{2}"); + g->GetXaxis()->CenterTitle(); + g->GetXaxis()->SetTitleOffset(1.4); + + // g->GetYaxis()->SetTitle(ylabel.c_str()); + g->GetYaxis()->CenterTitle(); + g->GetYaxis()->SetTitleOffset(1.4); + + g->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + g->GetXaxis()->SetLabelSize(24); + g->GetXaxis()->SetTitleSize(28); + g->GetXaxis()->SetTitleFont(43); + + g->GetYaxis()->SetNdivisions(505); + g->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + g->GetYaxis()->SetLabelSize(24); + g->GetYaxis()->SetTitleSize(28); + g->GetYaxis()->SetTitleFont(43); + + // g->GetYaxis()->ChangeLabel(1, -1, -1, -1, -1, -1, " "); + + // g->SetMarkerStyle(marker[style_id]); + // g->SetMarkerColor(color[style_id]); + g->SetMarkerSize(0.2); + + return; +} + +void format_efficiency(TEfficiency* &g) +{ + auto graph_test = g->GetPaintedGraph(); + if ( g->GetPaintedGraph() == NULL ) + printf("cannot find \n"); + + g->GetPaintedGraph()->GetXaxis()->CenterTitle(); + g->GetPaintedGraph()->GetXaxis()->SetTitleOffset(1.2); + + g->GetPaintedGraph()->GetYaxis()->SetTitleOffset(1.8); + g->GetPaintedGraph()->GetYaxis()->CenterTitle(); + + g->GetPaintedGraph()->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + g->GetPaintedGraph()->GetXaxis()->SetLabelSize(20); + g->GetPaintedGraph()->GetXaxis()->SetTitleSize(20); + g->GetPaintedGraph()->GetXaxis()->SetTitleFont(43); + + g->GetPaintedGraph()->GetYaxis()->SetNdivisions(505); + g->GetPaintedGraph()->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + g->GetPaintedGraph()->GetYaxis()->SetLabelSize(20); + g->GetPaintedGraph()->GetYaxis()->SetTitleSize(20); + g->GetPaintedGraph()->GetYaxis()->SetTitleFont(43); + + return; +} + +void format_histogram(TH1F* &h) +{ + h->GetXaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.2); + + h->GetYaxis()->SetTitleOffset(1.8); + h->GetYaxis()->CenterTitle(); + + h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetXaxis()->SetLabelSize(20); + h->GetXaxis()->SetTitleSize(20); + h->GetXaxis()->SetTitleFont(43); + + h->GetYaxis()->SetNdivisions(505); + h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetYaxis()->SetLabelSize(20); + h->GetYaxis()->SetTitleSize(20); + h->GetYaxis()->SetTitleFont(43); + + return; +} + +TCanvas* draw_2d_standard(TH2F* &h, std::string c_name, std::string c_title, double width, double height, bool is_log_z, bool is_std_scale) +{ + TCanvas* c = BookCanvas(c_name.c_str(), c_title.c_str(), width, height); + c->SetLogx(); + c->SetLogy(); + h->SetStats(0); + h->Draw("COLZ"); + + if ( is_log_z ) + c->SetLogz(); + + if (is_std_scale ) + { + h->GetXaxis()->SetRangeUser(x_gen_min, 1); + h->GetYaxis()->SetRangeUser(1,q_gen_max); + } + + return c; +} + +TCanvas* draw_2d_efficiency(TH2F* &h, std::string c_name, std::string c_title, double width, double height, bool is_log_z, bool is_std_scale) +{ + TCanvas* c = BookCanvas(c_name.c_str(), c_title.c_str(), width, height); + c->SetLogx(); + c->SetLogy(); + h->SetStats(0); + h->Draw("COLZ TEXT"); + + if ( is_log_z ) + c->SetLogz(); + + if (is_std_scale ) + { + h->GetXaxis()->SetRangeUser(x_gen_min, 1); + h->GetYaxis()->SetRangeUser(1,q_gen_max); + } + + return c; +} + +void set_2d_scale(TH2F* h) +{ + x_gen_min = h->GetXaxis()->GetBinCenter(h->FindFirstBinAbove(0, 1)) - h->GetXaxis()->GetBinWidth(h->FindFirstBinAbove(0, 1)/2.); + q_gen_max = h->GetYaxis()->GetBinCenter(h->FindLastBinAbove(0, 2)) + h->GetYaxis()->GetBinWidth(h->FindLastBinAbove(0, 2)/2.); + + return; +} + +void process_eff_hist(TH2F* &h_top, TH2F* &h_bottom) +{ + h_top->Divide(h_bottom); + for ( int ix = 0; ix < h_top->GetXaxis()->GetNbins(); ix ++ ) + { + for ( int iq = 0; iq < h_top->GetYaxis()->GetNbins(); iq ++ ) + { + double eff = h_top->GetBinContent(ix+1, iq+1); + double eff_round = std::round(eff * 1000) / 1000.; + if ( eff_round > 1.5 ) + eff_round = 1.5; + // h_top->SetBinContent(ix+1, iq+1, std::round(eff * 1000) / 1000.); + // if ( eff_round < 2 ) + h_top->SetBinContent(ix+1, iq+1, eff_round); + // else + // h_top->SetBinContent(ix+1, iq+1, 0); + } + } + + return; +} + +void format_eid_histogram(TH1F* &h) +{ + h->GetXaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.2); + + h->GetYaxis()->SetTitleOffset(1.8); + h->GetYaxis()->CenterTitle(); + + h->GetXaxis()->SetNdivisions(5); + h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetXaxis()->SetLabelSize(20); + h->GetXaxis()->SetTitleSize(20); + h->GetXaxis()->SetTitleFont(43); + + h->GetYaxis()->SetNdivisions(5); + h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetYaxis()->SetLabelSize(20); + h->GetYaxis()->SetTitleSize(20); + h->GetYaxis()->SetTitleFont(43); + + return; +} + +void format_eid_histogram(TH2F* &h) +{ + h->GetXaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.2); + + h->GetYaxis()->SetTitleOffset(1.8); + h->GetYaxis()->CenterTitle(); + + h->GetXaxis()->SetNdivisions(505); + h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetXaxis()->SetLabelSize(20); + h->GetXaxis()->SetTitleSize(20); + h->GetXaxis()->SetTitleFont(43); + + h->GetYaxis()->SetNdivisions(505); + h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetYaxis()->SetLabelSize(20); + h->GetYaxis()->SetTitleSize(20); + h->GetYaxis()->SetTitleFont(43); + + return; +} \ No newline at end of file diff --git a/ElectronID/kinematics.cc b/ElectronID/kinematics.cc new file mode 100644 index 0000000..75660d1 --- /dev/null +++ b/ElectronID/kinematics.cc @@ -0,0 +1,159 @@ +#include "kinematics.hh" +#include "reconMethod.hh" +#include "draw_helper.h" + +Kinematics::Kinematics(std::string method_name_, int draw_id_) +{ + method_name = method_name_; + draw_id = draw_id_; + + h_xq = BookTH2(Form("H_%s_Events", method_name.c_str()), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + h_xq_eff = BookTH2(Form("H_%s_Efficiency", method_name.c_str()), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + + std::string QrangeName[4] = {"lowQ", "midQ", "highQ", "ultraQ"}; + std::string Qrange[4] = {"Q^{2} #leq 10 (GeV/c^{2})^{2}", "10 (GeV/c^{2})^{2} < Q^{2} #leq 100 (GeV/c^{2})^{2}", "100 (GeV/c^{2})^{2} < Q^{2} #leq 1000 (GeV/c^{2})^{2}", "Q^{2} > 1000 (GeV/c^{2})^{2}"}; + for ( int i = 0; i < 4; i ++ ) + { + h_dq[i] = new TH1F(Form("H_%s_dQ_%s", method_name.c_str(), QrangeName[i].c_str()), Form("%s;(Q^{2}_{reco}-Q^{2}_{true})/Q^{2}_{true};Counts", Qrange[i].c_str()), 100, -1, 1); + h_dx[i] = new TH1F(Form("H_%s_dX_%s", method_name.c_str(), QrangeName[i].c_str()), Form("%s;(x_{reco}-x_{true})/x_{true};Counts", Qrange[i].c_str()), 100, -1, 1); + h_dy[i] = new TH1F(Form("H_%s_dY_%s", method_name.c_str(), QrangeName[i].c_str()), Form("%s;(y_{reco}-y_{true})/y_{true};Counts", Qrange[i].c_str()), 100, -1, 1); + + StyleHist(h_dq[i]); + StyleHist(h_dx[i]); + StyleHist(h_dy[i]); + } + + h_qvq = BookTH2(Form("H_%s_QVQ", method_name.c_str()), Form("%s;Q_{true}^{2} (GeV/c^{2})^{2};Q_{reco}^{2} (GeV/c^{2})^{2}", method_name.c_str()), 200, 0, 4, 200, 0, 4, kLightTemperature); + h_xvx = BookTH2(Form("H_%s_XVX", method_name.c_str()), Form("%s;x_{true};x_{reco}", method_name.c_str()), 100, -4, 0, 100, -4, 0, kLightTemperature); + // h_yvy = BookTH2(Form("H_%s_YVY", method_name.c_str()), Form("%s;y_{true};y_{reco}", method_name.c_str()), 100, -2, 0, 100, -2, 0, kLightTemperature); + h_yvy = new TH2F(Form("H_%s_YVY", method_name.c_str()), Form("%s;y_{true};y_{reco}", method_name.c_str()), 100, 0, 1, 100, 0, 1); + + StyleHist(h_qvq); + StyleHist(h_xvx); + StyleHist(h_yvy); + + std::string YrangeName[6] = {"lowY_lowX", "midY_lowX", "highY_lowX, lowY_highX", "midY_highX", "highY_highX"}; + std::string Yrange[6] = {"0.01 < y #leq 0.035, x #leq 0.025", "0.035 < y #leq 0.2, x #leq 0.025", "0.2 < y < 0.95, x #leq 0.025", "0.01 < y #leq 0.035, x > 0.025", "0.035 < y #leq 0.2, x > 0.025", "0.2 < y < 0.95, x > 0.025"}; + for ( int i = 0; i < 6; i ++ ) + { + h_dq_ycut[i] = new TH1F(Form("H_%s_dQ_%s", method_name.c_str(), YrangeName[i].c_str()), Form("%s;(Q^{2}_{reco}-Q^{2}_{true})/Q^{2}_{true};Counts", Yrange[i].c_str()), 100, -0.5, 0.5); + h_dx_ycut[i] = new TH1F(Form("H_%s_dX_%s", method_name.c_str(), YrangeName[i].c_str()), Form("%s;(x_{reco}-x_{true})/x_{true};Counts", Yrange[i].c_str()), 100, -0.5, 0.5); + h_dy_ycut[i] = new TH1F(Form("H_%s_dY_%s", method_name.c_str(), YrangeName[i].c_str()), Form("%s;(y_{reco}-y_{true})/y_{true};Counts", Yrange[i].c_str()), 100, -0.5, 0.5); + + StyleHist(h_dq_ycut[i]); + StyleHist(h_dx_ycut[i]); + StyleHist(h_dy_ycut[i]); + } +} + +Kinematics::~Kinematics() { +} + +void Kinematics::StyleHist(TH2F* h) +{ + h->SetStats(0); + h->SetLineColor(draw_id); + + h->GetXaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.3); + + h->GetYaxis()->SetTitleOffset(1.6); + h->GetYaxis()->CenterTitle(); + + h->GetXaxis()->SetNdivisions(5); + h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetXaxis()->SetLabelSize(20); + h->GetXaxis()->SetTitleSize(20); + h->GetXaxis()->SetTitleFont(43); + + h->GetYaxis()->SetNdivisions(5); + h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetYaxis()->SetLabelSize(20); + h->GetYaxis()->SetTitleSize(20); + h->GetYaxis()->SetTitleFont(43); +} + +void Kinematics::StyleHist(TH1F* h) +{ + h->SetStats(0); + h->SetLineColor(draw_id); + + h->GetXaxis()->CenterTitle(); + h->GetXaxis()->SetTitleOffset(1.3); + + h->GetYaxis()->SetTitleOffset(1.5); + h->GetYaxis()->CenterTitle(); + + h->GetXaxis()->SetNdivisions(5); + h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetXaxis()->SetLabelSize(20); + h->GetXaxis()->SetTitleSize(20); + h->GetXaxis()->SetTitleFont(43); + + h->GetYaxis()->SetNdivisions(5); + h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) + h->GetYaxis()->SetLabelSize(20); + h->GetYaxis()->SetTitleSize(20); + h->GetYaxis()->SetTitleFont(43); +} + +void Kinematics::Process_and_QA(double mc_xB, double mc_y, double mc_Q2) +{ + if ( xB == -999 ) + return; + + h_xq->Fill(xB, Q2); + + if ( h_xq_eff->GetXaxis()->FindBin(mc_xB) == h_xq_eff->GetXaxis()->FindBin(xB) ) + if ( h_xq_eff->GetYaxis()->FindBin(mc_Q2) == h_xq_eff->GetYaxis()->FindBin(Q2) ) + h_xq_eff->Fill(xB, Q2); + + int Qrange = 0; + if ( mc_Q2 > 1000 ) + Qrange = 3; + else if ( mc_Q2 > 100 ) + Qrange = 2; + else if ( mc_Q2 > 10 ) + Qrange = 1; + + h_dq[Qrange]->Fill((Q2-mc_Q2)/mc_Q2); + h_dx[Qrange]->Fill((xB-mc_xB)/mc_xB); + h_dy[Qrange]->Fill((y-mc_y)/mc_y); + + h_qvq->Fill(mc_Q2, Q2); + h_xvx->Fill(mc_xB, xB); + h_yvy->Fill(mc_y, y); + + int Yrange = xB > 0.025 ? 3 : 0; + if ( y > 0.2 ) + Yrange += 2; + else if ( y > 0.035 ) + Yrange += 1; + + h_dq_ycut[Yrange]->Fill((Q2-mc_Q2)/mc_Q2); + h_dx_ycut[Yrange]->Fill((xB-mc_xB)/mc_xB); + h_dy_ycut[Yrange]->Fill((y-mc_y)/mc_y); + + // if ( y > 0.95 ) + // cout << method_name << " Q2 " << mc_Q2 << " " << Q2 << " xB " << mc_xB << " " << xB << " y " << mc_y << " " << y << endl; + + return; +} + +void Kinematics::save_variables(std::vector reco, double Mp) +{ + xB = reco[0]; + y = reco[1]; + Q2 = reco[2]; + W2 = Mp*Mp + Q2 * (1./xB - 1); + nu = Q2/(2*Mp*xB); +} + +void Kinematics::reset() +{ + xB = -999; + Q2 = -999; + W2 = -999; + y = -999; + nu = -999; +} \ No newline at end of file diff --git a/ElectronID/kinematics.hh b/ElectronID/kinematics.hh new file mode 100644 index 0000000..c1a8c21 --- /dev/null +++ b/ElectronID/kinematics.hh @@ -0,0 +1,51 @@ +#ifndef KINEMATICS_HH +#define KINEMATICS_HH + +#include + +class Kinematics{ + +public: + + Kinematics(std::string method_name, int draw_id); + ~Kinematics(); + + void reset(); + + TH2F* h_xq; + TH2F* h_xq_eff; + + TH1F* h_dq[4]; + TH1F* h_dx[4]; + TH1F* h_dy[4]; + + TH1F* h_dq_ycut[6]; + TH1F* h_dx_ycut[6]; + TH1F* h_dy_ycut[6]; + + TH2F* h_qvq; + TH2F* h_xvx; + TH2F* h_yvy; + + // void fill_histograms(); + // void draw_histograms(); + + float xB; + float Q2; + float W2; + float y; + float nu; + + void StyleHist(TH1F* h); + void StyleHist(TH2F* h); + void Process_and_QA(double mc_xB, double mc_y, double mc_Q2); + void save_variables(std::vector reco, double Mp); + + std::string method_name; + int draw_id; + +private: + +}; + +#endif \ No newline at end of file diff --git a/ElectronID/reconMethod.hh b/ElectronID/reconMethod.hh new file mode 100644 index 0000000..d147f3d --- /dev/null +++ b/ElectronID/reconMethod.hh @@ -0,0 +1,43 @@ +#pragma once + +// electron method +std::vector calc_elec_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { + float Q2 = 2.*E_ebeam*E*(1+TMath::Cos(theta)); + float y = 1. - (E/E_ebeam)*TMath::Sin(theta/2)*TMath::Sin(theta/2); + float x = Q2/(4*E_ebeam*E_pbeam*y); + return {x, y, Q2}; +} + +// jb method +std::vector calc_jb_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { + float y = sigma_h/(2*E_ebeam); + float Q2 = pt_had*pt_had / (1-y); + float x = Q2/(4*E_ebeam*E_pbeam*y); + return {x, y, Q2}; +} + +// double angle method +std::vector calc_da_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { + float alpha_h = sigma_h/pt_had; + float alpha_e = TMath::Tan(theta/2); + float y = alpha_h / (alpha_e + alpha_h); + float Q2 = 4*E_ebeam*E_ebeam / (alpha_e * (alpha_h + alpha_e)); + float x = Q2/(4*E_ebeam*E_pbeam*y); + return {x, y, Q2}; +} + +// sigma method +std::vector calc_sig_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { + float y = sigma_h/(sigma_h + E*(1 - TMath::Cos(theta))); + float Q2 = E*E*TMath::Sin(theta)*TMath::Sin(theta) / (1-y); + float x = Q2/(4*E_ebeam*E_pbeam*y); + return {x, y, Q2}; +} + +// e-sigma method +std::vector calc_esig_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { + float Q2 = 2.*E_ebeam*E*(1+TMath::Cos(theta)); + float x = calc_sig_method(E,theta,pt_had,sigma_h,E_ebeam,E_pbeam)[0]; + float y = Q2/(4*E_ebeam*E_pbeam*x); + return {x, y, Q2}; +} \ No newline at end of file From 2850aff1b8f91efeb0b5dd5f7474142c7f5ee81e Mon Sep 17 00:00:00 2001 From: Win Lin Date: Mon, 22 Sep 2025 16:11:05 +0800 Subject: [PATCH 3/9] add missing file --- ElectronID/drawKinematics.C | 383 ++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 ElectronID/drawKinematics.C diff --git a/ElectronID/drawKinematics.C b/ElectronID/drawKinematics.C new file mode 100644 index 0000000..168fbc2 --- /dev/null +++ b/ElectronID/drawKinematics.C @@ -0,0 +1,383 @@ +#include "InclusiveSkim.h" + +void DefineHistograms() { + + // assume to split to 4 Q2 regions, should make this more flexible + std::string QrangeName[4] = {"lowQ", "midQ", "highQ", "ultraQ"}; + std::string Qrange[4] = {"Q^{2} #leq 10 (GeV/c^{2})^{2}", "10 (GeV/c^{2})^{2} < Q^{2} #leq 100 (GeV/c^{2})^{2}", "100 (GeV/c^{2})^{2} < Q^{2} #leq 1000 (GeV/c^{2})^{2}", "Q^{2} > 1000 (GeV/c^{2})^{2}"}; + for ( int i = 0; i < 4; i ++ ) + { + h_dEc[i] = new TH1F(Form("H_%s_dE_cal", QrangeName[i].c_str()), Form("%s;(Ee_{reco}-Ee_{true})/Ee_{true};Counts", Qrange[i].c_str()), 100, -1, 1); + h_dEt[i] = new TH1F(Form("H_%s_dE_track", QrangeName[i].c_str()), Form("%s;(Ee_{reco}-Ee_{true})/Ee_{true};Counts", Qrange[i].c_str()), 100, -1, 1); + h_dt[i] = new TH1F(Form("H_%s_dtheta", QrangeName[i].c_str()), Form("%s;(e_{reco}-e_{true})/e_{true};Counts", Qrange[i].c_str()), 40, -0.01, 0.01); + h_dp[i] = new TH1F(Form("H_%s_dphi", QrangeName[i].c_str()), Form("%s;(e_{reco}-e_{true})/e_{true};Counts", Qrange[i].c_str()), 40, -0.01, 0.01); + + h_dhf[i] = new TH1F(Form("H_%s_dhf", QrangeName[i].c_str()), Form("%s;(#delta_{h, reco}-#delta_{h, true})/#delta_{h, true};Counts", Qrange[i].c_str()), 100, -2, 2); + h_dpt[i] = new TH1F(Form("H_%s_dpt", QrangeName[i].c_str()), Form("%s;(p_{t, reco}-p_{t, true})/p_{t, true};Counts", Qrange[i].c_str()), 100, -2, 2); + } + + std::string etype[2] = {"cal", "track"}; + for ( int i = 0; i < 2; i ++ ) + { + h_tde[i] = new TH2F(Form("H_dEvT_%s", etype[i].c_str()), Form("dE_{%s} vs #theta_{mc};#theta_{e};dE/E", etype[i].c_str()), 180, 0, 180, 100, -1, 1); + } + h_tdp = new TH2F(Form("H_dPvT"), Form("d#phi vs #theta_{mc};#theta_{e};d#phi/#phi"), 180, 0, 180, 40, -0.01, 0.01); + h_pde = new TH2F(Form("H_dEvP_%s", etype[1].c_str()), Form("dE_{%s} vs p_{mc};p_{t,e};dE/E", etype[1].c_str()), 180, 0, 60, 100, -0.2, 0.2); + h_ede = new TH2F(Form("H_dEvE_%s", etype[0].c_str()), Form("dE_{%s} vs E_{mc};E_{e};dE/E", etype[0].c_str()), 180, 0, 60, 100, -0.2, 0.2); + h_pt = new TH2F(Form("H_PvT_%s", etype[1].c_str()), Form("p_{t,%s} vs #theta_{mc};#theta_{e};p_{t}", etype[1].c_str()), 180, 0, 180, 240, 0, 80); + h_et = new TH2F(Form("H_EvT_%s", etype[0].c_str()), Form("E_{%s} vs #theta_{mc};#theta_{e};E", etype[0].c_str()), 180, 0, 180, 240, 0, 80); + + h_hfs_dpz = new TH1F("H_HFS_dpz", Form(";(p_{z, reco}-p_{z, true})/p_{z, true};Counts"), 100, -1, 1); + h_hfs_dpt = new TH1F("H_HFS_dpt", Form(";(p_{t, reco}-p_{t, true})/p_{t, true};Counts"), 100, -1, 1); + h_hfs_de = new TH1F("H_HFS_de", Form(";(E_{reco}-E_{true})/E_{true};Counts"), 100, -1, 1); + h_hfs_dpz_t = new TH2F("H_HFS_dpz_vT", Form(";#theta_{mc};(p_{z, reco}-p_{z, true})/p_{z, true}"), 180, 0, 180, 100, -1, 1); + h_hfs_dpt_t = new TH2F("H_HFS_dpt_vT", Form(";#theta_{mc};(p_{t, reco}-p_{t, true})/p_{t, true}"), 180, 0, 180, 100, -1, 1); + h_hfs_de_t = new TH2F("H_HFS_de_vT", Form(";#theta_{mc};(E_{reco}-E_{true})/E_{true}"), 180, 0, 180, 100, -1, 1); +} + +void plot_kinematics_qa() +{ + TCanvas* c_eRecon_eff[algorithm.size()-1]; + + TCanvas* c_qa_plots = new TCanvas("c_qa_plots", "QA", 1600, 1400); + c_qa_plots->Divide(4, 3); + + TLegend* leg = new TLegend(0.60, 0.5, 0.88, 0.85); + leg->SetTextSize(0.04); + leg->SetBorderSize(0); + leg->SetFillColor(0); + + for ( int i = 0; i < algorithm.size()-1; i ++ ) + { + process_eff_hist(algorithm[i].h_xq_eff, algorithm[MC].h_xq); + c_eRecon_eff[i] = draw_2d_efficiency(algorithm[i].h_xq_eff, Form("c_%s_eff", algorithm[i].method_name.c_str()), Form("%s Efficiency", algorithm[i].method_name.c_str()), 1400, 600, false, false); + + for ( int j = 0; j < 4; j ++ ) + { + c_qa_plots->cd(j+1); + algorithm[i].h_dq[j]->Draw("HIST SAME"); + + c_qa_plots->cd(j+1+4); + algorithm[i].h_dx[j]->Draw("HIST SAME"); + + c_qa_plots->cd(j+1+8); + algorithm[i].h_dy[j]->Draw("HIST SAME"); + } + leg->AddEntry(algorithm[i].h_dq[0], algorithm[i].method_name.c_str(), "L"); + } + + for ( int i = 0; i < 12; i ++ ) + { + c_qa_plots->cd(i+1); + gPad->SetTickx(1); + gPad->SetTicky(1); + gPad->SetLeftMargin(0.15); + gPad->SetBottomMargin(0.18); + leg->Draw(); + } + + // + + TCanvas* c_ycut_qa = new TCanvas("c_ycut_qa", "QA_YCUT", 1800, 950); + c_ycut_qa->Divide(6, 3); + + double ycut_peak_max[3][6] = {0}; + for ( int i = 0; i < algorithm.size()-1; i ++ ) + { + for ( int j = 0; j < 6; j ++ ) + { + c_ycut_qa->cd(j+1); + algorithm[i].h_dq_ycut[j]->Draw("HIST SAME"); + if ( algorithm[i].h_dq_ycut[j]->GetMaximum() > ycut_peak_max[0][j] ) + ycut_peak_max[0][j] = algorithm[i].h_dq_ycut[j]->GetMaximum(); + + c_ycut_qa->cd(j+1+6); + algorithm[i].h_dx_ycut[j]->Draw("HIST SAME"); + if ( algorithm[i].h_dx_ycut[j]->GetMaximum() > ycut_peak_max[1][j] ) + ycut_peak_max[1][j] = algorithm[i].h_dx_ycut[j]->GetMaximum(); + + c_ycut_qa->cd(j+1+12); + algorithm[i].h_dy_ycut[j]->Draw("HIST SAME"); + if ( algorithm[i].h_dy_ycut[j]->GetMaximum() > ycut_peak_max[2][j] ) + ycut_peak_max[2][j] = algorithm[i].h_dy_ycut[j]->GetMaximum(); + } + } + + for ( int j = 0; j < 6; j ++ ) + { + algorithm[0].h_dq_ycut[j]->GetYaxis()->SetRangeUser(0, ycut_peak_max[0][j]*1.3); + algorithm[0].h_dx_ycut[j]->GetYaxis()->SetRangeUser(0, ycut_peak_max[1][j]*1.3); + algorithm[0].h_dy_ycut[j]->GetYaxis()->SetRangeUser(0, ycut_peak_max[2][j]*1.3); + } + + for ( int i = 0; i < 18; i ++ ) + { + c_ycut_qa->cd(i+1); + gPad->SetTickx(1); + gPad->SetTicky(1); + // gPad->SetRightMargin(0.05); + gPad->SetLeftMargin(0.15); + gPad->SetBottomMargin(0.2); + leg->Draw(); + } + + // + + TCanvas* c_reco_v_true = new TCanvas("c_reco_v_true", "RECO v TRUE", 1800, 1000); + c_reco_v_true->Divide(algorithm.size()-1, 3); + + for ( int i = 0; i < algorithm.size()-1; i ++ ) + { + c_reco_v_true->cd(i+1); + algorithm[i].h_qvq->Draw("COLZ"); + + c_reco_v_true->cd(i+1+(algorithm.size()-1)); + algorithm[i].h_xvx->Draw("COLZ"); + + c_reco_v_true->cd(i+1+2*(algorithm.size()-1)); + algorithm[i].h_yvy->Draw("COLZ"); + } + + for ( int i = 0; i < (algorithm.size()-1)*3; i ++ ) + { + c_reco_v_true->cd(i+1); + gPad->SetLogz(); + if ( i < (algorithm.size()-1)*2 ) + { + gPad->SetLogx(); + gPad->SetLogy(); + } + gPad->SetTickx(1); + gPad->SetTicky(1); + gPad->SetLeftMargin(0.2); + gPad->SetBottomMargin(0.2); + } + + c_reco_v_true->cd(1); + gPad->Update(); + TLine* l_q_diagonal = new TLine(1, 1, 1e4, 1e4); + l_q_diagonal->SetLineColor(kBlack); + l_q_diagonal->SetLineStyle(7); + + c_reco_v_true->cd(1+(algorithm.size()-1)); + gPad->Update(); + TLine* l_x_diagonal = new TLine(1e-4, 1e-4, 1, 1); + l_x_diagonal->SetLineColor(kBlack); + l_x_diagonal->SetLineStyle(7); + + c_reco_v_true->cd(1+2*(algorithm.size()-1)); + gPad->Update(); + TLine* l_y_diagonal = new TLine(0, 0, 1, 1); + l_y_diagonal->SetLineColor(kBlack); + l_y_diagonal->SetLineStyle(7); + + for ( int i = 0; i < algorithm.size()-1; i ++ ) + { + c_reco_v_true->cd(i+1); + l_q_diagonal->Draw("SAME"); + + c_reco_v_true->cd(i+1+(algorithm.size()-1)); + l_x_diagonal->Draw("SAME"); + + c_reco_v_true->cd(i+1+2*(algorithm.size()-1)); + l_y_diagonal->Draw("SAME"); + } + + // save to tree + + c_qa_plots->Write(); + c_reco_v_true->Write(); + c_ycut_qa->Write(); + + for ( int i = 0; i < algorithm.size()-1; i ++ ) + c_eRecon_eff[i]->Write(); +} + +void plot_energy_and_track() +{ + TCanvas* c1 = new TCanvas("c_cal_and_track_1", "Energy and Theta QA", 1600, 800); + c1->Divide(4, 2); + + for ( int i = 0; i < 8; i ++ ) + { + c1->cd(i+1); + gPad->SetTickx(1); + gPad->SetTicky(1); + gPad->SetLeftMargin(0.2); + gPad->SetBottomMargin(0.2); + } + + TLegend* leg = new TLegend(0.60, 0.70, 0.88, 0.85); + leg->SetTextSize(0.04); + leg->SetBorderSize(0); + leg->SetFillColor(0); + leg->SetFillStyle(0); + + leg->AddEntry(h_dEt[0], "Track", "L"); + leg->AddEntry(h_dEc[0], "Calorimeter", "L"); + + TLegend* leg_a = new TLegend(0.70, 0.5, 0.88, 0.85); + leg_a->SetTextSize(0.04); + leg_a->SetBorderSize(0); + leg_a->SetFillColor(0); + leg_a->SetFillStyle(0); + + leg_a->AddEntry(h_dp[0], "#phi_{e}", "L"); + leg_a->AddEntry(h_dt[0], "#theta_{e}", "L"); + + + for ( int i = 0; i < 4; i ++ ) + { + c1->cd(i+1); + h_dEt[i]->Draw("HIST SAME"); + h_dEt[i]->SetStats(0); + h_dEt[i]->SetLineColor(kRed); + format_eid_histogram(h_dEt[i]); + + h_dEc[i]->Draw("HIST SAME"); + h_dEc[i]->SetStats(0); + h_dEc[i]->SetLineColor(kBlue); + format_eid_histogram(h_dEc[i]); + + h_dEt[i]->GetYaxis()->SetRangeUser(0, fmax(h_dEt[i]->GetMaximum(), h_dEc[i]->GetMaximum())*1.1); + h_dEt[i]->SetStats(0); + + leg->Draw(); + + c1->cd(i+1+4); + h_dt[i]->Draw("HIST SAME"); + h_dt[i]->SetStats(0); + format_eid_histogram(h_dt[i]); + + h_dp[i]->Draw("HIST SAME"); + h_dp[i]->SetStats(0); + h_dp[i]->SetLineColor(kRed); + + leg_a->Draw(); + } + + TCanvas* c2 = new TCanvas("c_cal_and_track_2", "Energy and Theta QA", 1200, 900); + c2->Divide(3, 3); + + for ( int i = 0; i < 9; i ++ ) + { + c2->cd(i+1); + gPad->SetTickx(1); + gPad->SetTicky(1); + gPad->SetLogz(); + gPad->SetLeftMargin(0.2); + gPad->SetBottomMargin(0.2); + } + + c2->cd(1); + h_tde[0]->Draw("COLZ"); + h_tde[0]->SetStats(0); + format_eid_histogram(h_tde[0]); + + c2->cd(2); + h_tde[1]->Draw("COLZ"); + h_tde[1]->SetStats(0); + format_eid_histogram(h_tde[1]); + + c2->cd(3); + h_tdp->Draw("COLZ"); + h_tdp->SetStats(0); + format_eid_histogram(h_tdp); + + c2->cd(4); + h_et->Draw("COLZ"); + h_et->SetStats(0); + format_eid_histogram(h_et); + + c2->cd(5); + h_pt->Draw("COLZ"); + h_pt->SetStats(0); + format_eid_histogram(h_pt); + + c2->cd(7); + h_ede->Draw("COLZ"); + h_ede->SetStats(0); + format_eid_histogram(h_ede); + + c2->cd(8); + h_pde->Draw("COLZ"); + h_pde->SetStats(0); + format_eid_histogram(h_pde); + + TCanvas* c3 = new TCanvas("c_cal_and_track_3", "Hadronic final state QA", 1600, 800); + c3->Divide(4, 2); + + for ( int i = 0; i < 8; i ++ ) + { + c3->cd(i+1); + gPad->SetTickx(1); + gPad->SetTicky(1); + gPad->SetLeftMargin(0.2); + gPad->SetBottomMargin(0.2); + } + + for ( int i = 0; i < 4; i ++ ) + { + c3->cd(i+1); + h_dhf[i]->Draw("HIST SAME"); + h_dhf[i]->SetStats(0); + // h_dhf[i]->SetLineColor(kRed); + format_eid_histogram(h_dhf[i]); + + c3->cd(i+1+4); + h_dpt[i]->Draw("HIST SAME"); + h_dpt[i]->SetStats(0); + format_eid_histogram(h_dpt[i]); + } + + TCanvas* c4 = new TCanvas("c_cal_and_track_4", "Hadronic final state QA 2", 1600, 800); + c4->Divide(3, 2); + + for ( int i = 0; i < 6; i ++ ) + { + c4->cd(i+1); + gPad->SetTickx(1); + gPad->SetTicky(1); + gPad->SetLogz(); + gPad->SetLeftMargin(0.2); + gPad->SetBottomMargin(0.2); + } + + c4->cd(1); + h_hfs_dpt->Draw("HIST"); + h_hfs_dpt->SetStats(0); + format_eid_histogram(h_hfs_dpt); + + c4->cd(2); + h_hfs_dpz->Draw("HIST"); + h_hfs_dpz->SetStats(0); + format_eid_histogram(h_hfs_dpz); + + c4->cd(3); + h_hfs_de->Draw("HIST"); + h_hfs_de->SetStats(0); + format_eid_histogram(h_hfs_de); + + c4->cd(4); + h_hfs_dpt_t->Draw("COLZ"); + h_hfs_dpt_t->SetStats(0); + format_eid_histogram(h_hfs_dpt_t); + + c4->cd(5); + h_hfs_dpt_t->Draw("COLZ"); + h_hfs_dpt_t->SetStats(0); + format_eid_histogram(h_hfs_dpt_t); + + c4->cd(6); + h_hfs_de_t->Draw("COLZ"); + h_hfs_de_t->SetStats(0); + format_eid_histogram(h_hfs_de_t); + + // save to tree + c1->Write(); + c2->Write(); + c3->Write(); + c4->Write(); + + return; +} \ No newline at end of file From ad62429703a74861fb4e348cd38d33f245775e31 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Mon, 3 Nov 2025 10:58:58 -0500 Subject: [PATCH 4/9] add read me, new QA macro example, put inclusiveSkim back to original to keep it simple and will add reconExample instead --- ElectronID/ElectronID.cc | 215 ++++++++++++++++++---- ElectronID/ElectronID.hh | 29 ++- ElectronID/InclusiveSkim.C | 341 +++++++++-------------------------- ElectronID/InclusiveSkim.h | 61 ++----- ElectronID/InclusiveSkimQA.C | 237 ++++++++++++++++++++++++ ElectronID/InclusiveSkimQA.h | 45 +++++ ElectronID/README | 9 + ElectronID/constants.h | 4 +- ElectronID/drawKinematics.C | 2 +- ElectronID/ePICStyle.c | 114 ++++++++++++ ElectronID/ePICStyle.h | 22 +++ 11 files changed, 735 insertions(+), 344 deletions(-) create mode 100644 ElectronID/InclusiveSkimQA.C create mode 100644 ElectronID/InclusiveSkimQA.h create mode 100644 ElectronID/README create mode 100644 ElectronID/ePICStyle.c create mode 100644 ElectronID/ePICStyle.h diff --git a/ElectronID/ElectronID.cc b/ElectronID/ElectronID.cc index 1485526..064093e 100644 --- a/ElectronID/ElectronID.cc +++ b/ElectronID/ElectronID.cc @@ -1,7 +1,6 @@ #include "ElectronID.hh" #include "edm4hep/utils/vector_utils.h" -#include "edm4hep/utils/kinematics.h" #include "edm4eic/ClusterCollection.h" #include @@ -50,27 +49,66 @@ ElectronID::~ElectronID() { void ElectronID::SetEvent(const podio::Frame* event) { mEvent = event; + eScatIndex = -1; hfs_dpt.clear(); hfs_dpz.clear(); hfs_de.clear(); hfs_theta.clear(); + e_det.clear(); + pi_det.clear(); + else_det.clear(); } -edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost) { +int ElectronID::Check_eID(edm4eic::ReconstructedParticle e_rec) { + edm4hep::MCParticleCollection meMC = GetMCElectron(); + auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + for(const auto& assoc : RecoMC) { + if(assoc.getRec() == e_rec) + { + if (assoc.getSim() == meMC[0]) + return 0; + else + return assoc.getSim().getPDG(); + } + } + + return 86; +} + +edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool use_mc, int object_id, bool is_print, LorentzRotation boost) { + + // edm4eic::HadronicFinalStateCollection meRecon; edm4eic::ReconstructedParticleCollection meRecon; meRecon->setSubsetCollection(); edm4hep::MCParticleCollection meMiss; meMiss->setSubsetCollection(); + // auto& rcparts = mEvent->get("HadronicFinalState"); auto& rcparts = mEvent->get("ReconstructedParticles"); + // cout << "ef_rc_id after " << object_id << endl; + + if ( is_print ) + cout << " new HFS loop " << endl; + if ( use_mc ) { edm4hep::MCParticleCollection meMC = GetMCElectron(); auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); - + + if ( is_print ) + { + // cout << "scat e\n" << meMC[0] << endl; + PxPyPzEVector v(meMC[0].getMomentum().x, meMC[0].getMomentum().y, meMC[0].getMomentum().z, meMC[0].getEnergy()); + v = boost(v); + cout << "scat e .. " << Form("PDG %d, ", meMC[0].getPDG()) << Form("pt %f, ", v.Pt()) << Form("pz %f, ", v.Z()) << Form("E %f, ", v.E()) << Form("theta %f", v.Theta()) << endl; + } + + // if ( is_print ) + // cout << "hfs selected .. \n" << endl; + for(const auto& assoc : RecoMC) { if(assoc.getSim() != meMC[0] && assoc.getSim().getGeneratorStatus() == 1) @@ -84,11 +122,67 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool hfs_de.push_back((u.E()-v.E())/v.E()); hfs_theta.push_back(v.Theta()*(180./M_PI)); + // if ( (u.Pt()-v.Pt())/v.Pt() > 0.3 || (u.Pt()-v.Pt())/v.Pt() < -0.3 ) + // continue; + + // if ( (u.Z()-v.Z())/v.Z() > 0.3 || (u.Z()-v.Z())/v.Z() < -0.3 ) + // continue; + + // if ( (u.E()-v.E())/v.E() > 0.3 || (u.E()-v.E())/v.E() < -0.3 ) + // continue; + + v = boost(v); u = boost(u); c = boost(c); + // if ( assoc.getSim().getMomentum().z > 0 && assoc.getRec().getMomentum().z < 0 ) + // continue; + + // if ( assoc.getSim().getMomentum().z < 0 && assoc.getRec().getMomentum().z > 0 ) + // continue; + meRecon.push_back(assoc.getRec()); + + if ( is_print ) + { + // cout << "selected ..\n" << assoc.getSim() << endl; + cout << "selected .." << endl; + cout << " MC info .. " << Form("PDG %d, ", assoc.getSim().getPDG()) << Form("pt %f, ", v.Pt()) << Form("pz %f, ", v.Z()) << Form("E %f, ", v.E()) << Form("theta %f", v.Theta()) << endl; + cout << " REC info .. " << Form("PDG %d, ", assoc.getRec().getPDG()) << Form("pt %f, ", u.Pt()) << Form("pz %f, ", u.Z()) << Form("E %f, ", u.E()) << Form("CAL E %f, ", c.E()) << Form("theta %f", u.Theta()) << endl; + } + + } + + // cout << "recon asso " << assoc.getSim().getPDG() << endl; + } + + if ( is_print ) + { + // cout << "hfs missed .. \n" << endl; + + auto& mcparts = mEvent->get("MCParticles"); + for(const auto& mcp : mcparts) + { + if (mcp.getGeneratorStatus() == 1) + { + bool selected = (mcp == meMC[0]); + if ( !selected ) + { + for(const auto& assoc : RecoMC) + if ( mcp == assoc.getSim() ) + selected = true; + } + + if ( !selected ) + { + // cout << "missed ..\n" << mcp << endl; + PxPyPzEVector v(mcp.getMomentum().x, mcp.getMomentum().y, mcp.getMomentum().z, mcp.getEnergy()); + v = boost(v); + cout << "missed .. " << Form("PDG %d, ", mcp.getPDG()) << Form("pt %f, ", v.Pt()) << Form("pz %f, ", v.Z()) << Form("E %f, ", v.E()) << Form("theta %f", v.Theta()) << endl; + } + + } } } } @@ -103,25 +197,6 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool return meRecon; } -edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { - - edm4hep::MCParticleCollection mhMC; - mhMC->setSubsetCollection(); - - auto& mcparts = mEvent->get("MCParticles"); - - std::vector mc_hadronic; - edm4hep::MCParticleCollection meMC = GetMCElectron(); - - bool found_scattered_e = false; - for(const auto& mcp : mcparts) { - if (mcp.getGeneratorStatus() == 1 && mcp.getObjectID().index != meMC[0].getObjectID().index ) - mhMC.push_back(mcp); - } - - return mhMC; -} - edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { // Get all the edm4eic objects needed for electron ID @@ -148,7 +223,15 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { // Note that the rcpart_ variables are set in CalculateParticleValues double recon_EoP = rcpart_sum_cluster_E / edm4hep::utils::magnitude(reconPart.getMomentum()); double recon_isoE = rcpart_sum_cluster_E / rcpart_isolation_E; - + + if ( Check_eID(reconPart) == 0 ) + e_det.push_back({recon_EoP, recon_isoE}); + else if ( Check_eID(reconPart) == -211 ) + pi_det.push_back({recon_EoP, recon_isoE}); + else + else_det.push_back({recon_EoP, recon_isoE}); + + // Apply scattered electron ID cuts if(recon_EoP < mEoP_min || recon_EoP > mEoP_max) continue; if(recon_isoE < mIsoE) continue; @@ -162,28 +245,95 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { } +edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { + + edm4hep::MCParticleCollection mhMC; + mhMC->setSubsetCollection(); + + auto& mcparts = mEvent->get("MCParticles"); + + std::vector mc_hadronic; + edm4hep::MCParticleCollection meMC = GetMCElectron(); + + bool found_scattered_e = false; + for(const auto& mcp : mcparts) { + if (mcp.getGeneratorStatus() == 1 && mcp.getObjectID().index != meMC[0].getObjectID().index ) + mhMC.push_back(mcp); + } + + return mhMC; +} + edm4hep::MCParticleCollection ElectronID::GetMCElectron() { edm4hep::MCParticleCollection meMC; meMC->setSubsetCollection(); - + auto& mcparts = mEvent->get("MCParticles"); + if ( eScatIndex != -1 ) + meMC.push_back(mcparts[eScatIndex]); - std::vector mc_electrons; - + //// for(const auto& mcp : mcparts) { if(mcp.getPDG() == 11 && mcp.getGeneratorStatus() == 1) { - mc_electrons.push_back(mcp); + meMC.push_back(mcp); // For now, just take first electron + break; } } + //// - // For now, just take first electron - if(mc_electrons.size() > 0) { - meMC.push_back(mc_electrons[0]); + // std::vector mc_electrons; +/* + // cout << "new" << endl; + for(const auto& mcp : mcparts) + { + if ( mcp.getGeneratorStatus() == 4 && mcp.getPDG() == 11 ) + { + for (auto md = mcp.daughters_begin(), mend = mcp.daughters_end(); md != mend; ++md) + { + cout << "new daugter " << endl; + int mdIndex = md->getObjectID().index; + auto daughter = mcparts[mdIndex]; + cout << daughter << endl; + + // edm4hep::MCParticle daughter = mcp.getDaughters(0); // copy of mcp + for (auto it = daughter.daughters_begin(), end = daughter.daughters_end(); it != end; ++it) + { + int Index = it->getObjectID().index; + auto dau = mcparts[Index]; + cout << "dau " << endl; + cout << dau << endl; + if ( dau.getGeneratorStatus() == 1 && dau.getPDG() == 11) + { + meMC.push_back(dau); + eScatIndex = Index; + + // cout << dau << endl; + // for (auto dit = dau.parents_begin(), dend = dau.parents_end(); dit != dend; ++dit) + // { + // int dauIndex = dit->getObjectID().index; + // auto dpar = mcparts[dauIndex]; + // cout << dpar << "dau parent" << endl << dpar.getParents(0) << endl; + // } + break; + } + } + } + break; + } } +*/ + // cout << "full e list" << endl; + // for(const auto& mcp : mcparts) + // { + // if ( mcp.getGeneratorStatus() == 1 && mcp.getPDG() == 11) + // { + // cout << mcp << endl; + // } + // } + return meMC; - } edm4eic::ReconstructedParticleCollection ElectronID::GetTruthReconElectron() { @@ -202,11 +352,8 @@ edm4eic::ReconstructedParticleCollection ElectronID::GetTruthReconElectron() { } return meRecon; - } - - void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& rcp, const edm4eic::ReconstructedParticleCollection& rcparts) { diff --git a/ElectronID/ElectronID.hh b/ElectronID/ElectronID.hh index b113022..a214cc8 100644 --- a/ElectronID/ElectronID.hh +++ b/ElectronID/ElectronID.hh @@ -3,15 +3,14 @@ #include "podio/Frame.h" +#include "edm4eic/HadronicFinalStateCollection.h" #include "edm4eic/ReconstructedParticleCollection.h" #include "edm4hep/MCParticleCollection.h" -#include "constants.h" -#include "Beam.h" -#include "Boost.h" - +#include using ROOT::Math::LorentzRotation; + class ElectronID{ public: @@ -27,21 +26,37 @@ public: void SetEvent(const podio::Frame* event); - edm4eic::ReconstructedParticleCollection FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost); - edm4hep::MCParticleCollection GetMCHadronicFinalState(); + int Check_eID(edm4eic::ReconstructedParticle e_rec); + edm4eic::ReconstructedParticleCollection FindHadronicFinalState(bool use_mc, int object_id, bool is_print, LorentzRotation boost); edm4eic::ReconstructedParticleCollection FindScatteredElectron(); edm4eic::ReconstructedParticleCollection GetTruthReconElectron(); edm4hep::MCParticleCollection GetMCElectron(); + edm4hep::MCParticleCollection GetMCHadronicFinalState(); edm4eic::ReconstructedParticle SelectHighestPT(const edm4eic::ReconstructedParticleCollection& rcparts); double GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rcp); void GetBeam(LorentzRotation &boost, TLorentzVector &in_e, TLorentzVector &in_n); + double get_mEoP_min() const { return mEoP_min; } + double get_mEoP_max() const { return mEoP_max; } + double get_mDeltaH_min() const { return mDeltaH_min; } + double get_mDeltaH_max() const { return mDeltaH_max; } + double get_mIsoR() const { return mIsoR; } + double get_mIsoE() const { return mIsoE; } + // for HFS QA vector hfs_dpt; vector hfs_dpz; vector hfs_de; vector hfs_theta; + struct DetValues { + double recon_EoP; + double recon_isoE; + }; + vector e_det; + vector pi_det; + vector else_det; + private: const podio::Frame* mEvent; @@ -64,7 +79,7 @@ private: double rcpart_isolation_E; double rcpart_deltaH; - + int eScatIndex; }; #endif diff --git a/ElectronID/InclusiveSkim.C b/ElectronID/InclusiveSkim.C index d086614..b4b9111 100644 --- a/ElectronID/InclusiveSkim.C +++ b/ElectronID/InclusiveSkim.C @@ -6,7 +6,6 @@ #include "edm4eic/ClusterCollection.h" #include "edm4eic/MCRecoParticleAssociationCollection.h" #include "podio/Frame.h" -// #include "podio/ROOTFrameReader.h" -- for simulation campaign before March 2023 with eic-shell 25.03.2 #include "podio/ROOTReader.h" // ROOT headers @@ -18,48 +17,31 @@ // Analysis headers #include "InclusiveSkim.h" -#include "drawKinematics.C" +#include "ElectronID.cc" void InclusiveSkim() { - // Set beam energy double Ee = 10.; double Eh = 100.; - // Set what electron ID to use - int eID_type = truthID; - // access local file // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; // access remote file vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; - // auto reader = podio::ROOTFrameReader(); auto reader = podio::ROOTReader(); reader.openFiles(inFiles); - // setup eid ElectronID* eFinder = new ElectronID(Ee, Eh); - // setup kinematic algorithms - algorithm.push_back(Kinematics("E_Method", 2)); // electron method - algorithm.push_back(Kinematics("JB_Method", 4)); // Jacquet-Blondel method - algorithm.push_back(Kinematics("DA_Method", 1)); // Double-Angle method - algorithm.push_back(Kinematics("Sig_Method", kOrange+1)); // Sigma method - algorithm.push_back(Kinematics("ESig_Method", kGreen+3)); // E-Sigma method - algorithm.push_back(Kinematics("MC", kGray)); // MC info - - // setup output file and histograms TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); CreateOutputTree(outFileName); - DefineHistograms(); - // loop events + for(size_t ev = 0; ev < reader.getEntries("events"); ev++) { - if(ev%1000==0) - cout << "Event " << ev << "/" << reader.getEntries("events") << endl; + if(ev%1000==0) cout << "Event " << ev << "/" << reader.getEntries("events") << endl; ResetVariables(); @@ -69,231 +51,57 @@ void InclusiveSkim() { edm4hep::MCParticleCollection e_mc = eFinder->GetMCElectron(); // Skip events without scattered MC electron - if(e_mc.size() == 0) - continue; + if(e_mc.size() == 0) continue; - // Set boost and get incoming particles - TLorentzVector in_e; - TLorentzVector in_n; - LorentzRotation boost; - eFinder->GetBeam(boost, in_e, in_n); - in_e = boost(in_e); - in_n =boost(in_n); - - // Calculate kinematic variables using MC electron - TLorentzVector kprime; - kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, Me); - TLorentzVector true_e_lab = kprime; - kprime = boost(kprime); // boost back to head-on frame - - // Get momentum vector elements from MC electron - mc_p = edm4hep::utils::magnitude(e_mc[0].getMomentum()); - mc_eta = edm4hep::utils::eta(e_mc[0].getMomentum()); - mc_phi = edm4hep::utils::angleAzimuthal(e_mc[0].getMomentum()); - - // Don't have to boost if we are just calulcating x, Q2, y using e method because they are Lorentz invariant - // But since we boosted the outgoing ones earlier for later analysis, we need to boost the incoming ones as well - CalculateRealElectronKinematics(in_e, in_n, kprime, algorithm[MC]); - - if ( !pass_ke_cut(algorithm[MC]) ) - continue; - - // Set Range for plots - int Qrange = 0; - if ( algorithm[MC].Q2 > 1000 ) - Qrange = 3; - else if ( algorithm[MC].Q2 > 100 ) - Qrange = 2; - else if ( algorithm[MC].Q2 > 10 ) - Qrange = 1; - - // Find scattered electrons using mc association - auto e_truth = eFinder->GetTruthReconElectron(); - - // Find scattered electrons using detector information + // Find scattered electrons auto e_candidates = eFinder->FindScatteredElectron(); edm4eic::ReconstructedParticle e_rec; - - // If there are multiple candidates, select one with highest pT + // If there are multiple candidates, + // select one with highest pT if(e_candidates.size() > 0) { positive_eID = 1; e_rec = eFinder->SelectHighestPT(e_candidates); } - // select which eID we are using - PxPyPzEVector scat_ele(0, 0, 0, -1); - if ( eID_type == truthID ) { - if(e_truth.size() < 1) - continue; - - scat_ele.SetPxPyPzE(e_truth[0].getMomentum().x, e_truth[0].getMomentum().y, e_truth[0].getMomentum().z, e_truth[0].getEnergy()); - } - else if ( eID_type == mcID ) { - scat_ele = true_e_lab; - } - else { - if(!positive_eID) - continue; + // Get momentum vector elements from MC electron + mc_p = edm4hep::utils::magnitude(e_mc[0].getMomentum()); + mc_eta = edm4hep::utils::eta(e_mc[0].getMomentum()); + mc_phi = edm4hep::utils::angleAzimuthal(e_mc[0].getMomentum()); - scat_ele.SetPxPyPzE(e_rec.getMomentum().x, e_rec.getMomentum().y, e_rec.getMomentum().z, e_rec.getEnergy()); - } + // Calculate kinematic variables using MC electron + TLorentzVector kprime; + kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, Me); + CalculateElectronKinematics(Ee, Eh, kprime, mc_xB, mc_Q2, mc_W, mc_y, mc_nu); - PxPyPzEVector rec_e_lab = scat_ele; - if( eID_type!=2 ) - { - // Calculate kinematics using track info only - kprime.SetXYZM(rec_e_lab.Px(), rec_e_lab.Py(), rec_e_lab.Pz(), Me); - TLorentzVector track_kprime = kprime; - h_dEt[Qrange]->Fill((track_kprime.E()-true_e_lab.E())/true_e_lab.E()); - h_dt[Qrange]->Fill((track_kprime.Theta()-true_e_lab.Theta())/true_e_lab.Theta()); - h_dp[Qrange]->Fill((track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); - h_tde[1]->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); - h_tdp->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); - h_pde->Fill(true_e_lab.Pt(), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); - h_pt->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.Pt()); - - // Calculate kinematics using track + cluster energy - TVector3 e3v = kprime.Vect(); + // If electron was identified, get vector elements + // and kinematic variables from reconstructed particle + if(positive_eID) { + track_p = edm4hep::utils::magnitude(e_rec.getMomentum()); + track_eta = edm4hep::utils::eta(e_rec.getMomentum()); + track_phi = edm4hep::utils::angleAzimuthal(e_rec.getMomentum()); - double track_clust_E; - if ( eID_type == truthID ) - track_clust_E = eFinder->GetCalorimeterEnergy(e_truth[0]); - else if ( eID_type == mcID ) - track_clust_E = e_mc[0].getEnergy(); - else - track_clust_E = eFinder->GetCalorimeterEnergy(e_rec); + kprime.SetXYZM(e_rec.getMomentum().x, e_rec.getMomentum().y, e_rec.getMomentum().z, Me); + CalculateElectronKinematics(Ee, Eh, kprime, e_track_xB, e_track_Q2, e_track_W, e_track_y, e_track_nu); + // Calculate kinematic variables with calorimeter energy + TVector3 e3v = kprime.Vect(); + double track_clust_E = eFinder->GetCalorimeterEnergy(e_rec); e3v.SetMag(track_clust_E); kprime.SetVectM(e3v, Me); - h_dEc[Qrange]->Fill((track_clust_E-true_e_lab.E())/true_e_lab.E()); - h_tde[0]->Fill(true_e_lab.Theta()*(180./M_PI), (track_clust_E-true_e_lab.E())/true_e_lab.E()); - h_ede->Fill(true_e_lab.E(), (track_clust_E-true_e_lab.E())/true_e_lab.E()); - h_et->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.E()); - - TLorentzVector calo_kprime = kprime; - - // // cut example - // if ( algorithm[MC].Q2 > 100 ) - // scat_ele = calo_kprime; - } - - scat_ele = boost(scat_ele); - float theta = scat_ele.Theta(); - float E = scat_ele.E(); - - // Find hadronic final state - double pxsum = 0; - double pysum = 0; - double pzsum = 0; - double Esum = 0; - - // MC and Rec data structure are different.. not sure how to not repeat code here - auto mc_hfsCollection = eFinder->GetMCHadronicFinalState(); - for (const auto p : mc_hfsCollection) { - // Lorentz vector in lab frame - PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); - // Boost to colinear frame - hf = boost(hf); - - pxsum += hf.Px(); - pysum += hf.Py(); - pzsum += hf.Pz(); - Esum += hf.E(); - } - double true_sigma_h = Esum - pzsum; - double true_pt_had = sqrt(pxsum*pxsum + pysum*pysum); - - pxsum = 0; - pysum = 0; - pzsum = 0; - Esum = 0; - - auto hfsCollection = eFinder->FindHadronicFinalState(eID_type, e_rec.getObjectID().index, boost); - for (const auto p : hfsCollection) { - // Lorentz vector in lab frame - // double track_clust_E = eFinder->GetCalorimeterEnergy(p); - // cout << "energy " << track_clust_E << " " << p.getEnergy() << " " << track_clust_E - p.getEnergy() << endl; - PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); - // PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, track_clust_E); - // Boost to colinear frame - hf = boost(hf); - - pxsum += hf.Px(); - pysum += hf.Py(); - pzsum += hf.Pz(); - Esum += hf.E(); - } + CalculateElectronKinematics(Ee, Eh, kprime, e_clust_xB, e_clust_Q2, e_clust_W, e_clust_y, e_clust_nu); + } - double sigma_h = Esum - pzsum; - double pt_had = sqrt(pxsum*pxsum + pysum*pysum); - - for ( int i = 0; i < eFinder->hfs_dpt.size(); i++ ) - { - h_hfs_dpt->Fill(eFinder->hfs_dpt[i]); - h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpt[i]); - } - - for ( int i = 0; i < eFinder->hfs_dpz.size(); i++ ) - { - h_hfs_dpz->Fill(eFinder->hfs_dpz[i]); - h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpz[i]); - } - - for ( int i = 0; i < eFinder->hfs_de.size(); i++ ) - { - h_hfs_de->Fill(eFinder->hfs_de[i]); - h_hfs_de_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_de[i]); - } - - if ( eID_type == mcID ) - { - sigma_h = true_sigma_h; - pt_had = true_pt_had; - } - - // Calculate kinematics - - // example cut - // if ( abs((scat_ele.E() - true_e_lab.E())/true_e_lab.E()) > 0.2 ) - // return; - - if ( E > 0 ) - algorithm[EL].save_variables(calc_elec_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - - if ( hfsCollection.size() != 0 ) - { - h_dhf[Qrange]->Fill((sigma_h-true_sigma_h)/true_sigma_h); - h_dpt[Qrange]->Fill((pt_had-true_pt_had)/true_pt_had); - - algorithm[JB].save_variables(calc_jb_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - - if ( E > 0 ) - { - algorithm[DA].save_variables(calc_da_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - algorithm[SIG].save_variables(calc_sig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - algorithm[ESIG].save_variables(calc_esig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - } - } - - algorithm[MC].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); - for ( int i = 0; i < algorithm.size()-1; i ++ ) - algorithm[i].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); - outTree->Fill(); + } outFile->cd(); outTree->Write(outTree->GetName(), 2); - plot_energy_and_track(); - plot_kinematics_qa(); - - // outFile->Close(); - - return; } + void CreateOutputTree(TString outFileName) { outFile = new TFile(outFileName, "RECREATE"); @@ -301,32 +109,38 @@ void CreateOutputTree(TString outFileName) { outTree->Branch("positive_eID", &positive_eID); - // Create branches for each algorithm - for ( int i = 0; i < algorithm.size(); i ++ ) - { - outTree->Branch(Form("%s_xB", algorithm[i].method_name.c_str()), &algorithm[i].xB); - outTree->Branch(Form("%s_Q2", algorithm[i].method_name.c_str()), &algorithm[i].Q2); - outTree->Branch(Form("%s_y", algorithm[i].method_name.c_str()), &algorithm[i].y); - outTree->Branch(Form("%s_nu", algorithm[i].method_name.c_str()), &algorithm[i].nu); - outTree->Branch(Form("%s_W2", algorithm[i].method_name.c_str()), &algorithm[i].W2); - } - outTree->Branch("mc_p", &mc_p); outTree->Branch("mc_eta", &mc_eta); outTree->Branch("mc_phi", &mc_phi); outTree->Branch("track_p", &track_p); - outTree->Branch("track_eta", &track_eta); - outTree->Branch("track_phi", &track_phi); + outTree->Branch("track_eta", &track_eta); + outTree->Branch("track_phi", &track_phi); + + outTree->Branch("mc_xB", &mc_xB); + outTree->Branch("mc_Q2", &mc_Q2); + outTree->Branch("mc_W", &mc_W); + outTree->Branch("mc_y", &mc_y); + outTree->Branch("mc_nu", &mc_nu); + + outTree->Branch("e_track_xB", &e_track_xB); + outTree->Branch("e_track_Q2", &e_track_Q2); + outTree->Branch("e_track_W", &e_track_W); + outTree->Branch("e_track_y", &e_track_y); + outTree->Branch("e_track_nu", &e_track_nu); + + outTree->Branch("e_clust_xB", &e_clust_xB); + outTree->Branch("e_clust_Q2", &e_clust_Q2); + outTree->Branch("e_clust_W", &e_clust_W); + outTree->Branch("e_clust_y", &e_clust_y); + outTree->Branch("e_clust_nu", &e_clust_nu); + } void ResetVariables() { positive_eID = 0; - for ( auto &v : algorithm ) - v.reset(); - mc_p = -999; mc_eta = -999; mc_phi = -999; @@ -334,20 +148,41 @@ void ResetVariables() { track_p = -999; track_eta = -999; track_phi = -999; + + mc_xB = -999; + mc_Q2 = -999; + mc_W = -999; + mc_y = -999; + mc_nu = -999; + e_track_xB = -999; + e_track_Q2 = -999; + e_track_W = -999; + e_track_y = -999; + e_track_nu = -999; + + e_clust_xB = -999; + e_clust_Q2 = -999; + e_clust_W = -999; + e_clust_y = -999; + e_clust_nu = -999; + + } -// mc kinematics for comparison - use real incident particle kinematics -void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v) { - // input is boosted - TLorentzVector q = ki - kf; - v.Q2 = -(q.Dot(q)); - v.nu = (q.Dot(P))/Mp; - v.xB = v.Q2/(2.*Mp*v.nu); - v.y = (q.Dot(P))/(ki.Dot(P)); - v.W2 = (Mp*Mp + (2.*Mp*v.nu) - v.Q2); +void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, float& xB, float& Q2, float& W, float& y, float& nu) { + + TLorentzVector ki; ki.SetXYZM(0., 0., -fEe, Me); + TLorentzVector P = GetHadronBeam(fEh); + TLorentzVector q = ki - kf; + Q2 = -(q.Dot(q)); + nu = (q.Dot(P))/Mp; + xB = Q2/(2.*Mp*nu); + y = (q.Dot(P))/(ki.Dot(P)); + W = sqrt(Mp*Mp + (2.*Mp*nu) - Q2); } + TLorentzVector GetHadronBeam(double fEh) { TLorentzVector hadron_beam; @@ -357,18 +192,4 @@ TLorentzVector GetHadronBeam(double fEh) { hadron_beam.SetE(std::hypot(fEh, Mp)); return hadron_beam; -} - -bool pass_ke_cut(Kinematics v) -{ - if ( v.y <= 0.01 || v.y >= 0.95 ) - return false; - - if ( v.Q2 < 2 ) - return false; - - if ( v.W2 < 4 ) - return false; - - return true; } \ No newline at end of file diff --git a/ElectronID/InclusiveSkim.h b/ElectronID/InclusiveSkim.h index 633fffd..8ec7824 100644 --- a/ElectronID/InclusiveSkim.h +++ b/ElectronID/InclusiveSkim.h @@ -1,12 +1,3 @@ -// Analysis headers -#include "ElectronID.cc" -#include "kinematics.cc" -#include "draw_helper.h" -#include "reconMethod.hh" -#include "constants.h" - -#pragma once - TFile* outFile = NULL; TTree* outTree = NULL; @@ -14,45 +5,15 @@ const double Me = 0.511e-3; // GeV const double Mp = 0.938272; // GeV const double crossing_angle = -0.025; // rad -// QA histograms -TH1F* h_dEc[4]; -TH1F* h_dEt[4]; -TH1F* h_dt[4]; -TH1F* h_dp[4]; -TH2F* h_tde[2]; -TH2F* h_tdp; -TH2F* h_pde; -TH2F* h_ede; -TH2F* h_pt; -TH2F* h_et; - -TH1F* h_dhf[4]; -TH1F* h_dpt[4]; - -TH1F* h_hfs_dpz; -TH1F* h_hfs_dpt; -TH1F* h_hfs_de; -TH2F* h_hfs_dpz_t; -TH2F* h_hfs_dpt_t; -TH2F* h_hfs_de_t; - -enum {EL, JB, DA, SIG, ESIG, MC}; -enum {reconID, truthID, mcID}; - void SetInputBranchAddresses(); void CreateOutputTree(TString outFileName); void ResetVariables(); -void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v); +void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, float& xB, float& Q2, float& W, float& y, float& nu); TLorentzVector GetHadronBeam(double fEh); -void DefineHistograms(); -void plot_kinematics_qa(); -void plot_energy_and_track(); -bool pass_ke_cut(Kinematics v); using namespace std; int positive_eID; -vector algorithm; float mc_p; float mc_eta; @@ -60,4 +21,22 @@ float mc_phi; float track_p; float track_eta; -float track_phi; \ No newline at end of file +float track_phi; + +float mc_xB; +float mc_Q2; +float mc_W; +float mc_y; +float mc_nu; + +float e_track_xB; +float e_track_Q2; +float e_track_W; +float e_track_y; +float e_track_nu; + +float e_clust_xB; +float e_clust_Q2; +float e_clust_W; +float e_clust_y; +float e_clust_nu; diff --git a/ElectronID/InclusiveSkimQA.C b/ElectronID/InclusiveSkimQA.C new file mode 100644 index 0000000..a30d3fb --- /dev/null +++ b/ElectronID/InclusiveSkimQA.C @@ -0,0 +1,237 @@ +// Find inclusive scattered electrons + +#include "InclusiveSkimQA.h" + +void InclusiveSkimQA() +{ + // Standard setup + + SetePICStyle(); + + double Ee = 10.; + double Eh = 100.; + + // Set what electron ID to use + int eID_type = truthID; + + // access local file + // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; + + // access remote file + vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; + + // .. input setup + auto reader = podio::ROOTReader(); + reader.openFiles(inFiles); + + // .. output setup; + TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); + CreateOutputTree(outFileName); + + // .. ElectronID setup + ElectronID* eFinder = new ElectronID(Ee, Eh); + + DefineHistograms(); + + // Analysis loop + + for( size_t ev = 0; ev < reader.getEntries("events"); ev++ ) + { + const auto event = podio::Frame(reader.readNextEntry("events")); + eFinder->SetEvent(&event); + + if(ev%100==0) + cout << "Analysing event " << ev << "/" << reader.getEntries("events") << std::endl; + + // Generator information (mcID) + edm4hep::MCParticleCollection e_mc = eFinder->GetMCElectron(); + + // Use MC to find reconstructed electron (TruthID) + auto e_truth = eFinder->GetTruthReconElectron(); + + // Find scattered electrons (reconID) + auto e_candidates = eFinder->FindScatteredElectron(); + edm4eic::ReconstructedParticle e_rec; + + // If there are multiple candidates, select one with highest pT + if(e_candidates.size() > 0) + { + e_rec = eFinder->SelectHighestPT(e_candidates); + mc_PBG = eFinder->Check_eID(e_rec); + + if ( mc_PBG == 0 ) + eID_status = FOUND_E; + else if ( mc_PBG == -211 ) + eID_status = FOUND_PI; + else + eID_status = FOUND_OTHERS; + } + + // Fill histograms + for ( const auto& det_val : eFinder->e_det ) + { + h_EoP_e->Fill(det_val.recon_EoP); + h_isoE_e->Fill(det_val.recon_isoE); + } + for ( const auto& det_val : eFinder->pi_det ) + { + h_EoP_pi->Fill(det_val.recon_EoP); + h_isoE_pi->Fill(det_val.recon_isoE); + } + for ( const auto& det_val : eFinder->else_det ) + { + h_EoP_else->Fill(det_val.recon_EoP); + h_isoE_else->Fill(det_val.recon_isoE); + } + + // Calculate kinematic variables using MC electron + TLorentzVector kprime; + kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, MASS_ELECTRON); + CalculateElectronKinematics(Ee, Eh, kprime, mc_xB, mc_Q2, mc_W2, mc_y, mc_nu); + + outTree->Fill(); + ResetVariables(); + } + + // Canvas + double draw_max = 0.; + + TCanvas* c_EoP = new TCanvas("c_EoP", "c_EoP", 1000, 600); + c_EoP->SetLogy(); + + DrawComparison(c_EoP, h_EoP_e, h_EoP_pi, h_EoP_else, draw_max); + + c_EoP->cd(); + c_EoP->Update(); + + TLine* line_EoP_min = new TLine(eFinder->get_mEoP_min(), 0, eFinder->get_mEoP_min(), draw_max); + line_EoP_min->SetLineColor(kBlack); + line_EoP_min->SetLineStyle(7); + line_EoP_min->Draw("SAME"); + TLine* line_EoP_max = new TLine(eFinder->get_mEoP_max(), 0, eFinder->get_mEoP_max(), draw_max); + line_EoP_max->SetLineColor(kBlack); + line_EoP_max->SetLineStyle(7); + line_EoP_max->Draw("SAME"); + + TCanvas* c_isoE = new TCanvas("c_isoE", "c_isoE", 1000, 600); + c_isoE->SetLogy(); + + DrawComparison(c_isoE, h_isoE_e, h_isoE_pi, h_isoE_else, draw_max); + c_isoE->cd(); + c_isoE->Update(); + + TLine* line_isoE_min = new TLine(eFinder->get_mIsoE(), 0, eFinder->get_mIsoE(), draw_max); + line_isoE_min->SetLineColor(kBlack); + line_isoE_min->SetLineStyle(7); + line_isoE_min->Draw("SAME"); + + // Save + + outFile->cd(); + outTree->Write(outTree->GetName(), 2); + + c_EoP->Write(c_EoP->GetName(), 2); + c_isoE->Write(c_isoE->GetName(), 2); + + return; +} + +void DefineHistograms() { + + h_EoP_e = new TH1D("h_EoP_e", "EoP e; E/p; Counts", 100, 0., 2.); + h_EoP_pi = new TH1D("h_EoP_pi", "EoP pi; E/p; Counts", 100, 0., 2.); + h_EoP_else = new TH1D("h_EoP_else", "EoP; E/p; Counts", 100, 0., 2.); + + h_isoE_e = new TH1D("h_isoE_e", "Isolation Energy; Iso. E; Counts", 100, 0., 2.); + h_isoE_pi = new TH1D("h_isoE_pi", "Isolation Energy; Iso. E; Counts", 100, 0., 2.); + h_isoE_else = new TH1D("h_isoE_else", "Isolation Energy; Iso. E; Counts", 100, 0., 2.); + + return; +} + +void DrawComparison(TCanvas* c, TH1D* &h1, TH1D* &h2, TH1D* &h3, double &draw_max) { + + c->cd(); + + h3->Draw("HIST"); + h3->SetLineColor(kGray+2); + // h3->SetFillColor(kGray); + // h3->SetFillStyle(3003); + draw_max = 1.2*std::max({h1->GetMaximum(), h2->GetMaximum(), h3->GetMaximum()}); + h3->SetMaximum(draw_max); + + h2->Draw("HIST SAME"); + h2->SetLineColor(kBlue); + // h2->SetFillColor(kBlue); + // h2->SetFillStyle(3003); + + h1->Draw("HIST SAME"); + h1->SetLineWidth(2); + h1->SetLineColor(kRed); + h1->SetFillColor(kRed); + h1->SetFillStyle(3003); + + TLegend* leg = new TLegend(0.6, 0.6, 0.88, 0.88); + leg->SetBorderSize(0); + leg->SetFillStyle(0); + leg->AddEntry(h1, "Electrons", "f"); + leg->AddEntry(h2, "Pions", "f"); + leg->AddEntry(h3, "Others", "f"); + leg->Draw(); + + return; +} + +void CreateOutputTree(TString outFileName) { + + outFile = new TFile(outFileName, "RECREATE"); + outTree = new TTree("T_eID", "T_eID"); + + outTree->Branch("eID_status", &eID_status); + outTree->Branch("mc_PBG", &mc_PBG); + + outTree->Branch("mc_xB", &mc_xB); + outTree->Branch("mc_Q2", &mc_Q2); + outTree->Branch("mc_W2", &mc_W2); + outTree->Branch("mc_y", &mc_y); + outTree->Branch("mc_nu", &mc_nu); + + return; +} + +void ResetVariables() { + + eID_status = NO_FOUND; + mc_PBG = 0; + + mc_xB = -999; + mc_Q2 = -999; + mc_W2 = -999; + mc_y = -999; + mc_nu = -999; + + return; +} + +void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, double& xB, double& Q2, double& W2, double& y, double& nu) { + + TLorentzVector ki; ki.SetXYZM(0., 0., -fEe, MASS_ELECTRON); + TLorentzVector P = GetHadronBeam(fEh); + TLorentzVector q = ki - kf; + Q2 = -(q.Dot(q)); + nu = (q.Dot(P))/MASS_PROTON; + xB = Q2/(2.*MASS_PROTON*nu); + y = (q.Dot(P))/(ki.Dot(P)); + W2 = MASS_PROTON*MASS_PROTON + (2.*MASS_PROTON*nu) - Q2; +} + +TLorentzVector GetHadronBeam(double fEh) { + + TLorentzVector hadron_beam; + hadron_beam.SetX(fEh*sin(CROSSING_ANGLE)); + hadron_beam.SetY(0.); + hadron_beam.SetZ(fEh*cos(CROSSING_ANGLE)); + hadron_beam.SetE(std::hypot(fEh, MASS_PROTON)); + return hadron_beam; + +} \ No newline at end of file diff --git a/ElectronID/InclusiveSkimQA.h b/ElectronID/InclusiveSkimQA.h new file mode 100644 index 0000000..be2310f --- /dev/null +++ b/ElectronID/InclusiveSkimQA.h @@ -0,0 +1,45 @@ +#ifndef EIDANA_H +#define EIDANA_H + +#include "podio/Frame.h" +#include "podio/ROOTReader.h" + +#include "constants.h" +#include "ePICStyle.c" + +#include "ElectronID.cc" + +void InclusiveSkimQA(); +void CreateOutputTree(TString outFileName); +void ResetVariables(); + +void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, double& xB, double& Q2, double& W2, double& y, double& nu); +TLorentzVector GetHadronBeam(double fEh); + +void DefineHistograms(); +void DrawComparison(TCanvas* c, TH1D* &h1, TH1D* &h2, TH1D* &h3, double& draw_max); + +TFile* outFile; +TTree* outTree; +// ElectronID* eFinder; + +int eID_status; +int mc_PBG; + +double mc_xB; +double mc_Q2; +double mc_y; +double mc_W2; +double mc_nu; + +enum { NO_FOUND, FOUND_E, FOUND_PI, FOUND_OTHERS }; +enum {reconID, truthID, mcID}; + +TH1D* h_EoP_e; +TH1D* h_EoP_pi; +TH1D* h_EoP_else; +TH1D* h_isoE_e; +TH1D* h_isoE_pi; +TH1D* h_isoE_else; + +#endif \ No newline at end of file diff --git a/ElectronID/README b/ElectronID/README new file mode 100644 index 0000000..ed61f31 --- /dev/null +++ b/ElectronID/README @@ -0,0 +1,9 @@ +Three example ROOT macros are provided as examples on how to include the Electron Finder in your analysis. They can also be run to get a ROOT tree with the scattered electrons. + +To run any of them, modify the beam setting, input files, and the type of electronID you want in the beginning of the file. Then run the ROOT macro in eic-shell. + +- InclusvieSkim.C: Simple example on how to call the various functions in the electron library. Kinematics calculated using tracking and calorimeter information are also saved to the tree. + +- InclusiveQA.C: Simple example on saving the scattered electrons to the output tree. QA plots for the cuts applied are made. + +- ReconExample.C: Longer example for also testing the kinematic reconstruction using various algorithms. diff --git a/ElectronID/constants.h b/ElectronID/constants.h index b62f090..62a8073 100644 --- a/ElectronID/constants.h +++ b/ElectronID/constants.h @@ -7,4 +7,6 @@ // PDG code #define ID_ELECTRON 11 #define ID_PROTON 2212 -#define ID_NEUTRON 2112 \ No newline at end of file +#define ID_NEUTRON 2112 + +#define CROSSING_ANGLE -0.025 // rad \ No newline at end of file diff --git a/ElectronID/drawKinematics.C b/ElectronID/drawKinematics.C index 168fbc2..87db218 100644 --- a/ElectronID/drawKinematics.C +++ b/ElectronID/drawKinematics.C @@ -1,4 +1,4 @@ -#include "InclusiveSkim.h" +#include "ReconExample.h" void DefineHistograms() { diff --git a/ElectronID/ePICStyle.c b/ElectronID/ePICStyle.c new file mode 100644 index 0000000..14ff6b2 --- /dev/null +++ b/ElectronID/ePICStyle.c @@ -0,0 +1,114 @@ +// +// ePIC Style, based on a style file from BaBar, v0.1 +// + +#include +#include "ePICStyle.h" +#include "TROOT.h" + +void SetePICStyle () +{ + static TStyle* epicStyle = 0; + std::cout << "ePICStyle: Applying nominal settings." << std::endl ; + if ( epicStyle==0 ) epicStyle = ePICStyle(); + gROOT->SetStyle("ePIC"); + gROOT->ForceStyle(); +} + +TStyle* ePICStyle() +{ + TStyle *ePICStyle = new TStyle("ePIC","ePIC style"); + + // use plain black on white colors + Int_t icol=0; // WHITE + ePICStyle->SetFrameBorderMode(icol); + ePICStyle->SetFrameFillColor(icol); + ePICStyle->SetCanvasBorderMode(icol); + ePICStyle->SetCanvasColor(icol); + ePICStyle->SetPadBorderMode(icol); + ePICStyle->SetPadColor(icol); + ePICStyle->SetStatColor(icol); + //ePICStyle->SetFillColor(icol); // don't use: white fill color for *all* objects + + // set the paper & margin sizes + ePICStyle->SetPaperSize(20,26); + + // set margin sizes + ePICStyle->SetPadTopMargin(0.05); + ePICStyle->SetPadRightMargin(0.18); + ePICStyle->SetPadBottomMargin(0.16); + ePICStyle->SetPadLeftMargin(0.15); + + // set title offsets (for axis label) + ePICStyle->SetTitleXOffset(1.4); + ePICStyle->SetTitleYOffset(1.2); + ePICStyle->SetTitleOffset(1.2,"z"); // Set the offset for Z axis titles expliticly to avoid it being cut off + + // use large fonts + //Int_t font=72; // Helvetica italics + Int_t font=42; // Helvetica + Double_t tsize=0.05; + ePICStyle->SetTextFont(font); + + ePICStyle->SetTextSize(tsize); + ePICStyle->SetLabelFont(font,"x"); + ePICStyle->SetTitleFont(font,"x"); + ePICStyle->SetLabelFont(font,"y"); + ePICStyle->SetTitleFont(font,"y"); + ePICStyle->SetLabelFont(font,"z"); + ePICStyle->SetTitleFont(font,"z"); + + ePICStyle->SetLabelSize(tsize,"x"); + ePICStyle->SetTitleSize(tsize,"x"); + ePICStyle->SetLabelSize(tsize,"y"); + ePICStyle->SetTitleSize(tsize,"y"); + ePICStyle->SetLabelSize(tsize,"z"); + ePICStyle->SetTitleSize(tsize,"z"); + + // use bold lines and markers + ePICStyle->SetMarkerStyle(20); + ePICStyle->SetMarkerSize(1.2); + ePICStyle->SetHistLineWidth(2.); + ePICStyle->SetLineStyleString(2,"[12 12]"); // postscript dashes + + // get rid of X error bars + //ePICStyle->SetErrorX(0.001); + // get rid of error bar caps + ePICStyle->SetEndErrorSize(0.); + + // do not display any of the standard histogram decorations + ePICStyle->SetOptTitle(0); + //ePICStyle->SetOptStat(1111); + ePICStyle->SetOptStat(0); + //ePICStyle->SetOptFit(1111); + ePICStyle->SetOptFit(0); + + // put tick marks on top and RHS of plots + ePICStyle->SetPadTickX(1); + ePICStyle->SetPadTickY(1); + + // legend modification + ePICStyle->SetLegendBorderSize(0); + ePICStyle->SetLegendFillColor(0); + ePICStyle->SetLegendFont(font); + +#if ROOT_VERSION_CODE >= ROOT_VERSION(6,00,0) + std::cout << "ePICStyle: ROOT6 mode" << std::endl; + ePICStyle->SetLegendTextSize(tsize); + ePICStyle->SetPalette(kBird); +#else + std::cout << "ePICStyle: ROOT5 mode" << std::endl; + // color palette - manually define 'kBird' palette only available in ROOT 6 + Int_t alpha = 0; + Double_t stops[9] = { 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000}; + Double_t red[9] = { 0.2082, 0.0592, 0.0780, 0.0232, 0.1802, 0.5301, 0.8186, 0.9956, 0.9764}; + Double_t green[9] = { 0.1664, 0.3599, 0.5041, 0.6419, 0.7178, 0.7492, 0.7328, 0.7862, 0.9832}; + Double_t blue[9] = { 0.5293, 0.8684, 0.8385, 0.7914, 0.6425, 0.4662, 0.3499, 0.1968, 0.0539}; + TColor::CreateGradientColorTable(9, stops, red, green, blue, 255, alpha); +#endif + + ePICStyle->SetNumberContours(80); + + return ePICStyle; + +} diff --git a/ElectronID/ePICStyle.h b/ElectronID/ePICStyle.h new file mode 100644 index 0000000..8d326c7 --- /dev/null +++ b/ElectronID/ePICStyle.h @@ -0,0 +1,22 @@ +// +// @file ePICStyle.h +// +// ePIC Style, based on a style file from ATLAS +// +// +// @author Peter Steinberg adapted from sPHENIX/ATLAS style for ECCE, Stephen Kay subsequently repurposed for ePIC +// +// Copyright (C) 2025 ePIC Collaboration +// +// Version 0.1 + +#ifndef __ePICSTYLE_H +#define __ePICSTYLE_H + +#include "TStyle.h" + +void SetePICStyle(); + +TStyle* ePICStyle(); + +#endif // __ePICSTYLE_H From 0ed026c2f9187e279724fc93facc9d0398bd1d96 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Mon, 3 Nov 2025 15:08:55 -0500 Subject: [PATCH 5/9] add ReconExample for kinematic reconstruction study --- ElectronID/ElectronID.cc | 142 +-------------- ElectronID/ElectronID.hh | 6 +- ElectronID/ReconExample.C | 374 ++++++++++++++++++++++++++++++++++++++ ElectronID/ReconExample.h | 63 +++++++ 4 files changed, 452 insertions(+), 133 deletions(-) create mode 100644 ElectronID/ReconExample.C create mode 100644 ElectronID/ReconExample.h diff --git a/ElectronID/ElectronID.cc b/ElectronID/ElectronID.cc index 064093e..5eb7efe 100644 --- a/ElectronID/ElectronID.cc +++ b/ElectronID/ElectronID.cc @@ -76,39 +76,21 @@ int ElectronID::Check_eID(edm4eic::ReconstructedParticle e_rec) { return 86; } -edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool use_mc, int object_id, bool is_print, LorentzRotation boost) { +edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost) { - // edm4eic::HadronicFinalStateCollection meRecon; edm4eic::ReconstructedParticleCollection meRecon; meRecon->setSubsetCollection(); edm4hep::MCParticleCollection meMiss; meMiss->setSubsetCollection(); - // auto& rcparts = mEvent->get("HadronicFinalState"); auto& rcparts = mEvent->get("ReconstructedParticles"); - // cout << "ef_rc_id after " << object_id << endl; - - if ( is_print ) - cout << " new HFS loop " << endl; - if ( use_mc ) { edm4hep::MCParticleCollection meMC = GetMCElectron(); auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); - - if ( is_print ) - { - // cout << "scat e\n" << meMC[0] << endl; - PxPyPzEVector v(meMC[0].getMomentum().x, meMC[0].getMomentum().y, meMC[0].getMomentum().z, meMC[0].getEnergy()); - v = boost(v); - cout << "scat e .. " << Form("PDG %d, ", meMC[0].getPDG()) << Form("pt %f, ", v.Pt()) << Form("pz %f, ", v.Z()) << Form("E %f, ", v.E()) << Form("theta %f", v.Theta()) << endl; - } - - // if ( is_print ) - // cout << "hfs selected .. \n" << endl; - + for(const auto& assoc : RecoMC) { if(assoc.getSim() != meMC[0] && assoc.getSim().getGeneratorStatus() == 1) @@ -122,67 +104,11 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool hfs_de.push_back((u.E()-v.E())/v.E()); hfs_theta.push_back(v.Theta()*(180./M_PI)); - // if ( (u.Pt()-v.Pt())/v.Pt() > 0.3 || (u.Pt()-v.Pt())/v.Pt() < -0.3 ) - // continue; - - // if ( (u.Z()-v.Z())/v.Z() > 0.3 || (u.Z()-v.Z())/v.Z() < -0.3 ) - // continue; - - // if ( (u.E()-v.E())/v.E() > 0.3 || (u.E()-v.E())/v.E() < -0.3 ) - // continue; - - v = boost(v); u = boost(u); c = boost(c); - // if ( assoc.getSim().getMomentum().z > 0 && assoc.getRec().getMomentum().z < 0 ) - // continue; - - // if ( assoc.getSim().getMomentum().z < 0 && assoc.getRec().getMomentum().z > 0 ) - // continue; - meRecon.push_back(assoc.getRec()); - - if ( is_print ) - { - // cout << "selected ..\n" << assoc.getSim() << endl; - cout << "selected .." << endl; - cout << " MC info .. " << Form("PDG %d, ", assoc.getSim().getPDG()) << Form("pt %f, ", v.Pt()) << Form("pz %f, ", v.Z()) << Form("E %f, ", v.E()) << Form("theta %f", v.Theta()) << endl; - cout << " REC info .. " << Form("PDG %d, ", assoc.getRec().getPDG()) << Form("pt %f, ", u.Pt()) << Form("pz %f, ", u.Z()) << Form("E %f, ", u.E()) << Form("CAL E %f, ", c.E()) << Form("theta %f", u.Theta()) << endl; - } - - } - - // cout << "recon asso " << assoc.getSim().getPDG() << endl; - } - - if ( is_print ) - { - // cout << "hfs missed .. \n" << endl; - - auto& mcparts = mEvent->get("MCParticles"); - for(const auto& mcp : mcparts) - { - if (mcp.getGeneratorStatus() == 1) - { - bool selected = (mcp == meMC[0]); - if ( !selected ) - { - for(const auto& assoc : RecoMC) - if ( mcp == assoc.getSim() ) - selected = true; - } - - if ( !selected ) - { - // cout << "missed ..\n" << mcp << endl; - PxPyPzEVector v(mcp.getMomentum().x, mcp.getMomentum().y, mcp.getMomentum().z, mcp.getEnergy()); - v = boost(v); - cout << "missed .. " << Form("PDG %d, ", mcp.getPDG()) << Form("pt %f, ", v.Pt()) << Form("pz %f, ", v.Z()) << Form("E %f, ", v.E()) << Form("theta %f", v.Theta()) << endl; - } - - } } } } @@ -268,72 +194,24 @@ edm4hep::MCParticleCollection ElectronID::GetMCElectron() { edm4hep::MCParticleCollection meMC; meMC->setSubsetCollection(); - + auto& mcparts = mEvent->get("MCParticles"); - if ( eScatIndex != -1 ) - meMC.push_back(mcparts[eScatIndex]); - //// + std::vector mc_electrons; + for(const auto& mcp : mcparts) { if(mcp.getPDG() == 11 && mcp.getGeneratorStatus() == 1) { - meMC.push_back(mcp); // For now, just take first electron - break; + mc_electrons.push_back(mcp); } } - //// - // std::vector mc_electrons; -/* - // cout << "new" << endl; - for(const auto& mcp : mcparts) - { - if ( mcp.getGeneratorStatus() == 4 && mcp.getPDG() == 11 ) - { - for (auto md = mcp.daughters_begin(), mend = mcp.daughters_end(); md != mend; ++md) - { - cout << "new daugter " << endl; - int mdIndex = md->getObjectID().index; - auto daughter = mcparts[mdIndex]; - cout << daughter << endl; - - // edm4hep::MCParticle daughter = mcp.getDaughters(0); // copy of mcp - for (auto it = daughter.daughters_begin(), end = daughter.daughters_end(); it != end; ++it) - { - int Index = it->getObjectID().index; - auto dau = mcparts[Index]; - cout << "dau " << endl; - cout << dau << endl; - if ( dau.getGeneratorStatus() == 1 && dau.getPDG() == 11) - { - meMC.push_back(dau); - eScatIndex = Index; - - // cout << dau << endl; - // for (auto dit = dau.parents_begin(), dend = dau.parents_end(); dit != dend; ++dit) - // { - // int dauIndex = dit->getObjectID().index; - // auto dpar = mcparts[dauIndex]; - // cout << dpar << "dau parent" << endl << dpar.getParents(0) << endl; - // } - break; - } - } - } - break; - } + // For now, just take first electron + if(mc_electrons.size() > 0) { + meMC.push_back(mc_electrons[0]); } -*/ - // cout << "full e list" << endl; - // for(const auto& mcp : mcparts) - // { - // if ( mcp.getGeneratorStatus() == 1 && mcp.getPDG() == 11) - // { - // cout << mcp << endl; - // } - // } - return meMC; + } edm4eic::ReconstructedParticleCollection ElectronID::GetTruthReconElectron() { diff --git a/ElectronID/ElectronID.hh b/ElectronID/ElectronID.hh index a214cc8..171c056 100644 --- a/ElectronID/ElectronID.hh +++ b/ElectronID/ElectronID.hh @@ -7,6 +7,10 @@ #include "edm4eic/ReconstructedParticleCollection.h" #include "edm4hep/MCParticleCollection.h" +#include "constants.h" +#include "Beam.h" +#include "Boost.h" + #include using ROOT::Math::LorentzRotation; @@ -27,7 +31,7 @@ public: void SetEvent(const podio::Frame* event); int Check_eID(edm4eic::ReconstructedParticle e_rec); - edm4eic::ReconstructedParticleCollection FindHadronicFinalState(bool use_mc, int object_id, bool is_print, LorentzRotation boost); + edm4eic::ReconstructedParticleCollection FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost); edm4eic::ReconstructedParticleCollection FindScatteredElectron(); edm4eic::ReconstructedParticleCollection GetTruthReconElectron(); edm4hep::MCParticleCollection GetMCElectron(); diff --git a/ElectronID/ReconExample.C b/ElectronID/ReconExample.C new file mode 100644 index 0000000..908427a --- /dev/null +++ b/ElectronID/ReconExample.C @@ -0,0 +1,374 @@ +// Data model headers +#include "edm4eic/ReconstructedParticleCollection.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/utils/vector_utils.h" +#include "edm4hep/utils/kinematics.h" +#include "edm4eic/ClusterCollection.h" +#include "edm4eic/MCRecoParticleAssociationCollection.h" +#include "podio/Frame.h" +// #include "podio/ROOTFrameReader.h" -- for simulation campaign before March 2023 with eic-shell 25.03.2 +#include "podio/ROOTReader.h" + +// ROOT headers +#include "TTree.h" +#include "TFile.h" +#include "TString.h" +#include "TVector3.h" +#include "TLorentzVector.h" + +// Analysis headers +#include "ReconExample.h" +#include "drawKinematics.C" + +void ReconExample() { + + // Set beam energy + double Ee = 10.; + double Eh = 100.; + + // Set what electron ID to use + int eID_type = truthID; + + // access local file + // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; + + // access remote file + vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; + + // auto reader = podio::ROOTFrameReader(); + auto reader = podio::ROOTReader(); + reader.openFiles(inFiles); + + // setup eid + ElectronID* eFinder = new ElectronID(Ee, Eh); + + // setup kinematic algorithms + algorithm.push_back(Kinematics("E_Method", 2)); // electron method + algorithm.push_back(Kinematics("JB_Method", 4)); // Jacquet-Blondel method + algorithm.push_back(Kinematics("DA_Method", 1)); // Double-Angle method + algorithm.push_back(Kinematics("Sig_Method", kOrange+1)); // Sigma method + algorithm.push_back(Kinematics("ESig_Method", kGreen+3)); // E-Sigma method + algorithm.push_back(Kinematics("MC", kGray)); // MC info + + // setup output file and histograms + TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); + CreateOutputTree(outFileName); + DefineHistograms(); + + // loop events + for(size_t ev = 0; ev < reader.getEntries("events"); ev++) { + + if(ev%1000==0) + cout << "Event " << ev << "/" << reader.getEntries("events") << endl; + + ResetVariables(); + + const auto event = podio::Frame(reader.readNextEntry("events")); + eFinder->SetEvent(&event); + + edm4hep::MCParticleCollection e_mc = eFinder->GetMCElectron(); + + // Skip events without scattered MC electron + if(e_mc.size() == 0) + continue; + + // Set boost and get incoming particles + TLorentzVector in_e; + TLorentzVector in_n; + LorentzRotation boost; + eFinder->GetBeam(boost, in_e, in_n); + in_e = boost(in_e); + in_n =boost(in_n); + + // Calculate kinematic variables using MC electron + TLorentzVector kprime; + kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, Me); + TLorentzVector true_e_lab = kprime; + kprime = boost(kprime); // boost back to head-on frame + + // Get momentum vector elements from MC electron + mc_p = edm4hep::utils::magnitude(e_mc[0].getMomentum()); + mc_eta = edm4hep::utils::eta(e_mc[0].getMomentum()); + mc_phi = edm4hep::utils::angleAzimuthal(e_mc[0].getMomentum()); + + // Don't have to boost if we are just calulcating x, Q2, y using e method because they are Lorentz invariant + // But since we boosted the outgoing ones earlier for later analysis, we need to boost the incoming ones as well + CalculateRealElectronKinematics(in_e, in_n, kprime, algorithm[MC]); + + if ( !pass_ke_cut(algorithm[MC]) ) + continue; + + // Set Range for plots + int Qrange = 0; + if ( algorithm[MC].Q2 > 1000 ) + Qrange = 3; + else if ( algorithm[MC].Q2 > 100 ) + Qrange = 2; + else if ( algorithm[MC].Q2 > 10 ) + Qrange = 1; + + // Find scattered electrons using mc association + auto e_truth = eFinder->GetTruthReconElectron(); + + // Find scattered electrons using detector information + auto e_candidates = eFinder->FindScatteredElectron(); + edm4eic::ReconstructedParticle e_rec; + + // If there are multiple candidates, select one with highest pT + if(e_candidates.size() > 0) { + positive_eID = 1; + e_rec = eFinder->SelectHighestPT(e_candidates); + } + + // select which eID we are using + PxPyPzEVector scat_ele(0, 0, 0, -1); + if ( eID_type == truthID ) { + if(e_truth.size() < 1) + continue; + + scat_ele.SetPxPyPzE(e_truth[0].getMomentum().x, e_truth[0].getMomentum().y, e_truth[0].getMomentum().z, e_truth[0].getEnergy()); + } + else if ( eID_type == mcID ) { + scat_ele = true_e_lab; + } + else { + if(!positive_eID) + continue; + + scat_ele.SetPxPyPzE(e_rec.getMomentum().x, e_rec.getMomentum().y, e_rec.getMomentum().z, e_rec.getEnergy()); + } + + PxPyPzEVector rec_e_lab = scat_ele; + if( eID_type!=2 ) + { + // Calculate kinematics using track info only + kprime.SetXYZM(rec_e_lab.Px(), rec_e_lab.Py(), rec_e_lab.Pz(), Me); + TLorentzVector track_kprime = kprime; + h_dEt[Qrange]->Fill((track_kprime.E()-true_e_lab.E())/true_e_lab.E()); + h_dt[Qrange]->Fill((track_kprime.Theta()-true_e_lab.Theta())/true_e_lab.Theta()); + h_dp[Qrange]->Fill((track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); + h_tde[1]->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); + h_tdp->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); + h_pde->Fill(true_e_lab.Pt(), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); + h_pt->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.Pt()); + + // Calculate kinematics using track + cluster energy + TVector3 e3v = kprime.Vect(); + + double track_clust_E; + if ( eID_type == truthID ) + track_clust_E = eFinder->GetCalorimeterEnergy(e_truth[0]); + else if ( eID_type == mcID ) + track_clust_E = e_mc[0].getEnergy(); + else + track_clust_E = eFinder->GetCalorimeterEnergy(e_rec); + + e3v.SetMag(track_clust_E); + kprime.SetVectM(e3v, Me); + h_dEc[Qrange]->Fill((track_clust_E-true_e_lab.E())/true_e_lab.E()); + h_tde[0]->Fill(true_e_lab.Theta()*(180./M_PI), (track_clust_E-true_e_lab.E())/true_e_lab.E()); + h_ede->Fill(true_e_lab.E(), (track_clust_E-true_e_lab.E())/true_e_lab.E()); + h_et->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.E()); + + TLorentzVector calo_kprime = kprime; + + // // cut example + // if ( algorithm[MC].Q2 > 100 ) + // scat_ele = calo_kprime; + } + + scat_ele = boost(scat_ele); + float theta = scat_ele.Theta(); + float E = scat_ele.E(); + + // Find hadronic final state + double pxsum = 0; + double pysum = 0; + double pzsum = 0; + double Esum = 0; + + // MC and Rec data structure are different.. not sure how to not repeat code here + auto mc_hfsCollection = eFinder->GetMCHadronicFinalState(); + for (const auto p : mc_hfsCollection) { + // Lorentz vector in lab frame + PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); + // Boost to colinear frame + hf = boost(hf); + + pxsum += hf.Px(); + pysum += hf.Py(); + pzsum += hf.Pz(); + Esum += hf.E(); + } + double true_sigma_h = Esum - pzsum; + double true_pt_had = sqrt(pxsum*pxsum + pysum*pysum); + + pxsum = 0; + pysum = 0; + pzsum = 0; + Esum = 0; + + auto hfsCollection = eFinder->FindHadronicFinalState(eID_type, e_rec.getObjectID().index, boost); + for (const auto p : hfsCollection) { + // Lorentz vector in lab frame + // double track_clust_E = eFinder->GetCalorimeterEnergy(p); + // cout << "energy " << track_clust_E << " " << p.getEnergy() << " " << track_clust_E - p.getEnergy() << endl; + PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); + // PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, track_clust_E); + // Boost to colinear frame + hf = boost(hf); + + pxsum += hf.Px(); + pysum += hf.Py(); + pzsum += hf.Pz(); + Esum += hf.E(); + } + + double sigma_h = Esum - pzsum; + double pt_had = sqrt(pxsum*pxsum + pysum*pysum); + + for ( int i = 0; i < eFinder->hfs_dpt.size(); i++ ) + { + h_hfs_dpt->Fill(eFinder->hfs_dpt[i]); + h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpt[i]); + } + + for ( int i = 0; i < eFinder->hfs_dpz.size(); i++ ) + { + h_hfs_dpz->Fill(eFinder->hfs_dpz[i]); + h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpz[i]); + } + + for ( int i = 0; i < eFinder->hfs_de.size(); i++ ) + { + h_hfs_de->Fill(eFinder->hfs_de[i]); + h_hfs_de_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_de[i]); + } + + if ( eID_type == mcID ) + { + sigma_h = true_sigma_h; + pt_had = true_pt_had; + } + + // Calculate kinematics + + // example cut + // if ( abs((scat_ele.E() - true_e_lab.E())/true_e_lab.E()) > 0.2 ) + // return; + + if ( E > 0 ) + algorithm[EL].save_variables(calc_elec_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + + if ( hfsCollection.size() != 0 ) + { + h_dhf[Qrange]->Fill((sigma_h-true_sigma_h)/true_sigma_h); + h_dpt[Qrange]->Fill((pt_had-true_pt_had)/true_pt_had); + + algorithm[JB].save_variables(calc_jb_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + + if ( E > 0 ) + { + algorithm[DA].save_variables(calc_da_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + algorithm[SIG].save_variables(calc_sig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + algorithm[ESIG].save_variables(calc_esig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); + } + } + + algorithm[MC].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); + for ( int i = 0; i < algorithm.size()-1; i ++ ) + algorithm[i].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); + + + outTree->Fill(); + } + + outFile->cd(); + outTree->Write(outTree->GetName(), 2); + + plot_energy_and_track(); + plot_kinematics_qa(); + + // outFile->Close(); + + return; +} + +void CreateOutputTree(TString outFileName) { + + outFile = new TFile(outFileName, "RECREATE"); + outTree = new TTree("T", "Reconstructed and generated information from EICRecon"); + + outTree->Branch("positive_eID", &positive_eID); + + // Create branches for each algorithm + for ( int i = 0; i < algorithm.size(); i ++ ) + { + outTree->Branch(Form("%s_xB", algorithm[i].method_name.c_str()), &algorithm[i].xB); + outTree->Branch(Form("%s_Q2", algorithm[i].method_name.c_str()), &algorithm[i].Q2); + outTree->Branch(Form("%s_y", algorithm[i].method_name.c_str()), &algorithm[i].y); + outTree->Branch(Form("%s_nu", algorithm[i].method_name.c_str()), &algorithm[i].nu); + outTree->Branch(Form("%s_W2", algorithm[i].method_name.c_str()), &algorithm[i].W2); + } + + outTree->Branch("mc_p", &mc_p); + outTree->Branch("mc_eta", &mc_eta); + outTree->Branch("mc_phi", &mc_phi); + + outTree->Branch("track_p", &track_p); + outTree->Branch("track_eta", &track_eta); + outTree->Branch("track_phi", &track_phi); +} + +void ResetVariables() { + + positive_eID = 0; + + for ( auto &v : algorithm ) + v.reset(); + + mc_p = -999; + mc_eta = -999; + mc_phi = -999; + + track_p = -999; + track_eta = -999; + track_phi = -999; + +} + +// mc kinematics for comparison - use real incident particle kinematics +void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v) { + // input is boosted + TLorentzVector q = ki - kf; + v.Q2 = -(q.Dot(q)); + v.nu = (q.Dot(P))/Mp; + v.xB = v.Q2/(2.*Mp*v.nu); + v.y = (q.Dot(P))/(ki.Dot(P)); + v.W2 = (Mp*Mp + (2.*Mp*v.nu) - v.Q2); +} + +TLorentzVector GetHadronBeam(double fEh) { + + TLorentzVector hadron_beam; + hadron_beam.SetX(fEh*sin(crossing_angle)); + hadron_beam.SetY(0.); + hadron_beam.SetZ(fEh*cos(crossing_angle)); + hadron_beam.SetE(std::hypot(fEh, Mp)); + return hadron_beam; + +} + +bool pass_ke_cut(Kinematics v) +{ + if ( v.y <= 0.01 || v.y >= 0.95 ) + return false; + + if ( v.Q2 < 2 ) + return false; + + if ( v.W2 < 4 ) + return false; + + return true; +} \ No newline at end of file diff --git a/ElectronID/ReconExample.h b/ElectronID/ReconExample.h new file mode 100644 index 0000000..633fffd --- /dev/null +++ b/ElectronID/ReconExample.h @@ -0,0 +1,63 @@ +// Analysis headers +#include "ElectronID.cc" +#include "kinematics.cc" +#include "draw_helper.h" +#include "reconMethod.hh" +#include "constants.h" + +#pragma once + +TFile* outFile = NULL; +TTree* outTree = NULL; + +const double Me = 0.511e-3; // GeV +const double Mp = 0.938272; // GeV +const double crossing_angle = -0.025; // rad + +// QA histograms +TH1F* h_dEc[4]; +TH1F* h_dEt[4]; +TH1F* h_dt[4]; +TH1F* h_dp[4]; +TH2F* h_tde[2]; +TH2F* h_tdp; +TH2F* h_pde; +TH2F* h_ede; +TH2F* h_pt; +TH2F* h_et; + +TH1F* h_dhf[4]; +TH1F* h_dpt[4]; + +TH1F* h_hfs_dpz; +TH1F* h_hfs_dpt; +TH1F* h_hfs_de; +TH2F* h_hfs_dpz_t; +TH2F* h_hfs_dpt_t; +TH2F* h_hfs_de_t; + +enum {EL, JB, DA, SIG, ESIG, MC}; +enum {reconID, truthID, mcID}; + +void SetInputBranchAddresses(); +void CreateOutputTree(TString outFileName); +void ResetVariables(); +void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v); +TLorentzVector GetHadronBeam(double fEh); +void DefineHistograms(); +void plot_kinematics_qa(); +void plot_energy_and_track(); +bool pass_ke_cut(Kinematics v); + +using namespace std; + +int positive_eID; +vector algorithm; + +float mc_p; +float mc_eta; +float mc_phi; + +float track_p; +float track_eta; +float track_phi; \ No newline at end of file From 888a0cdba60f0f507b7a4099d1b7aad1b0822633 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Tue, 10 Feb 2026 09:49:54 -0500 Subject: [PATCH 6/9] new eic-shell seems to have some issues with the lib, load all the lib before running macro to make sure root knows all podio stuff --- ElectronID/ElectronID.cc | 250 ++++++++++++++++++++++++----------- ElectronID/ElectronID.hh | 17 ++- ElectronID/InclusiveSkim.C | 2 + ElectronID/InclusiveSkimQA.C | 9 ++ ElectronID/ReconExample.C | 2 + ElectronID/eff.C | 100 ++++++++++++++ ElectronID/preLoadLib.hh | 8 ++ 7 files changed, 308 insertions(+), 80 deletions(-) create mode 100644 ElectronID/eff.C create mode 100644 ElectronID/preLoadLib.hh diff --git a/ElectronID/ElectronID.cc b/ElectronID/ElectronID.cc index 5eb7efe..c7a77a0 100644 --- a/ElectronID/ElectronID.cc +++ b/ElectronID/ElectronID.cc @@ -14,7 +14,7 @@ ElectronID::ElectronID() { mEh = 100.; std::cout << "!!! ElectronID: You have not specified beam energies...defaulting to 10x100 GeV !!!" << std::endl; - mEoP_min = 0.9; + mEoP_min = 0.8; mEoP_max = 1.2; mDeltaH_min = 0.*mEe; @@ -23,7 +23,9 @@ ElectronID::ElectronID() { mIsoR = 0.4; mIsoE = 0.9; + minTrackPoints = 3; + boost = LorentzRotation(); // Initialize to identity } ElectronID::ElectronID(double Ee, double Eh) { @@ -31,7 +33,7 @@ ElectronID::ElectronID(double Ee, double Eh) { mEe = Ee; mEh = Eh; - mEoP_min = 0.9; + mEoP_min = 0.8; mEoP_max = 1.2; mDeltaH_min = 0.*mEe; @@ -40,14 +42,17 @@ ElectronID::ElectronID(double Ee, double Eh) { mIsoR = 0.4; mIsoE = 0.9; + minTrackPoints = 3; + + boost = LorentzRotation(); // Initialize to identity } ElectronID::~ElectronID() { } - void ElectronID::SetEvent(const podio::Frame* event) { + // std::cout << "** Setting event in ElectronID... " << std::endl; mEvent = event; eScatIndex = -1; hfs_dpt.clear(); @@ -55,14 +60,36 @@ void ElectronID::SetEvent(const podio::Frame* event) { hfs_de.clear(); hfs_theta.clear(); e_det.clear(); + jet_e_det.clear(); pi_det.clear(); else_det.clear(); + // std::cout << "** Event set in ElectronID. " << std::endl; + return; +} + +edm4hep::MCParticle ElectronID::GetMC(edm4eic::ReconstructedParticle e_rec) { + + // std::cout << "Available collections:" << std::endl; + // for (const auto& name : mEvent->getAvailableCollections()) { + // std::cout << " " << name << std::endl; + // } + + const auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + for(const auto& assoc : RecoMC) { + if(assoc.getRec() == e_rec) + return assoc.getSim(); + } + + return edm4hep::MCParticle(); } int ElectronID::Check_eID(edm4eic::ReconstructedParticle e_rec) { edm4hep::MCParticleCollection meMC = GetMCElectron(); - auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + if ( meMC.size() == 0 ) + return 86; // No MC electron found + + const auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); for(const auto& assoc : RecoMC) { if(assoc.getRec() == e_rec) { @@ -76,72 +103,70 @@ int ElectronID::Check_eID(edm4eic::ReconstructedParticle e_rec) { return 86; } -edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost) { +void ElectronID::CheckClusters() { - edm4eic::ReconstructedParticleCollection meRecon; - meRecon->setSubsetCollection(); + const auto& EcalEndcapNClusters = mEvent->get("EcalEndcapNClusters"); + const auto& EcalBarrelScFiClusters = mEvent->get("EcalBarrelScFiClusters"); + const auto& EcalEndcapPClusters = mEvent->get("EcalEndcapPClusters"); - edm4hep::MCParticleCollection meMiss; - meMiss->setSubsetCollection(); + std::cout << " Number of clusters in EcalEndcapN: " << EcalEndcapNClusters.size() << std::endl; + std::cout << " Number of clusters in EcalBarrelScFi: " << EcalBarrelScFiClusters.size() << std::endl; + std::cout << " Number of clusters in EcalEndcapP: " << EcalEndcapPClusters.size() << std::endl; + + return; +} - auto& rcparts = mEvent->get("ReconstructedParticles"); +edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(int object_id) { - if ( use_mc ) - { - edm4hep::MCParticleCollection meMC = GetMCElectron(); - auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); - - for(const auto& assoc : RecoMC) - { - if(assoc.getSim() != meMC[0] && assoc.getSim().getGeneratorStatus() == 1) - { - PxPyPzEVector v(assoc.getSim().getMomentum().x, assoc.getSim().getMomentum().y, assoc.getSim().getMomentum().z, assoc.getSim().getEnergy()); - PxPyPzEVector u(assoc.getRec().getMomentum().x, assoc.getRec().getMomentum().y, assoc.getRec().getMomentum().z, assoc.getRec().getEnergy()); - PxPyPzEVector c(assoc.getRec().getMomentum().x, assoc.getRec().getMomentum().y, assoc.getRec().getMomentum().z, GetCalorimeterEnergy(assoc.getRec())); - - hfs_dpt.push_back((u.Pt()-v.Pt())/v.Pt()); - hfs_dpz.push_back((u.Z()-v.Z())/v.Z()); - hfs_de.push_back((u.E()-v.E())/v.E()); - hfs_theta.push_back(v.Theta()*(180./M_PI)); + // edm4eic::HadronicFinalStateCollection meRecon; + edm4eic::ReconstructedParticleCollection meRecon; + meRecon.setSubsetCollection(); - v = boost(v); - u = boost(u); - c = boost(c); + // auto& rcparts = mEvent->get("HadronicFinalState"); + const auto& rcparts = mEvent->get("ReconstructedParticles"); - meRecon.push_back(assoc.getRec()); - } - } - } - else - { - for(const auto& mcp : rcparts) { - if ( mcp.getObjectID().index != object_id ) - meRecon.push_back(mcp); - } + for(const auto& mcp : rcparts) { + if ( mcp.getObjectID().index != object_id ) + meRecon.push_back(mcp); } - + return meRecon; } edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { + // std::cout << "\nFinding scattered electron candidates..." << std::endl; + // CheckClusters(); + // Get all the edm4eic objects needed for electron ID - auto& rcparts = mEvent->get("ReconstructedParticles"); + const auto& rcparts = mEvent->get("ReconstructedParticles"); // Create collection for storing scattered electron candidates // (subset collection of ReconstructedParticleCollection) edm4eic::ReconstructedParticleCollection scatteredElectronCandidates; - scatteredElectronCandidates->setSubsetCollection(); + scatteredElectronCandidates.setSubsetCollection(); // Loop over all ReconstructedParticles for this event for (const auto& reconPart : rcparts) { - // Require negative particle - if(reconPart.getCharge() >= 0) continue; + // std::cout << "par id: " << reconPart.getPDG() << " cluster size: " << reconPart.getClusters().size() << ", track size: " << reconPart.getTracks().size() << std::endl; + + // for (const auto& track : reconPart.getTracks()) + // { + // int n_measurements = track.measurements_size(); + // int n_track_hits = track.getTrajectory().getNMeasurements(); + // // std::cout << " track with " << n_measurements << " measurements, " << n_track_hits << " hits." << std::endl; + // } // Require at least one track and one cluster if(reconPart.getClusters().size() == 0 || reconPart.getTracks().size() == 0) continue; + int n_track_points = reconPart.getTracks()[0].measurements_size(); + if ( n_track_points < minTrackPoints ) continue; + + // Require negative particle + if(reconPart.getCharge() >= 0) continue; + // Calculate rcpart_ member variables for this event CalculateParticleValues(reconPart, rcparts); @@ -150,13 +175,15 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { double recon_EoP = rcpart_sum_cluster_E / edm4hep::utils::magnitude(reconPart.getMomentum()); double recon_isoE = rcpart_sum_cluster_E / rcpart_isolation_E; - if ( Check_eID(reconPart) == 0 ) - e_det.push_back({recon_EoP, recon_isoE}); - else if ( Check_eID(reconPart) == -211 ) - pi_det.push_back({recon_EoP, recon_isoE}); + int found_id = Check_eID(reconPart); + if ( found_id == 0 ) + e_det.push_back({n_track_points, recon_EoP, recon_isoE}); + else if ( found_id == 11 ) + jet_e_det.push_back({n_track_points, recon_EoP, recon_isoE}); + else if ( found_id == -211 ) + pi_det.push_back({n_track_points, recon_EoP, recon_isoE}); else - else_det.push_back({recon_EoP, recon_isoE}); - + else_det.push_back({n_track_points, recon_EoP, recon_isoE}); // Apply scattered electron ID cuts if(recon_EoP < mEoP_min || recon_EoP > mEoP_max) continue; @@ -174,17 +201,22 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { edm4hep::MCParticleCollection mhMC; - mhMC->setSubsetCollection(); + mhMC.setSubsetCollection(); - auto& mcparts = mEvent->get("MCParticles"); + const auto& mcparts = mEvent->get("MCParticles"); std::vector mc_hadronic; edm4hep::MCParticleCollection meMC = GetMCElectron(); - + bool found_scattered_e = false; for(const auto& mcp : mcparts) { - if (mcp.getGeneratorStatus() == 1 && mcp.getObjectID().index != meMC[0].getObjectID().index ) - mhMC.push_back(mcp); + if (mcp.getGeneratorStatus() == 1) + { + if ( meMC.size() == 0 ) + mhMC.push_back(mcp); + else if (mcp.getObjectID().index != meMC[0].getObjectID().index ) + mhMC.push_back(mcp); + } } return mhMC; @@ -193,36 +225,82 @@ edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { edm4hep::MCParticleCollection ElectronID::GetMCElectron() { edm4hep::MCParticleCollection meMC; - meMC->setSubsetCollection(); + meMC.setSubsetCollection(); + + const auto& mcparts = mEvent->get("MCParticles"); + if ( eScatIndex != -1 ) + meMC.push_back(mcparts[eScatIndex]); - auto& mcparts = mEvent->get("MCParticles"); + //// - std::vector mc_electrons; - - for(const auto& mcp : mcparts) { - if(mcp.getPDG() == 11 && mcp.getGeneratorStatus() == 1) { - mc_electrons.push_back(mcp); + // cout << "\n** Searching for MC electrons..." << endl; + + for (const auto& mcp : mcparts) + { + if (mcp.getPDG() != 11 || mcp.getGeneratorStatus() != 4) + continue; + + std::vector stack; + stack.insert(stack.end(), mcp.getDaughters().begin(), mcp.getDaughters().end()); + + int shortest_gen = 999; + int generations = 0; + edm4hep::MCParticle meMC_candidates; + + while (!stack.empty() ) { + generations++; + auto cur = stack.back(); + stack.pop_back(); + + if (cur.getPDG() == 11 && cur.getGeneratorStatus() == 1) { + + if ( generations < shortest_gen ) + { + shortest_gen = generations; + meMC_candidates = cur; + } + break; + } + + const auto& kids = cur.getDaughters(); + if (!kids.empty()) { + stack.insert(stack.end(), kids.begin(), kids.end()); + } } + + if ( meMC_candidates.isAvailable() ) + meMC.push_back(meMC_candidates); } - // For now, just take first electron - if(mc_electrons.size() > 0) { - meMC.push_back(mc_electrons[0]); + if ( meMC.size() == 0 ) + { + std::cout << "** No MC electron found! " << std::endl; + for (const auto& mcp : mcparts) + cout << mcp << endl; } - return meMC; + // cout << "** Total MC electrons found: " << meMC.size() << endl; + return meMC; } edm4eic::ReconstructedParticleCollection ElectronID::GetTruthReconElectron() { - edm4hep::MCParticleCollection meMC = GetMCElectron(); + // cout << "New process " << endl; + + const edm4hep::MCParticleCollection meMC = GetMCElectron(); edm4eic::ReconstructedParticleCollection meRecon; - meRecon->setSubsetCollection(); + meRecon.setSubsetCollection(); - auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + if ( meMC.size() == 0 ) + return meRecon; // No MC electron found + + const auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + + for(const auto& assoc : RecoMC) + { + auto e_candidat = assoc.getSim(); - for(const auto& assoc : RecoMC) { if(assoc.getSim() == meMC[0]) { meRecon.push_back(assoc.getRec()); break; @@ -257,8 +335,6 @@ void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& r double lead_phi = edm4hep::utils::angleAzimuthal(lead_pos); for (const auto& other_rcp : rcparts) { - if (&other_rcp == &rcp) continue; // Skip the same particle - for (const auto& other_cluster : other_rcp.getClusters()) { const auto& other_pos = other_cluster.getPosition(); @@ -284,12 +360,38 @@ void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& r return; } +void ElectronID::GetEminusPzSum(double &TrackEminusPzSum, double &CalEminusPzSum) { + + const auto& rcparts = mEvent->get("ReconstructedParticles"); + + for (const auto& reconPart : rcparts) { + + // Require at least one track and one cluster + if(reconPart.getClusters().size() == 0 || reconPart.getTracks().size() == 0) continue; + + int n_track_points = reconPart.getTracks()[0].measurements_size(); + if ( n_track_points < minTrackPoints ) continue; + + PxPyPzEVector vC(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, GetCalorimeterEnergy(reconPart)); + vC = boost(vC); + CalEminusPzSum += (vC.E() - vC.Pz()); + + PxPyPzEVector vT(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, reconPart.getEnergy()); + vT = boost(vT); + TrackEminusPzSum += (vT.E() - vT.Pz()); + } + + // std::cout << " recon E - Pz sum: " << reconEminusPzSum << std::endl; + + return; +} + edm4eic::ReconstructedParticle ElectronID::SelectHighestPT(const edm4eic::ReconstructedParticleCollection& ecandidates) { edm4eic::ReconstructedParticle erec; double max_pT = 0.; - for(auto ecand : ecandidates) { + for(const auto& ecand : ecandidates) { double e_pT = edm4hep::utils::magnitudeTransverse(ecand.getMomentum()); if(e_pT > max_pT) { erec = ecand; diff --git a/ElectronID/ElectronID.hh b/ElectronID/ElectronID.hh index 171c056..c34b827 100644 --- a/ElectronID/ElectronID.hh +++ b/ElectronID/ElectronID.hh @@ -3,14 +3,10 @@ #include "podio/Frame.h" -#include "edm4eic/HadronicFinalStateCollection.h" #include "edm4eic/ReconstructedParticleCollection.h" +#include "edm4eic/MCRecoParticleAssociationCollection.h" #include "edm4hep/MCParticleCollection.h" -#include "constants.h" -#include "Beam.h" -#include "Boost.h" - #include using ROOT::Math::LorentzRotation; @@ -27,17 +23,22 @@ public: inline void SetEoPMin(double eopmin) {mEoP_min = eopmin;} inline void SetDeltaHMin(double deltahmin) {mDeltaH_min = deltahmin;} inline void SetIsolation(double isor, double isoe) {mIsoR = isor; mIsoE = isoe;} + inline void SetMinTrackPoints(int minPoints) { minTrackPoints = minPoints; } void SetEvent(const podio::Frame* event); + void SetBoost(LorentzRotation fboost) { boost = fboost; } int Check_eID(edm4eic::ReconstructedParticle e_rec); - edm4eic::ReconstructedParticleCollection FindHadronicFinalState(bool use_mc, int object_id, LorentzRotation boost); + edm4hep::MCParticle GetMC(edm4eic::ReconstructedParticle e_rec); + edm4eic::ReconstructedParticleCollection FindHadronicFinalState(int object_id); edm4eic::ReconstructedParticleCollection FindScatteredElectron(); edm4eic::ReconstructedParticleCollection GetTruthReconElectron(); edm4hep::MCParticleCollection GetMCElectron(); edm4hep::MCParticleCollection GetMCHadronicFinalState(); edm4eic::ReconstructedParticle SelectHighestPT(const edm4eic::ReconstructedParticleCollection& rcparts); double GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rcp); + void GetEminusPzSum(double &TrackEminusPzSum, double &CalEminusPzSum); + void CheckClusters(); void GetBeam(LorentzRotation &boost, TLorentzVector &in_e, TLorentzVector &in_n); double get_mEoP_min() const { return mEoP_min; } @@ -54,10 +55,12 @@ public: vector hfs_theta; struct DetValues { + int nTrackPoints; double recon_EoP; double recon_isoE; }; vector e_det; + vector jet_e_det; vector pi_det; vector else_det; @@ -67,6 +70,7 @@ private: double mEe; double mEh; + LorentzRotation boost; double mEoP_min; double mEoP_max; @@ -74,6 +78,7 @@ private: double mDeltaH_max; double mIsoR; double mIsoE; + int minTrackPoints = 3; void CalculateParticleValues(const edm4eic::ReconstructedParticle& rcp, const edm4eic::ReconstructedParticleCollection& rcparts); diff --git a/ElectronID/InclusiveSkim.C b/ElectronID/InclusiveSkim.C index b4b9111..c21fcad 100644 --- a/ElectronID/InclusiveSkim.C +++ b/ElectronID/InclusiveSkim.C @@ -1,3 +1,5 @@ +#include "preLoadLib.hh" + // Data model headers #include "edm4eic/ReconstructedParticleCollection.h" #include "edm4hep/MCParticleCollection.h" diff --git a/ElectronID/InclusiveSkimQA.C b/ElectronID/InclusiveSkimQA.C index a30d3fb..52bc63b 100644 --- a/ElectronID/InclusiveSkimQA.C +++ b/ElectronID/InclusiveSkimQA.C @@ -1,5 +1,14 @@ // Find inclusive scattered electrons +R__LOAD_LIBRARY(libpodio.so) +R__LOAD_LIBRARY(libpodioRootIO.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hep.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hepDict.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hepUtils.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hepRDF.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4eic.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4eicDict.so) + #include "InclusiveSkimQA.h" void InclusiveSkimQA() diff --git a/ElectronID/ReconExample.C b/ElectronID/ReconExample.C index 908427a..90b4edc 100644 --- a/ElectronID/ReconExample.C +++ b/ElectronID/ReconExample.C @@ -1,3 +1,5 @@ +#include "preLoadLib.hh" + // Data model headers #include "edm4eic/ReconstructedParticleCollection.h" #include "edm4hep/MCParticleCollection.h" diff --git a/ElectronID/eff.C b/ElectronID/eff.C new file mode 100644 index 0000000..2f85512 --- /dev/null +++ b/ElectronID/eff.C @@ -0,0 +1,100 @@ + +#include "../GlobalUtil/ePICStyle.c" +#include "../GlobalUtil/Constants.hh" +#include "../GlobalUtil/drawHelper.h" + +const std::string group[3] = {"1to10", "10to100", "100to1000"}; +const double total_lumi = 8.65*3; // fb^-1 + +double cs[3][2] = {{0.198440424611563, 0.205327493968226}, {4.04371412707044E-02, 4.41976212963417E-02}, {1.36416909784756E-03, 1.69583242740138E-03}}; +double ev[3][2] = {{333675, 666325}, {333694, 666306}, {333365, 666640}}; + +enum { NO_FOUND, FOUND_E, FOUND_PI, FOUND_OTHERS }; + +void eff() +{ + SetePICStyle(); + + TH2F* h_xq2_all = BookTH2(Form("h_xq2_all"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + TH2F* h_xq2_acp = BookTH2(Form("h_xq2_acp"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + TH2F* h_xq2_eID = BookTH2(Form("h_xq2_eID"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + TH2F* h_xq2_piID = BookTH2(Form("h_xq2_piID"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + + for ( int i = 0; i < 3; i ++ ) + { + double gen_lumi = ev[i][0]/(cs[i][0]*(1e-34/1e-43)) + ev[i][1]/(cs[i][1]*(1e-34/1e-43)); + double n_lumi = ev[i][0]/(cs[i][0]*(1e-34/1e-43)); + double p_lumi = ev[i][1]/(cs[i][1]*(1e-34/1e-43)); + + TH2F* h_tmp_all = BookTH2(Form("h_tmp_all_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + TH2F* h_tmp_acp = BookTH2(Form("h_tmp_acp_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + TH2F* h_tmp_eID = BookTH2(Form("h_tmp_eID_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + TH2F* h_tmp_piID = BookTH2(Form("h_tmp_piID_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); + + TFile* file = new TFile(Form("../data/eID/lowerEoPcut/10x166_%s_eIDrecon.root", group[i].c_str())); + + TTreeReader reader("T_eID", file); + TTreeReaderValue eID_status(reader, "eID_status"); + TTreeReaderValue mc_xB(reader, "mc_xB"); + TTreeReaderValue mc_Q2(reader, "mc_Q2"); + TTreeReaderValue mc_y(reader, "mc_y"); + TTreeReaderValue mc_W2(reader, "mc_W2"); + TTreeReaderValue mc_nu(reader, "mc_nu"); + + Long64_t nEntries = reader.GetEntries(); + + for( size_t ev = 0; ev < nEntries; ev++ ) + { + reader.Next(); + // if(ev%100==0) + // cout << "Analysing file " << i << " event " << ev << "/" << nEntries << "\t\r" << std::flush; + + int status = *eID_status; + float xB = *mc_xB; + float Q2 = *mc_Q2; + float y = *mc_y; + float W2 = *mc_W2; + float nu = *mc_nu; + + h_tmp_all->Fill(xB, Q2); + if ( status != NO_FOUND ) + h_tmp_acp->Fill(xB, Q2); + if ( status == FOUND_E ) + h_tmp_eID->Fill(xB, Q2); + if ( status == FOUND_PI ) + h_tmp_piID->Fill(xB, Q2); + } + + h_tmp_all->Scale(total_lumi/gen_lumi); + h_tmp_acp->Scale(total_lumi/gen_lumi); + h_tmp_eID->Scale(total_lumi/gen_lumi); + h_tmp_piID->Scale(total_lumi/gen_lumi); + + h_xq2_all->Add(h_tmp_all); + h_xq2_acp->Add(h_tmp_acp); + h_xq2_eID->Add(h_tmp_eID); + h_xq2_piID->Add(h_tmp_piID); + + file->Close(); + } + + set_2d_scale(h_xq2_all); + TCanvas* c_xq2_all = draw_2d_standard(h_xq2_all, "c_xq2_all", "all events", 700, 600, true, true); + TCanvas* c_xq2_acp = draw_2d_standard(h_xq2_acp, "c_xq2_acp", "acp events", 700, 600, true, true); + TCanvas* c_xq2_eID = draw_2d_standard(h_xq2_eID, "c_xq2_eID", "eID events", 700, 600, true, true); + TCanvas* c_xq2_piID = draw_2d_standard(h_xq2_piID, "c_xq2_piID", "piID events", 700, 600, true, true); + + TH2F* h_xq2_acp_copy = (TH2F*)h_xq2_acp->Clone(); + process_eff_hist(h_xq2_acp_copy, h_xq2_all); + TCanvas* c_xq2_acp_eff = draw_2d_efficiency(h_xq2_acp_copy, "c_xq2_acp_eff", "xq2 acp eff", 1400, 600, false, true); + + TH2F* h_xq2_eID_copy = (TH2F*)h_xq2_eID->Clone(); + process_eff_hist(h_xq2_eID_copy, h_xq2_acp); + TCanvas* c_xq2_eID_eff = draw_2d_efficiency(h_xq2_eID_copy, "c_xq2_eID_eff", "xq2 eID eff", 1400, 600, false, true); + + TH2F* h_xq2_piID_copy = (TH2F*)h_xq2_piID->Clone(); + process_eff_hist(h_xq2_piID_copy, h_xq2_acp); + TCanvas* c_xq2_piID_eff = draw_2d_efficiency(h_xq2_piID_copy, "c_xq2_piID_eff", "xq2 piID eff", 1400, 600, false, true); + + return; +} \ No newline at end of file diff --git a/ElectronID/preLoadLib.hh b/ElectronID/preLoadLib.hh new file mode 100644 index 0000000..186f421 --- /dev/null +++ b/ElectronID/preLoadLib.hh @@ -0,0 +1,8 @@ +R__LOAD_LIBRARY(libpodio.so) +R__LOAD_LIBRARY(libpodioRootIO.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hep.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hepDict.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hepUtils.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4hepRDF.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4eic.so) +R__LOAD_LIBRARY(/opt/local/lib/libedm4eicDict.so) \ No newline at end of file From b5dd48a031ec94ddfe463c709b0e9fd18e2e938a Mon Sep 17 00:00:00 2001 From: Win Lin Date: Tue, 10 Feb 2026 17:37:28 -0500 Subject: [PATCH 7/9] missed to commit the loading lib for this example --- ElectronID/InclusiveSkimQA.C | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ElectronID/InclusiveSkimQA.C b/ElectronID/InclusiveSkimQA.C index 52bc63b..85325d2 100644 --- a/ElectronID/InclusiveSkimQA.C +++ b/ElectronID/InclusiveSkimQA.C @@ -1,13 +1,6 @@ // Find inclusive scattered electrons -R__LOAD_LIBRARY(libpodio.so) -R__LOAD_LIBRARY(libpodioRootIO.so) -R__LOAD_LIBRARY(/opt/local/lib/libedm4hep.so) -R__LOAD_LIBRARY(/opt/local/lib/libedm4hepDict.so) -R__LOAD_LIBRARY(/opt/local/lib/libedm4hepUtils.so) -R__LOAD_LIBRARY(/opt/local/lib/libedm4hepRDF.so) -R__LOAD_LIBRARY(/opt/local/lib/libedm4eic.so) -R__LOAD_LIBRARY(/opt/local/lib/libedm4eicDict.so) +#include "preLoadLib.hh" #include "InclusiveSkimQA.h" From 90a6df693ecfd8ac5ffc06710ceed0a63d1bb2c0 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Wed, 22 Apr 2026 13:32:52 -0400 Subject: [PATCH 8/9] updated code to run with most updated eic-shell. restore code to the simpler example --- ElectronID/Beam.h | 74 ------- ElectronID/Boost/Beam.h | 74 +++++++ ElectronID/{ => Boost}/Boost.h | 29 +++ ElectronID/Boost/getBoost.h | 47 ++++ ElectronID/ElectronID.cc | 310 +++++++++++++++----------- ElectronID/ElectronID.hh | 18 +- ElectronID/InclusiveSkim.C | 18 +- ElectronID/InclusiveSkim.h | 3 + ElectronID/InclusiveSkimQA.C | 239 -------------------- ElectronID/InclusiveSkimQA.h | 45 ---- ElectronID/README | 13 +- ElectronID/ReconExample.C | 376 -------------------------------- ElectronID/ReconExample.h | 63 ------ ElectronID/constants.h | 12 -- ElectronID/drawKinematics.C | 383 --------------------------------- ElectronID/draw_helper.h | 320 --------------------------- ElectronID/ePICStyle.c | 114 ---------- ElectronID/ePICStyle.h | 22 -- ElectronID/eff.C | 100 --------- ElectronID/kinematics.cc | 159 -------------- ElectronID/kinematics.hh | 51 ----- ElectronID/reconMethod.hh | 43 ---- 22 files changed, 366 insertions(+), 2147 deletions(-) delete mode 100644 ElectronID/Beam.h create mode 100644 ElectronID/Boost/Beam.h rename ElectronID/{ => Boost}/Boost.h (54%) create mode 100644 ElectronID/Boost/getBoost.h delete mode 100644 ElectronID/InclusiveSkimQA.C delete mode 100644 ElectronID/InclusiveSkimQA.h delete mode 100644 ElectronID/ReconExample.C delete mode 100644 ElectronID/ReconExample.h delete mode 100644 ElectronID/constants.h delete mode 100644 ElectronID/drawKinematics.C delete mode 100644 ElectronID/draw_helper.h delete mode 100644 ElectronID/ePICStyle.c delete mode 100644 ElectronID/ePICStyle.h delete mode 100644 ElectronID/eff.C delete mode 100644 ElectronID/kinematics.cc delete mode 100644 ElectronID/kinematics.hh delete mode 100644 ElectronID/reconMethod.hh diff --git a/ElectronID/Beam.h b/ElectronID/Beam.h deleted file mode 100644 index 5b754ba..0000000 --- a/ElectronID/Beam.h +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Wouter Deconinck - -#pragma once - -#include -#include -#include -#include - -using ROOT::Math::PxPyPzEVector; - -namespace eicrecon { - -template auto find_first_with_pdg(const T* parts, const std::set& pdg) { - T c; - c.setSubsetCollection(); - for (const auto& p : *parts) { - if (pdg.count(p.getPDG()) > 0) { - c.push_back(p); - break; - } - } - return c; -} - -template -auto find_first_with_status_pdg(const T* parts, const std::set& status, - const std::set& pdg) { - T c; - c.setSubsetCollection(); - for (const auto& p : *parts) { - if (status.count(p.getGeneratorStatus()) > 0 && pdg.count(p.getPDG()) > 0) { - c.push_back(p); - break; - } - } - return c; -} - -inline auto find_first_beam_electron(const edm4hep::MCParticleCollection* mcparts) { - return find_first_with_status_pdg(mcparts, {4}, {11}); -} - -inline auto find_first_beam_hadron(const edm4hep::MCParticleCollection* mcparts) { - return find_first_with_status_pdg(mcparts, {4}, {2212, 2112}); -} - -inline auto find_first_scattered_electron(const edm4hep::MCParticleCollection* mcparts) { - return find_first_with_status_pdg(mcparts, {1}, {11}); -} - -inline auto find_first_scattered_electron(const edm4eic::ReconstructedParticleCollection* rcparts) { - return find_first_with_pdg(rcparts, {11}); -} - -template -PxPyPzEVector round_beam_four_momentum(const Vector3& p_in, const float mass, - const std::vector& pz_set, - const float crossing_angle = 0.0) { - PxPyPzEVector p_out; - for (const auto& pz : pz_set) { - if (fabs(p_in.z / pz - 1) < 0.1) { - p_out.SetPz(pz); - break; - } - } - p_out.SetPx(p_out.Pz() * sin(crossing_angle)); - p_out.SetPz(p_out.Pz() * cos(crossing_angle)); - p_out.SetE(std::hypot(p_out.Px(), p_out.Pz(), mass)); - return p_out; -} - -} // namespace eicrecon diff --git a/ElectronID/Boost/Beam.h b/ElectronID/Boost/Beam.h new file mode 100644 index 0000000..8843381 --- /dev/null +++ b/ElectronID/Boost/Beam.h @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Wouter Deconinck + +#pragma once + +#include +// #include +// #include +#include + +using ROOT::Math::PxPyPzEVector; + +namespace eicrecon { + +// template auto find_first_with_pdg(const T* parts, const std::set& pdg) { +// T c; +// c.setSubsetCollection(); +// for (const auto& p : *parts) { +// if (pdg.count(p.getPDG()) > 0) { +// c.push_back(p); +// break; +// } +// } +// return c; +// } + +// template +// auto find_first_with_status_pdg(const T* parts, const std::set& status, +// const std::set& pdg) { +// T c; +// c.setSubsetCollection(); +// for (const auto& p : *parts) { +// if (status.count(p.getGeneratorStatus()) > 0 && pdg.count(p.getPDG()) > 0) { +// c.push_back(p); +// break; +// } +// } +// return c; +// } + +// inline auto find_first_beam_electron(const edm4hep::MCParticleCollection* mcparts) { +// return find_first_with_status_pdg(mcparts, {4}, {11}); +// } + +// inline auto find_first_beam_hadron(const edm4hep::MCParticleCollection* mcparts) { +// return find_first_with_status_pdg(mcparts, {4}, {2212, 2112}); +// } + +// inline auto find_first_scattered_electron(const edm4hep::MCParticleCollection* mcparts) { +// return find_first_with_status_pdg(mcparts, {1}, {11}); +// } + +// inline auto find_first_scattered_electron(const edm4eic::ReconstructedParticleCollection* rcparts) { +// return find_first_with_pdg(rcparts, {11}); +// } + +template +PxPyPzEVector round_beam_four_momentum(const Vector3& p_in, const float mass, + const std::vector& pz_set, + const float crossing_angle = 0.0) { + PxPyPzEVector p_out; + for (const auto& pz : pz_set) { + if (fabs(p_in.Z() / pz - 1) < 0.1) { + p_out.SetPz(pz); + break; + } + } + p_out.SetPx(p_out.Pz() * sin(crossing_angle)); + p_out.SetPz(p_out.Pz() * cos(crossing_angle)); + p_out.SetE(std::hypot(p_out.Px(), p_out.Pz(), mass)); + return p_out; +} + +} // namespace eicrecon diff --git a/ElectronID/Boost.h b/ElectronID/Boost/Boost.h similarity index 54% rename from ElectronID/Boost.h rename to ElectronID/Boost/Boost.h index 321e6a2..1dc9eca 100644 --- a/ElectronID/Boost.h +++ b/ElectronID/Boost/Boost.h @@ -1,3 +1,5 @@ +// Modified from EICrecon Boost.h + // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (C) 2022 Wouter Deconinck, Barak Schmookler @@ -28,6 +30,8 @@ inline LorentzRotation determine_boost(PxPyPzEVector ei, PxPyPzEVector pi) { PxPyPzEVector eo = ei; PxPyPzEVector po = pi; + // cout << "lab e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", ei.Px(), ei.Py(), ei.Pz(), ei.E(), pi.Px(), pi.Py(), pi.Pz(), pi.E()) << endl; + // Define the Boost to make beams back-to-back const auto cmBoost = (ei + pi).BoostToCM(); const Boost boost_to_cm(cmBoost); @@ -35,20 +39,41 @@ inline LorentzRotation determine_boost(PxPyPzEVector ei, PxPyPzEVector pi) { // Boost to COM frame pi = boost_to_cm(pi); ei = boost_to_cm(ei); + // cout << "CM boosted e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", ei.Px(), ei.Py(), ei.Pz(), ei.E(), pi.Px(), pi.Py(), pi.Pz(), pi.E()) << endl; // This will boost beams from a center of momentum frame back to (nearly) their original energies PxPyPzEVector eh(0, 0, -1*sqrt(pow(eo.E(),2)-pow(eo.M(),2)), eo.E()); PxPyPzEVector ph(0, 0, sqrt(pow(po.E(),2)-pow(po.M(),2)), po.E()); + // cout << "headon e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", eh.Px(), eh.Py(), eh.Pz(), eh.E(), ph.Px(), ph.Py(), ph.Pz(), ph.E()) << endl; const auto hoBoost = (eh + ph).BoostToCM(); + // const Boost headon_to_cm(hoBoost); const Boost boost_to_headon(-hoBoost); + // PxPyPzEVector et = headon_to_cm(eh); + // PxPyPzEVector pt = headon_to_cm(ph); + // cout << "headon boosted to CM e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", et.Px(), et.Py(), et.Pz(), et.E(), pt.Px(), pt.Py(), pt.Pz(), pt.E()) << endl; + + // PxPyPzEVector erb = boost_to_headon(et); + // PxPyPzEVector prb = boost_to_headon(pt); + // cout << "reversed boost e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", erb.Px(), erb.Py(), erb.Pz(), erb.E(), prb.Px(), prb.Py(), prb.Pz(), prb.E()) << endl; + // Boost and rotate the incoming beams to find the proper rotations TLorentzVector // Rotate to head-on RotationY rotAboutY(-1.0 * atan2(pi.Px(), pi.Pz())); // Rotate to remove x component of beams RotationX rotAboutX(+1.0 * atan2(pi.Py(), pi.Pz())); // Rotate to remove y component of beams + // PxPyPzEVector er = rotAboutX(rotAboutY(ei)); + // PxPyPzEVector pr = rotAboutX(rotAboutY(pi)); + // cout << "rotation e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", er.Px(), er.Py(), er.Pz(), er.E(), pr.Px(), pr.Py(), pr.Pz(), pr.E()) << endl; + + // PxPyPzEVector ef = boost_to_headon(er); + // PxPyPzEVector pf = boost_to_headon(pr); + // cout << "final boost e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", ef.Px(), ef.Py(), ef.Pz(), ef.E(), pf.Px(), pf.Py(), pf.Pz(), pf.E()) << endl; + + // cout << "**" << endl; + // final matrix: P' = [BtoH][RX][RY][BtoCM]P <-- Matrix multi. goes from R to L LorentzRotation tf; tf *= boost_to_headon; @@ -56,6 +81,10 @@ inline LorentzRotation determine_boost(PxPyPzEVector ei, PxPyPzEVector pi) { tf *= rotAboutY; tf *= boost_to_cm; + // PxPyPzEVector em = tf(eo); + // PxPyPzEVector pm = tf(po); + // cout << "boost matrix e and p: " << Form("(%f, %f, %f, %f) (%f, %f, %f, %f)", em.Px(), em.Py(), em.Pz(), em.E(), pm.Px(), pm.Py(), pm.Pz(), pm.E()) << endl; + return tf; } diff --git a/ElectronID/Boost/getBoost.h b/ElectronID/Boost/getBoost.h new file mode 100644 index 0000000..f08665a --- /dev/null +++ b/ElectronID/Boost/getBoost.h @@ -0,0 +1,47 @@ +#pragma once + +#include "Beam.h" +#include "Boost.h" + +#include +using ROOT::Math::PxPyPzEVector; + +#include +using ROOT::Math::LorentzRotation; + +LorentzRotation getBoost(double eE, double eN, double mE, double mN) { + + TVector3 ve(0,0,-sqrt(eE*eE-mE*mE)); + TVector3 vn(0,0,sqrt(eN*eN-mN*mN)); + + const PxPyPzEVector ei( + eicrecon::round_beam_four_momentum( + ve, + mE, + {-1*eE}, + 0.0) + ); + + const PxPyPzEVector ni( + eicrecon::round_beam_four_momentum( + vn, + mN, + {eN}, + -0.025) + ); + + // std::cout << "initial electron beam: " << Form("(%f, %f, %f, %f)", ei.Px(), ei.Py(), ei.Pz(), ei.E()) << std::endl; + // std::cout << "initial nucleon beam: " << Form("(%f, %f, %f, %f)", ni.Px(), ni.Py(), ni.Pz(), ni.E()) << std::endl; + // std::cout << "Created vector, e, p (mrad) " << ei.Theta() * 1000 << " " << ni.Theta() * 1000 << std::endl; + + LorentzRotation boost = eicrecon::determine_boost(ei, ni); + + PxPyPzEVector boosted_e = boost(ei); + PxPyPzEVector boosted_n = boost(ni); + + // std::cout << "Boosted electron beam: " << Form("(%f, %f, %f, %f)", boosted_e.Px(), boosted_e.Py(), boosted_e.Pz(), boosted_e.E()) << std::endl; + // std::cout << "Boosted nucleon beam: " << Form("(%f, %f, %f, %f)", boosted_n.Px(), boosted_n.Py(), boosted_n.Pz(), boosted_n.E()) << std::endl; + // std::cout << "Incoming headon, e, p (mrad) " << boosted_e.Theta() * 1000 << " " << boosted_n.Theta() * 1000 << std::endl; + + return boost; +} diff --git a/ElectronID/ElectronID.cc b/ElectronID/ElectronID.cc index c7a77a0..508a21c 100644 --- a/ElectronID/ElectronID.cc +++ b/ElectronID/ElectronID.cc @@ -20,7 +20,7 @@ ElectronID::ElectronID() { mDeltaH_min = 0.*mEe; mDeltaH_min = 5.*mEe; - mIsoR = 0.4; + mIsoR = 0.7; mIsoE = 0.9; minTrackPoints = 3; @@ -39,7 +39,8 @@ ElectronID::ElectronID(double Ee, double Eh) { mDeltaH_min = 0.*mEe; mDeltaH_min = 5.*mEe; - mIsoR = 0.4; + // mIsoR = 2; // tested for theta > 150 + mIsoR = 0.7; mIsoE = 0.9; minTrackPoints = 3; @@ -63,18 +64,16 @@ void ElectronID::SetEvent(const podio::Frame* event) { jet_e_det.clear(); pi_det.clear(); else_det.clear(); + det_val.clear(); // std::cout << "** Event set in ElectronID. " << std::endl; return; } edm4hep::MCParticle ElectronID::GetMC(edm4eic::ReconstructedParticle e_rec) { - // std::cout << "Available collections:" << std::endl; - // for (const auto& name : mEvent->getAvailableCollections()) { - // std::cout << " " << name << std::endl; - // } + // std::cout << "Getting MC particle associated with reconstructed particle..." << std::endl; - const auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + const auto& RecoMC = static_cast(*(mEvent->get("ReconstructedParticleAssociations"))); for(const auto& assoc : RecoMC) { if(assoc.getRec() == e_rec) return assoc.getSim(); @@ -89,7 +88,7 @@ int ElectronID::Check_eID(edm4eic::ReconstructedParticle e_rec) { if ( meMC.size() == 0 ) return 86; // No MC electron found - const auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + const auto& RecoMC = static_cast(*(mEvent->get("ReconstructedParticleAssociations"))); for(const auto& assoc : RecoMC) { if(assoc.getRec() == e_rec) { @@ -105,9 +104,9 @@ int ElectronID::Check_eID(edm4eic::ReconstructedParticle e_rec) { void ElectronID::CheckClusters() { - const auto& EcalEndcapNClusters = mEvent->get("EcalEndcapNClusters"); - const auto& EcalBarrelScFiClusters = mEvent->get("EcalBarrelScFiClusters"); - const auto& EcalEndcapPClusters = mEvent->get("EcalEndcapPClusters"); + const auto& EcalEndcapNClusters = static_cast(*(mEvent->get("EcalEndcapNClusters"))); + const auto& EcalBarrelScFiClusters = static_cast(*(mEvent->get("EcalBarrelScFiClusters"))); + const auto& EcalEndcapPClusters = static_cast(*(mEvent->get("EcalEndcapPClusters"))); std::cout << " Number of clusters in EcalEndcapN: " << EcalEndcapNClusters.size() << std::endl; std::cout << " Number of clusters in EcalBarrelScFi: " << EcalBarrelScFiClusters.size() << std::endl; @@ -123,79 +122,81 @@ edm4eic::ReconstructedParticleCollection ElectronID::FindHadronicFinalState(int meRecon.setSubsetCollection(); // auto& rcparts = mEvent->get("HadronicFinalState"); - const auto& rcparts = mEvent->get("ReconstructedParticles"); + const auto& rcparts = static_cast(*(mEvent->get("ReconstructedParticles"))); for(const auto& mcp : rcparts) { if ( mcp.getObjectID().index != object_id ) meRecon.push_back(mcp); } - + return meRecon; } edm4eic::ReconstructedParticleCollection ElectronID::FindScatteredElectron() { // std::cout << "\nFinding scattered electron candidates..." << std::endl; - // CheckClusters(); // Get all the edm4eic objects needed for electron ID - const auto& rcparts = mEvent->get("ReconstructedParticles"); + const auto& rcparts = static_cast(*(mEvent->get("ReconstructedParticles"))); // Create collection for storing scattered electron candidates // (subset collection of ReconstructedParticleCollection) edm4eic::ReconstructedParticleCollection scatteredElectronCandidates; scatteredElectronCandidates.setSubsetCollection(); + edm4eic::ReconstructedParticleCollection scatteredElectronCandidates_noEoP; + scatteredElectronCandidates_noEoP.setSubsetCollection(); + // Loop over all ReconstructedParticles for this event for (const auto& reconPart : rcparts) { - // std::cout << "par id: " << reconPart.getPDG() << " cluster size: " << reconPart.getClusters().size() << ", track size: " << reconPart.getTracks().size() << std::endl; - - // for (const auto& track : reconPart.getTracks()) - // { - // int n_measurements = track.measurements_size(); - // int n_track_hits = track.getTrajectory().getNMeasurements(); - // // std::cout << " track with " << n_measurements << " measurements, " << n_track_hits << " hits." << std::endl; - // } - // Require at least one track and one cluster - if(reconPart.getClusters().size() == 0 || reconPart.getTracks().size() == 0) continue; + if(reconPart.getClusters().size() > 0 && reconPart.getTracks().size() > 0) + { + // Require negative particle + if(reconPart.getCharge() >= 0) + continue; - int n_track_points = reconPart.getTracks()[0].measurements_size(); - if ( n_track_points < minTrackPoints ) continue; + int n_track_points = reconPart.getTracks()[0].measurements_size(); - // Require negative particle - if(reconPart.getCharge() >= 0) continue; + // Calculate rcpart_ member variables for this event + CalculateParticleValues(reconPart, rcparts); - // Calculate rcpart_ member variables for this event - CalculateParticleValues(reconPart, rcparts); + // Calculate isolation fraction for this event + double recon_isoE = rcpart_sum_cluster_E / rcpart_isolation_E; - // Calculate E/p and isolation fraction for this event - // Note that the rcpart_ variables are set in CalculateParticleValues - double recon_EoP = rcpart_sum_cluster_E / edm4hep::utils::magnitude(reconPart.getMomentum()); - double recon_isoE = rcpart_sum_cluster_E / rcpart_isolation_E; + // Calculate E/p for this event + double recon_EoP = rcpart_sum_cluster_E / edm4hep::utils::magnitude(reconPart.getMomentum()); - int found_id = Check_eID(reconPart); - if ( found_id == 0 ) - e_det.push_back({n_track_points, recon_EoP, recon_isoE}); - else if ( found_id == 11 ) - jet_e_det.push_back({n_track_points, recon_EoP, recon_isoE}); - else if ( found_id == -211 ) - pi_det.push_back({n_track_points, recon_EoP, recon_isoE}); - else - else_det.push_back({n_track_points, recon_EoP, recon_isoE}); + det_val.push_back({Check_eID(reconPart), n_track_points, recon_EoP, recon_isoE}); - // Apply scattered electron ID cuts - if(recon_EoP < mEoP_min || recon_EoP > mEoP_max) continue; - if(recon_isoE < mIsoE) continue; + if ( n_track_points < minTrackPoints ) + continue; - // If particle passes cuts, add to output collection - scatteredElectronCandidates.push_back(reconPart); + if(recon_isoE < mIsoE) + continue; - } + double trackTheta = edm4hep::utils::anglePolar(reconPart.getMomentum())*(180./M_PI); + double clusterTheta = GetMomentumVectorFromCluster(reconPart, 0).Theta()*(180./M_PI); - return scatteredElectronCandidates; + if ( recon_EoP > mEoP_min && recon_EoP < mEoP_max ) + { + scatteredElectronCandidates.push_back(reconPart); + continue; + } + else if ( (trackTheta > 158 && trackTheta < 162) || (clusterTheta > 22 && clusterTheta < 33) ) + { + scatteredElectronCandidates_noEoP.push_back(reconPart); + continue; + } + } + } + // If EoP is found use that, otherwise loosen cuts + if (scatteredElectronCandidates.size() > 0) + return scatteredElectronCandidates; + else + return scatteredElectronCandidates_noEoP; } edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { @@ -203,7 +204,7 @@ edm4hep::MCParticleCollection ElectronID::GetMCHadronicFinalState() { edm4hep::MCParticleCollection mhMC; mhMC.setSubsetCollection(); - const auto& mcparts = mEvent->get("MCParticles"); + const auto& mcparts = static_cast(*(mEvent->get("MCParticles"))); std::vector mc_hadronic; edm4hep::MCParticleCollection meMC = GetMCElectron(); @@ -227,14 +228,12 @@ edm4hep::MCParticleCollection ElectronID::GetMCElectron() { edm4hep::MCParticleCollection meMC; meMC.setSubsetCollection(); - const auto& mcparts = mEvent->get("MCParticles"); + const auto& mcparts = static_cast(*(mEvent->get("MCParticles"))); if ( eScatIndex != -1 ) meMC.push_back(mcparts[eScatIndex]); //// - // cout << "\n** Searching for MC electrons..." << endl; - for (const auto& mcp : mcparts) { if (mcp.getPDG() != 11 || mcp.getGeneratorStatus() != 4) @@ -246,6 +245,7 @@ edm4hep::MCParticleCollection ElectronID::GetMCElectron() { int shortest_gen = 999; int generations = 0; edm4hep::MCParticle meMC_candidates; + bool found_candidate = false; while (!stack.empty() ) { generations++; @@ -258,6 +258,7 @@ edm4hep::MCParticleCollection ElectronID::GetMCElectron() { { shortest_gen = generations; meMC_candidates = cur; + found_candidate = true; } break; } @@ -268,19 +269,10 @@ edm4hep::MCParticleCollection ElectronID::GetMCElectron() { } } - if ( meMC_candidates.isAvailable() ) + if ( found_candidate ) meMC.push_back(meMC_candidates); } - if ( meMC.size() == 0 ) - { - std::cout << "** No MC electron found! " << std::endl; - for (const auto& mcp : mcparts) - cout << mcp << endl; - } - - // cout << "** Total MC electrons found: " << meMC.size() << endl; - return meMC; } @@ -295,7 +287,7 @@ edm4eic::ReconstructedParticleCollection ElectronID::GetTruthReconElectron() { if ( meMC.size() == 0 ) return meRecon; // No MC electron found - const auto& RecoMC = mEvent->get("ReconstructedParticleAssociations"); + const auto& RecoMC = static_cast(*(mEvent->get("ReconstructedParticleAssociations"))); for(const auto& assoc : RecoMC) { @@ -303,10 +295,16 @@ edm4eic::ReconstructedParticleCollection ElectronID::GetTruthReconElectron() { if(assoc.getSim() == meMC[0]) { meRecon.push_back(assoc.getRec()); - break; + // break; } } + const auto& rcparts = static_cast(*(mEvent->get("ReconstructedParticles"))); + edm4hep::Vector3f lead_pos(meMC[0].getEndpoint().x, meMC[0].getEndpoint().y, meMC[0].getEndpoint().z); + CheckSurroundingClusters(lead_pos, rcparts); + + // std::cout << meRecon.size() << " reconstructed particles associated with the MC electron." << std::endl; + return meRecon; } @@ -316,7 +314,6 @@ void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& r rcpart_sum_cluster_E = 0.; rcpart_lead_cluster_E = 0.; rcpart_isolation_E = 0.; - rcpart_deltaH = 0.; const edm4eic::Cluster* lead_cluster = nullptr; @@ -330,7 +327,17 @@ void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& r if(!lead_cluster) return; - const auto& lead_pos = lead_cluster->getPosition(); + CheckSurroundingClusters(lead_cluster->getPosition(), rcparts); + + return; +} + +void ElectronID::CheckSurroundingClusters(const edm4hep::Vector3f& lead_pos, + const edm4eic::ReconstructedParticleCollection& rcparts) { + + rcpart_isolation_E = 0.; + rcpart_n_clusters = 0; + double lead_eta = edm4hep::utils::eta(lead_pos); double lead_phi = edm4hep::utils::angleAzimuthal(lead_pos); @@ -353,6 +360,7 @@ void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& r // Check if the cluster is within the isolation cone if (dR < mIsoR) { rcpart_isolation_E += other_cluster.getEnergy(); + rcpart_n_clusters ++; } } } @@ -362,23 +370,38 @@ void ElectronID::CalculateParticleValues(const edm4eic::ReconstructedParticle& r void ElectronID::GetEminusPzSum(double &TrackEminusPzSum, double &CalEminusPzSum) { - const auto& rcparts = mEvent->get("ReconstructedParticles"); + const auto& rcparts = static_cast(*(mEvent->get("ReconstructedParticles"))); for (const auto& reconPart : rcparts) { // Require at least one track and one cluster - if(reconPart.getClusters().size() == 0 || reconPart.getTracks().size() == 0) continue; - - int n_track_points = reconPart.getTracks()[0].measurements_size(); - if ( n_track_points < minTrackPoints ) continue; + // if(reconPart.getClusters().size() == 0 || reconPart.getTracks().size() == 0) continue; - PxPyPzEVector vC(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, GetCalorimeterEnergy(reconPart)); - vC = boost(vC); - CalEminusPzSum += (vC.E() - vC.Pz()); - - PxPyPzEVector vT(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, reconPart.getEnergy()); - vT = boost(vT); - TrackEminusPzSum += (vT.E() - vT.Pz()); + if(reconPart.getTracks().size() > 0 ) + { + int n_track_points = reconPart.getTracks()[0].measurements_size(); + if ( n_track_points < minTrackPoints ) continue; + + PxPyPzEVector vT(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, reconPart.getEnergy()); + vT = boost(vT); + TrackEminusPzSum += (vT.E() - vT.Pz()); + + if ( reconPart.getClusters().size() > 0 ) + { + PxPyPzEVector vC(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, GetCalorimeterEnergy(reconPart)); + // PxPyPzEVector vC = GetMomentumVectorFromCluster(reconPart, reconPart.getMass()); + // if ( reconPart.getTracks().size() > 0 && n_track_points >= minTrackPoints ) + // vC.SetPxPyPzE(reconPart.getMomentum().x, reconPart.getMomentum().y, reconPart.getMomentum().z, GetCalorimeterEnergy(reconPart)); + vC = boost(vC); + CalEminusPzSum += (vC.E() - vC.Pz()); + } + } + else if (reconPart.getClusters().size() > 0 ) + { + PxPyPzEVector vC = GetMomentumVectorFromCluster(reconPart, 0); + vC = boost(vC); + CalEminusPzSum += (vC.E() - vC.E()*std::cos(vC.Theta())); + } } // std::cout << " recon E - Pz sum: " << reconEminusPzSum << std::endl; @@ -392,7 +415,7 @@ edm4eic::ReconstructedParticle ElectronID::SelectHighestPT(const edm4eic::Recons double max_pT = 0.; for(const auto& ecand : ecandidates) { - double e_pT = edm4hep::utils::magnitudeTransverse(ecand.getMomentum()); + double e_pT = ecand.getTracks().size() > 0 ? edm4hep::utils::magnitudeTransverse(ecand.getMomentum()) : GetMomentumVectorFromCluster(ecand, 0.000511).Pt(); if(e_pT > max_pT) { erec = ecand; max_pT = e_pT; @@ -400,7 +423,45 @@ edm4eic::ReconstructedParticle ElectronID::SelectHighestPT(const edm4eic::Recons } return erec; +} + +double ElectronID::GetClusterCone(const edm4eic::ReconstructedParticle& rcp, double frac=1) +{ + const edm4eic::Cluster* lead_cluster = nullptr; + double sum_cluster_E = 0.; + double lead_cluster_E = 0.; + + for (const auto& cluster : rcp.getClusters()) { + sum_cluster_E += cluster.getEnergy(); + if(cluster.getEnergy() > lead_cluster_E) { + lead_cluster = &cluster; + lead_cluster_E = cluster.getEnergy(); + } + } + + if (!lead_cluster) + return -1.; + + std::vector> dr_de; + + for (const auto& cluster : rcp.getClusters()) + { + if (lead_cluster == &cluster) + continue; + double d_eta = edm4hep::utils::eta(cluster.getPosition()) - edm4hep::utils::eta(lead_cluster->getPosition()); + double d_phi = edm4hep::utils::angleAzimuthal(cluster.getPosition()) - edm4hep::utils::angleAzimuthal(lead_cluster->getPosition()); + + if (d_phi > M_PI) d_phi -= 2 * M_PI; + if (d_phi < -M_PI) d_phi += 2 * M_PI; + + double dR = std::sqrt(std::pow(d_eta, 2) + std::pow(d_phi, 2)); + dr_de.emplace_back(dR, cluster.getEnergy()); + } + + std::sort(dr_de.begin(), dr_de.end(), [](const auto& left, const auto& right) {return left.first < right.first;}); + + return dr_de.back().first; // Return the dR of the farthest cluster } double ElectronID::GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rcp) { @@ -413,49 +474,46 @@ double ElectronID::GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rc } -void ElectronID::GetBeam(LorentzRotation &boost, TLorentzVector &in_e, TLorentzVector &in_n) -{ - edm4hep::MCParticle mc_electron; - edm4hep::MCParticle mc_nucleon; - - auto& mcparts = mEvent->get("MCParticles"); - vector spec_protons; - - for(const auto& mcp : mcparts) - { - if ( mcp.getGeneratorStatus() == 4 ) - { - if ( mcp.getPDG() == ID_ELECTRON ) - mc_electron = mcp; - else - mc_nucleon = mcp; - } - } - - if ( !mc_electron.isAvailable() || !mc_nucleon.isAvailable() ) - return; - - in_e.SetPxPyPzE(mc_electron.getMomentum().x, mc_electron.getMomentum().y, mc_electron.getMomentum().z, mc_electron.getEnergy()); - in_n.SetPxPyPzE(mc_nucleon.getMomentum().x, mc_nucleon.getMomentum().y, mc_nucleon.getMomentum().z, mc_nucleon.getEnergy()); - - // get boost matrix -- redo every run because the proton / neutron has different mass .. but really this should not change per event .. to be changed - const PxPyPzEVector ei( - eicrecon::round_beam_four_momentum( - mc_electron.getMomentum(), - mc_electron.getMass(), - {-1*mEe}, - 0.0) - ); - - const PxPyPzEVector pi( - eicrecon::round_beam_four_momentum( - mc_nucleon.getMomentum(), - mc_nucleon.getMass(), - {mEh}, - -0.025) - ); - - boost = eicrecon::determine_boost(ei, pi); // Get boost to colinear frame +double ElectronID::GetClusterTheta(const edm4eic::ReconstructedParticle& rcp) { - return; + const edm4eic::Cluster* lead_cluster = nullptr; + double lead_E = 0.; + + for (const auto& cluster : rcp.getClusters()) { + if(cluster.getEnergy() > lead_E) { + lead_cluster = &cluster; + lead_E = cluster.getEnergy(); + } + } + + if(!lead_cluster) return -999.; + + return lead_cluster->getIntrinsicTheta(); +} + +PxPyPzEVector ElectronID::GetMomentumVectorFromCluster(const edm4eic::ReconstructedParticle& rcp, double mass) { + + const edm4eic::Cluster* lead_cluster = nullptr; + double sum_cluster_E = 0.; + double lead_E = 0.; + + for (const auto& cluster : rcp.getClusters()) { + sum_cluster_E += cluster.getEnergy(); + if(cluster.getEnergy() > lead_E) { + lead_cluster = &cluster; + lead_E = cluster.getEnergy(); + } + } + + if(!lead_cluster) + cout << "Warning: No clusters found for this reconstructed particle!" << endl; + + if(!lead_cluster) return PxPyPzEVector(0, 0, 0, 0); + + double p = std::sqrt(std::pow(sum_cluster_E, 2) - std::pow(mass, 2)); + double px = p * (lead_cluster->getPosition().x / edm4hep::utils::magnitude(lead_cluster->getPosition())); + double py = p * (lead_cluster->getPosition().y / edm4hep::utils::magnitude(lead_cluster->getPosition())); + double pz = p * (lead_cluster->getPosition().z / edm4hep::utils::magnitude(lead_cluster->getPosition())); + + return PxPyPzEVector(px, py, pz, sum_cluster_E); } diff --git a/ElectronID/ElectronID.hh b/ElectronID/ElectronID.hh index c34b827..0633c11 100644 --- a/ElectronID/ElectronID.hh +++ b/ElectronID/ElectronID.hh @@ -6,10 +6,16 @@ #include "edm4eic/ReconstructedParticleCollection.h" #include "edm4eic/MCRecoParticleAssociationCollection.h" #include "edm4hep/MCParticleCollection.h" +#include "edm4hep/utils/vector_utils.h" +#include "edm4eic/ClusterCollection.h" #include using ROOT::Math::LorentzRotation; +#include +using ROOT::Math::PxPyPzEVector; + +#include class ElectronID{ @@ -37,9 +43,11 @@ public: edm4hep::MCParticleCollection GetMCHadronicFinalState(); edm4eic::ReconstructedParticle SelectHighestPT(const edm4eic::ReconstructedParticleCollection& rcparts); double GetCalorimeterEnergy(const edm4eic::ReconstructedParticle& rcp); + double GetClusterCone(const edm4eic::ReconstructedParticle& rcp, double frac=1); + PxPyPzEVector GetMomentumVectorFromCluster(const edm4eic::ReconstructedParticle& rcp, double mass); + double GetClusterTheta(const edm4eic::ReconstructedParticle& rcp); void GetEminusPzSum(double &TrackEminusPzSum, double &CalEminusPzSum); void CheckClusters(); - void GetBeam(LorentzRotation &boost, TLorentzVector &in_e, TLorentzVector &in_n); double get_mEoP_min() const { return mEoP_min; } double get_mEoP_max() const { return mEoP_max; } @@ -47,6 +55,7 @@ public: double get_mDeltaH_max() const { return mDeltaH_max; } double get_mIsoR() const { return mIsoR; } double get_mIsoE() const { return mIsoE; } + int GetMinTrackPoints() const { return minTrackPoints; } // for HFS QA vector hfs_dpt; @@ -55,15 +64,19 @@ public: vector hfs_theta; struct DetValues { + int parType; // 0 for dis electron, rest follow pdg code int nTrackPoints; double recon_EoP; double recon_isoE; }; + vector det_val; vector e_det; vector jet_e_det; vector pi_det; vector else_det; + double rcpart_n_clusters; + private: const podio::Frame* mEvent; @@ -82,11 +95,12 @@ private: void CalculateParticleValues(const edm4eic::ReconstructedParticle& rcp, const edm4eic::ReconstructedParticleCollection& rcparts); + void CheckSurroundingClusters(const edm4hep::Vector3f& lead_pos, + const edm4eic::ReconstructedParticleCollection& rcparts); double rcpart_sum_cluster_E; double rcpart_lead_cluster_E; double rcpart_isolation_E; - double rcpart_deltaH; int eScatIndex; }; diff --git a/ElectronID/InclusiveSkim.C b/ElectronID/InclusiveSkim.C index c21fcad..e99bf0f 100644 --- a/ElectronID/InclusiveSkim.C +++ b/ElectronID/InclusiveSkim.C @@ -1,12 +1,6 @@ #include "preLoadLib.hh" // Data model headers -#include "edm4eic/ReconstructedParticleCollection.h" -#include "edm4hep/MCParticleCollection.h" -#include "edm4hep/utils/vector_utils.h" -#include "edm4hep/utils/kinematics.h" -#include "edm4eic/ClusterCollection.h" -#include "edm4eic/MCRecoParticleAssociationCollection.h" #include "podio/Frame.h" #include "podio/ROOTReader.h" @@ -20,6 +14,7 @@ // Analysis headers #include "InclusiveSkim.h" #include "ElectronID.cc" +#include "Boost/getBoost.h" void InclusiveSkim() { @@ -30,16 +25,21 @@ void InclusiveSkim() { // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; // access remote file - vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; + vector inFiles = {"root://dtn-eic.jlab.org:1094//volatile/eic/EPIC//RECO/26.02.0/epic_craterlake/DIS/NC/18x275/minQ2=10/pythia8NCDIS_18x275_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; auto reader = podio::ROOTReader(); reader.openFiles(inFiles); - ElectronID* eFinder = new ElectronID(Ee, Eh); - TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); CreateOutputTree(outFileName); + ElectronID* eFinder = new ElectronID(Ee, Eh); + eFinder->SetEoPMin(0.8); // set E/p cut + eFinder->SetIsolation(0.7, 0.9); // set isolation parameters (cone size, energy fraction) + eFinder->SetMinTrackPoints(4); // set number of minimum points required for a track + + LorentzRotation boost = getBoost( Ee, Eh, MASS_ELECTRON, MASS_PROTON); // if you have your own boost calculation, you can replace this line. + eFinder->SetBoost(boost); for(size_t ev = 0; ev < reader.getEntries("events"); ev++) { diff --git a/ElectronID/InclusiveSkim.h b/ElectronID/InclusiveSkim.h index 8ec7824..bdf3177 100644 --- a/ElectronID/InclusiveSkim.h +++ b/ElectronID/InclusiveSkim.h @@ -11,6 +11,9 @@ void ResetVariables(); void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, float& xB, float& Q2, float& W, float& y, float& nu); TLorentzVector GetHadronBeam(double fEh); +#define MASS_ELECTRON 0.000511 +#define MASS_PROTON 0.93827 + using namespace std; int positive_eID; diff --git a/ElectronID/InclusiveSkimQA.C b/ElectronID/InclusiveSkimQA.C deleted file mode 100644 index 85325d2..0000000 --- a/ElectronID/InclusiveSkimQA.C +++ /dev/null @@ -1,239 +0,0 @@ -// Find inclusive scattered electrons - -#include "preLoadLib.hh" - -#include "InclusiveSkimQA.h" - -void InclusiveSkimQA() -{ - // Standard setup - - SetePICStyle(); - - double Ee = 10.; - double Eh = 100.; - - // Set what electron ID to use - int eID_type = truthID; - - // access local file - // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; - - // access remote file - vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; - - // .. input setup - auto reader = podio::ROOTReader(); - reader.openFiles(inFiles); - - // .. output setup; - TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); - CreateOutputTree(outFileName); - - // .. ElectronID setup - ElectronID* eFinder = new ElectronID(Ee, Eh); - - DefineHistograms(); - - // Analysis loop - - for( size_t ev = 0; ev < reader.getEntries("events"); ev++ ) - { - const auto event = podio::Frame(reader.readNextEntry("events")); - eFinder->SetEvent(&event); - - if(ev%100==0) - cout << "Analysing event " << ev << "/" << reader.getEntries("events") << std::endl; - - // Generator information (mcID) - edm4hep::MCParticleCollection e_mc = eFinder->GetMCElectron(); - - // Use MC to find reconstructed electron (TruthID) - auto e_truth = eFinder->GetTruthReconElectron(); - - // Find scattered electrons (reconID) - auto e_candidates = eFinder->FindScatteredElectron(); - edm4eic::ReconstructedParticle e_rec; - - // If there are multiple candidates, select one with highest pT - if(e_candidates.size() > 0) - { - e_rec = eFinder->SelectHighestPT(e_candidates); - mc_PBG = eFinder->Check_eID(e_rec); - - if ( mc_PBG == 0 ) - eID_status = FOUND_E; - else if ( mc_PBG == -211 ) - eID_status = FOUND_PI; - else - eID_status = FOUND_OTHERS; - } - - // Fill histograms - for ( const auto& det_val : eFinder->e_det ) - { - h_EoP_e->Fill(det_val.recon_EoP); - h_isoE_e->Fill(det_val.recon_isoE); - } - for ( const auto& det_val : eFinder->pi_det ) - { - h_EoP_pi->Fill(det_val.recon_EoP); - h_isoE_pi->Fill(det_val.recon_isoE); - } - for ( const auto& det_val : eFinder->else_det ) - { - h_EoP_else->Fill(det_val.recon_EoP); - h_isoE_else->Fill(det_val.recon_isoE); - } - - // Calculate kinematic variables using MC electron - TLorentzVector kprime; - kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, MASS_ELECTRON); - CalculateElectronKinematics(Ee, Eh, kprime, mc_xB, mc_Q2, mc_W2, mc_y, mc_nu); - - outTree->Fill(); - ResetVariables(); - } - - // Canvas - double draw_max = 0.; - - TCanvas* c_EoP = new TCanvas("c_EoP", "c_EoP", 1000, 600); - c_EoP->SetLogy(); - - DrawComparison(c_EoP, h_EoP_e, h_EoP_pi, h_EoP_else, draw_max); - - c_EoP->cd(); - c_EoP->Update(); - - TLine* line_EoP_min = new TLine(eFinder->get_mEoP_min(), 0, eFinder->get_mEoP_min(), draw_max); - line_EoP_min->SetLineColor(kBlack); - line_EoP_min->SetLineStyle(7); - line_EoP_min->Draw("SAME"); - TLine* line_EoP_max = new TLine(eFinder->get_mEoP_max(), 0, eFinder->get_mEoP_max(), draw_max); - line_EoP_max->SetLineColor(kBlack); - line_EoP_max->SetLineStyle(7); - line_EoP_max->Draw("SAME"); - - TCanvas* c_isoE = new TCanvas("c_isoE", "c_isoE", 1000, 600); - c_isoE->SetLogy(); - - DrawComparison(c_isoE, h_isoE_e, h_isoE_pi, h_isoE_else, draw_max); - c_isoE->cd(); - c_isoE->Update(); - - TLine* line_isoE_min = new TLine(eFinder->get_mIsoE(), 0, eFinder->get_mIsoE(), draw_max); - line_isoE_min->SetLineColor(kBlack); - line_isoE_min->SetLineStyle(7); - line_isoE_min->Draw("SAME"); - - // Save - - outFile->cd(); - outTree->Write(outTree->GetName(), 2); - - c_EoP->Write(c_EoP->GetName(), 2); - c_isoE->Write(c_isoE->GetName(), 2); - - return; -} - -void DefineHistograms() { - - h_EoP_e = new TH1D("h_EoP_e", "EoP e; E/p; Counts", 100, 0., 2.); - h_EoP_pi = new TH1D("h_EoP_pi", "EoP pi; E/p; Counts", 100, 0., 2.); - h_EoP_else = new TH1D("h_EoP_else", "EoP; E/p; Counts", 100, 0., 2.); - - h_isoE_e = new TH1D("h_isoE_e", "Isolation Energy; Iso. E; Counts", 100, 0., 2.); - h_isoE_pi = new TH1D("h_isoE_pi", "Isolation Energy; Iso. E; Counts", 100, 0., 2.); - h_isoE_else = new TH1D("h_isoE_else", "Isolation Energy; Iso. E; Counts", 100, 0., 2.); - - return; -} - -void DrawComparison(TCanvas* c, TH1D* &h1, TH1D* &h2, TH1D* &h3, double &draw_max) { - - c->cd(); - - h3->Draw("HIST"); - h3->SetLineColor(kGray+2); - // h3->SetFillColor(kGray); - // h3->SetFillStyle(3003); - draw_max = 1.2*std::max({h1->GetMaximum(), h2->GetMaximum(), h3->GetMaximum()}); - h3->SetMaximum(draw_max); - - h2->Draw("HIST SAME"); - h2->SetLineColor(kBlue); - // h2->SetFillColor(kBlue); - // h2->SetFillStyle(3003); - - h1->Draw("HIST SAME"); - h1->SetLineWidth(2); - h1->SetLineColor(kRed); - h1->SetFillColor(kRed); - h1->SetFillStyle(3003); - - TLegend* leg = new TLegend(0.6, 0.6, 0.88, 0.88); - leg->SetBorderSize(0); - leg->SetFillStyle(0); - leg->AddEntry(h1, "Electrons", "f"); - leg->AddEntry(h2, "Pions", "f"); - leg->AddEntry(h3, "Others", "f"); - leg->Draw(); - - return; -} - -void CreateOutputTree(TString outFileName) { - - outFile = new TFile(outFileName, "RECREATE"); - outTree = new TTree("T_eID", "T_eID"); - - outTree->Branch("eID_status", &eID_status); - outTree->Branch("mc_PBG", &mc_PBG); - - outTree->Branch("mc_xB", &mc_xB); - outTree->Branch("mc_Q2", &mc_Q2); - outTree->Branch("mc_W2", &mc_W2); - outTree->Branch("mc_y", &mc_y); - outTree->Branch("mc_nu", &mc_nu); - - return; -} - -void ResetVariables() { - - eID_status = NO_FOUND; - mc_PBG = 0; - - mc_xB = -999; - mc_Q2 = -999; - mc_W2 = -999; - mc_y = -999; - mc_nu = -999; - - return; -} - -void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, double& xB, double& Q2, double& W2, double& y, double& nu) { - - TLorentzVector ki; ki.SetXYZM(0., 0., -fEe, MASS_ELECTRON); - TLorentzVector P = GetHadronBeam(fEh); - TLorentzVector q = ki - kf; - Q2 = -(q.Dot(q)); - nu = (q.Dot(P))/MASS_PROTON; - xB = Q2/(2.*MASS_PROTON*nu); - y = (q.Dot(P))/(ki.Dot(P)); - W2 = MASS_PROTON*MASS_PROTON + (2.*MASS_PROTON*nu) - Q2; -} - -TLorentzVector GetHadronBeam(double fEh) { - - TLorentzVector hadron_beam; - hadron_beam.SetX(fEh*sin(CROSSING_ANGLE)); - hadron_beam.SetY(0.); - hadron_beam.SetZ(fEh*cos(CROSSING_ANGLE)); - hadron_beam.SetE(std::hypot(fEh, MASS_PROTON)); - return hadron_beam; - -} \ No newline at end of file diff --git a/ElectronID/InclusiveSkimQA.h b/ElectronID/InclusiveSkimQA.h deleted file mode 100644 index be2310f..0000000 --- a/ElectronID/InclusiveSkimQA.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef EIDANA_H -#define EIDANA_H - -#include "podio/Frame.h" -#include "podio/ROOTReader.h" - -#include "constants.h" -#include "ePICStyle.c" - -#include "ElectronID.cc" - -void InclusiveSkimQA(); -void CreateOutputTree(TString outFileName); -void ResetVariables(); - -void CalculateElectronKinematics(double fEe, double fEh, TLorentzVector kf, double& xB, double& Q2, double& W2, double& y, double& nu); -TLorentzVector GetHadronBeam(double fEh); - -void DefineHistograms(); -void DrawComparison(TCanvas* c, TH1D* &h1, TH1D* &h2, TH1D* &h3, double& draw_max); - -TFile* outFile; -TTree* outTree; -// ElectronID* eFinder; - -int eID_status; -int mc_PBG; - -double mc_xB; -double mc_Q2; -double mc_y; -double mc_W2; -double mc_nu; - -enum { NO_FOUND, FOUND_E, FOUND_PI, FOUND_OTHERS }; -enum {reconID, truthID, mcID}; - -TH1D* h_EoP_e; -TH1D* h_EoP_pi; -TH1D* h_EoP_else; -TH1D* h_isoE_e; -TH1D* h_isoE_pi; -TH1D* h_isoE_else; - -#endif \ No newline at end of file diff --git a/ElectronID/README b/ElectronID/README index ed61f31..2a13398 100644 --- a/ElectronID/README +++ b/ElectronID/README @@ -1,9 +1,4 @@ -Three example ROOT macros are provided as examples on how to include the Electron Finder in your analysis. They can also be run to get a ROOT tree with the scattered electrons. - -To run any of them, modify the beam setting, input files, and the type of electronID you want in the beginning of the file. Then run the ROOT macro in eic-shell. - -- InclusvieSkim.C: Simple example on how to call the various functions in the electron library. Kinematics calculated using tracking and calorimeter information are also saved to the tree. - -- InclusiveQA.C: Simple example on saving the scattered electrons to the output tree. QA plots for the cuts applied are made. - -- ReconExample.C: Longer example for also testing the kinematic reconstruction using various algorithms. +DIS Electron Finder: +* Example codes assume the use of eic-shell and PODIO +* ElectronID.cc and ElectronID.hh provides a list of functions for DIS electron analysis. Use the function FindScatteredElectron() for the standard electron finding method. +* InclusiveSkim.C is an example on how to use the ElectronFinder. This can be ran with the most updated eic-shell for simulation campaign after 25.05. diff --git a/ElectronID/ReconExample.C b/ElectronID/ReconExample.C deleted file mode 100644 index 90b4edc..0000000 --- a/ElectronID/ReconExample.C +++ /dev/null @@ -1,376 +0,0 @@ -#include "preLoadLib.hh" - -// Data model headers -#include "edm4eic/ReconstructedParticleCollection.h" -#include "edm4hep/MCParticleCollection.h" -#include "edm4hep/utils/vector_utils.h" -#include "edm4hep/utils/kinematics.h" -#include "edm4eic/ClusterCollection.h" -#include "edm4eic/MCRecoParticleAssociationCollection.h" -#include "podio/Frame.h" -// #include "podio/ROOTFrameReader.h" -- for simulation campaign before March 2023 with eic-shell 25.03.2 -#include "podio/ROOTReader.h" - -// ROOT headers -#include "TTree.h" -#include "TFile.h" -#include "TString.h" -#include "TVector3.h" -#include "TLorentzVector.h" - -// Analysis headers -#include "ReconExample.h" -#include "drawKinematics.C" - -void ReconExample() { - - // Set beam energy - double Ee = 10.; - double Eh = 100.; - - // Set what electron ID to use - int eID_type = truthID; - - // access local file - // vector inFiles = {"pythia8NCDIS_10x100_minQ2=10_beamEffects_xAngle=-0.025_hiDiv_1.0001.eicrecon.tree.edm4eic.root"}; - - // access remote file - vector inFiles = {"root://dtn-rucio.jlab.org:1094//volatile/eic/EPIC/RECO/25.05.0/epic_craterlake/DIS/NC/10x100/minQ2=1/pythia8NCDIS_10x100_minQ2=1_beamEffects_xAngle=-0.025_hiDiv_1.0000.eicrecon.edm4eic.root"}; - - // auto reader = podio::ROOTFrameReader(); - auto reader = podio::ROOTReader(); - reader.openFiles(inFiles); - - // setup eid - ElectronID* eFinder = new ElectronID(Ee, Eh); - - // setup kinematic algorithms - algorithm.push_back(Kinematics("E_Method", 2)); // electron method - algorithm.push_back(Kinematics("JB_Method", 4)); // Jacquet-Blondel method - algorithm.push_back(Kinematics("DA_Method", 1)); // Double-Angle method - algorithm.push_back(Kinematics("Sig_Method", kOrange+1)); // Sigma method - algorithm.push_back(Kinematics("ESig_Method", kGreen+3)); // E-Sigma method - algorithm.push_back(Kinematics("MC", kGray)); // MC info - - // setup output file and histograms - TString outFileName = Form("inclusive_skim_%.0fx%.0fGeV.root", Ee, Eh); - CreateOutputTree(outFileName); - DefineHistograms(); - - // loop events - for(size_t ev = 0; ev < reader.getEntries("events"); ev++) { - - if(ev%1000==0) - cout << "Event " << ev << "/" << reader.getEntries("events") << endl; - - ResetVariables(); - - const auto event = podio::Frame(reader.readNextEntry("events")); - eFinder->SetEvent(&event); - - edm4hep::MCParticleCollection e_mc = eFinder->GetMCElectron(); - - // Skip events without scattered MC electron - if(e_mc.size() == 0) - continue; - - // Set boost and get incoming particles - TLorentzVector in_e; - TLorentzVector in_n; - LorentzRotation boost; - eFinder->GetBeam(boost, in_e, in_n); - in_e = boost(in_e); - in_n =boost(in_n); - - // Calculate kinematic variables using MC electron - TLorentzVector kprime; - kprime.SetXYZM(e_mc[0].getMomentum().x, e_mc[0].getMomentum().y, e_mc[0].getMomentum().z, Me); - TLorentzVector true_e_lab = kprime; - kprime = boost(kprime); // boost back to head-on frame - - // Get momentum vector elements from MC electron - mc_p = edm4hep::utils::magnitude(e_mc[0].getMomentum()); - mc_eta = edm4hep::utils::eta(e_mc[0].getMomentum()); - mc_phi = edm4hep::utils::angleAzimuthal(e_mc[0].getMomentum()); - - // Don't have to boost if we are just calulcating x, Q2, y using e method because they are Lorentz invariant - // But since we boosted the outgoing ones earlier for later analysis, we need to boost the incoming ones as well - CalculateRealElectronKinematics(in_e, in_n, kprime, algorithm[MC]); - - if ( !pass_ke_cut(algorithm[MC]) ) - continue; - - // Set Range for plots - int Qrange = 0; - if ( algorithm[MC].Q2 > 1000 ) - Qrange = 3; - else if ( algorithm[MC].Q2 > 100 ) - Qrange = 2; - else if ( algorithm[MC].Q2 > 10 ) - Qrange = 1; - - // Find scattered electrons using mc association - auto e_truth = eFinder->GetTruthReconElectron(); - - // Find scattered electrons using detector information - auto e_candidates = eFinder->FindScatteredElectron(); - edm4eic::ReconstructedParticle e_rec; - - // If there are multiple candidates, select one with highest pT - if(e_candidates.size() > 0) { - positive_eID = 1; - e_rec = eFinder->SelectHighestPT(e_candidates); - } - - // select which eID we are using - PxPyPzEVector scat_ele(0, 0, 0, -1); - if ( eID_type == truthID ) { - if(e_truth.size() < 1) - continue; - - scat_ele.SetPxPyPzE(e_truth[0].getMomentum().x, e_truth[0].getMomentum().y, e_truth[0].getMomentum().z, e_truth[0].getEnergy()); - } - else if ( eID_type == mcID ) { - scat_ele = true_e_lab; - } - else { - if(!positive_eID) - continue; - - scat_ele.SetPxPyPzE(e_rec.getMomentum().x, e_rec.getMomentum().y, e_rec.getMomentum().z, e_rec.getEnergy()); - } - - PxPyPzEVector rec_e_lab = scat_ele; - if( eID_type!=2 ) - { - // Calculate kinematics using track info only - kprime.SetXYZM(rec_e_lab.Px(), rec_e_lab.Py(), rec_e_lab.Pz(), Me); - TLorentzVector track_kprime = kprime; - h_dEt[Qrange]->Fill((track_kprime.E()-true_e_lab.E())/true_e_lab.E()); - h_dt[Qrange]->Fill((track_kprime.Theta()-true_e_lab.Theta())/true_e_lab.Theta()); - h_dp[Qrange]->Fill((track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); - h_tde[1]->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); - h_tdp->Fill(true_e_lab.Theta()*(180./M_PI), (track_kprime.Phi()-true_e_lab.Phi())/true_e_lab.Phi()); - h_pde->Fill(true_e_lab.Pt(), (track_kprime.E()-true_e_lab.E())/true_e_lab.E()); - h_pt->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.Pt()); - - // Calculate kinematics using track + cluster energy - TVector3 e3v = kprime.Vect(); - - double track_clust_E; - if ( eID_type == truthID ) - track_clust_E = eFinder->GetCalorimeterEnergy(e_truth[0]); - else if ( eID_type == mcID ) - track_clust_E = e_mc[0].getEnergy(); - else - track_clust_E = eFinder->GetCalorimeterEnergy(e_rec); - - e3v.SetMag(track_clust_E); - kprime.SetVectM(e3v, Me); - h_dEc[Qrange]->Fill((track_clust_E-true_e_lab.E())/true_e_lab.E()); - h_tde[0]->Fill(true_e_lab.Theta()*(180./M_PI), (track_clust_E-true_e_lab.E())/true_e_lab.E()); - h_ede->Fill(true_e_lab.E(), (track_clust_E-true_e_lab.E())/true_e_lab.E()); - h_et->Fill(true_e_lab.Theta()*(180./M_PI),true_e_lab.E()); - - TLorentzVector calo_kprime = kprime; - - // // cut example - // if ( algorithm[MC].Q2 > 100 ) - // scat_ele = calo_kprime; - } - - scat_ele = boost(scat_ele); - float theta = scat_ele.Theta(); - float E = scat_ele.E(); - - // Find hadronic final state - double pxsum = 0; - double pysum = 0; - double pzsum = 0; - double Esum = 0; - - // MC and Rec data structure are different.. not sure how to not repeat code here - auto mc_hfsCollection = eFinder->GetMCHadronicFinalState(); - for (const auto p : mc_hfsCollection) { - // Lorentz vector in lab frame - PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); - // Boost to colinear frame - hf = boost(hf); - - pxsum += hf.Px(); - pysum += hf.Py(); - pzsum += hf.Pz(); - Esum += hf.E(); - } - double true_sigma_h = Esum - pzsum; - double true_pt_had = sqrt(pxsum*pxsum + pysum*pysum); - - pxsum = 0; - pysum = 0; - pzsum = 0; - Esum = 0; - - auto hfsCollection = eFinder->FindHadronicFinalState(eID_type, e_rec.getObjectID().index, boost); - for (const auto p : hfsCollection) { - // Lorentz vector in lab frame - // double track_clust_E = eFinder->GetCalorimeterEnergy(p); - // cout << "energy " << track_clust_E << " " << p.getEnergy() << " " << track_clust_E - p.getEnergy() << endl; - PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, p.getEnergy()); - // PxPyPzEVector hf(p.getMomentum().x, p.getMomentum().y, p.getMomentum().z, track_clust_E); - // Boost to colinear frame - hf = boost(hf); - - pxsum += hf.Px(); - pysum += hf.Py(); - pzsum += hf.Pz(); - Esum += hf.E(); - } - - double sigma_h = Esum - pzsum; - double pt_had = sqrt(pxsum*pxsum + pysum*pysum); - - for ( int i = 0; i < eFinder->hfs_dpt.size(); i++ ) - { - h_hfs_dpt->Fill(eFinder->hfs_dpt[i]); - h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpt[i]); - } - - for ( int i = 0; i < eFinder->hfs_dpz.size(); i++ ) - { - h_hfs_dpz->Fill(eFinder->hfs_dpz[i]); - h_hfs_dpt_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_dpz[i]); - } - - for ( int i = 0; i < eFinder->hfs_de.size(); i++ ) - { - h_hfs_de->Fill(eFinder->hfs_de[i]); - h_hfs_de_t->Fill(eFinder->hfs_theta[i], eFinder->hfs_de[i]); - } - - if ( eID_type == mcID ) - { - sigma_h = true_sigma_h; - pt_had = true_pt_had; - } - - // Calculate kinematics - - // example cut - // if ( abs((scat_ele.E() - true_e_lab.E())/true_e_lab.E()) > 0.2 ) - // return; - - if ( E > 0 ) - algorithm[EL].save_variables(calc_elec_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - - if ( hfsCollection.size() != 0 ) - { - h_dhf[Qrange]->Fill((sigma_h-true_sigma_h)/true_sigma_h); - h_dpt[Qrange]->Fill((pt_had-true_pt_had)/true_pt_had); - - algorithm[JB].save_variables(calc_jb_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - - if ( E > 0 ) - { - algorithm[DA].save_variables(calc_da_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - algorithm[SIG].save_variables(calc_sig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - algorithm[ESIG].save_variables(calc_esig_method(E, theta, pt_had, sigma_h, Ee, Eh), Mp); - } - } - - algorithm[MC].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); - for ( int i = 0; i < algorithm.size()-1; i ++ ) - algorithm[i].Process_and_QA(algorithm[MC].xB, algorithm[MC].y, algorithm[MC].Q2); - - - outTree->Fill(); - } - - outFile->cd(); - outTree->Write(outTree->GetName(), 2); - - plot_energy_and_track(); - plot_kinematics_qa(); - - // outFile->Close(); - - return; -} - -void CreateOutputTree(TString outFileName) { - - outFile = new TFile(outFileName, "RECREATE"); - outTree = new TTree("T", "Reconstructed and generated information from EICRecon"); - - outTree->Branch("positive_eID", &positive_eID); - - // Create branches for each algorithm - for ( int i = 0; i < algorithm.size(); i ++ ) - { - outTree->Branch(Form("%s_xB", algorithm[i].method_name.c_str()), &algorithm[i].xB); - outTree->Branch(Form("%s_Q2", algorithm[i].method_name.c_str()), &algorithm[i].Q2); - outTree->Branch(Form("%s_y", algorithm[i].method_name.c_str()), &algorithm[i].y); - outTree->Branch(Form("%s_nu", algorithm[i].method_name.c_str()), &algorithm[i].nu); - outTree->Branch(Form("%s_W2", algorithm[i].method_name.c_str()), &algorithm[i].W2); - } - - outTree->Branch("mc_p", &mc_p); - outTree->Branch("mc_eta", &mc_eta); - outTree->Branch("mc_phi", &mc_phi); - - outTree->Branch("track_p", &track_p); - outTree->Branch("track_eta", &track_eta); - outTree->Branch("track_phi", &track_phi); -} - -void ResetVariables() { - - positive_eID = 0; - - for ( auto &v : algorithm ) - v.reset(); - - mc_p = -999; - mc_eta = -999; - mc_phi = -999; - - track_p = -999; - track_eta = -999; - track_phi = -999; - -} - -// mc kinematics for comparison - use real incident particle kinematics -void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v) { - // input is boosted - TLorentzVector q = ki - kf; - v.Q2 = -(q.Dot(q)); - v.nu = (q.Dot(P))/Mp; - v.xB = v.Q2/(2.*Mp*v.nu); - v.y = (q.Dot(P))/(ki.Dot(P)); - v.W2 = (Mp*Mp + (2.*Mp*v.nu) - v.Q2); -} - -TLorentzVector GetHadronBeam(double fEh) { - - TLorentzVector hadron_beam; - hadron_beam.SetX(fEh*sin(crossing_angle)); - hadron_beam.SetY(0.); - hadron_beam.SetZ(fEh*cos(crossing_angle)); - hadron_beam.SetE(std::hypot(fEh, Mp)); - return hadron_beam; - -} - -bool pass_ke_cut(Kinematics v) -{ - if ( v.y <= 0.01 || v.y >= 0.95 ) - return false; - - if ( v.Q2 < 2 ) - return false; - - if ( v.W2 < 4 ) - return false; - - return true; -} \ No newline at end of file diff --git a/ElectronID/ReconExample.h b/ElectronID/ReconExample.h deleted file mode 100644 index 633fffd..0000000 --- a/ElectronID/ReconExample.h +++ /dev/null @@ -1,63 +0,0 @@ -// Analysis headers -#include "ElectronID.cc" -#include "kinematics.cc" -#include "draw_helper.h" -#include "reconMethod.hh" -#include "constants.h" - -#pragma once - -TFile* outFile = NULL; -TTree* outTree = NULL; - -const double Me = 0.511e-3; // GeV -const double Mp = 0.938272; // GeV -const double crossing_angle = -0.025; // rad - -// QA histograms -TH1F* h_dEc[4]; -TH1F* h_dEt[4]; -TH1F* h_dt[4]; -TH1F* h_dp[4]; -TH2F* h_tde[2]; -TH2F* h_tdp; -TH2F* h_pde; -TH2F* h_ede; -TH2F* h_pt; -TH2F* h_et; - -TH1F* h_dhf[4]; -TH1F* h_dpt[4]; - -TH1F* h_hfs_dpz; -TH1F* h_hfs_dpt; -TH1F* h_hfs_de; -TH2F* h_hfs_dpz_t; -TH2F* h_hfs_dpt_t; -TH2F* h_hfs_de_t; - -enum {EL, JB, DA, SIG, ESIG, MC}; -enum {reconID, truthID, mcID}; - -void SetInputBranchAddresses(); -void CreateOutputTree(TString outFileName); -void ResetVariables(); -void CalculateRealElectronKinematics(TLorentzVector ki, TLorentzVector P, TLorentzVector kf, Kinematics &v); -TLorentzVector GetHadronBeam(double fEh); -void DefineHistograms(); -void plot_kinematics_qa(); -void plot_energy_and_track(); -bool pass_ke_cut(Kinematics v); - -using namespace std; - -int positive_eID; -vector algorithm; - -float mc_p; -float mc_eta; -float mc_phi; - -float track_p; -float track_eta; -float track_phi; \ No newline at end of file diff --git a/ElectronID/constants.h b/ElectronID/constants.h deleted file mode 100644 index 62a8073..0000000 --- a/ElectronID/constants.h +++ /dev/null @@ -1,12 +0,0 @@ -// masses in GeV -#define MASS_ELECTRON 0.000511 -#define MASS_PROTON 0.93827 -#define MASS_NEUTRON 0.93957 -#define MASS_HELIUM3 2.8094 - -// PDG code -#define ID_ELECTRON 11 -#define ID_PROTON 2212 -#define ID_NEUTRON 2112 - -#define CROSSING_ANGLE -0.025 // rad \ No newline at end of file diff --git a/ElectronID/drawKinematics.C b/ElectronID/drawKinematics.C deleted file mode 100644 index 87db218..0000000 --- a/ElectronID/drawKinematics.C +++ /dev/null @@ -1,383 +0,0 @@ -#include "ReconExample.h" - -void DefineHistograms() { - - // assume to split to 4 Q2 regions, should make this more flexible - std::string QrangeName[4] = {"lowQ", "midQ", "highQ", "ultraQ"}; - std::string Qrange[4] = {"Q^{2} #leq 10 (GeV/c^{2})^{2}", "10 (GeV/c^{2})^{2} < Q^{2} #leq 100 (GeV/c^{2})^{2}", "100 (GeV/c^{2})^{2} < Q^{2} #leq 1000 (GeV/c^{2})^{2}", "Q^{2} > 1000 (GeV/c^{2})^{2}"}; - for ( int i = 0; i < 4; i ++ ) - { - h_dEc[i] = new TH1F(Form("H_%s_dE_cal", QrangeName[i].c_str()), Form("%s;(Ee_{reco}-Ee_{true})/Ee_{true};Counts", Qrange[i].c_str()), 100, -1, 1); - h_dEt[i] = new TH1F(Form("H_%s_dE_track", QrangeName[i].c_str()), Form("%s;(Ee_{reco}-Ee_{true})/Ee_{true};Counts", Qrange[i].c_str()), 100, -1, 1); - h_dt[i] = new TH1F(Form("H_%s_dtheta", QrangeName[i].c_str()), Form("%s;(e_{reco}-e_{true})/e_{true};Counts", Qrange[i].c_str()), 40, -0.01, 0.01); - h_dp[i] = new TH1F(Form("H_%s_dphi", QrangeName[i].c_str()), Form("%s;(e_{reco}-e_{true})/e_{true};Counts", Qrange[i].c_str()), 40, -0.01, 0.01); - - h_dhf[i] = new TH1F(Form("H_%s_dhf", QrangeName[i].c_str()), Form("%s;(#delta_{h, reco}-#delta_{h, true})/#delta_{h, true};Counts", Qrange[i].c_str()), 100, -2, 2); - h_dpt[i] = new TH1F(Form("H_%s_dpt", QrangeName[i].c_str()), Form("%s;(p_{t, reco}-p_{t, true})/p_{t, true};Counts", Qrange[i].c_str()), 100, -2, 2); - } - - std::string etype[2] = {"cal", "track"}; - for ( int i = 0; i < 2; i ++ ) - { - h_tde[i] = new TH2F(Form("H_dEvT_%s", etype[i].c_str()), Form("dE_{%s} vs #theta_{mc};#theta_{e};dE/E", etype[i].c_str()), 180, 0, 180, 100, -1, 1); - } - h_tdp = new TH2F(Form("H_dPvT"), Form("d#phi vs #theta_{mc};#theta_{e};d#phi/#phi"), 180, 0, 180, 40, -0.01, 0.01); - h_pde = new TH2F(Form("H_dEvP_%s", etype[1].c_str()), Form("dE_{%s} vs p_{mc};p_{t,e};dE/E", etype[1].c_str()), 180, 0, 60, 100, -0.2, 0.2); - h_ede = new TH2F(Form("H_dEvE_%s", etype[0].c_str()), Form("dE_{%s} vs E_{mc};E_{e};dE/E", etype[0].c_str()), 180, 0, 60, 100, -0.2, 0.2); - h_pt = new TH2F(Form("H_PvT_%s", etype[1].c_str()), Form("p_{t,%s} vs #theta_{mc};#theta_{e};p_{t}", etype[1].c_str()), 180, 0, 180, 240, 0, 80); - h_et = new TH2F(Form("H_EvT_%s", etype[0].c_str()), Form("E_{%s} vs #theta_{mc};#theta_{e};E", etype[0].c_str()), 180, 0, 180, 240, 0, 80); - - h_hfs_dpz = new TH1F("H_HFS_dpz", Form(";(p_{z, reco}-p_{z, true})/p_{z, true};Counts"), 100, -1, 1); - h_hfs_dpt = new TH1F("H_HFS_dpt", Form(";(p_{t, reco}-p_{t, true})/p_{t, true};Counts"), 100, -1, 1); - h_hfs_de = new TH1F("H_HFS_de", Form(";(E_{reco}-E_{true})/E_{true};Counts"), 100, -1, 1); - h_hfs_dpz_t = new TH2F("H_HFS_dpz_vT", Form(";#theta_{mc};(p_{z, reco}-p_{z, true})/p_{z, true}"), 180, 0, 180, 100, -1, 1); - h_hfs_dpt_t = new TH2F("H_HFS_dpt_vT", Form(";#theta_{mc};(p_{t, reco}-p_{t, true})/p_{t, true}"), 180, 0, 180, 100, -1, 1); - h_hfs_de_t = new TH2F("H_HFS_de_vT", Form(";#theta_{mc};(E_{reco}-E_{true})/E_{true}"), 180, 0, 180, 100, -1, 1); -} - -void plot_kinematics_qa() -{ - TCanvas* c_eRecon_eff[algorithm.size()-1]; - - TCanvas* c_qa_plots = new TCanvas("c_qa_plots", "QA", 1600, 1400); - c_qa_plots->Divide(4, 3); - - TLegend* leg = new TLegend(0.60, 0.5, 0.88, 0.85); - leg->SetTextSize(0.04); - leg->SetBorderSize(0); - leg->SetFillColor(0); - - for ( int i = 0; i < algorithm.size()-1; i ++ ) - { - process_eff_hist(algorithm[i].h_xq_eff, algorithm[MC].h_xq); - c_eRecon_eff[i] = draw_2d_efficiency(algorithm[i].h_xq_eff, Form("c_%s_eff", algorithm[i].method_name.c_str()), Form("%s Efficiency", algorithm[i].method_name.c_str()), 1400, 600, false, false); - - for ( int j = 0; j < 4; j ++ ) - { - c_qa_plots->cd(j+1); - algorithm[i].h_dq[j]->Draw("HIST SAME"); - - c_qa_plots->cd(j+1+4); - algorithm[i].h_dx[j]->Draw("HIST SAME"); - - c_qa_plots->cd(j+1+8); - algorithm[i].h_dy[j]->Draw("HIST SAME"); - } - leg->AddEntry(algorithm[i].h_dq[0], algorithm[i].method_name.c_str(), "L"); - } - - for ( int i = 0; i < 12; i ++ ) - { - c_qa_plots->cd(i+1); - gPad->SetTickx(1); - gPad->SetTicky(1); - gPad->SetLeftMargin(0.15); - gPad->SetBottomMargin(0.18); - leg->Draw(); - } - - // - - TCanvas* c_ycut_qa = new TCanvas("c_ycut_qa", "QA_YCUT", 1800, 950); - c_ycut_qa->Divide(6, 3); - - double ycut_peak_max[3][6] = {0}; - for ( int i = 0; i < algorithm.size()-1; i ++ ) - { - for ( int j = 0; j < 6; j ++ ) - { - c_ycut_qa->cd(j+1); - algorithm[i].h_dq_ycut[j]->Draw("HIST SAME"); - if ( algorithm[i].h_dq_ycut[j]->GetMaximum() > ycut_peak_max[0][j] ) - ycut_peak_max[0][j] = algorithm[i].h_dq_ycut[j]->GetMaximum(); - - c_ycut_qa->cd(j+1+6); - algorithm[i].h_dx_ycut[j]->Draw("HIST SAME"); - if ( algorithm[i].h_dx_ycut[j]->GetMaximum() > ycut_peak_max[1][j] ) - ycut_peak_max[1][j] = algorithm[i].h_dx_ycut[j]->GetMaximum(); - - c_ycut_qa->cd(j+1+12); - algorithm[i].h_dy_ycut[j]->Draw("HIST SAME"); - if ( algorithm[i].h_dy_ycut[j]->GetMaximum() > ycut_peak_max[2][j] ) - ycut_peak_max[2][j] = algorithm[i].h_dy_ycut[j]->GetMaximum(); - } - } - - for ( int j = 0; j < 6; j ++ ) - { - algorithm[0].h_dq_ycut[j]->GetYaxis()->SetRangeUser(0, ycut_peak_max[0][j]*1.3); - algorithm[0].h_dx_ycut[j]->GetYaxis()->SetRangeUser(0, ycut_peak_max[1][j]*1.3); - algorithm[0].h_dy_ycut[j]->GetYaxis()->SetRangeUser(0, ycut_peak_max[2][j]*1.3); - } - - for ( int i = 0; i < 18; i ++ ) - { - c_ycut_qa->cd(i+1); - gPad->SetTickx(1); - gPad->SetTicky(1); - // gPad->SetRightMargin(0.05); - gPad->SetLeftMargin(0.15); - gPad->SetBottomMargin(0.2); - leg->Draw(); - } - - // - - TCanvas* c_reco_v_true = new TCanvas("c_reco_v_true", "RECO v TRUE", 1800, 1000); - c_reco_v_true->Divide(algorithm.size()-1, 3); - - for ( int i = 0; i < algorithm.size()-1; i ++ ) - { - c_reco_v_true->cd(i+1); - algorithm[i].h_qvq->Draw("COLZ"); - - c_reco_v_true->cd(i+1+(algorithm.size()-1)); - algorithm[i].h_xvx->Draw("COLZ"); - - c_reco_v_true->cd(i+1+2*(algorithm.size()-1)); - algorithm[i].h_yvy->Draw("COLZ"); - } - - for ( int i = 0; i < (algorithm.size()-1)*3; i ++ ) - { - c_reco_v_true->cd(i+1); - gPad->SetLogz(); - if ( i < (algorithm.size()-1)*2 ) - { - gPad->SetLogx(); - gPad->SetLogy(); - } - gPad->SetTickx(1); - gPad->SetTicky(1); - gPad->SetLeftMargin(0.2); - gPad->SetBottomMargin(0.2); - } - - c_reco_v_true->cd(1); - gPad->Update(); - TLine* l_q_diagonal = new TLine(1, 1, 1e4, 1e4); - l_q_diagonal->SetLineColor(kBlack); - l_q_diagonal->SetLineStyle(7); - - c_reco_v_true->cd(1+(algorithm.size()-1)); - gPad->Update(); - TLine* l_x_diagonal = new TLine(1e-4, 1e-4, 1, 1); - l_x_diagonal->SetLineColor(kBlack); - l_x_diagonal->SetLineStyle(7); - - c_reco_v_true->cd(1+2*(algorithm.size()-1)); - gPad->Update(); - TLine* l_y_diagonal = new TLine(0, 0, 1, 1); - l_y_diagonal->SetLineColor(kBlack); - l_y_diagonal->SetLineStyle(7); - - for ( int i = 0; i < algorithm.size()-1; i ++ ) - { - c_reco_v_true->cd(i+1); - l_q_diagonal->Draw("SAME"); - - c_reco_v_true->cd(i+1+(algorithm.size()-1)); - l_x_diagonal->Draw("SAME"); - - c_reco_v_true->cd(i+1+2*(algorithm.size()-1)); - l_y_diagonal->Draw("SAME"); - } - - // save to tree - - c_qa_plots->Write(); - c_reco_v_true->Write(); - c_ycut_qa->Write(); - - for ( int i = 0; i < algorithm.size()-1; i ++ ) - c_eRecon_eff[i]->Write(); -} - -void plot_energy_and_track() -{ - TCanvas* c1 = new TCanvas("c_cal_and_track_1", "Energy and Theta QA", 1600, 800); - c1->Divide(4, 2); - - for ( int i = 0; i < 8; i ++ ) - { - c1->cd(i+1); - gPad->SetTickx(1); - gPad->SetTicky(1); - gPad->SetLeftMargin(0.2); - gPad->SetBottomMargin(0.2); - } - - TLegend* leg = new TLegend(0.60, 0.70, 0.88, 0.85); - leg->SetTextSize(0.04); - leg->SetBorderSize(0); - leg->SetFillColor(0); - leg->SetFillStyle(0); - - leg->AddEntry(h_dEt[0], "Track", "L"); - leg->AddEntry(h_dEc[0], "Calorimeter", "L"); - - TLegend* leg_a = new TLegend(0.70, 0.5, 0.88, 0.85); - leg_a->SetTextSize(0.04); - leg_a->SetBorderSize(0); - leg_a->SetFillColor(0); - leg_a->SetFillStyle(0); - - leg_a->AddEntry(h_dp[0], "#phi_{e}", "L"); - leg_a->AddEntry(h_dt[0], "#theta_{e}", "L"); - - - for ( int i = 0; i < 4; i ++ ) - { - c1->cd(i+1); - h_dEt[i]->Draw("HIST SAME"); - h_dEt[i]->SetStats(0); - h_dEt[i]->SetLineColor(kRed); - format_eid_histogram(h_dEt[i]); - - h_dEc[i]->Draw("HIST SAME"); - h_dEc[i]->SetStats(0); - h_dEc[i]->SetLineColor(kBlue); - format_eid_histogram(h_dEc[i]); - - h_dEt[i]->GetYaxis()->SetRangeUser(0, fmax(h_dEt[i]->GetMaximum(), h_dEc[i]->GetMaximum())*1.1); - h_dEt[i]->SetStats(0); - - leg->Draw(); - - c1->cd(i+1+4); - h_dt[i]->Draw("HIST SAME"); - h_dt[i]->SetStats(0); - format_eid_histogram(h_dt[i]); - - h_dp[i]->Draw("HIST SAME"); - h_dp[i]->SetStats(0); - h_dp[i]->SetLineColor(kRed); - - leg_a->Draw(); - } - - TCanvas* c2 = new TCanvas("c_cal_and_track_2", "Energy and Theta QA", 1200, 900); - c2->Divide(3, 3); - - for ( int i = 0; i < 9; i ++ ) - { - c2->cd(i+1); - gPad->SetTickx(1); - gPad->SetTicky(1); - gPad->SetLogz(); - gPad->SetLeftMargin(0.2); - gPad->SetBottomMargin(0.2); - } - - c2->cd(1); - h_tde[0]->Draw("COLZ"); - h_tde[0]->SetStats(0); - format_eid_histogram(h_tde[0]); - - c2->cd(2); - h_tde[1]->Draw("COLZ"); - h_tde[1]->SetStats(0); - format_eid_histogram(h_tde[1]); - - c2->cd(3); - h_tdp->Draw("COLZ"); - h_tdp->SetStats(0); - format_eid_histogram(h_tdp); - - c2->cd(4); - h_et->Draw("COLZ"); - h_et->SetStats(0); - format_eid_histogram(h_et); - - c2->cd(5); - h_pt->Draw("COLZ"); - h_pt->SetStats(0); - format_eid_histogram(h_pt); - - c2->cd(7); - h_ede->Draw("COLZ"); - h_ede->SetStats(0); - format_eid_histogram(h_ede); - - c2->cd(8); - h_pde->Draw("COLZ"); - h_pde->SetStats(0); - format_eid_histogram(h_pde); - - TCanvas* c3 = new TCanvas("c_cal_and_track_3", "Hadronic final state QA", 1600, 800); - c3->Divide(4, 2); - - for ( int i = 0; i < 8; i ++ ) - { - c3->cd(i+1); - gPad->SetTickx(1); - gPad->SetTicky(1); - gPad->SetLeftMargin(0.2); - gPad->SetBottomMargin(0.2); - } - - for ( int i = 0; i < 4; i ++ ) - { - c3->cd(i+1); - h_dhf[i]->Draw("HIST SAME"); - h_dhf[i]->SetStats(0); - // h_dhf[i]->SetLineColor(kRed); - format_eid_histogram(h_dhf[i]); - - c3->cd(i+1+4); - h_dpt[i]->Draw("HIST SAME"); - h_dpt[i]->SetStats(0); - format_eid_histogram(h_dpt[i]); - } - - TCanvas* c4 = new TCanvas("c_cal_and_track_4", "Hadronic final state QA 2", 1600, 800); - c4->Divide(3, 2); - - for ( int i = 0; i < 6; i ++ ) - { - c4->cd(i+1); - gPad->SetTickx(1); - gPad->SetTicky(1); - gPad->SetLogz(); - gPad->SetLeftMargin(0.2); - gPad->SetBottomMargin(0.2); - } - - c4->cd(1); - h_hfs_dpt->Draw("HIST"); - h_hfs_dpt->SetStats(0); - format_eid_histogram(h_hfs_dpt); - - c4->cd(2); - h_hfs_dpz->Draw("HIST"); - h_hfs_dpz->SetStats(0); - format_eid_histogram(h_hfs_dpz); - - c4->cd(3); - h_hfs_de->Draw("HIST"); - h_hfs_de->SetStats(0); - format_eid_histogram(h_hfs_de); - - c4->cd(4); - h_hfs_dpt_t->Draw("COLZ"); - h_hfs_dpt_t->SetStats(0); - format_eid_histogram(h_hfs_dpt_t); - - c4->cd(5); - h_hfs_dpt_t->Draw("COLZ"); - h_hfs_dpt_t->SetStats(0); - format_eid_histogram(h_hfs_dpt_t); - - c4->cd(6); - h_hfs_de_t->Draw("COLZ"); - h_hfs_de_t->SetStats(0); - format_eid_histogram(h_hfs_de_t); - - // save to tree - c1->Write(); - c2->Write(); - c3->Write(); - c4->Write(); - - return; -} \ No newline at end of file diff --git a/ElectronID/draw_helper.h b/ElectronID/draw_helper.h deleted file mode 100644 index adcc14e..0000000 --- a/ElectronID/draw_helper.h +++ /dev/null @@ -1,320 +0,0 @@ -// Some plot formatting -// But should switch to standard ePIC format .. - -#pragma once - -// bin setting -const int n_x_bin = 25; -const int n_q_bin = 25; - -// axis range -double x_gen_min = 0; -double q_gen_max = 0; - -void BinLogX(TH1F* &h) // taken from https://root.cern.ch/root/roottalk/roottalk06/1213.html -{ - TAxis *axis = h->GetXaxis(); - int bins = axis->GetNbins(); - - Axis_t from = axis->GetXmin(); - Axis_t to = axis->GetXmax(); - Axis_t width = (to - from) / bins; - Axis_t *new_bins = new Axis_t[bins + 1]; - - for (int i = 0; i <= bins; i++) - new_bins[i] = pow(10, from + i * width); - - axis->Set(bins, new_bins); - delete[] new_bins; -} - -void BinLogX(TH2F* &h, int a) // taken from https://root.cern.ch/root/roottalk/roottalk06/1213.html -{ - TAxis *axis = a == 0 ? h->GetXaxis() : h->GetYaxis(); - int bins = axis->GetNbins(); - - Axis_t from = axis->GetXmin(); - Axis_t to = axis->GetXmax(); - Axis_t width = (to - from) / bins; - Axis_t *new_bins = new Axis_t[bins + 1]; - - for (int i = 0; i <= bins; i++) - new_bins[i] = pow(10, from + i * width); - - axis->Set(bins, new_bins); - delete[] new_bins; -} - -void BinLogXY(TH2F* &h) -{ - for ( int j = 0; j < 2; j ++ ) - { - BinLogX(h, j); - // TAxis *axis = j == 0 ? h->GetXaxis() : h->GetYaxis(); - - // int bins = axis->GetNbins(); - // Axis_t from = axis->GetXmin(); - // Axis_t to = axis->GetXmax(); - // Axis_t width = (to - from) / bins; - // Axis_t *new_bins = new Axis_t[bins + 1]; - - // for (int i = 0; i <= bins; i++) - // new_bins[i] = pow(10, from + i * width); - - // axis->Set(bins, new_bins); - - // delete[] new_bins; - } -} - -TH1F* BookTH1(std::string name, std::string title, double n_bins, double min, double max) -{ - TH1F* h = new TH1F(name.c_str(), title.c_str(), n_bins, min, max); - h->GetXaxis()->CenterTitle(); - h->GetYaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.5); - h->GetYaxis()->SetTitleOffset(1.5); - - BinLogX(h); - - return h; -} - -TH2F* BookTH2(std::string name, std::string title, double n_xbins, double xmin, double xmax, double n_ybins, double ymin, double ymax, int colorMap) -{ - TH2F* h = new TH2F(name.c_str(), title.c_str(), n_xbins, xmin, xmax, n_ybins, ymin, ymax); - h->GetXaxis()->CenterTitle(); - h->GetYaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.5); - h->GetYaxis()->SetTitleOffset(1.5); - - TExec *exDefault = new TExec("ex1","gStyle->SetPalette(kBird)"); - TExec *exUser = new TExec("ex1",Form("gStyle->SetPalette(%d)",colorMap)); - - if ( colorMap != 0 ) - h->GetListOfFunctions()->Add(exUser); - else - h->GetListOfFunctions()->Add(exDefault); - - BinLogXY(h); - - return h; -} - -TCanvas* BookCanvas(std::string name, std::string title, double width, double height) -{ - TCanvas* c = new TCanvas(name.c_str(), title.c_str(), width, height); - c->SetLeftMargin(0.13); - c->SetBottomMargin(0.13); - c->SetRightMargin(0.13); - - return c; -} - -void plot_2d_xq(std::string c_name, std::string c_title, double c_min, double c_max, TH2F* h_xq2, double x_gen_min, double q_gen_max) -{ - TCanvas* c_xq = BookCanvas(c_name, c_title, c_min, c_max); - c_xq->SetLogx(); - c_xq->SetLogy(); - // c_xq->SetLogz(); - h_xq2->SetStats(0); - h_xq2->GetXaxis()->SetRangeUser(x_gen_min, 1); - h_xq2->GetYaxis()->SetRangeUser(1,q_gen_max); - h_xq2->Draw("COLZ TEXT"); - - return; -} - -void format_graph(TGraph* g) -{ - // g->GetXaxis()->SetTitle("Q^{2} (GeV/c^{2})^{2}"); - g->GetXaxis()->CenterTitle(); - g->GetXaxis()->SetTitleOffset(1.4); - - // g->GetYaxis()->SetTitle(ylabel.c_str()); - g->GetYaxis()->CenterTitle(); - g->GetYaxis()->SetTitleOffset(1.4); - - g->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - g->GetXaxis()->SetLabelSize(24); - g->GetXaxis()->SetTitleSize(28); - g->GetXaxis()->SetTitleFont(43); - - g->GetYaxis()->SetNdivisions(505); - g->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - g->GetYaxis()->SetLabelSize(24); - g->GetYaxis()->SetTitleSize(28); - g->GetYaxis()->SetTitleFont(43); - - // g->GetYaxis()->ChangeLabel(1, -1, -1, -1, -1, -1, " "); - - // g->SetMarkerStyle(marker[style_id]); - // g->SetMarkerColor(color[style_id]); - g->SetMarkerSize(0.2); - - return; -} - -void format_efficiency(TEfficiency* &g) -{ - auto graph_test = g->GetPaintedGraph(); - if ( g->GetPaintedGraph() == NULL ) - printf("cannot find \n"); - - g->GetPaintedGraph()->GetXaxis()->CenterTitle(); - g->GetPaintedGraph()->GetXaxis()->SetTitleOffset(1.2); - - g->GetPaintedGraph()->GetYaxis()->SetTitleOffset(1.8); - g->GetPaintedGraph()->GetYaxis()->CenterTitle(); - - g->GetPaintedGraph()->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - g->GetPaintedGraph()->GetXaxis()->SetLabelSize(20); - g->GetPaintedGraph()->GetXaxis()->SetTitleSize(20); - g->GetPaintedGraph()->GetXaxis()->SetTitleFont(43); - - g->GetPaintedGraph()->GetYaxis()->SetNdivisions(505); - g->GetPaintedGraph()->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - g->GetPaintedGraph()->GetYaxis()->SetLabelSize(20); - g->GetPaintedGraph()->GetYaxis()->SetTitleSize(20); - g->GetPaintedGraph()->GetYaxis()->SetTitleFont(43); - - return; -} - -void format_histogram(TH1F* &h) -{ - h->GetXaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.2); - - h->GetYaxis()->SetTitleOffset(1.8); - h->GetYaxis()->CenterTitle(); - - h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetXaxis()->SetLabelSize(20); - h->GetXaxis()->SetTitleSize(20); - h->GetXaxis()->SetTitleFont(43); - - h->GetYaxis()->SetNdivisions(505); - h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetYaxis()->SetLabelSize(20); - h->GetYaxis()->SetTitleSize(20); - h->GetYaxis()->SetTitleFont(43); - - return; -} - -TCanvas* draw_2d_standard(TH2F* &h, std::string c_name, std::string c_title, double width, double height, bool is_log_z, bool is_std_scale) -{ - TCanvas* c = BookCanvas(c_name.c_str(), c_title.c_str(), width, height); - c->SetLogx(); - c->SetLogy(); - h->SetStats(0); - h->Draw("COLZ"); - - if ( is_log_z ) - c->SetLogz(); - - if (is_std_scale ) - { - h->GetXaxis()->SetRangeUser(x_gen_min, 1); - h->GetYaxis()->SetRangeUser(1,q_gen_max); - } - - return c; -} - -TCanvas* draw_2d_efficiency(TH2F* &h, std::string c_name, std::string c_title, double width, double height, bool is_log_z, bool is_std_scale) -{ - TCanvas* c = BookCanvas(c_name.c_str(), c_title.c_str(), width, height); - c->SetLogx(); - c->SetLogy(); - h->SetStats(0); - h->Draw("COLZ TEXT"); - - if ( is_log_z ) - c->SetLogz(); - - if (is_std_scale ) - { - h->GetXaxis()->SetRangeUser(x_gen_min, 1); - h->GetYaxis()->SetRangeUser(1,q_gen_max); - } - - return c; -} - -void set_2d_scale(TH2F* h) -{ - x_gen_min = h->GetXaxis()->GetBinCenter(h->FindFirstBinAbove(0, 1)) - h->GetXaxis()->GetBinWidth(h->FindFirstBinAbove(0, 1)/2.); - q_gen_max = h->GetYaxis()->GetBinCenter(h->FindLastBinAbove(0, 2)) + h->GetYaxis()->GetBinWidth(h->FindLastBinAbove(0, 2)/2.); - - return; -} - -void process_eff_hist(TH2F* &h_top, TH2F* &h_bottom) -{ - h_top->Divide(h_bottom); - for ( int ix = 0; ix < h_top->GetXaxis()->GetNbins(); ix ++ ) - { - for ( int iq = 0; iq < h_top->GetYaxis()->GetNbins(); iq ++ ) - { - double eff = h_top->GetBinContent(ix+1, iq+1); - double eff_round = std::round(eff * 1000) / 1000.; - if ( eff_round > 1.5 ) - eff_round = 1.5; - // h_top->SetBinContent(ix+1, iq+1, std::round(eff * 1000) / 1000.); - // if ( eff_round < 2 ) - h_top->SetBinContent(ix+1, iq+1, eff_round); - // else - // h_top->SetBinContent(ix+1, iq+1, 0); - } - } - - return; -} - -void format_eid_histogram(TH1F* &h) -{ - h->GetXaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.2); - - h->GetYaxis()->SetTitleOffset(1.8); - h->GetYaxis()->CenterTitle(); - - h->GetXaxis()->SetNdivisions(5); - h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetXaxis()->SetLabelSize(20); - h->GetXaxis()->SetTitleSize(20); - h->GetXaxis()->SetTitleFont(43); - - h->GetYaxis()->SetNdivisions(5); - h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetYaxis()->SetLabelSize(20); - h->GetYaxis()->SetTitleSize(20); - h->GetYaxis()->SetTitleFont(43); - - return; -} - -void format_eid_histogram(TH2F* &h) -{ - h->GetXaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.2); - - h->GetYaxis()->SetTitleOffset(1.8); - h->GetYaxis()->CenterTitle(); - - h->GetXaxis()->SetNdivisions(505); - h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetXaxis()->SetLabelSize(20); - h->GetXaxis()->SetTitleSize(20); - h->GetXaxis()->SetTitleFont(43); - - h->GetYaxis()->SetNdivisions(505); - h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetYaxis()->SetLabelSize(20); - h->GetYaxis()->SetTitleSize(20); - h->GetYaxis()->SetTitleFont(43); - - return; -} \ No newline at end of file diff --git a/ElectronID/ePICStyle.c b/ElectronID/ePICStyle.c deleted file mode 100644 index 14ff6b2..0000000 --- a/ElectronID/ePICStyle.c +++ /dev/null @@ -1,114 +0,0 @@ -// -// ePIC Style, based on a style file from BaBar, v0.1 -// - -#include -#include "ePICStyle.h" -#include "TROOT.h" - -void SetePICStyle () -{ - static TStyle* epicStyle = 0; - std::cout << "ePICStyle: Applying nominal settings." << std::endl ; - if ( epicStyle==0 ) epicStyle = ePICStyle(); - gROOT->SetStyle("ePIC"); - gROOT->ForceStyle(); -} - -TStyle* ePICStyle() -{ - TStyle *ePICStyle = new TStyle("ePIC","ePIC style"); - - // use plain black on white colors - Int_t icol=0; // WHITE - ePICStyle->SetFrameBorderMode(icol); - ePICStyle->SetFrameFillColor(icol); - ePICStyle->SetCanvasBorderMode(icol); - ePICStyle->SetCanvasColor(icol); - ePICStyle->SetPadBorderMode(icol); - ePICStyle->SetPadColor(icol); - ePICStyle->SetStatColor(icol); - //ePICStyle->SetFillColor(icol); // don't use: white fill color for *all* objects - - // set the paper & margin sizes - ePICStyle->SetPaperSize(20,26); - - // set margin sizes - ePICStyle->SetPadTopMargin(0.05); - ePICStyle->SetPadRightMargin(0.18); - ePICStyle->SetPadBottomMargin(0.16); - ePICStyle->SetPadLeftMargin(0.15); - - // set title offsets (for axis label) - ePICStyle->SetTitleXOffset(1.4); - ePICStyle->SetTitleYOffset(1.2); - ePICStyle->SetTitleOffset(1.2,"z"); // Set the offset for Z axis titles expliticly to avoid it being cut off - - // use large fonts - //Int_t font=72; // Helvetica italics - Int_t font=42; // Helvetica - Double_t tsize=0.05; - ePICStyle->SetTextFont(font); - - ePICStyle->SetTextSize(tsize); - ePICStyle->SetLabelFont(font,"x"); - ePICStyle->SetTitleFont(font,"x"); - ePICStyle->SetLabelFont(font,"y"); - ePICStyle->SetTitleFont(font,"y"); - ePICStyle->SetLabelFont(font,"z"); - ePICStyle->SetTitleFont(font,"z"); - - ePICStyle->SetLabelSize(tsize,"x"); - ePICStyle->SetTitleSize(tsize,"x"); - ePICStyle->SetLabelSize(tsize,"y"); - ePICStyle->SetTitleSize(tsize,"y"); - ePICStyle->SetLabelSize(tsize,"z"); - ePICStyle->SetTitleSize(tsize,"z"); - - // use bold lines and markers - ePICStyle->SetMarkerStyle(20); - ePICStyle->SetMarkerSize(1.2); - ePICStyle->SetHistLineWidth(2.); - ePICStyle->SetLineStyleString(2,"[12 12]"); // postscript dashes - - // get rid of X error bars - //ePICStyle->SetErrorX(0.001); - // get rid of error bar caps - ePICStyle->SetEndErrorSize(0.); - - // do not display any of the standard histogram decorations - ePICStyle->SetOptTitle(0); - //ePICStyle->SetOptStat(1111); - ePICStyle->SetOptStat(0); - //ePICStyle->SetOptFit(1111); - ePICStyle->SetOptFit(0); - - // put tick marks on top and RHS of plots - ePICStyle->SetPadTickX(1); - ePICStyle->SetPadTickY(1); - - // legend modification - ePICStyle->SetLegendBorderSize(0); - ePICStyle->SetLegendFillColor(0); - ePICStyle->SetLegendFont(font); - -#if ROOT_VERSION_CODE >= ROOT_VERSION(6,00,0) - std::cout << "ePICStyle: ROOT6 mode" << std::endl; - ePICStyle->SetLegendTextSize(tsize); - ePICStyle->SetPalette(kBird); -#else - std::cout << "ePICStyle: ROOT5 mode" << std::endl; - // color palette - manually define 'kBird' palette only available in ROOT 6 - Int_t alpha = 0; - Double_t stops[9] = { 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000}; - Double_t red[9] = { 0.2082, 0.0592, 0.0780, 0.0232, 0.1802, 0.5301, 0.8186, 0.9956, 0.9764}; - Double_t green[9] = { 0.1664, 0.3599, 0.5041, 0.6419, 0.7178, 0.7492, 0.7328, 0.7862, 0.9832}; - Double_t blue[9] = { 0.5293, 0.8684, 0.8385, 0.7914, 0.6425, 0.4662, 0.3499, 0.1968, 0.0539}; - TColor::CreateGradientColorTable(9, stops, red, green, blue, 255, alpha); -#endif - - ePICStyle->SetNumberContours(80); - - return ePICStyle; - -} diff --git a/ElectronID/ePICStyle.h b/ElectronID/ePICStyle.h deleted file mode 100644 index 8d326c7..0000000 --- a/ElectronID/ePICStyle.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// @file ePICStyle.h -// -// ePIC Style, based on a style file from ATLAS -// -// -// @author Peter Steinberg adapted from sPHENIX/ATLAS style for ECCE, Stephen Kay subsequently repurposed for ePIC -// -// Copyright (C) 2025 ePIC Collaboration -// -// Version 0.1 - -#ifndef __ePICSTYLE_H -#define __ePICSTYLE_H - -#include "TStyle.h" - -void SetePICStyle(); - -TStyle* ePICStyle(); - -#endif // __ePICSTYLE_H diff --git a/ElectronID/eff.C b/ElectronID/eff.C deleted file mode 100644 index 2f85512..0000000 --- a/ElectronID/eff.C +++ /dev/null @@ -1,100 +0,0 @@ - -#include "../GlobalUtil/ePICStyle.c" -#include "../GlobalUtil/Constants.hh" -#include "../GlobalUtil/drawHelper.h" - -const std::string group[3] = {"1to10", "10to100", "100to1000"}; -const double total_lumi = 8.65*3; // fb^-1 - -double cs[3][2] = {{0.198440424611563, 0.205327493968226}, {4.04371412707044E-02, 4.41976212963417E-02}, {1.36416909784756E-03, 1.69583242740138E-03}}; -double ev[3][2] = {{333675, 666325}, {333694, 666306}, {333365, 666640}}; - -enum { NO_FOUND, FOUND_E, FOUND_PI, FOUND_OTHERS }; - -void eff() -{ - SetePICStyle(); - - TH2F* h_xq2_all = BookTH2(Form("h_xq2_all"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - TH2F* h_xq2_acp = BookTH2(Form("h_xq2_acp"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - TH2F* h_xq2_eID = BookTH2(Form("h_xq2_eID"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - TH2F* h_xq2_piID = BookTH2(Form("h_xq2_piID"), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - - for ( int i = 0; i < 3; i ++ ) - { - double gen_lumi = ev[i][0]/(cs[i][0]*(1e-34/1e-43)) + ev[i][1]/(cs[i][1]*(1e-34/1e-43)); - double n_lumi = ev[i][0]/(cs[i][0]*(1e-34/1e-43)); - double p_lumi = ev[i][1]/(cs[i][1]*(1e-34/1e-43)); - - TH2F* h_tmp_all = BookTH2(Form("h_tmp_all_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - TH2F* h_tmp_acp = BookTH2(Form("h_tmp_acp_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - TH2F* h_tmp_eID = BookTH2(Form("h_tmp_eID_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - TH2F* h_tmp_piID = BookTH2(Form("h_tmp_piID_%d", i), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - - TFile* file = new TFile(Form("../data/eID/lowerEoPcut/10x166_%s_eIDrecon.root", group[i].c_str())); - - TTreeReader reader("T_eID", file); - TTreeReaderValue eID_status(reader, "eID_status"); - TTreeReaderValue mc_xB(reader, "mc_xB"); - TTreeReaderValue mc_Q2(reader, "mc_Q2"); - TTreeReaderValue mc_y(reader, "mc_y"); - TTreeReaderValue mc_W2(reader, "mc_W2"); - TTreeReaderValue mc_nu(reader, "mc_nu"); - - Long64_t nEntries = reader.GetEntries(); - - for( size_t ev = 0; ev < nEntries; ev++ ) - { - reader.Next(); - // if(ev%100==0) - // cout << "Analysing file " << i << " event " << ev << "/" << nEntries << "\t\r" << std::flush; - - int status = *eID_status; - float xB = *mc_xB; - float Q2 = *mc_Q2; - float y = *mc_y; - float W2 = *mc_W2; - float nu = *mc_nu; - - h_tmp_all->Fill(xB, Q2); - if ( status != NO_FOUND ) - h_tmp_acp->Fill(xB, Q2); - if ( status == FOUND_E ) - h_tmp_eID->Fill(xB, Q2); - if ( status == FOUND_PI ) - h_tmp_piID->Fill(xB, Q2); - } - - h_tmp_all->Scale(total_lumi/gen_lumi); - h_tmp_acp->Scale(total_lumi/gen_lumi); - h_tmp_eID->Scale(total_lumi/gen_lumi); - h_tmp_piID->Scale(total_lumi/gen_lumi); - - h_xq2_all->Add(h_tmp_all); - h_xq2_acp->Add(h_tmp_acp); - h_xq2_eID->Add(h_tmp_eID); - h_xq2_piID->Add(h_tmp_piID); - - file->Close(); - } - - set_2d_scale(h_xq2_all); - TCanvas* c_xq2_all = draw_2d_standard(h_xq2_all, "c_xq2_all", "all events", 700, 600, true, true); - TCanvas* c_xq2_acp = draw_2d_standard(h_xq2_acp, "c_xq2_acp", "acp events", 700, 600, true, true); - TCanvas* c_xq2_eID = draw_2d_standard(h_xq2_eID, "c_xq2_eID", "eID events", 700, 600, true, true); - TCanvas* c_xq2_piID = draw_2d_standard(h_xq2_piID, "c_xq2_piID", "piID events", 700, 600, true, true); - - TH2F* h_xq2_acp_copy = (TH2F*)h_xq2_acp->Clone(); - process_eff_hist(h_xq2_acp_copy, h_xq2_all); - TCanvas* c_xq2_acp_eff = draw_2d_efficiency(h_xq2_acp_copy, "c_xq2_acp_eff", "xq2 acp eff", 1400, 600, false, true); - - TH2F* h_xq2_eID_copy = (TH2F*)h_xq2_eID->Clone(); - process_eff_hist(h_xq2_eID_copy, h_xq2_acp); - TCanvas* c_xq2_eID_eff = draw_2d_efficiency(h_xq2_eID_copy, "c_xq2_eID_eff", "xq2 eID eff", 1400, 600, false, true); - - TH2F* h_xq2_piID_copy = (TH2F*)h_xq2_piID->Clone(); - process_eff_hist(h_xq2_piID_copy, h_xq2_acp); - TCanvas* c_xq2_piID_eff = draw_2d_efficiency(h_xq2_piID_copy, "c_xq2_piID_eff", "xq2 piID eff", 1400, 600, false, true); - - return; -} \ No newline at end of file diff --git a/ElectronID/kinematics.cc b/ElectronID/kinematics.cc deleted file mode 100644 index 75660d1..0000000 --- a/ElectronID/kinematics.cc +++ /dev/null @@ -1,159 +0,0 @@ -#include "kinematics.hh" -#include "reconMethod.hh" -#include "draw_helper.h" - -Kinematics::Kinematics(std::string method_name_, int draw_id_) -{ - method_name = method_name_; - draw_id = draw_id_; - - h_xq = BookTH2(Form("H_%s_Events", method_name.c_str()), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - h_xq_eff = BookTH2(Form("H_%s_Efficiency", method_name.c_str()), ";x;Q^{2} (GeV/c^{2})^{2}", n_x_bin, -5, 0, n_q_bin, 0, 5, kLightTemperature); - - std::string QrangeName[4] = {"lowQ", "midQ", "highQ", "ultraQ"}; - std::string Qrange[4] = {"Q^{2} #leq 10 (GeV/c^{2})^{2}", "10 (GeV/c^{2})^{2} < Q^{2} #leq 100 (GeV/c^{2})^{2}", "100 (GeV/c^{2})^{2} < Q^{2} #leq 1000 (GeV/c^{2})^{2}", "Q^{2} > 1000 (GeV/c^{2})^{2}"}; - for ( int i = 0; i < 4; i ++ ) - { - h_dq[i] = new TH1F(Form("H_%s_dQ_%s", method_name.c_str(), QrangeName[i].c_str()), Form("%s;(Q^{2}_{reco}-Q^{2}_{true})/Q^{2}_{true};Counts", Qrange[i].c_str()), 100, -1, 1); - h_dx[i] = new TH1F(Form("H_%s_dX_%s", method_name.c_str(), QrangeName[i].c_str()), Form("%s;(x_{reco}-x_{true})/x_{true};Counts", Qrange[i].c_str()), 100, -1, 1); - h_dy[i] = new TH1F(Form("H_%s_dY_%s", method_name.c_str(), QrangeName[i].c_str()), Form("%s;(y_{reco}-y_{true})/y_{true};Counts", Qrange[i].c_str()), 100, -1, 1); - - StyleHist(h_dq[i]); - StyleHist(h_dx[i]); - StyleHist(h_dy[i]); - } - - h_qvq = BookTH2(Form("H_%s_QVQ", method_name.c_str()), Form("%s;Q_{true}^{2} (GeV/c^{2})^{2};Q_{reco}^{2} (GeV/c^{2})^{2}", method_name.c_str()), 200, 0, 4, 200, 0, 4, kLightTemperature); - h_xvx = BookTH2(Form("H_%s_XVX", method_name.c_str()), Form("%s;x_{true};x_{reco}", method_name.c_str()), 100, -4, 0, 100, -4, 0, kLightTemperature); - // h_yvy = BookTH2(Form("H_%s_YVY", method_name.c_str()), Form("%s;y_{true};y_{reco}", method_name.c_str()), 100, -2, 0, 100, -2, 0, kLightTemperature); - h_yvy = new TH2F(Form("H_%s_YVY", method_name.c_str()), Form("%s;y_{true};y_{reco}", method_name.c_str()), 100, 0, 1, 100, 0, 1); - - StyleHist(h_qvq); - StyleHist(h_xvx); - StyleHist(h_yvy); - - std::string YrangeName[6] = {"lowY_lowX", "midY_lowX", "highY_lowX, lowY_highX", "midY_highX", "highY_highX"}; - std::string Yrange[6] = {"0.01 < y #leq 0.035, x #leq 0.025", "0.035 < y #leq 0.2, x #leq 0.025", "0.2 < y < 0.95, x #leq 0.025", "0.01 < y #leq 0.035, x > 0.025", "0.035 < y #leq 0.2, x > 0.025", "0.2 < y < 0.95, x > 0.025"}; - for ( int i = 0; i < 6; i ++ ) - { - h_dq_ycut[i] = new TH1F(Form("H_%s_dQ_%s", method_name.c_str(), YrangeName[i].c_str()), Form("%s;(Q^{2}_{reco}-Q^{2}_{true})/Q^{2}_{true};Counts", Yrange[i].c_str()), 100, -0.5, 0.5); - h_dx_ycut[i] = new TH1F(Form("H_%s_dX_%s", method_name.c_str(), YrangeName[i].c_str()), Form("%s;(x_{reco}-x_{true})/x_{true};Counts", Yrange[i].c_str()), 100, -0.5, 0.5); - h_dy_ycut[i] = new TH1F(Form("H_%s_dY_%s", method_name.c_str(), YrangeName[i].c_str()), Form("%s;(y_{reco}-y_{true})/y_{true};Counts", Yrange[i].c_str()), 100, -0.5, 0.5); - - StyleHist(h_dq_ycut[i]); - StyleHist(h_dx_ycut[i]); - StyleHist(h_dy_ycut[i]); - } -} - -Kinematics::~Kinematics() { -} - -void Kinematics::StyleHist(TH2F* h) -{ - h->SetStats(0); - h->SetLineColor(draw_id); - - h->GetXaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.3); - - h->GetYaxis()->SetTitleOffset(1.6); - h->GetYaxis()->CenterTitle(); - - h->GetXaxis()->SetNdivisions(5); - h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetXaxis()->SetLabelSize(20); - h->GetXaxis()->SetTitleSize(20); - h->GetXaxis()->SetTitleFont(43); - - h->GetYaxis()->SetNdivisions(5); - h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetYaxis()->SetLabelSize(20); - h->GetYaxis()->SetTitleSize(20); - h->GetYaxis()->SetTitleFont(43); -} - -void Kinematics::StyleHist(TH1F* h) -{ - h->SetStats(0); - h->SetLineColor(draw_id); - - h->GetXaxis()->CenterTitle(); - h->GetXaxis()->SetTitleOffset(1.3); - - h->GetYaxis()->SetTitleOffset(1.5); - h->GetYaxis()->CenterTitle(); - - h->GetXaxis()->SetNdivisions(5); - h->GetXaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetXaxis()->SetLabelSize(20); - h->GetXaxis()->SetTitleSize(20); - h->GetXaxis()->SetTitleFont(43); - - h->GetYaxis()->SetNdivisions(5); - h->GetYaxis()->SetLabelFont(43); // Absolute font size in pixel (precision 3) - h->GetYaxis()->SetLabelSize(20); - h->GetYaxis()->SetTitleSize(20); - h->GetYaxis()->SetTitleFont(43); -} - -void Kinematics::Process_and_QA(double mc_xB, double mc_y, double mc_Q2) -{ - if ( xB == -999 ) - return; - - h_xq->Fill(xB, Q2); - - if ( h_xq_eff->GetXaxis()->FindBin(mc_xB) == h_xq_eff->GetXaxis()->FindBin(xB) ) - if ( h_xq_eff->GetYaxis()->FindBin(mc_Q2) == h_xq_eff->GetYaxis()->FindBin(Q2) ) - h_xq_eff->Fill(xB, Q2); - - int Qrange = 0; - if ( mc_Q2 > 1000 ) - Qrange = 3; - else if ( mc_Q2 > 100 ) - Qrange = 2; - else if ( mc_Q2 > 10 ) - Qrange = 1; - - h_dq[Qrange]->Fill((Q2-mc_Q2)/mc_Q2); - h_dx[Qrange]->Fill((xB-mc_xB)/mc_xB); - h_dy[Qrange]->Fill((y-mc_y)/mc_y); - - h_qvq->Fill(mc_Q2, Q2); - h_xvx->Fill(mc_xB, xB); - h_yvy->Fill(mc_y, y); - - int Yrange = xB > 0.025 ? 3 : 0; - if ( y > 0.2 ) - Yrange += 2; - else if ( y > 0.035 ) - Yrange += 1; - - h_dq_ycut[Yrange]->Fill((Q2-mc_Q2)/mc_Q2); - h_dx_ycut[Yrange]->Fill((xB-mc_xB)/mc_xB); - h_dy_ycut[Yrange]->Fill((y-mc_y)/mc_y); - - // if ( y > 0.95 ) - // cout << method_name << " Q2 " << mc_Q2 << " " << Q2 << " xB " << mc_xB << " " << xB << " y " << mc_y << " " << y << endl; - - return; -} - -void Kinematics::save_variables(std::vector reco, double Mp) -{ - xB = reco[0]; - y = reco[1]; - Q2 = reco[2]; - W2 = Mp*Mp + Q2 * (1./xB - 1); - nu = Q2/(2*Mp*xB); -} - -void Kinematics::reset() -{ - xB = -999; - Q2 = -999; - W2 = -999; - y = -999; - nu = -999; -} \ No newline at end of file diff --git a/ElectronID/kinematics.hh b/ElectronID/kinematics.hh deleted file mode 100644 index c1a8c21..0000000 --- a/ElectronID/kinematics.hh +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef KINEMATICS_HH -#define KINEMATICS_HH - -#include - -class Kinematics{ - -public: - - Kinematics(std::string method_name, int draw_id); - ~Kinematics(); - - void reset(); - - TH2F* h_xq; - TH2F* h_xq_eff; - - TH1F* h_dq[4]; - TH1F* h_dx[4]; - TH1F* h_dy[4]; - - TH1F* h_dq_ycut[6]; - TH1F* h_dx_ycut[6]; - TH1F* h_dy_ycut[6]; - - TH2F* h_qvq; - TH2F* h_xvx; - TH2F* h_yvy; - - // void fill_histograms(); - // void draw_histograms(); - - float xB; - float Q2; - float W2; - float y; - float nu; - - void StyleHist(TH1F* h); - void StyleHist(TH2F* h); - void Process_and_QA(double mc_xB, double mc_y, double mc_Q2); - void save_variables(std::vector reco, double Mp); - - std::string method_name; - int draw_id; - -private: - -}; - -#endif \ No newline at end of file diff --git a/ElectronID/reconMethod.hh b/ElectronID/reconMethod.hh deleted file mode 100644 index d147f3d..0000000 --- a/ElectronID/reconMethod.hh +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -// electron method -std::vector calc_elec_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { - float Q2 = 2.*E_ebeam*E*(1+TMath::Cos(theta)); - float y = 1. - (E/E_ebeam)*TMath::Sin(theta/2)*TMath::Sin(theta/2); - float x = Q2/(4*E_ebeam*E_pbeam*y); - return {x, y, Q2}; -} - -// jb method -std::vector calc_jb_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { - float y = sigma_h/(2*E_ebeam); - float Q2 = pt_had*pt_had / (1-y); - float x = Q2/(4*E_ebeam*E_pbeam*y); - return {x, y, Q2}; -} - -// double angle method -std::vector calc_da_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { - float alpha_h = sigma_h/pt_had; - float alpha_e = TMath::Tan(theta/2); - float y = alpha_h / (alpha_e + alpha_h); - float Q2 = 4*E_ebeam*E_ebeam / (alpha_e * (alpha_h + alpha_e)); - float x = Q2/(4*E_ebeam*E_pbeam*y); - return {x, y, Q2}; -} - -// sigma method -std::vector calc_sig_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { - float y = sigma_h/(sigma_h + E*(1 - TMath::Cos(theta))); - float Q2 = E*E*TMath::Sin(theta)*TMath::Sin(theta) / (1-y); - float x = Q2/(4*E_ebeam*E_pbeam*y); - return {x, y, Q2}; -} - -// e-sigma method -std::vector calc_esig_method(float E, float theta, float pt_had, float sigma_h, float E_ebeam, float E_pbeam) { - float Q2 = 2.*E_ebeam*E*(1+TMath::Cos(theta)); - float x = calc_sig_method(E,theta,pt_had,sigma_h,E_ebeam,E_pbeam)[0]; - float y = Q2/(4*E_ebeam*E_pbeam*x); - return {x, y, Q2}; -} \ No newline at end of file From d3af2001f2baf63c6c9c963d3cd38cf9482239a1 Mon Sep 17 00:00:00 2001 From: Win Lin Date: Wed, 22 Apr 2026 13:41:47 -0400 Subject: [PATCH 9/9] add cut explanation to readme --- ElectronID/README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ElectronID/README b/ElectronID/README index 2a13398..b0c7f76 100644 --- a/ElectronID/README +++ b/ElectronID/README @@ -2,3 +2,9 @@ DIS Electron Finder: * Example codes assume the use of eic-shell and PODIO * ElectronID.cc and ElectronID.hh provides a list of functions for DIS electron analysis. Use the function FindScatteredElectron() for the standard electron finding method. * InclusiveSkim.C is an example on how to use the ElectronFinder. This can be ran with the most updated eic-shell for simulation campaign after 25.05. + +The current algorithm apply cuts as follows to select the DIS electron: +* Particle has associated track with negative curvature (negative charge). +* Track with momentum $p$ can be matched to ECAL cluster with compatible energy $E_\text{clus}$ such that $0.9 < E_\text{clus}/p < 1.2$. +* Isolation of the matched ECAL cluster, such that the matched cluster constitutes more than $90~\%$ of the energy contained within an $\eta-\phi$ cone centered on the matched cluster: $E_\text{clus} / \sum (E_{\Delta R < 0.4}) > 0.9$, with $\Delta R = \sqrt{\Delta \eta^2 - \Delta \phi^2}$. +* If more than one candidate remains after this selection, the highest pT candidate is chosen as the DIS electron. \ No newline at end of file