From 4b85dad2b1c4aae7fb64e3899f5eceaeb0d85613 Mon Sep 17 00:00:00 2001 From: Tanu Gahlaut <154991749+TGahlaut1@users.noreply.github.com> Date: Tue, 27 Oct 2026 18:19:55 +0530 Subject: [PATCH] Adjust nSigma cuts and histogram entries for particles Updated nSigma cuts for particle selection and added TOF nSigma shifts. Modified histogram entries for truth primary tracks. --- PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx | 120 ++++++++++-------- 1 file changed, 65 insertions(+), 55 deletions(-) diff --git a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx index 7f4432ae05e..657cd511aa4 100644 --- a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx @@ -72,17 +72,21 @@ struct MeanPtFlucId { Configurable cfgCutNSig3{"cfgCutNSig3", 3.0, "nSigma cut: 3"}; Configurable cfgCutNSig5{"cfgCutNSig5", 5.0, "nSigma cut: 5"}; Configurable cfgCutNSigTpcTof{"cfgCutNSigTpcTof", 3.0, "nSigma TPC cut when TPC + TOF "}; - Configurable cfgSelCutNSigTpcPi{"cfgSelCutNSigTpcPi", 2.0, "nSigma TPC cut for pion selection"}; - Configurable cfgSelCutNSigTpcKa{"cfgSelCutNSigTpcKa", 2.0, "nSigma TPC cut for kaon selection"}; - Configurable cfgSelCutNSigTpcPr{"cfgSelCutNSigTpcPr", 2.0, "nSigma TPC cut for proton selection"}; - Configurable cfgSelCutNSigTofPi{"cfgSelCutNSigTofPi", 2.0, "nSigma TOF cut for pion selection"}; - Configurable cfgSelCutNSigTofKa{"cfgSelCutNSigTofKa", 2.0, "nSigma TOF cut for kaon selection"}; - Configurable cfgSelCutNSigTofPr{"cfgSelCutNSigTofPr", 2.0, "nSigma TOF cut for proton selection"}; + Configurable cfgSelCutNSigTpcPi{"cfgSelCutNSigTpcPi", 3.0, "nSigma TPC cut for pion selection"}; + Configurable cfgSelCutNSigTpcKa{"cfgSelCutNSigTpcKa", 3.0, "nSigma TPC cut for kaon selection"}; + Configurable cfgSelCutNSigTpcPr{"cfgSelCutNSigTpcPr", 3.0, "nSigma TPC cut for proton selection"}; + Configurable cfgSelCutNSigTofPi{"cfgSelCutNSigTofPi", 3.0, "nSigma TOF cut for pion selection"}; + Configurable cfgSelCutNSigTofKa{"cfgSelCutNSigTofKa", 3.0, "nSigma TOF cut for kaon selection"}; + Configurable cfgSelCutNSigTofPr{"cfgSelCutNSigTofPr", 3.0, "nSigma TOF cut for proton selection"}; + // Signed TOF nSigma offsets: corrected = raw - shift. Zero preserves the original PID. + Configurable cfgTofShiftPi{"cfgTofShiftPi", 0.f, "Pion TOF nSigma offset to subtract (not a time shift in ps)"}; + Configurable cfgTofShiftKa{"cfgTofShiftKa", 0.f, "Kaon TOF nSigma offset to subtract (not a time shift in ps)"}; + Configurable cfgTofShiftPr{"cfgTofShiftPr", 0.f, "Proton TOF nSigma offset to subtract (not a time shift in ps)"}; Configurable cfgCutPiPtMin{"cfgCutPiPtMin", 0.2, "Minimum pion p_{T} cut"}; Configurable cfgCutKaPtMin{"cfgCutKaPtMin", 0.3, "Minimum kaon p_{T} cut"}; Configurable cfgCutPrPtMin{"cfgCutPrPtMin", 0.5, "Minimum proton p_{T} cut"}; Configurable cfgCutPiThrsldP{"cfgCutPiThrsldP", 0.7, "Momentum threshold for requiring pion TOF PID"}; - Configurable cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.8, "Momentum threshold for requiring kaon TOF PID"}; + Configurable cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.55, "Momentum threshold for requiring kaon TOF PID"}; Configurable cfgCutPrThrsldP{"cfgCutPrThrsldP", 0.8, "Momentum threshold for requiring proton TOF PID"}; Configurable cfgP0U{"cfgP0U", 6.36269, "p_{0} for upper cut for N_{TPC} vs N{sim}"}; Configurable cfgP1U{"cfgP1U", 2.22108, "p_{1} for upper cut for N_{TPC} vs N{sim}"}; @@ -240,6 +244,10 @@ struct MeanPtFlucId { void init(InitContext const&) { + if (!std::isfinite(cfgTofShiftPi.value) || !std::isfinite(cfgTofShiftKa.value) || !std::isfinite(cfgTofShiftPr.value)) { + LOGF(fatal, "TOF nSigma shifts must be finite: pion=%g, kaon=%g, proton=%g", + cfgTofShiftPi.value, cfgTofShiftKa.value, cfgTofShiftPr.value); + } if (nPtBins <= 0 || cfgCutPtMin >= cfgCutPtMax || cfgCutPiPtMin >= cfgCutPtMax || cfgCutKaPtMin >= cfgCutPtMax || cfgCutPrPtMin >= cfgCutPtMax) { @@ -418,7 +426,7 @@ struct MeanPtFlucId { hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtCh}}); hist.add("QA/Charged/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); hist.add("QA/Charged/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); - hist.add("QA/Charged/h3_Pt_EtaMC_primary_centFT0M", "Selected primary MC particles;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); + hist.add("QA/Charged/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); hist.add("QA/Charged/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtCh}}); }; addTrackQAHistograms(); @@ -429,7 +437,7 @@ struct MeanPtFlucId { hist.add("QA/Pion/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPi}}); hist.add("QA/Pion/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); hist.add("QA/Pion/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); - hist.add("QA/Pion/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary pions;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + hist.add("QA/Pion/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); hist.add("QA/Pion/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPi}}); hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPi}); hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPi}); @@ -446,7 +454,7 @@ struct MeanPtFlucId { hist.add("QA/Kaon/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtKa}}); hist.add("QA/Kaon/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); hist.add("QA/Kaon/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); - hist.add("QA/Kaon/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary kaons;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + hist.add("QA/Kaon/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); hist.add("QA/Kaon/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtKa}}); hist.add("QA/Kaon/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtKa}); hist.add("QA/Kaon/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtKa}); @@ -463,7 +471,7 @@ struct MeanPtFlucId { hist.add("QA/Proton/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPr}}); hist.add("QA/Proton/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); hist.add("QA/Proton/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); - hist.add("QA/Proton/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary protons;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/Proton/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); hist.add("QA/Proton/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPr}}); hist.add("QA/Proton/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPr}); hist.add("QA/Proton/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPr}); @@ -689,12 +697,25 @@ struct MeanPtFlucId { std::fabs(track.tpcNSigmaPr()) > cfgCutNSig3); } + // Share the corrected hypotheses between PID selection and selected-particle QA. + // The before-PID histograms intentionally retain raw values for calibration. + template + std::array getTofNSigmaForPid(T const& track) const + { + std::array values = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; + if (track.hasTOF()) { + values[static_cast(PIDType::kPions)] -= cfgTofShiftPi.value; + values[static_cast(PIDType::kKaons)] -= cfgTofShiftKa.value; + values[static_cast(PIDType::kProtons)] -= cfgTofShiftPr.value; + } + return values; + } + // PID cuts for identified particles template - bool identifyParticle(T const& track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold) + bool identifyParticle(T const& track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold, const std::array& tofNSigma) { const std::array tpcNSigma = {-999.f, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; - const std::array tofNSigma = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; const int selSpecies = static_cast(species); const int rejSpecies1 = static_cast(reject1); @@ -1092,9 +1113,10 @@ struct MeanPtFlucId { float nSigmaTPCPi = track.tpcNSigmaPi(); float nSigmaTPCKa = track.tpcNSigmaKa(); float nSigmaTPCPr = track.tpcNSigmaPr(); - float nSigmaTOFPi = track.tofNSigmaPi(); - float nSigmaTOFKa = track.tofNSigmaKa(); - float nSigmaTOFPr = track.tofNSigmaPr(); + const auto tofNSigma = getTofNSigmaForPid(track); + const float nSigmaTOFPi = tofNSigma[static_cast(PIDType::kPions)]; + const float nSigmaTOFKa = tofNSigma[static_cast(PIDType::kKaons)]; + const float nSigmaTOFPr = tofNSigma[static_cast(PIDType::kProtons)]; float rapPi = track.rapidity(MassPiPlus); float rapKa = track.rapidity(MassKPlus); float rapPr = track.rapidity(MassProton); @@ -1129,16 +1151,13 @@ struct MeanPtFlucId { hist.fill(HIST("QA/after/h_DCAxy_primary"), track.dcaXY()); hist.fill(HIST("QA/after/h_DCAz_primary"), track.dcaZ()); hist.fill(HIST("QA/Charged/h_PtTruth_primary"), track.pt()); - const bool mcInChargedAcceptance = ptMC >= cfgCutPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; - if (mcInChargedAcceptance) { - hist.fill(HIST("QA/Charged/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); - if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { - double weight = 0.; - if (!getEfficiencyWeight(PIDType::kNone, ptMC, etaMC, weight)) { - LOGF(fatal, "Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); - } - chargedTracksTruthMatchedCorrected.push_back({ptMC, weight}); + hist.fill(HIST("QA/Charged/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kNone, pt, eta, weight)) { + LOGF(fatal, "Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); } + chargedTracksTruthMatchedCorrected.push_back({pt, weight}); } } else { hist.fill(HIST("QA/after/h_DCAxy_secondary"), track.dcaXY()); @@ -1169,9 +1188,9 @@ struct MeanPtFlucId { if (cfgRejTrk && rejectTracks(track)) { continue; } - auto selIDPion = identifyParticle(track, PIDType::kPions, PIDType::kKaons, PIDType::kProtons, p, cfgCutPiThrsldP); - auto selIDKaon = identifyParticle(track, PIDType::kKaons, PIDType::kPions, PIDType::kProtons, p, cfgCutKaThrsldP); - auto selIDProton = identifyParticle(track, PIDType::kProtons, PIDType::kPions, PIDType::kKaons, p, cfgCutPrThrsldP); + auto selIDPion = identifyParticle(track, PIDType::kPions, PIDType::kKaons, PIDType::kProtons, p, cfgCutPiThrsldP, tofNSigma); + auto selIDKaon = identifyParticle(track, PIDType::kKaons, PIDType::kPions, PIDType::kProtons, p, cfgCutKaThrsldP, tofNSigma); + auto selIDProton = identifyParticle(track, PIDType::kProtons, PIDType::kPions, PIDType::kKaons, p, cfgCutPrThrsldP, tofNSigma); if (selIDPion && track.pt() >= cfgCutPiPtMin) { if (cfgApplyEfficiencyCorrection) { @@ -1213,17 +1232,14 @@ struct MeanPtFlucId { fillPtMCHist(false, pt, eta, rapPi, phi, pid, kPiPlus, kPiMinus); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/Pion/h_PtTruth_primary"), track.pt()); + hist.fill(HIST("QA/Pion/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M); hist.fill(HIST("QA/Pion/h2_Pt_EtaTruth_primary"), track.eta(), track.pt()); - const bool mcInPionAcceptance = ptMC >= cfgCutPiPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; - if (mcInPionAcceptance) { - hist.fill(HIST("QA/Pion/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); - if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { - double weight = 0.; - if (!getEfficiencyWeight(PIDType::kPions, ptMC, etaMC, weight)) { - LOGF(fatal, "Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); - } - pionTracksTruthMatchedCorrected.push_back({ptMC, weight}); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kPions, pt, eta, weight)) { + LOGF(fatal, "Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); } + pionTracksTruthMatchedCorrected.push_back({pt, weight}); } } else { hist.fill(HIST("QA/Pion/h_PtTruth_secondary"), track.pt()); @@ -1236,17 +1252,14 @@ struct MeanPtFlucId { fillPtMCHist(false, pt, eta, rapKa, phi, pid, kKPlus, kKMinus); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/Kaon/h_PtTruth_primary"), track.pt()); + hist.fill(HIST("QA/Kaon/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M); hist.fill(HIST("QA/Kaon/h2_Pt_EtaTruth_primary"), track.eta(), track.pt()); - const bool mcInKaonAcceptance = ptMC >= cfgCutKaPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; - if (mcInKaonAcceptance) { - hist.fill(HIST("QA/Kaon/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); - if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { - double weight = 0.; - if (!getEfficiencyWeight(PIDType::kKaons, ptMC, etaMC, weight)) { - LOGF(fatal, "Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); - } - kaonTracksTruthMatchedCorrected.push_back({ptMC, weight}); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kKaons, pt, eta, weight)) { + LOGF(fatal, "Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); } + kaonTracksTruthMatchedCorrected.push_back({pt, weight}); } } else { hist.fill(HIST("QA/Kaon/h_PtTruth_secondary"), track.pt()); @@ -1259,17 +1272,14 @@ struct MeanPtFlucId { fillPtMCHist(false, pt, eta, rapPr, phi, pid, kProton, kProtonBar); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/Proton/h_PtTruth_primary"), track.pt()); + hist.fill(HIST("QA/Proton/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M); hist.fill(HIST("QA/Proton/h2_Pt_EtaTruth_primary"), track.eta(), track.pt()); - const bool mcInProtonAcceptance = ptMC >= cfgCutPrPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; - if (mcInProtonAcceptance) { - hist.fill(HIST("QA/Proton/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); - if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { - double weight = 0.; - if (!getEfficiencyWeight(PIDType::kProtons, ptMC, etaMC, weight)) { - LOGF(fatal, "Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); - } - protonTracksTruthMatchedCorrected.push_back({ptMC, weight}); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kProtons, pt, eta, weight)) { + LOGF(fatal, "Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); } + protonTracksTruthMatchedCorrected.push_back({pt, weight}); } } else { hist.fill(HIST("QA/Proton/h_PtTruth_secondary"), track.pt());