diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaProtonBalanceFunction.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaProtonBalanceFunction.cxx index 9d503bdc453..bb09321931a 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaProtonBalanceFunction.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaProtonBalanceFunction.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// \file lambdaProtonBalanceFunction.cxx -/// \brief Single- and two-particle density correlations (rho1, rho2) and R2 correlations for Lambda-proton pairs to measure the balance function. +/// \brief Single- and two-particle density correlations (rho1, rho2) and R2 correlations for Lambda-proton, proton-proton and Lambda-Lambda pairs (plus antiparticle combinations) to measure the balance function. /// \author Anoop Poruthiyil #include "PWGLF/DataModel/LFStrangenessTables.h" @@ -61,10 +61,26 @@ using MyTracks = soa::Join; +// Per-centrality-bin histogram set. Defined at file scope (NOT inside the task struct), +// otherwise O2's struct reflection in adaptAnalysisTask fails to compile. +struct CentRho2Set { + // eta space (only booked if cFillEtaSpace && cFillCentEtaSpace) + std::shared_ptr Lp, LAp, ALp, ALAp, pp, pAp, App, ApAp, LL, LAL, ALL, ALAL; + // y space + std::shared_ptr Lp_y, LAp_y, ALp_y, ALAp_y, pp_y, pAp_y, App_y, ApAp_y, LL_y, LAL_y, ALL_y, ALAL_y; + // rho1 eta + std::shared_ptr rho1_Proton, rho1_AntiProton, rho1_Lambda, rho1_AntiLambda; + // rho1 y + std::shared_ptr rho1_Proton_y, rho1_AntiProton_y, rho1_Lambda_y, rho1_AntiLambda_y; + // event counter + std::shared_ptr hEvents; +}; + struct LambdaProtonBalanceFunction { HistogramRegistry registryLambda{"Lambda_invMass", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryLambdaExtended{"Lambda_invMassExtended", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryRho{"rho1ANDrho2_LP", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry registryCent{"rho1ANDrho2_LP_CentralityBased", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryOther{"Other_Hists", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryPid{"PID", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryQaDetector{"QA_Detec", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -75,7 +91,7 @@ struct LambdaProtonBalanceFunction { // Contains per-event distributions of N_before, N_after, N_removed, fraction. HistogramRegistry registryProtonVetoQA{"ProtonVetoQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - // pT bins 0.6 → 6.0 in steps of 0.2 (used for per-bin rho2 / mass histograms) + // pT bins 0.6 → 3.6 in steps of 0.2 (used for per-bin rho2 / mass histograms) std::vector ptEdges; // ════════════════════════════════════════════════════════════════════════ @@ -87,11 +103,11 @@ struct LambdaProtonBalanceFunction { std::shared_ptr hMassAntiLambdaMerged; // ════════════════════════════════════════════════════════════════════════ - // SECTION A2 — Extended invariant-mass histograms (y × pT grid) + // SECTION A2— Extended invariant-mass histograms (y × pT grid) // hMassLambdaExtended[iY][iPt] → Lambda_invMassExtended/Lambda/ // hMassAntiLambdaExtended[iY][iPt] → Lambda_invMassExtended/AntiLambda/ - // Rapidity bins: [-1.0,-0.9), [-0.9,-0.8), [-0.8,-0.7), [-0.7,-0.6] - // pT bins: [0.0,0.1), [0.1,0.2), ..., [2.4,2.5] + // Rapidity bins (kExtNyBins = 2): [-0.8,-0.7), [-0.7,-0.6] + // pT bins (kExtNptBins = 25): [0.0,0.1), [0.1,0.2), ..., [2.4,2.5] // ════════════════════════════════════════════════════════════════════════ static constexpr int kExtNyBins = 2; static constexpr int kExtNptBins = 25; @@ -108,7 +124,9 @@ struct LambdaProtonBalanceFunction { // ════════════════════════════════════════════════════════════════════════ // SECTION B — rho2 eta-space histograms // Naming: hRho2_ = per-pT-bin vector - // hRho2__pT015toMaxDefined = merged (full pT range) + // hRho2__pT015toMaxDefined = merged (full pT range as + // set by the pT cuts: protons 0.5-3.6, Lambdas 0.6-3.6 GeV/c; + // "015" is a legacy name and does NOT reflect the actual lower cut) // ════════════════════════════════════════════════════════════════════════ // Lambda–proton family std::shared_ptr hRho2_Lp_pT015toMaxDefined; @@ -147,6 +165,10 @@ struct LambdaProtonBalanceFunction { std::shared_ptr hRho2_ALL_y_pT015toMaxDefined; std::shared_ptr hRho2_ALAL_y_pT015toMaxDefined; + // SECTION E — centrality-differential storage (struct CentRho2Set is defined above the task) + std::vector centSets; + std::vector centEdgesLocal; + // ════════════════════════════════════════════════════════════════════════ // SECTION D — pT-spectra and pair-count monitoring histograms // ════════════════════════════════════════════════════════════════════════ @@ -172,11 +194,16 @@ struct LambdaProtonBalanceFunction { // sample before constructing future Balance Functions. int64_t runTotalProtonBeforeVeto = 0; ///< sum of N_before_veto over all events int64_t runTotalProtonRemovedVeto = 0; ///< sum of N_removed_by_veto over all events + int64_t runTotalAntiPBeforeVeto = 0; ///< antiproton: sum of N_before_veto + int64_t runTotalAntiPRemovedVeto = 0; ///< antiproton: sum of N_removed_by_veto // ───────────────────────────────────────────────────────────────────── // ── Configurables ───────────────────────────────────────────────────── - Configurable cPPandV0NBins{"cPPandV0NBins", 100, "N bins in all histos"}; + Configurable cPPandV0ZVertexCut{"cPPandV0ZVertexCut", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cFillEtaSpace{"cFillEtaSpace", false, "Fill eta-space rho1/rho2 histograms"}; + Configurable cUseQinvCut{"cUseQinvCut", true, "Apply q_inv > 0.01 GeV/c pair cut (false = no q_inv rejection)"}; + Configurable cFillCentHists{"cFillCentHists", true, "Fill centrality-differential rho1/rho2 histograms in separate rho1ANDrho2_LP_CentralityBased folder"}; // Track quality cuts Configurable pProtonTPCMinRows{"pProtonTPCMinRows", 70, "Minimum TPC crossed rows"}; @@ -186,7 +213,7 @@ struct LambdaProtonBalanceFunction { Configurable pProtonITSMaxChi2PerCluster{"pProtonITSMaxChi2PerCluster", 36.0f, "Max ITS chi2 / Ncls"}; Configurable cPPMinTpcSignal{"cPPMinTpcSignal", 10.0f, "Min raw TPC signal (sanity cut)"}; // DCA cuts - Configurable pProtonMaxDCAxy{"pProtonMaxDCAxy", 0.02f, "Max |DCAxy| (cm)"}; // changed 0.1-->0.05-->0.02 (tightened for cleanest primary-proton sample) + Configurable pProtonMaxDCAxy{"pProtonMaxDCAxy", 0.02f, "Max |DCAxy| (cm)"}; // tight cut for cleanest primary-proton sample Configurable pProtonMaxDCAz{"pProtonMaxDCAz", 0.1f, "Max |DCAz| (cm)"}; Configurable pProtonTPCTOFSwitchP{"pProtonTPCTOFSwitchP", 0.700000238f, "p threshold (GeV/c) above which TOF is used if available"}; @@ -214,16 +241,17 @@ struct LambdaProtonBalanceFunction { // ───────────────────────────────────────────────────────────────────── // Proton Kinematic Cuts (from strange9) - Configurable pProtonMinP{"pProtonMinP", 0.5f, "Min p_{TPC} for primary protons"}; - Configurable pProtonMaxP{"pProtonMaxP", 3.5999999f, "Max p for primary protons"}; - Configurable pProtonMaxEta{"pProtonMaxEta", 0.5f, "Max |eta| for primary protons"}; + Configurable pProtonMinP{"pProtonMinP", 0.5f, "Min p for primary protons (GeV/c)"}; + Configurable pProtonMaxP{"pProtonMaxP", 3.6f, "Max p for primary protons (GeV/c)"}; + Configurable pProtonMinPt{"pProtonMinPt", 0.5f, "Min pT for primary protons (GeV/c)"}; + Configurable pProtonMaxPt{"pProtonMaxPt", 3.6f, "Max pT for primary protons (GeV/c)"}; + Configurable pProtonMaxY{"pProtonMaxY", 0.5f, "Max |y| for primary protons"}; // Lambda Kinematic Cuts (from strange9) Configurable lambdaV0MinPt{"lambdaV0MinPt", 0.60f, "Min pT for Lambdas"}; Configurable lambdaV0MaxPt{"lambdaV0MaxPt", 3.60f, "Max pT for Lambdas"}; Configurable lambdaV0MaxY{"lambdaV0MaxY", 0.5f, "Max |y| for Lambdas"}; - Configurable lambdaV0MaxEta{"lambdaV0MaxEta", 0.5f, "Max |eta| for Lambdas"}; // V0 Mass and Topology Cuts (from strange9) Configurable lambdaV0MaxCTau{"lambdaV0MaxCTau", 30.0f, "Max V0 ctau (cm)"}; @@ -235,13 +263,11 @@ struct LambdaProtonBalanceFunction { Configurable cV0DauMinPt{"cV0DauMinPt", 0.1f, "Daughter pT minimum"}; Configurable cV0DauMaxEta{"cV0DauMaxEta", 0.8f, "Daughter |eta| cut"}; Configurable cV0DauMinTpcCrossedRows{"cV0DauMinTpcCrossedRows", 70, "Daughter TPC min crossed rows"}; - // Rapidity-specific constants matched to PProtonMaxY's default value (0.8). + // Rapidity-specific constants matched to pProtonMaxY's default value (0.5). // Note: Since these are compile-time constexpr, the axis will NOT auto-update - // if PProtonMaxY is changed via configurable at runtime. The axis just needs to + // if pProtonMaxY is changed via configurable at runtime. The axis just needs to // stay >= the cut, not exactly equal. - // When u change JSON, adjust this also (not needed is my new finding) - // Eta static constexpr int kRhoEtaBins = 40; static constexpr float kRhoMin = -0.5f; @@ -254,13 +280,16 @@ struct LambdaProtonBalanceFunction { static constexpr int kRhoPhiBins = 72; static constexpr int kRhoUnrolledBins = kRhoEtaBins * kRhoPhiBins; + static constexpr int kRhoUnrolledBinsY = kRhoYBins * kRhoPhiBins; void buildPtBins() { ptEdges.clear(); - static constexpr float kPtEdgeMax = 6.0001f; - for (float pt = 0.6f; pt <= kPtEdgeMax; pt += 0.2f) { - ptEdges.push_back(pt); + static constexpr int kNPtEdges = 16; // 0.6, 0.8, ..., 3.6 GeV/c (15 bins) + static constexpr float kPtEdgeMin = 0.6f; + static constexpr float kPtEdgeStep = 0.2f; + for (int i = 0; i < kNPtEdges; ++i) { + ptEdges.push_back(kPtEdgeMin + kPtEdgeStep * static_cast(i)); } } @@ -317,7 +346,7 @@ struct LambdaProtonBalanceFunction { static constexpr float kMassProton = o2::constants::physics::MassProton; static constexpr float kMassLambda = o2::constants::physics::MassLambda; - // Femtoscopic q_inv cut (applied only to QA Before/After plots, not to physics rho2 histograms): + // Femtoscopic q_inv cut: pairs with q_inv <= kQinvCutLP are rejected from all rho2 histograms (pp, pAp, App, ApAp, LP-family, LL-family): static constexpr float kQinvCutLP = 0.01f; template @@ -325,25 +354,32 @@ struct LambdaProtonBalanceFunction { { return RecoDecay::y(std::array{track.px(), track.py(), track.pz()}, kMassProton); } - // Fills both eta-space and rapidity-space rho2 histograms in one call. - // Separated guards prevent filling when either index is out of acceptance. - void fillRho2Pair( - std::shared_ptr& histEta, std::shared_ptr& histY, - int idxEta1, int idxEta2, int idxY1, int idxY2) const - { - if (idxEta1 >= 0 && idxEta2 >= 0) { - histEta->Fill(idxEta1, idxEta2); - } - if (idxY1 >= 0 && idxY2 >= 0) { - histY->Fill(idxY1, idxY2); - } - } float displayDeltaPhi(float dPhi) const { return RecoDecay::constrainAngle(dPhi, -o2::constants::math::PI / 2.0f); } + // k* = |p*| of one particle in the pair rest frame, from four-momenta. + float computeKstar(float px1, float py1, float pz1, float m1, + float px2, float py2, float pz2, float m2) const + { + const float E1 = std::sqrt(px1 * px1 + py1 * py1 + pz1 * pz1 + m1 * m1); + const float E2 = std::sqrt(px2 * px2 + py2 * py2 + pz2 * pz2 + m2 * m2); + const float sx = px1 + px2; + const float sy = py1 + py2; + const float sz = pz1 + pz2; + const float sE = E1 + E2; + const float s = sE * sE - sx * sx - sy * sy - sz * sz; + if (s <= 0.f) { + return 0.f; + } + // k*^2 = [ (s - (m1+m2)^2)(s - (m1-m2)^2) ] / (4 s) + const float a = s - (m1 + m2) * (m1 + m2); + const float b = s - (m1 - m2) * (m1 - m2); + return std::sqrt(std::max(a * b, 0.f) / (4.f * s)); + } + // ── Femtoscopic q_inv computation ──────────────────────────────────────── // Returns q_inv = sqrt( -(p1 - p2)^2 ) in natural units (GeV/c). // E1 and E2 must be computed by the caller using the appropriate mass @@ -361,6 +397,31 @@ struct LambdaProtonBalanceFunction { // q2 should be <= 0 for physical pairs; protect sqrt from numerical noise return std::sqrt(std::max(-q2, 0.0f)); } + + // true => pair is rejected by the q_inv cut (never true when the cut is switched off) + bool failsQinvCut(float qinv) const + { + return cUseQinvCut.value && (qinv <= kQinvCutLP); + } + + // Returns index of centrality bin for cent, or -1 if outside all bins. + int centBinIndex(float cent) const + { + for (size_t i = 0; i + 1 < centEdgesLocal.size(); ++i) { + if (cent >= centEdgesLocal[i] && cent < centEdgesLocal[i + 1]) { + return static_cast(i); + } + } + return -1; + } + + // Fill helper: fills h (if valid) at (a,b) only when both indices are in range. + static void fillIdx(std::shared_ptr const& h, int a, int b) + { + if (h && a >= 0 && b >= 0) { + h->Fill(a, b); + } + } // ───────────────────────────────────────────────────────────────────── // ── Two-region PID selection for (anti)protons ──────────────────────── @@ -370,23 +431,16 @@ struct LambdaProtonBalanceFunction { const float pTPC = trk.tpcInnerParam(); // NOTE: pTPC, not trk.p() — matches reference exactly const float nsPr = trk.tpcNSigmaPr(); + if (std::abs(nsPr) >= pProtonTPCNsigma.value) { + return false; + } if (pTPC < pProtonTPCTOFSwitchP.value) { - if (std::abs(nsPr) >= pProtonTPCNsigma.value) { - return false; - } - return true; - } else { - if (std::abs(nsPr) >= pProtonTPCNsigma.value) { - return false; - } - if (!trk.hasTOF()) { - return false; - } - if (std::abs(trk.tofNSigmaPr()) >= pProtonTOFNsigma.value) { - return false; - } return true; } + if (!trk.hasTOF()) { + return false; + } + return std::abs(trk.tofNSigmaPr()) < pProtonTOFNsigma.value; } // ───────────────────────────────────────────────────────────────────── @@ -396,9 +450,9 @@ struct LambdaProtonBalanceFunction { /// Canonical analysis stages for (anti)proton QA fills. enum class ProtonQAStage : int { - RawAfterTrackSel = 0, ///< truly RAW — before any track selection, DCA, or PID - TpcPid = 1, ///< after DCA + TPC PID cut passes - TpcTofPid = 2, ///< after DCA + TPC PID + TOF PID all pass + RawAfterTrackSel = 0, ///< after track-quality selection (TrackSelection table), before DCA cuts and PID + TpcPid = 1, ///< after DCA + TPC PID cut passes (all momenta) + TpcTofPid = 2, ///< after DCA + full PID: TPC everywhere, plus TOF required only above pProtonTPCTOFSwitchP FinalSelected = 3 ///< entered selectedPrimProtons / selectedPrimAntiProtons }; @@ -476,10 +530,10 @@ struct LambdaProtonBalanceFunction { void fillProtonDetectorQuality(ProtonQAStage stage, TTrack const& trk) { const float pt = trk.pt(); - const float tpcCR = static_cast(trk.tpcNClsCrossedRows()); + const auto tpcCR = static_cast(trk.tpcNClsCrossedRows()); const float tpcCRoF = trk.tpcCrossedRowsOverFindableCls(); const float tpcChi2 = trk.tpcChi2NCl(); - const float itsN = static_cast(trk.itsNCls()); + const auto itsN = static_cast(trk.itsNCls()); const float itsChi2 = trk.itsChi2NCl(); const float dcaXY = trk.dcaXY(); const float dcaZ = trk.dcaZ(); @@ -1072,15 +1126,41 @@ struct LambdaProtonBalanceFunction { } } + // Per-particle cache used by the pair loops (avoids recomputing per pair). + struct PartInfo { + int64_t gid; + float px, py, pz, E; + float eta, phi, y, pt; + int idxEta; + int idxY; + }; + + template + PartInfo makeProtonInfo(TTrack const& t) const + { + PartInfo p; + p.gid = t.globalIndex(); + p.px = t.px(); + p.py = t.py(); + p.pz = t.pz(); + p.E = std::sqrt(p.px * p.px + p.py * p.py + p.pz * p.pz + kMassProton * kMassProton); + p.eta = t.eta(); + p.phi = t.phi(); + p.pt = t.pt(); + p.y = protonRapidity(t); + p.idxEta = unrolledIndex(p.eta, p.phi); + p.idxY = unrolledIndexY(p.y, p.phi); + return p; + } + void init(InitContext const&) { buildPtBins(); // ── Common axis definitions ────────────────────────────────────────── AxisSpec lambdaMassAxis = {200, 1.08f, 1.15f, "#it{M}_{inv} [GeV/#it{c}^{2}]"}; - AxisSpec vertexZAxis = {cPPandV0NBins, -15.f, 15.f, "vrtx_{Z} [cm]"}; + AxisSpec vertexZAxis = {100, -15.f, 15.f, "vrtx_{Z} [cm]"}; AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec pzAxis = {200, -10.0f, 10.0f, "p_{z} (GeV/#it{c})"}; AxisSpec axisP = {200, 0.0f, 6.0f, "p (GeV/c)"}; // axisPTPC: TPC inner momentum — the variable that drives the proton PID selection logic. // Used alongside axisP so both total-p and pTPC views are available for every diagnostic plot. @@ -1094,13 +1174,11 @@ struct LambdaProtonBalanceFunction { AxisSpec nsigmaAxis = {100, -10.0f, 10.0f, "n#sigma"}; AxisSpec dcaAxis = {100, -1.0f, 1.0f, "DCAxy (cm)"}; AxisSpec dcaZAxis = {100, -1.0f, 1.0f, "DCAz (cm)"}; - AxisSpec massAxis = {200, 1.08f, 1.15f, "M (GeV/#it{c}^{2})"}; AxisSpec dcaAxisWide = {200, 0.0f, 5.0f, "DCA (cm)"}; AxisSpec multAxis = {100, 0.0f, 100.0f, "FT0M Percentile (%)"}; AxisSpec etaAxis = {kRhoEtaBins, kRhoMin, kRhoMax, "#eta"}; AxisSpec phiAxis = {kRhoPhiBins, 0.0f, o2::constants::math::TwoPI, "#varphi"}; AxisSpec unrolledAxis = {kRhoUnrolledBins, 0.0f, static_cast(kRhoUnrolledBins), "index(#eta,#varphi)"}; - static constexpr int kRhoUnrolledBinsY = kRhoYBins * kRhoPhiBins; AxisSpec unrolledAxisY = {kRhoUnrolledBinsY, 0.0f, static_cast(kRhoUnrolledBinsY), "index(y,#varphi)"}; AxisSpec rapidityAxis = {kRhoYBins, kRhoYMin, kRhoYMax, "y"}; AxisSpec yAxis = {kRhoYBins, kRhoYMin, kRhoYMax, "y"}; @@ -1126,16 +1204,14 @@ struct LambdaProtonBalanceFunction { registryOther.add("hNPrimAntiProtonRemovedByVeto", "AntiProton candidates removed by V0-daughter veto;N;Events", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); registryOther.add("hNPrimAntiProtonAfterVeto", "AntiProton candidates after V0-daughter veto;N;Events", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); // ───────────────────────────────────────────────────────────────────── - registryOther.add("hPtSelLambda", "#Lambda p_{T} yield", {HistType::kTH1F, {ptAxis}}); - registryOther.add("hPtSelAntiLambda", "#bar{#Lambda} p_{T} yield", {HistType::kTH1F, {ptAxis}}); - registryOther.add("hPtSelectedPrimProton", "Selected primary proton p_{T} yield", {HistType::kTH1F, {ptAxis}}); - registryOther.add("hPtSelectedPrimAntiProton", "Selected primary antiproton p_{T} yield", {HistType::kTH1F, {ptAxis}}); - registryOther.add("hNPairs_Lambda_PrimProton", "#Lambda-p pairs per event", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); - registryOther.add("hNPairs_Lambda_PrimAntiProton", "#Lambda-#bar{p} pairs per event", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); - registryOther.add("hNPairs_AntiLambda_PrimProton", "#bar{#Lambda}-p pairs per event", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); - registryOther.add("hNPairs_AntiLambda_PrimAntiProton", "#bar{#Lambda}-#bar{p} pairs per event", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); - - // ── Event cutflow ───────────────────────────────────────── + registryOther.add("hPtSelLambda", "Selected #Lambda p_{T} spectrum (raw counts);#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); + registryOther.add("hPtSelAntiLambda", "Selected #bar{#Lambda} p_{T} spectrum (raw counts);#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); + registryOther.add("hPtSelectedPrimProton", "Selected primary proton p_{T} spectrum (raw counts, after V0-daughter veto);#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); + registryOther.add("hPtSelectedPrimAntiProton", "Selected primary antiproton p_{T} spectrum (raw counts, after V0-daughter veto);#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); + registryOther.add("hNPairs_Lambda_PrimProton", "#Lambda-p pairs per event (after q_{inv} cut);N_{pairs};Events", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); + registryOther.add("hNPairs_Lambda_PrimAntiProton", "#Lambda-#bar{p} pairs per event (after q_{inv} cut);N_{pairs};Events", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); + registryOther.add("hNPairs_AntiLambda_PrimProton", "#bar{#Lambda}-p pairs per event (after q_{inv} cut);N_{pairs};Events", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); + registryOther.add("hNPairs_AntiLambda_PrimAntiProton", "#bar{#Lambda}-#bar{p} pairs per event (after q_{inv} cut);N_{pairs};Events", {HistType::kTH1F, {{200, 0.0f, 200.0f}}}); // ══════════════════════════════════════════════════════════════════════════ // NEW STAGED QA_Detec REGISTRATION @@ -1147,8 +1223,7 @@ struct LambdaProtonBalanceFunction { AxisSpec axisCosPA_zoom = {200, 0.99f, 1.0f, "Cos(PA)"}; AxisSpec axisDecayR = {100, 0.0f, 50.0f, "cm"}; AxisSpec axisCtau = {100, 0.0f, 50.0f, "ctau (cm)"}; - AxisSpec axisCutFlow = {5, 0.5f, 5.5f, "Cut stage"}; - AxisSpec axisTOFMatchFrac = {50, 0.0f, 1.0f, "TOF matching fraction"}; + AxisSpec axisCutFlow = {14, 0.5f, 14.5f, "Cut stage"}; auto addProtonQAForStage = [&](const char* species, const char* stage) { // Kinematics @@ -1197,16 +1272,16 @@ struct LambdaProtonBalanceFunction { auto addLambdaQAForStage = [&](const char* species, const char* stage) { // Kinematics - registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_pt", species, stage), "p_{T};p_{T} (GeV/c);Counts", {HistType::kTH1F, {axisPtProton}}); - registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_eta", species, stage), "#eta;#eta;Counts", {HistType::kTH1F, {qaEtaAxis}}); - registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_phi", species, stage), "#phi;#phi;Counts", {HistType::kTH1F, {qaPhiAxis}}); + registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_pt", species, stage), "V0 p_{T} (RawCandidate = all V0s before any cut, both hypotheses);p_{T} (GeV/c);Counts", {HistType::kTH1F, {axisPtProton}}); + registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_eta", species, stage), "V0 #eta (RawCandidate = all V0s before any cut, both hypotheses);#eta;Counts", {HistType::kTH1F, {qaEtaAxis}}); + registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_phi", species, stage), "V0 #varphi (RawCandidate = all V0s before any cut, both hypotheses);#varphi;Counts", {HistType::kTH1F, {qaPhiAxis}}); if (std::string(stage) == "02_Final") { registryQaDetector.add(Form("%s/01_Kinematics/%s/h1f_rapidity", species, stage), "y;y;Counts", {HistType::kTH1F, {rapidityAxis}}); } // Topology - registryQaDetector.add(Form("%s/02_Topology/%s/h1f_cospa", species, stage), "Cos(PA);Cos(PA);Counts", {HistType::kTH1F, {{100, 0.9f, 1.0f, "Cos(PA)"}}}); - registryQaDetector.add(Form("%s/02_Topology/%s/h1f_cospa_zoom", species, stage), "Cos(PA);Cos(PA);Counts", {HistType::kTH1F, {axisCosPA_zoom}}); + registryQaDetector.add(Form("%s/02_Topology/%s/h1f_cospa", species, stage), "V0 cos(PA), full range;cos(PA);Counts", {HistType::kTH1F, {{100, 0.9f, 1.0f, "cos(PA)"}}}); + registryQaDetector.add(Form("%s/02_Topology/%s/h1f_cospa_zoom", species, stage), "V0 cos(PA), zoom 0.99-1.0;cos(PA);Counts", {HistType::kTH1F, {axisCosPA_zoom}}); registryQaDetector.add(Form("%s/02_Topology/%s/h1f_dcaV0toPV", species, stage), "DCA V0 to PV;DCA (cm);Counts", {HistType::kTH1F, {dcaAxisWide}}); registryQaDetector.add(Form("%s/02_Topology/%s/h1f_ctau", species, stage), "ctau;ctau (cm);Counts", {HistType::kTH1F, {axisCtau}}); if (std::string(stage) == "01_RawCandidate" || std::string(stage) == "02_Final") { @@ -1280,21 +1355,45 @@ struct LambdaProtonBalanceFunction { addDaughterQA("02_AntiLambda", "02_AntiPion", stage); } - registryQaDetector.add("Selection/TOF_Matching/hTOFMatchedFractionVsPt", "TOF matched fraction vs p_{T};p_{T};Fraction", {HistType::kTProfile, {axisPtProton}}); + registryQaDetector.add("Selection/TOF_Matching/hTOFMatchedFractionVsPt", "TOF-matched fraction of selected (anti)protons (before V0-daughter veto) vs p_{T};p_{T} (GeV/c);TOF-matched fraction", {HistType::kTProfile, {axisPtProton}}); // ── Item 4: 2D TOF-matching efficiency maps (eta × phi) ────────────────── registryQaDetector.add("Selection/TOF_Matching/h2f_TOFMatchedFractionVsEtaPhi", - "Proton TOF matched fraction vs (#eta, #varphi);#eta;#varphi;Fraction", + "TOF-matched fraction of selected (anti)protons (before V0-daughter veto) vs (#eta, #varphi);#eta;#varphi;TOF-matched fraction", {HistType::kTProfile2D, {qaEtaAxis, qaPhiAxis}}); // ───────────────────────────────────────────────────────────────────────── - registryQaDetector.add("Selection/TOF_Matching/hCutFlow", "Proton Track Cutflow;Stage;Counts", {HistType::kTH1F, {axisCutFlow}}); + registryQaDetector.add("Selection/TOF_Matching/hCutFlow", "(Anti)proton track cutflow (both charges);Stage;Counts", {HistType::kTH1F, {axisCutFlow}}); + { + auto hCF = registryQaDetector.get(HIST("Selection/TOF_Matching/hCutFlow")); + hCF->GetXaxis()->SetBinLabel(1, "All tracks"); + hCF->GetXaxis()->SetBinLabel(2, "hasTPC"); + hCF->GetXaxis()->SetBinLabel(3, "TPC crossed rows"); + hCF->GetXaxis()->SetBinLabel(4, "TPC rows/findable"); + hCF->GetXaxis()->SetBinLabel(5, "TPC chi2"); + hCF->GetXaxis()->SetBinLabel(6, "ITS Ncls"); + hCF->GetXaxis()->SetBinLabel(7, "ITS chi2"); + hCF->GetXaxis()->SetBinLabel(8, "TPC signal"); + hCF->GetXaxis()->SetBinLabel(9, "p_TPC & pT window"); + hCF->GetXaxis()->SetBinLabel(10, "|y| window"); + hCF->GetXaxis()->SetBinLabel(11, "DCA xy,z"); + hCF->GetXaxis()->SetBinLabel(12, "PID (TPC/TOF)"); + hCF->GetXaxis()->SetBinLabel(13, "V0-daughter veto"); + hCF->GetXaxis()->SetBinLabel(14, "Selected"); + } // ══════════════════════════════════════════════════════════════════════════ // EXISTING QA_Detec REGISTRATION (Preserved for backward compatibility) // ══════════════════════════════════════════════════════════════════════════ - // -- Proton (existing) --r INEL > 0 + // -- Event cutflow -- registryOther.add("hEventCutflow", "Event Cutflow;Step;Counts", {HistType::kTH1F, {{4, 0.5f, 4.5f}}}); + { + auto hEC = registryOther.get(HIST("hEventCutflow")); + hEC->GetXaxis()->SetBinLabel(1, "sel8 + |z|GetXaxis()->SetBinLabel(2, "numContrib >= 1"); + hEC->GetXaxis()->SetBinLabel(3, "centFT0M < 80"); + hEC->GetXaxis()->SetBinLabel(4, "INEL > 0"); + } // ── ProtonVetoQA histograms ─────────────────────────────────────────── // Purpose: quantify the importance of the V0-daughter veto for the @@ -1330,12 +1429,21 @@ struct LambdaProtonBalanceFunction { // hPileupFlags: each bin corresponds to a different event-selection bit. // Bin 1 = kNoSameBunchPileup, Bin 2 = kIsGoodZvtxFT0vsPV, // Bin 3 = kIsVertexITSTPC, Bin 4 = kIsVertexTOFmatched, - // Bin 5 = kIsVertexTRDmatched, Bin 6 = any pileup-rejection bit fired. + // Bin 5 = kIsVertexTRDmatched, Bin 6 = kNoSameBunchPileup && kIsGoodZvtxFT0vsPV && kIsVertexITSTPC all set. registryOther.add("hPileupFlags", - "Event-level pile-up rejection flags (Bin 6: All 3 passed (AND));Flag;Events passing", + "Event-level pile-up rejection flags;Flag;Events passing", {HistType::kTH1F, {{6, 0.5f, 6.5f, "Pileup flag"}}}); + { + auto hPU = registryOther.get(HIST("hPileupFlags")); + hPU->GetXaxis()->SetBinLabel(1, "NoSameBunchPileup"); + hPU->GetXaxis()->SetBinLabel(2, "GoodZvtxFT0vsPV"); + hPU->GetXaxis()->SetBinLabel(3, "VertexITSTPC"); + hPU->GetXaxis()->SetBinLabel(4, "VertexTOFmatched"); + hPU->GetXaxis()->SetBinLabel(5, "VertexTRDmatched"); + hPU->GetXaxis()->SetBinLabel(6, "NoSBPU&&GoodZvtx&&ITSTPC"); + } registryOther.add("h2f_NTracks_vs_Cent", - "N_{tracks}(|#eta|<0.8) vs FT0M cent;FT0M (%);N_{tracks}(|#eta|<0.8)", + "N_{tracks}(|#eta|<0.8, all TracksIU, no quality cut) vs FT0M cent;FT0M (%);N_{tracks}(|#eta|<0.8)", {HistType::kTH2F, {multAxis, {200, 0.0f, 200.0f, "N_{tracks}"}}}); registryOther.add("h2f_NumContrib_vs_Cent", "N_{contribs} vs FT0M percentile;FT0M (%);N_{contribs}", @@ -1362,15 +1470,15 @@ struct LambdaProtonBalanceFunction { // ── Rho histograms ─────────────────────────────────────────────────── registryRho.add("hEventCounter", "Events", {HistType::kTH1F, {{1, 0.0, 1.0}}}); // eta-based rho1 - registryRho.add("h2_rho1_Proton", "rho1 proton", {HistType::kTH2F, {etaAxis, phiAxis}}); - registryRho.add("h2_rho1_AntiProton", "rho1 pbar", {HistType::kTH2F, {etaAxis, phiAxis}}); - registryRho.add("h2_rho1_Lambda", "rho1 lambda", {HistType::kTH2F, {etaAxis, phiAxis}}); - registryRho.add("h2_rho1_AntiLambda", "rho1 lambdabar", {HistType::kTH2F, {etaAxis, phiAxis}}); + registryRho.add("h2_rho1_Proton", "#rho_{1}(p) in (#eta,#varphi) (after V0-daughter veto)", {HistType::kTH2F, {etaAxis, phiAxis}}); + registryRho.add("h2_rho1_AntiProton", "#rho_{1}(#bar{p}) in (#eta,#varphi) (after V0-daughter veto)", {HistType::kTH2F, {etaAxis, phiAxis}}); + registryRho.add("h2_rho1_Lambda", "#rho_{1}(#Lambda) in (#eta,#varphi)", {HistType::kTH2F, {etaAxis, phiAxis}}); + registryRho.add("h2_rho1_AntiLambda", "#rho_{1}(#bar{#Lambda}) in (#eta,#varphi)", {HistType::kTH2F, {etaAxis, phiAxis}}); // rapidity-based rho1 - registryRho.add("h2_rho1_Proton_y", "rho1 proton (y)", {HistType::kTH2F, {yAxis, phiAxis}}); - registryRho.add("h2_rho1_AntiProton_y", "rho1 pbar (y)", {HistType::kTH2F, {yAxis, phiAxis}}); - registryRho.add("h2_rho1_Lambda_y", "rho1 lambda (y)", {HistType::kTH2F, {yAxis, phiAxis}}); - registryRho.add("h2_rho1_AntiLambda_y", "rho1 lambdabar (y)", {HistType::kTH2F, {yAxis, phiAxis}}); + registryRho.add("h2_rho1_Proton_y", "#rho_{1}(p) in (y,#varphi) (after V0-daughter veto)", {HistType::kTH2F, {yAxis, phiAxis}}); + registryRho.add("h2_rho1_AntiProton_y", "#rho_{1}(#bar{p}) in (y,#varphi) (after V0-daughter veto)", {HistType::kTH2F, {yAxis, phiAxis}}); + registryRho.add("h2_rho1_Lambda_y", "#rho_{1}(#Lambda) in (y,#varphi)", {HistType::kTH2F, {yAxis, phiAxis}}); + registryRho.add("h2_rho1_AntiLambda_y", "#rho_{1}(#bar{#Lambda}) in (y,#varphi)", {HistType::kTH2F, {yAxis, phiAxis}}); // ───────────────────────────────────────────────────────────────────── // ── Autocorrelation / feed-down diagnostic histograms ──────────────── @@ -1379,28 +1487,30 @@ struct LambdaProtonBalanceFunction { // Folder: CorrelationQA/PrimaryProton_vs_LambdaDaughter/ // // h2f_dEta_dPhi : Δη vs Δφ for every (selected Lambda, selected - // primary proton) pair. No veto on shared tracks. - // A peak at (0,0) indicates track sharing / feed-down. + // primary proton) pair. The primary-proton list is + // ALREADY cleaned by the V0-daughter veto, so the same + // track cannot appear; this checks for residual + // proximity correlation (e.g. undetected feed-down). // h2f_dEta_dPhi_nonSameTrack : same, restricted to pairs where the primary // proton track is NOT the Lambda positive daughter. - AxisSpec axisCorDEta = {64, -1.6f, 1.6f}; + AxisSpec axisCorDEta = {64, -1.6f, 1.6f, "#Delta#eta"}; AxisSpec axisCorDPhi = {72, -o2::constants::math::PI, o2::constants::math::PI, "#Delta#varphi"}; AxisSpec axisCorDPhiDisplay = {72, -o2::constants::math::PI / 2.0f, 3.0f * o2::constants::math::PI / 2.0f, "#Delta#varphi"}; registryCorrelationQA.add( "PrimaryProton_vs_LambdaDaughter/h2f_dEta_dPhi", - "Primary Proton vs #Lambda Daughter Proton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", + "Primary Proton (after V0-daughter veto) vs #Lambda Daughter Proton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", {HistType::kTH2F, {axisCorDEta, axisCorDPhi}}); registryCorrelationQA.add( "PrimaryProton_vs_LambdaDaughter/h2f_dEta_dPhi_display", - "Primary Proton vs #Lambda Daughter Proton (display shifted #Delta#varphi);#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", + "Primary Proton (after V0-daughter veto) vs #Lambda Daughter Proton (display shifted #Delta#varphi);#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", {HistType::kTH2F, {axisCorDEta, axisCorDPhiDisplay}}); registryCorrelationQA.add( "PrimaryProton_vs_LambdaDaughter/h2f_dEta_dPhi_nonSameTrack", - "Primary Proton vs #Lambda Daughter (non-same-track pairs only);#Delta#eta;#Delta#varphi", + "Primary Proton (after V0-daughter veto) vs #Lambda Daughter (non-same-track pairs only);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhi}}); registryCorrelationQA.add( "PrimaryProton_vs_LambdaDaughter/h2f_dEta_dPhi_nonSameTrack_display", - "Primary Proton vs #Lambda Daughter (non-same-track pairs only, display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", + "Primary Proton (after V0-daughter veto) vs #Lambda Daughter (non-same-track pairs only, display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhiDisplay}}); // ───────────────────────────────────────────────────────────────────── @@ -1410,11 +1520,11 @@ struct LambdaProtonBalanceFunction { // Same-track matching is impossible here (opposite charges). registryCorrelationQA.add( "PrimaryAntiProton_vs_LambdaDaughter/h2f_dEta_dPhi", - "Primary AntiProton vs #Lambda Daughter Proton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", + "Primary AntiProton (after V0-daughter veto) vs #Lambda Daughter Proton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", {HistType::kTH2F, {axisCorDEta, axisCorDPhi}}); registryCorrelationQA.add( "PrimaryAntiProton_vs_LambdaDaughter/h2f_dEta_dPhi_display", - "Primary AntiProton vs #Lambda Daughter Proton (display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", + "Primary AntiProton (after V0-daughter veto) vs #Lambda Daughter Proton (display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhiDisplay}}); // ───────────────────────────────────────────────────────────────────── @@ -1424,11 +1534,11 @@ struct LambdaProtonBalanceFunction { // Same-track matching is impossible here (opposite charges). registryCorrelationQA.add( "PrimaryProton_vs_AntiLambdaDaughter/h2f_dEta_dPhi", - "Primary Proton vs #bar{#Lambda} Daughter AntiProton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", + "Primary Proton (after V0-daughter veto) vs #bar{#Lambda} Daughter AntiProton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", {HistType::kTH2F, {axisCorDEta, axisCorDPhi}}); registryCorrelationQA.add( "PrimaryProton_vs_AntiLambdaDaughter/h2f_dEta_dPhi_display", - "Primary Proton vs #bar{#Lambda} Daughter AntiProton (display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", + "Primary Proton (after V0-daughter veto) vs #bar{#Lambda} Daughter AntiProton (display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhiDisplay}}); // ───────────────────────────────────────────────────────────────────── @@ -1440,19 +1550,19 @@ struct LambdaProtonBalanceFunction { // the AntiLambda neg-daughter (i.e. genuine different-track pairs). registryCorrelationQA.add( "PrimaryAntiProton_vs_AntiLambdaDaughter/h2f_dEta_dPhi", - "Primary AntiProton vs #bar{#Lambda} Daughter AntiProton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", + "Primary AntiProton (after V0-daughter veto) vs #bar{#Lambda} Daughter AntiProton;#Delta#eta = #eta_{prim} - #eta_{dau};#Delta#varphi = #varphi_{prim} - #varphi_{dau}", {HistType::kTH2F, {axisCorDEta, axisCorDPhi}}); registryCorrelationQA.add( "PrimaryAntiProton_vs_AntiLambdaDaughter/h2f_dEta_dPhi_display", - "Primary AntiProton vs #bar{#Lambda} Daughter AntiProton (display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", + "Primary AntiProton (after V0-daughter veto) vs #bar{#Lambda} Daughter AntiProton (display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhiDisplay}}); registryCorrelationQA.add( "PrimaryAntiProton_vs_AntiLambdaDaughter/h2f_dEta_dPhi_nonSameTrack", - "Primary AntiProton vs #bar{#Lambda} Daughter (non-same-track pairs only);#Delta#eta;#Delta#varphi", + "Primary AntiProton (after V0-daughter veto) vs #bar{#Lambda} Daughter (non-same-track pairs only);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhi}}); registryCorrelationQA.add( "PrimaryAntiProton_vs_AntiLambdaDaughter/h2f_dEta_dPhi_nonSameTrack_display", - "Primary AntiProton vs #bar{#Lambda} Daughter (non-same-track pairs only, display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", + "Primary AntiProton (after V0-daughter veto) vs #bar{#Lambda} Daughter (non-same-track pairs only, display shifted #Delta#varphi);#Delta#eta;#Delta#varphi", {HistType::kTH2F, {axisCorDEta, axisCorDPhiDisplay}}); // ───────────────────────────────────────────────────────────────────── @@ -1478,13 +1588,14 @@ struct LambdaProtonBalanceFunction { registryCorrelationQA.add( "QA3/PairCleaning/h1f_pairCleaning", "p-p pair cleaning;Step;Counts", - {HistType::kTH1F, {{3, 0.5f, 3.5f}}}); + {HistType::kTH1F, {{4, 0.5f, 4.5f}}}); // Bin labels are set after histogram registration { auto h = registryCorrelationQA.get(HIST("QA3/PairCleaning/h1f_pairCleaning")); h->GetXaxis()->SetBinLabel(1, "All Candidate Pairs"); h->GetXaxis()->SetBinLabel(2, "Rejected Same Track"); - h->GetXaxis()->SetBinLabel(3, "Accepted"); + h->GetXaxis()->SetBinLabel(3, "Rejected q_inv"); + h->GetXaxis()->SetBinLabel(4, "Accepted"); } // ───────────────────────────────────────────────────────────────────── @@ -1512,33 +1623,62 @@ struct LambdaProtonBalanceFunction { {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_qinv_LP_Before_qinvCut", - "Split-track QA: q_{inv} for #Lambda-p pairs, before q_{inv} cut;q_{inv} (GeV/c);Counts", + "Split-track QA: q_{inv} for #Lambda/#bar{#Lambda}-p/#bar{p} pairs (all four LP combos), before q_{inv} cut;q_{inv} (GeV/c);Counts", {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_qinv_LL_Before_qinvCut", - "Split-track QA: q_{inv} for #Lambda-#Lambda pairs, before q_{inv} cut;q_{inv} (GeV/c);Counts", + "Split-track QA: q_{inv} for #Lambda/#bar{#Lambda}-#Lambda/#bar{#Lambda} pairs (all four LL combos), before q_{inv} cut;q_{inv} (GeV/c);Counts", {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); // "After_qinvCut": filled only for pairs surviving the q_inv cut - // (q_inv > kQinvCutLP), applied uniformly to PP, LP, and LL pairs. + // (q_inv > kQinvCutLP), applied uniformly to all pair types (PP, pAp, App, ApAp, LP-family, LL-family). registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_qinv_PP_After_qinvCut", - "Split-track QA: q_{inv} for p-p pairs, after q_{inv} cut;q_{inv} (GeV/c);Counts", + "Split-track QA: q_{inv} for p-p pairs, after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_qinv_LP_After_qinvCut", - "Split-track QA: q_{inv} for #Lambda-p pairs, after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", + "Split-track QA: q_{inv} for #Lambda/#bar{#Lambda}-p/#bar{p} pairs (all four LP combos), after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut", - "Split-track QA: q_{inv} for #Lambda-#Lambda pairs, after q_{inv} cut;q_{inv} (GeV/c);Counts", + "Split-track QA: q_{inv} for #Lambda/#bar{#Lambda}-#Lambda/#bar{#Lambda} pairs (all four LL combos), after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", + {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + // q_inv Before/After QA for p-pbar, pbar-p and pbar-pbar pairs + registryCorrelationQA.add( + "QA3/SplitTrackQA/h1f_qinv_pAp_Before_qinvCut", + "Split-track QA: q_{inv} for p-#bar{p} pairs, before q_{inv} cut;q_{inv} (GeV/c);Counts", + {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + registryCorrelationQA.add( + "QA3/SplitTrackQA/h1f_qinv_pAp_After_qinvCut", + "Split-track QA: q_{inv} for p-#bar{p} pairs, after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + registryCorrelationQA.add( + "QA3/SplitTrackQA/h1f_qinv_App_Before_qinvCut", + "Split-track QA: q_{inv} for #bar{p}-p pairs, before q_{inv} cut;q_{inv} (GeV/c);Counts", + {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + registryCorrelationQA.add( + "QA3/SplitTrackQA/h1f_qinv_App_After_qinvCut", + "Split-track QA: q_{inv} for #bar{p}-p pairs, after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", + {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + registryCorrelationQA.add( + "QA3/SplitTrackQA/h1f_qinv_ApAp_Before_qinvCut", + "Split-track QA: q_{inv} for #bar{p}-#bar{p} pairs, before q_{inv} cut;q_{inv} (GeV/c);Counts", + {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + registryCorrelationQA.add( + "QA3/SplitTrackQA/h1f_qinv_ApAp_After_qinvCut", + "Split-track QA: q_{inv} for #bar{p}-#bar{p} pairs, after q_{inv} cut (q_{inv} > 0.01 GeV/c);q_{inv} (GeV/c);Counts", + {HistType::kTH1F, {{600, 0.0f, 6.0f, "q_{inv} (GeV/c)"}}}); + registryCorrelationQA.add("QA3/Kstar/h1f_kstar_Lp", "k* of #Lambda-p pairs (after q_{inv} cut);k* (GeV/c);Counts", {HistType::kTH1F, {{200, 0.0f, 2.0f}}}); + registryCorrelationQA.add("QA3/Kstar/h1f_kstar_LAp", "k* of #Lambda-#bar{p} pairs (after q_{inv} cut);k* (GeV/c);Counts", {HistType::kTH1F, {{200, 0.0f, 2.0f}}}); + registryCorrelationQA.add("QA3/Kstar/h1f_kstar_ALp", "k* of #bar{#Lambda}-p pairs (after q_{inv} cut);k* (GeV/c);Counts", {HistType::kTH1F, {{200, 0.0f, 2.0f}}}); + registryCorrelationQA.add("QA3/Kstar/h1f_kstar_ALAp", "k* of #bar{#Lambda}-#bar{p} pairs (after q_{inv} cut);k* (GeV/c);Counts", {HistType::kTH1F, {{200, 0.0f, 2.0f}}}); registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_sharedClsFraction_t1", - "Split-track QA: TPC shared-cluster fraction (track 1 in close p-p pairs);Fraction;Counts", + "Split-track QA: TPC shared-cluster fraction, track 1 (p-p: first proton; #Lambda-p: V0 daughter) in close pairs;Fraction;Counts", {HistType::kTH1F, {{50, 0.0f, 1.0f}}}); registryCorrelationQA.add( "QA3/SplitTrackQA/h1f_sharedClsFraction_t2", - "Split-track QA: TPC shared-cluster fraction (track 2 in close p-p pairs);Fraction;Counts", + "Split-track QA: TPC shared-cluster fraction, track 2 (p-p: second proton; #Lambda-p: primary (anti)proton) in close pairs;Fraction;Counts", {HistType::kTH1F, {{50, 0.0f, 1.0f}}}); // ───────────────────────────────────────────────────────────────────── @@ -1553,58 +1693,58 @@ struct LambdaProtonBalanceFunction { {HistType::kTH1F, {pidCheckPtAxis}}); h_TPCorTOF = registryProtonPidCheck.add("h_TPCorTOF", - "Proton candidates: TPC mandatory, TOF optional if present;#it{p}_{T} (GeV/#it{c});Counts", + "Proton candidates: TPC required; if TOF present at any p, TOF n#sigma also required (differs from final selection, which requires TOF only above p_{TPC} switch);#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {pidCheckPtAxis}}); // ───────────────────────────────────────────────────────────────────── // ── Merged / pT015toMaxDefined histograms ─────────────────────────────────── hRho2_Lp_pT015toMaxDefined = registryRho.add("h2_rho2_Lp_pT015toMaxDefined", - "Lambda-p correlation (integrated pT range)", + "#rho_{2}(#Lambda, p) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #Lambda (trigger);index(#eta,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_LAp_pT015toMaxDefined = registryRho.add("h2_rho2_LAp_pT015toMaxDefined", - "Lambda-pbar correlation (integrated pT range)", + "#rho_{2}(#Lambda, #bar{p}) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #Lambda (trigger);index(#eta,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_ALp_pT015toMaxDefined = registryRho.add("h2_rho2_ALp_pT015toMaxDefined", - "AntiLambda-p correlation (integrated pT range)", + "#rho_{2}(#bar{#Lambda}, p) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #bar{#Lambda} (trigger);index(#eta,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_ALAp_pT015toMaxDefined = registryRho.add("h2_rho2_ALAp_pT015toMaxDefined", - "AntiLambda-pbar correlation (integrated pT range)", + "#rho_{2}(#bar{#Lambda}, #bar{p}) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #bar{#Lambda} (trigger);index(#eta,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_pp_pT015toMaxDefined = registryRho.add("h2_rho2_pp_pT015toMaxDefined", - "pp correlation", + "#rho_{2}(p, p) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of p (trigger);index(#eta,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_pAp_pT015toMaxDefined = registryRho.add("h2_rho2_pAp_pT015toMaxDefined", - "p-pbar correlation", + "#rho_{2}(p, #bar{p}) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of p (trigger);index(#eta,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_App_pT015toMaxDefined = registryRho.add("h2_rho2_App_pT015toMaxDefined", - "pbar-p correlation", + "#rho_{2}(#bar{p}, p) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #bar{p} (trigger);index(#eta,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_ApAp_pT015toMaxDefined = registryRho.add("h2_rho2_ApAp_pT015toMaxDefined", - "pbar-pbar correlation", + "#rho_{2}(#bar{p}, #bar{p}) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #bar{p} (trigger);index(#eta,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_LL_pT015toMaxDefined = registryRho.add("h2_rho2_LL_pT015toMaxDefined", - "Lambda-Lambda correlation", + "#rho_{2}(#Lambda, #Lambda) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #Lambda (trigger);index(#eta,#varphi) of #Lambda (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_LAL_pT015toMaxDefined = registryRho.add("h2_rho2_LAL_pT015toMaxDefined", - "Lambda-AntiLambda correlation", + "#rho_{2}(#Lambda, #bar{#Lambda}) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #Lambda (trigger);index(#eta,#varphi) of #bar{#Lambda} (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_ALL_pT015toMaxDefined = registryRho.add("h2_rho2_ALL_pT015toMaxDefined", - "AntiLambda-Lambda correlation", + "#rho_{2}(#bar{#Lambda}, #Lambda) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #bar{#Lambda} (trigger);index(#eta,#varphi) of #Lambda (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); hRho2_ALAL_pT015toMaxDefined = registryRho.add("h2_rho2_ALAL_pT015toMaxDefined", - "AntiLambda-AntiLambda correlation", + "#rho_{2}(#bar{#Lambda}, #bar{#Lambda}) in (#eta,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(#eta,#varphi) of #bar{#Lambda} (trigger);index(#eta,#varphi) of #bar{#Lambda} (associate)", {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); // ── Rapidity merged rho2 histograms ───────────────────────────────────── @@ -1614,55 +1754,55 @@ struct LambdaProtonBalanceFunction { // so the booked axis must match that range or downstream R2/BF code that // expects y-space-sized histograms will see a dimension mismatch. hRho2_Lp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_Lp_y_pT015toMaxDefined", "Lambda-p (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_Lp_y_pT015toMaxDefined", "#rho_{2}(#Lambda, p) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #Lambda (trigger);index(y,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_LAp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_LAp_y_pT015toMaxDefined", "Lambda-pbar (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_LAp_y_pT015toMaxDefined", "#rho_{2}(#Lambda, #bar{p}) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #Lambda (trigger);index(y,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_ALp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_ALp_y_pT015toMaxDefined", "AntiLambda-p (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_ALp_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda}, p) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #bar{#Lambda} (trigger);index(y,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_ALAp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_ALAp_y_pT015toMaxDefined", "AntiLambda-pbar (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_ALAp_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda}, #bar{p}) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #bar{#Lambda} (trigger);index(y,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_pp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_pp_y_pT015toMaxDefined", "pp (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_pp_y_pT015toMaxDefined", "#rho_{2}(p, p) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of p (trigger);index(y,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_pAp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_pAp_y_pT015toMaxDefined", "p-pbar (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_pAp_y_pT015toMaxDefined", "#rho_{2}(p, #bar{p}) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of p (trigger);index(y,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_App_y_pT015toMaxDefined = - registryRho.add("h2_rho2_App_y_pT015toMaxDefined", "pbar-p (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_App_y_pT015toMaxDefined", "#rho_{2}(#bar{p}, p) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #bar{p} (trigger);index(y,#varphi) of p (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_ApAp_y_pT015toMaxDefined = - registryRho.add("h2_rho2_ApAp_y_pT015toMaxDefined", "pbar-pbar (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_ApAp_y_pT015toMaxDefined", "#rho_{2}(#bar{p}, #bar{p}) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #bar{p} (trigger);index(y,#varphi) of #bar{p} (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_LL_y_pT015toMaxDefined = - registryRho.add("h2_rho2_LL_y_pT015toMaxDefined", "Lambda-Lambda (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_LL_y_pT015toMaxDefined", "#rho_{2}(#Lambda, #Lambda) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #Lambda (trigger);index(y,#varphi) of #Lambda (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_LAL_y_pT015toMaxDefined = - registryRho.add("h2_rho2_LAL_y_pT015toMaxDefined", "Lambda-AntiLambda (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_LAL_y_pT015toMaxDefined", "#rho_{2}(#Lambda, #bar{#Lambda}) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #Lambda (trigger);index(y,#varphi) of #bar{#Lambda} (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_ALL_y_pT015toMaxDefined = - registryRho.add("h2_rho2_ALL_y_pT015toMaxDefined", "AntiLambda-Lambda (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_ALL_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda}, #Lambda) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #bar{#Lambda} (trigger);index(y,#varphi) of #Lambda (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); hRho2_ALAL_y_pT015toMaxDefined = - registryRho.add("h2_rho2_ALAL_y_pT015toMaxDefined", "AntiLambda-AntiLambda (y)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + registryRho.add("h2_rho2_ALAL_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda}, #bar{#Lambda}) in (y,#varphi) space, q_{inv} > 0.01 GeV/#it{c};index(y,#varphi) of #bar{#Lambda} (trigger);index(y,#varphi) of #bar{#Lambda} (associate)", {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); // ───────────────────────────────────────────────────────────────────── hPtSelectedPrimProton_pT015toMaxDefined = registryOther.add("hPtSelectedPrimProton_pT015toMaxDefined", - "Proton p_{T} yield (integrated pT range)", + "Selected primary proton p_{T} spectrum (integrated, 0.5-3.6 GeV/#it{c});#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); hPtSelectedPrimAntiProton_pT015toMaxDefined = registryOther.add("hPtSelectedPrimAntiProton_pT015toMaxDefined", - "Antiproton p_{T} yield (integrated pT range)", + "Selected primary antiproton p_{T} spectrum (integrated, 0.5-3.6 GeV/#it{c});#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); hPtSelLambda_pT015toMaxDefined = registryOther.add("hPtSelLambda_pT015toMaxDefined", - "#Lambda p_{T} yield (integrated pT range)", + "Selected #Lambda p_{T} spectrum (integrated, 0.6-3.6 GeV/#it{c});#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); hPtSelAntiLambda_pT015toMaxDefined = registryOther.add("hPtSelAntiLambda_pT015toMaxDefined", - "#bar{#Lambda} p_{T} yield (integrated pT range)", + "Selected #bar{#Lambda} p_{T} spectrum (integrated, 0.6-3.6 GeV/#it{c});#it{p}_{T} (GeV/#it{c});Counts", {HistType::kTH1F, {ptAxis}}); hMassLambdaMerged = registryLambda.add("hMassLambdaNoMassCut_pT015toMaxDefined", - "Lambda Mass No Mass Cut (integrated pT range)", + "#Lambda mass (all selections except #Lambda mass window), integrated #it{p}_{T} 0.6-3.6 GeV/#it{c};#it{M}_{inv} [GeV/#it{c}^{2}];Counts", {HistType::kTH1F, {lambdaMassAxis}}); hMassAntiLambdaMerged = registryLambda.add("hMassAntiLambdaNoMassCut_pT015toMaxDefined", - "AntiLambda Mass No Mass Cut (integrated pT range)", + "#bar{#Lambda} mass (all selections except #Lambda mass window), integrated #it{p}_{T} 0.6-3.6 GeV/#it{c};#it{M}_{inv} [GeV/#it{c}^{2}];Counts", {HistType::kTH1F, {lambdaMassAxis}}); // ───────────────────────────────────────────────────────────────────── @@ -1681,39 +1821,39 @@ struct LambdaProtonBalanceFunction { hPtPrimProton_Lambda.push_back( registryOther.add( Form("hPtPrimProton_Lambda_ptBin%02zu", i), - Form("Proton pT in #Lambda-p pairs %.1f < pT < %.1f", ptLo, ptHi), + Form("Proton #it{p}_{T} in #Lambda-p pairs, #Lambda #it{p}_{T} in [%.1f, %.1f) GeV/#it{c};#it{p}_{T}^{p} (GeV/#it{c});Counts", ptLo, ptHi), {HistType::kTH1F, {ptAxis}})); hPtPrimAntiProton_Lambda.push_back( registryOther.add( Form("hPtPrimAntiProton_Lambda_ptBin%02zu", i), - Form("Antiproton pT in #Lambda-#bar{p} pairs %.1f < pT < %.1f", ptLo, ptHi), + Form("Antiproton #it{p}_{T} in #Lambda-#bar{p} pairs, #Lambda #it{p}_{T} in [%.1f, %.1f) GeV/#it{c};#it{p}_{T}^{#bar{p}} (GeV/#it{c});Counts", ptLo, ptHi), {HistType::kTH1F, {ptAxis}})); hPtPrimProton_AntiLambda.push_back( registryOther.add( Form("hPtPrimProton_AntiLambda_ptBin%02zu", i), - Form("Proton pT in #bar{#Lambda}-p pairs %.1f < pT < %.1f", ptLo, ptHi), + Form("Proton #it{p}_{T} in #bar{#Lambda}-p pairs, #bar{#Lambda} #it{p}_{T} in [%.1f, %.1f) GeV/#it{c};#it{p}_{T}^{p} (GeV/#it{c});Counts", ptLo, ptHi), {HistType::kTH1F, {ptAxis}})); hPtPrimAntiProton_AntiLambda.push_back( registryOther.add( Form("hPtPrimAntiProton_AntiLambda_ptBin%02zu", i), - Form("Antiproton pT in #bar{#Lambda}-#bar{p} pairs %.1f < pT < %.1f", ptLo, ptHi), + Form("Antiproton #it{p}_{T} in #bar{#Lambda}-#bar{p} pairs, #bar{#Lambda} #it{p}_{T} in [%.1f, %.1f) GeV/#it{c};#it{p}_{T}^{#bar{p}} (GeV/#it{c});Counts", ptLo, ptHi), {HistType::kTH1F, {ptAxis}})); hMassLambdaPtBins.push_back( registryLambda.add( Form("hMassLambdaNoMassCut_ptBin%02zu", i), - Form("Lambda Mass No Mass Cut %.1f < pT < %.1f", ptLo, ptHi), + Form("#Lambda mass (all selections except #Lambda mass window), %.1f #leq #it{p}_{T} < %.1f GeV/#it{c};#it{M}_{inv} [GeV/#it{c}^{2}];Counts", ptLo, ptHi), {HistType::kTH1F, {lambdaMassAxis}})); hMassAntiLambdaPtBins.push_back( registryLambda.add( Form("hMassAntiLambdaNoMassCut_ptBin%02zu", i), - Form("AntiLambda Mass No Mass Cut %.1f < pT < %.1f", ptLo, ptHi), + Form("#bar{#Lambda} mass (all selections except #Lambda mass window), %.1f #leq #it{p}_{T} < %.1f GeV/#it{c};#it{M}_{inv} [GeV/#it{c}^{2}];Counts", ptLo, ptHi), {HistType::kTH1F, {lambdaMassAxis}})); } // ───────────────────────────────────────────────────────────────────── // ── Extended y × pT invariant-mass histograms ───────────────────────── - // Rapidity bins: 4 bins from -1.0 to -0.6 in steps of 0.1 + // Rapidity bins: 2 bins from -0.8 to -0.6 in steps of 0.1 // pT bins: 25 bins from 0.0 to 2.5 in steps of 0.1 // Folder structure: // Lambda_invMassExtended/Lambda/hMassLambda_yBinXX_ptBinYY @@ -1744,7 +1884,7 @@ struct LambdaProtonBalanceFunction { hMassLambdaExtended[iY][iPt] = registryLambdaExtended.add( Form("Lambda/hMassLambda_yBin%02d_ptBin%02d", iY, iPt), - Form("Lambda Invariant Mass | %.1f <= y %s %.1f | %.1f <= pT %s %.1f GeV/c", + Form("#Lambda mass (no mass-window cut) | %.1f #leq y %s %.1f | %.1f #leq #it{p}_{T} %s %.1f GeV/#it{c};#it{M}_{inv} [GeV/#it{c}^{2}];Counts", yLow, yUpBracket, yHigh, ptLow, ptUpBracket, ptHigh), {HistType::kTH1F, {lambdaMassAxis}}); @@ -1752,12 +1892,81 @@ struct LambdaProtonBalanceFunction { hMassAntiLambdaExtended[iY][iPt] = registryLambdaExtended.add( Form("AntiLambda/hMassAntiLambda_yBin%02d_ptBin%02d", iY, iPt), - Form("AntiLambda Invariant Mass | %.1f <= y %s %.1f | %.1f <= pT %s %.1f GeV/c", + Form("#bar{#Lambda} mass (no mass-window cut) | %.1f #leq y %s %.1f | %.1f #leq #it{p}_{T} %s %.1f GeV/#it{c};#it{M}_{inv} [GeV/#it{c}^{2}];Counts", yLow, yUpBracket, yHigh, ptLow, ptUpBracket, ptHigh), {HistType::kTH1F, {lambdaMassAxis}}); } } // ───────────────────────────────────────────────────────────────────── + + // ══════════════════════════════════════════════════════════════════════ + // Centrality-differential histograms → top-level folder "rho1ANDrho2_LP_CentralityBased" + // ══════════════════════════════════════════════════════════════════════ + centSets.clear(); + centEdgesLocal = {0.f, 5.f, 10.f, 20.f, 40.f, 60.f, 80.f}; + if (cFillCentHists.value) { + const size_t nCent = centEdgesLocal.size() - 1; + centSets.resize(nCent); + + for (size_t ic = 0; ic < nCent; ++ic) { + const float cLo = centEdgesLocal[ic]; + const float cHi = centEdgesLocal[ic + 1]; + const std::string dir = Form("Cent%02d_%02d", static_cast(cLo), static_cast(cHi)); + const std::string ctag = Form("FT0M %.0f-%.0f%%", cLo, cHi); + auto& S = centSets[ic]; + + S.hEvents = registryCent.add((dir + "/hEventCounter").c_str(), + ("Events, " + ctag).c_str(), + {HistType::kTH1F, {{1, 0.0, 1.0}}}); + + // ── rho1, y space (always) ── + S.rho1_Proton_y = registryCent.add((dir + "/h2_rho1_Proton_y").c_str(), ("#rho_{1}(p) in (y,#varphi), " + ctag).c_str(), {HistType::kTH2F, {yAxis, phiAxis}}); + S.rho1_AntiProton_y = registryCent.add((dir + "/h2_rho1_AntiProton_y").c_str(), ("#rho_{1}(#bar{p}) in (y,#varphi), " + ctag).c_str(), {HistType::kTH2F, {yAxis, phiAxis}}); + S.rho1_Lambda_y = registryCent.add((dir + "/h2_rho1_Lambda_y").c_str(), ("#rho_{1}(#Lambda) in (y,#varphi), " + ctag).c_str(), {HistType::kTH2F, {yAxis, phiAxis}}); + S.rho1_AntiLambda_y = registryCent.add((dir + "/h2_rho1_AntiLambda_y").c_str(), ("#rho_{1}(#bar{#Lambda}) in (y,#varphi), " + ctag).c_str(), {HistType::kTH2F, {yAxis, phiAxis}}); + + // ── rho2, y space (always) ── + auto addY = [&](std::shared_ptr& h, const char* name, const char* title) { + h = registryCent.add((dir + "/" + name).c_str(), (std::string(title) + ", " + ctag).c_str(), {HistType::kTH2F, {unrolledAxisY, unrolledAxisY}}); + }; + addY(S.Lp_y, "h2_rho2_Lp_y_pT015toMaxDefined", "#rho_{2}(#Lambda,p) (y,#varphi)"); + addY(S.LAp_y, "h2_rho2_LAp_y_pT015toMaxDefined", "#rho_{2}(#Lambda,#bar{p}) (y,#varphi)"); + addY(S.ALp_y, "h2_rho2_ALp_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},p) (y,#varphi)"); + addY(S.ALAp_y, "h2_rho2_ALAp_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},#bar{p}) (y,#varphi)"); + addY(S.pp_y, "h2_rho2_pp_y_pT015toMaxDefined", "#rho_{2}(p,p) (y,#varphi)"); + addY(S.pAp_y, "h2_rho2_pAp_y_pT015toMaxDefined", "#rho_{2}(p,#bar{p}) (y,#varphi)"); + addY(S.App_y, "h2_rho2_App_y_pT015toMaxDefined", "#rho_{2}(#bar{p},p) (y,#varphi)"); + addY(S.ApAp_y, "h2_rho2_ApAp_y_pT015toMaxDefined", "#rho_{2}(#bar{p},#bar{p}) (y,#varphi)"); + addY(S.LL_y, "h2_rho2_LL_y_pT015toMaxDefined", "#rho_{2}(#Lambda,#Lambda) (y,#varphi)"); + addY(S.LAL_y, "h2_rho2_LAL_y_pT015toMaxDefined", "#rho_{2}(#Lambda,#bar{#Lambda}) (y,#varphi)"); + addY(S.ALL_y, "h2_rho2_ALL_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},#Lambda) (y,#varphi)"); + addY(S.ALAL_y, "h2_rho2_ALAL_y_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},#bar{#Lambda}) (y,#varphi)"); + + // ── eta space (only if BOTH switches on: memory heavy) ── + if (cFillEtaSpace.value) { + S.rho1_Proton = registryCent.add((dir + "/h2_rho1_Proton").c_str(), ("#rho_{1}(p) in (#eta,#varphi), " + ctag).c_str(), {HistType::kTH2F, {etaAxis, phiAxis}}); + S.rho1_AntiProton = registryCent.add((dir + "/h2_rho1_AntiProton").c_str(), ("#rho_{1}(#bar{p}) in (#eta,#varphi), " + ctag).c_str(), {HistType::kTH2F, {etaAxis, phiAxis}}); + S.rho1_Lambda = registryCent.add((dir + "/h2_rho1_Lambda").c_str(), ("#rho_{1}(#Lambda) in (#eta,#varphi), " + ctag).c_str(), {HistType::kTH2F, {etaAxis, phiAxis}}); + S.rho1_AntiLambda = registryCent.add((dir + "/h2_rho1_AntiLambda").c_str(), ("#rho_{1}(#bar{#Lambda}) in (#eta,#varphi), " + ctag).c_str(), {HistType::kTH2F, {etaAxis, phiAxis}}); + + auto addEta = [&](std::shared_ptr& h, const char* name, const char* title) { + h = registryCent.add((dir + "/" + name).c_str(), (std::string(title) + ", " + ctag).c_str(), {HistType::kTH2F, {unrolledAxis, unrolledAxis}}); + }; + addEta(S.Lp, "h2_rho2_Lp_pT015toMaxDefined", "#rho_{2}(#Lambda,p) (#eta,#varphi)"); + addEta(S.LAp, "h2_rho2_LAp_pT015toMaxDefined", "#rho_{2}(#Lambda,#bar{p}) (#eta,#varphi)"); + addEta(S.ALp, "h2_rho2_ALp_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},p) (#eta,#varphi)"); + addEta(S.ALAp, "h2_rho2_ALAp_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},#bar{p}) (#eta,#varphi)"); + addEta(S.pp, "h2_rho2_pp_pT015toMaxDefined", "#rho_{2}(p,p) (#eta,#varphi)"); + addEta(S.pAp, "h2_rho2_pAp_pT015toMaxDefined", "#rho_{2}(p,#bar{p}) (#eta,#varphi)"); + addEta(S.App, "h2_rho2_App_pT015toMaxDefined", "#rho_{2}(#bar{p},p) (#eta,#varphi)"); + addEta(S.ApAp, "h2_rho2_ApAp_pT015toMaxDefined", "#rho_{2}(#bar{p},#bar{p}) (#eta,#varphi)"); + addEta(S.LL, "h2_rho2_LL_pT015toMaxDefined", "#rho_{2}(#Lambda,#Lambda) (#eta,#varphi)"); + addEta(S.LAL, "h2_rho2_LAL_pT015toMaxDefined", "#rho_{2}(#Lambda,#bar{#Lambda}) (#eta,#varphi)"); + addEta(S.ALL, "h2_rho2_ALL_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},#Lambda) (#eta,#varphi)"); + addEta(S.ALAL, "h2_rho2_ALAL_pT015toMaxDefined", "#rho_{2}(#bar{#Lambda},#bar{#Lambda}) (#eta,#varphi)"); + } + } + } } Filter eventFilter = (o2::aod::evsel::sel8 == true); @@ -1798,9 +2007,9 @@ struct LambdaProtonBalanceFunction { // ALAp : trigger=AntiLambda,assoc=antiproton // LL/LAL/ALL/ALAL: both V0s from respective selected lists (self-pairs rejected) // - // Each channel has BOTH eta-space (unrolledIndex) and - // rapidity-space (unrolledIndexY) versions filled in the SAME loop. - // fillRho2Pair() handles both fills atomically. + // Each channel has both eta-space (unrolledIndex) and + // rapidity-space (unrolledIndexY) versions filled in the same loop; the + // eta-space fills are gated by cFillEtaSpace. // ───────────────────────────────────────────────────────────────────── // ── Event cutflow bin 1 — enters process (after sel8 + posZ filters) ── @@ -1819,7 +2028,7 @@ struct LambdaProtonBalanceFunction { // ── Event cutflow bin 3 — after centFT0M < 80 ──────────────────────── registryOther.fill(HIST("hEventCutflow"), 3.0f); - // INEL > 0: require at least one charged track in |eta| < 1.0 + // INEL > 0: require at least one charged track in |eta| < 0.8 int nTracksINEL = 0; static constexpr float kMaxInelEta = 0.8f; for (auto const& trk : tracks) { @@ -1834,6 +2043,17 @@ struct LambdaProtonBalanceFunction { registryOther.fill(HIST("hEventCutflow"), 4.0f); registryRho.fill(HIST("hEventCounter"), 0.5); + + // ── Centrality bin for the centrality-differential histograms ───────── + CentRho2Set* cs = nullptr; + if (cFillCentHists.value) { + const int iCent = centBinIndex(collision.centFT0M()); + if (iCent >= 0 && iCent < static_cast(centSets.size())) { + cs = ¢Sets[iCent]; + cs->hEvents->Fill(0.5); + } + } + registryOther.fill(HIST("hVertexZRec"), collision.posZ()); registryOther.fill(HIST("hFT0MPercentile"), collision.centFT0M()); @@ -1869,6 +2089,7 @@ struct LambdaProtonBalanceFunction { // ====== Step 1: Initialise containers ====================================== std::unordered_set v0DaughterTrackIds; + v0DaughterTrackIds.reserve(64); std::vector selectedPrimProtons; std::vector selectedPrimAntiProtons; std::vector selectedLambdas; @@ -1896,6 +2117,8 @@ struct LambdaProtonBalanceFunction { constexpr float mK0PDG = o2::constants::physics::MassK0Short; for (const auto& v0 : V0s) { + const auto& v0PosDauCached = v0.posTrack_as(); + const auto& v0NegDauCached = v0.negTrack_as(); // ── TRULY RAW QA Fills — before any V0 selection cut ───────────── // Placed here at the very top of the loop: before v0Type, daughter @@ -1905,8 +2128,8 @@ struct LambdaProtonBalanceFunction { // and the AntiLambda hypothesis (pos=pion, neg=proton) since no PID // decision has been made yet. This gives the true combinatorial view. { - const auto& rawPosDau = v0.posTrack_as(); - const auto& rawNegDau = v0.negTrack_as(); + const auto& rawPosDau = v0PosDauCached; + const auto& rawNegDau = v0NegDauCached; const float rawCtau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * mLambdaPDG; const float rawBgctau = rawCtau * v0.p() / mLambdaPDG; // Lambda hypothesis (positive daughter assumed proton) @@ -1932,8 +2155,8 @@ struct LambdaProtonBalanceFunction { } // ───────────────────────────────────────────────────────────────── - const auto& v0PosDau = v0.posTrack_as(); - const auto& v0NegDau = v0.negTrack_as(); + const auto& v0PosDau = v0PosDauCached; + const auto& v0NegDau = v0NegDauCached; // ── Daughter kinematic quality cuts (from strange9) ─────────────── if (v0PosDau.pt() <= cV0DauMinPt.value || v0NegDau.pt() <= cV0DauMinPt.value || @@ -2075,7 +2298,7 @@ struct LambdaProtonBalanceFunction { // ── Extended y × pT Lambda invariant-mass fill ──────────────────── // Use the same rapidity variable `y` computed above // and the same pT variable `pt` = v0.pt() already in scope. - // Accept only -1.0 <= y <= -0.6 and 0.0 <= pT <= 2.5 GeV/c. + // Accept only -0.8 <= y <= -0.6 and 0.0 <= pT <= 2.5 GeV/c. if (y >= kExtYMin && y <= kExtYMax && pt >= kExtPtMin && pt <= kExtPtMax) { // Determine rapidity bin index int iYext = static_cast((y - kExtYMin) / kExtYStep); @@ -2110,7 +2333,7 @@ struct LambdaProtonBalanceFunction { // ── Extended y × pT AntiLambda invariant-mass fill ──────────────── // Use the same rapidity variable `y` computed above // and the same pT variable `pt` = v0.pt() already in scope. - // Accept only -1.0 <= y <= -0.6 and 0.0 <= pT <= 2.5 GeV/c. + // Accept only -0.8 <= y <= -0.6 and 0.0 <= pT <= 2.5 GeV/c. if (y >= kExtYMin && y <= kExtYMax && pt >= kExtPtMin && pt <= kExtPtMax) { int iYext = static_cast((y - kExtYMin) / kExtYStep); if (iYext >= kExtNyBins) { @@ -2165,8 +2388,16 @@ struct LambdaProtonBalanceFunction { fillDaughterQA(DaughterQAStage::Final, v0PosDau); fillDaughterQA(DaughterQAStage::Final, v0NegDau); - registryRho.fill(HIST("h2_rho1_Lambda"), v0.eta(), v0.phi()); + if (cFillEtaSpace.value) { + registryRho.fill(HIST("h2_rho1_Lambda"), v0.eta(), v0.phi()); + } registryRho.fill(HIST("h2_rho1_Lambda_y"), v0.rapidity(1), v0.phi()); + if (cs) { + cs->rho1_Lambda_y->Fill(v0.rapidity(1), v0.phi()); + if (cs->rho1_Lambda) { + cs->rho1_Lambda->Fill(v0.eta(), v0.phi()); + } + } registryOther.fill(HIST("hPtSelLambda"), pt); hPtSelLambda_pT015toMaxDefined->Fill(pt); } @@ -2181,8 +2412,16 @@ struct LambdaProtonBalanceFunction { fillDaughterQA(DaughterQAStage::Final, v0NegDau); fillDaughterQA(DaughterQAStage::Final, v0PosDau); - registryRho.fill(HIST("h2_rho1_AntiLambda"), v0.eta(), v0.phi()); + if (cFillEtaSpace.value) { + registryRho.fill(HIST("h2_rho1_AntiLambda"), v0.eta(), v0.phi()); + } registryRho.fill(HIST("h2_rho1_AntiLambda_y"), v0.rapidity(2), v0.phi()); + if (cs) { + cs->rho1_AntiLambda_y->Fill(v0.rapidity(2), v0.phi()); + if (cs->rho1_AntiLambda) { + cs->rho1_AntiLambda->Fill(v0.eta(), v0.phi()); + } + } registryOther.fill(HIST("hPtSelAntiLambda"), pt); hPtSelAntiLambda_pT015toMaxDefined->Fill(pt); } @@ -2199,47 +2438,54 @@ struct LambdaProtonBalanceFunction { if (trk.sign() > 0) { fillProtonKinematics(ProtonQAStage::RawAfterTrackSel, trk); fillProtonDetectorQuality(ProtonQAStage::RawAfterTrackSel, trk); - if (trk.hasTPC()) + if (trk.hasTPC()) { fillProtonTpcQA(ProtonQAStage::RawAfterTrackSel, trk); - if (trk.hasTOF()) + } + if (trk.hasTOF()) { fillProtonTofQA(ProtonQAStage::RawAfterTrackSel, trk); + } } else { fillProtonKinematics(ProtonQAStage::RawAfterTrackSel, trk); fillProtonDetectorQuality(ProtonQAStage::RawAfterTrackSel, trk); - if (trk.hasTPC()) + if (trk.hasTPC()) { fillProtonTpcQA(ProtonQAStage::RawAfterTrackSel, trk); - if (trk.hasTOF()) + } + if (trk.hasTOF()) { fillProtonTofQA(ProtonQAStage::RawAfterTrackSel, trk); + } } // ───────────────────────────────────────────────────────────────── // ── Track quality cuts ──────────────────────────────────────────── - registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 1.0f); // Quality cut starting point (after kinematics) + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 1.0f); if (!trk.hasTPC()) { continue; } - registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 2.0f); // passed hasTPC + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 2.0f); if (trk.tpcNClsCrossedRows() < pProtonTPCMinRows.value) { continue; } - registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 3.0f); // passed tpcNClsCrossedRows + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 3.0f); if (trk.tpcCrossedRowsOverFindableCls() < pProtonTPCMinRowsOverFindable.value) { continue; } - registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 4.0f); // passed tpcCrossedRowsOverFindableCls + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 4.0f); if (trk.tpcChi2NCl() > pProtonTPCMaxChi2PerCluster.value) { continue; } - registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 5.0f); // passed tpcChi2NCl + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 5.0f); if (trk.itsNCls() < pProtonITSMinClusters.value) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 6.0f); if (trk.itsChi2NCl() > pProtonITSMaxChi2PerCluster.value) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 7.0f); if (trk.tpcSignal() < cPPMinTpcSignal.value) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 8.0f); // ───────────────────────────────────────────────────────────────── // ── p_TPC and pT acceptance cuts ───────────────────────────────────────────── @@ -2247,9 +2493,10 @@ struct LambdaProtonBalanceFunction { if (pTPC < pProtonMinP.value || pTPC > pProtonMaxP.value) { continue; } - if (trk.pt() < pProtonMinP.value || trk.pt() > pProtonMaxP.value) { + if (trk.pt() < pProtonMinPt.value || trk.pt() > pProtonMaxPt.value) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 9.0f); // ───────────────────────────────────────────────────────────────── // ── Proton kinematic acceptance ─────────────────────────────────── @@ -2259,6 +2506,7 @@ struct LambdaProtonBalanceFunction { if (std::abs(y) > pProtonMaxY.value) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 10.0f); // ───────────────────────────────────────────────────────────────── // ── DCA cuts ───────────────────────────────────────────────────── const bool passDCA = (std::abs(trk.dcaXY()) < pProtonMaxDCAxy.value) && @@ -2266,6 +2514,7 @@ struct LambdaProtonBalanceFunction { if (!passDCA) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 11.0f); // ───────────────────────────────────────────────────────────────── // FIX-4: ProtonCounts_byPID_Check — protons only (sign > 0 guard added) @@ -2294,14 +2543,16 @@ struct LambdaProtonBalanceFunction { fillProtonKinematics(ProtonQAStage::TpcPid, trk); fillProtonDetectorQuality(ProtonQAStage::TpcPid, trk); fillProtonTpcQA(ProtonQAStage::TpcPid, trk); - if (trk.hasTOF()) + if (trk.hasTOF()) { fillProtonTofQA(ProtonQAStage::TpcPid, trk); + } } else { fillProtonKinematics(ProtonQAStage::TpcPid, trk); fillProtonDetectorQuality(ProtonQAStage::TpcPid, trk); fillProtonTpcQA(ProtonQAStage::TpcPid, trk); - if (trk.hasTOF()) + if (trk.hasTOF()) { fillProtonTofQA(ProtonQAStage::TpcPid, trk); + } } } @@ -2324,6 +2575,7 @@ struct LambdaProtonBalanceFunction { if (!passesPrimProtonPid(trk)) { continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 12.0f); // TOF Matching Fraction check on selected protons registryQaDetector.fill(HIST("Selection/TOF_Matching/hTOFMatchedFractionVsPt"), trk.pt(), trk.hasTOF() ? 1.0f : 0.0f); @@ -2363,7 +2615,7 @@ struct LambdaProtonBalanceFunction { // This MUST appear before push_back so that every pp histogram // (which iterates selectedPrimProtons / selectedPrimAntiProtons) // automatically uses the cleaned collection. - const bool isV0Daughter = v0DaughterTrackIds.count(trk.globalIndex()) > 0; + const bool isV0Daughter = v0DaughterTrackIds.contains(trk.globalIndex()); if (trk.sign() > 0) { ++nProtonBeforeVeto; } else { @@ -2378,9 +2630,11 @@ struct LambdaProtonBalanceFunction { } continue; } + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 13.0f); // ───────────────────────────────────────────────────────────────── // ── Classify into proton / antiproton lists ─────────────────────── + registryQaDetector.fill(HIST("Selection/TOF_Matching/hCutFlow"), 14.0f); // VS Code: commented out unused variables. // const float pz = trk.pt() * std::sinh(trk.eta()); // const float eta = trk.eta(); @@ -2391,8 +2645,9 @@ struct LambdaProtonBalanceFunction { fillProtonTpcQA(ProtonQAStage::FinalSelected, trk); // TOF QA only when track was accepted through the TPC+TOF branch: // p > PProtonTPC_TOFSwitchP guarantees hasTOF() and nSigmaTOF passed (beta window cut removed). //BETACUTCommented - if (pTPC > pProtonTPCTOFSwitchP.value) + if (pTPC >= pProtonTPCTOFSwitchP.value) { fillProtonTofQA(ProtonQAStage::FinalSelected, trk); + } registryOther.fill(HIST("hPtSelectedPrimProton"), trk.pt()); hPtSelectedPrimProton_pT015toMaxDefined->Fill(trk.pt()); @@ -2403,8 +2658,9 @@ struct LambdaProtonBalanceFunction { fillProtonTpcQA(ProtonQAStage::FinalSelected, trk); // TOF QA only when track was accepted through the TPC+TOF branch: // p > pProtonTPCTOFSwitchP guarantees hasTOF() and nSigmaTOF passed (beta window cut removed). //BETACUTCommented - if (pTPC > pProtonTPCTOFSwitchP.value) + if (pTPC >= pProtonTPCTOFSwitchP.value) { fillProtonTofQA(ProtonQAStage::FinalSelected, trk); + } registryOther.fill(HIST("hPtSelectedPrimAntiProton"), trk.pt()); hPtSelectedPrimAntiProton_pT015toMaxDefined->Fill(trk.pt()); @@ -2442,25 +2698,55 @@ struct LambdaProtonBalanceFunction { // Accumulate run-level totals for endOfStream() summary. runTotalProtonBeforeVeto += nBefore; runTotalProtonRemovedVeto += nRemoved; + runTotalAntiPBeforeVeto += nAntiPBeforeVeto; + runTotalAntiPRemovedVeto += nAntiPRemovedVeto; } // ───────────────────────────────────────────────────────────────────── // ── Single-particle density for protons (eta and y) ────────────────── for (auto const& primProton : selectedPrimProtons) { - registryRho.fill(HIST("h2_rho1_Proton"), primProton.eta(), primProton.phi()); + if (cFillEtaSpace.value) { + registryRho.fill(HIST("h2_rho1_Proton"), primProton.eta(), primProton.phi()); + } const float yp = protonRapidity(primProton); registryRho.fill(HIST("h2_rho1_Proton_y"), yp, primProton.phi()); + if (cs) { + cs->rho1_Proton_y->Fill(yp, primProton.phi()); + if (cs->rho1_Proton) { + cs->rho1_Proton->Fill(primProton.eta(), primProton.phi()); + } + } } for (auto const& primAntiProton : selectedPrimAntiProtons) { - registryRho.fill(HIST("h2_rho1_AntiProton"), primAntiProton.eta(), primAntiProton.phi()); + if (cFillEtaSpace.value) { + registryRho.fill(HIST("h2_rho1_AntiProton"), primAntiProton.eta(), primAntiProton.phi()); + } const float yap = protonRapidity(primAntiProton); registryRho.fill(HIST("h2_rho1_AntiProton_y"), yap, primAntiProton.phi()); + if (cs) { + cs->rho1_AntiProton_y->Fill(yap, primAntiProton.phi()); + if (cs->rho1_AntiProton) { + cs->rho1_AntiProton->Fill(primAntiProton.eta(), primAntiProton.phi()); + } + } } // ───────────────────────────────────────────────────────────────────── registryOther.fill(HIST("hNSelectedPrimProtons"), static_cast(selectedPrimProtons.size())); registryOther.fill(HIST("hNSelectedPrimAntiProtons"), static_cast(selectedPrimAntiProtons.size())); + // ── Per-particle caches for the pair loops ─────────────────────────── + std::vector protonInfo; + std::vector antiProtonInfo; + protonInfo.reserve(selectedPrimProtons.size()); + antiProtonInfo.reserve(selectedPrimAntiProtons.size()); + for (auto const& t : selectedPrimProtons) { + protonInfo.push_back(makeProtonInfo(t)); + } + for (auto const& t : selectedPrimAntiProtons) { + antiProtonInfo.push_back(makeProtonInfo(t)); + } + // ── pp rho2 fills (eta and y) ─────────────────────────────────────────── for (auto const& p1 : selectedPrimProtons) { const float y1_pp = protonRapidity(p1); @@ -2472,8 +2758,7 @@ struct LambdaProtonBalanceFunction { registryCorrelationQA.fill(HIST("QA3/PairCleaning/h1f_pairCleaning"), 2); continue; } // CHANGED from globalIndex() - // QA3/PairCleaning: accepted pair - registryCorrelationQA.fill(HIST("QA3/PairCleaning/h1f_pairCleaning"), 3); + // QA3/PairCleaning: bins 3 (Rejected q_inv) and 4 (Accepted) are filled at the q_inv cut below // QA3/RawPairDensity: fill Δη vs Δφ for every accepted p-p pair { @@ -2490,7 +2775,7 @@ struct LambdaProtonBalanceFunction { const float E2 = std::sqrt(p2mag * p2mag + kMassProton * kMassProton); const float qinvPP = computeQinv(p1.px(), p1.py(), p1.pz(), E1, p2.px(), p2.py(), p2.pz(), E2); registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_PP_Before_qinvCut"), qinvPP); - if (qinvPP > kQinvCutLP) { + if (!failsQinvCut(qinvPP)) { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_PP_After_qinvCut"), qinvPP); } } @@ -2512,68 +2797,94 @@ struct LambdaProtonBalanceFunction { } } + // q_inv cut (pp) + { + const float qE1 = std::sqrt(p1.px() * p1.px() + p1.py() * p1.py() + p1.pz() * p1.pz() + kMassProton * kMassProton); + const float qE2 = std::sqrt(p2.px() * p2.px() + p2.py() * p2.py() + p2.pz() * p2.pz() + kMassProton * kMassProton); + if (failsQinvCut(computeQinv(p1.px(), p1.py(), p1.pz(), qE1, p2.px(), p2.py(), p2.pz(), qE2))) { + registryCorrelationQA.fill(HIST("QA3/PairCleaning/h1f_pairCleaning"), 3); + continue; + } + registryCorrelationQA.fill(HIST("QA3/PairCleaning/h1f_pairCleaning"), 4); + } const int idx1 = unrolledIndex(p1.eta(), p1.phi()); const int idx2 = unrolledIndex(p2.eta(), p2.phi()); const float y2_pp = protonRapidity(p2); const int idxY1 = unrolledIndexY(y1_pp, p1.phi()); const int idxY2 = unrolledIndexY(y2_pp, p2.phi()); - // Physics pair correlations (rho2): q_inv cut not applied to rho2 - if (idx1 >= 0 && idx2 >= 0) { + // Physics pair correlations (rho2): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (cFillEtaSpace.value && idx1 >= 0 && idx2 >= 0) { hRho2_pp_pT015toMaxDefined->Fill(idx1, idx2); } if (idxY1 >= 0 && idxY2 >= 0) { hRho2_pp_y_pT015toMaxDefined->Fill(idxY1, idxY2); } + if (cs) { + fillIdx(cs->pp, idx1, idx2); + fillIdx(cs->pp_y, idxY1, idxY2); + } } } - for (auto const& p1 : selectedPrimProtons) { - const float y1_pAp = protonRapidity(p1); - for (auto const& p2 : selectedPrimAntiProtons) { - const int idx1 = unrolledIndex(p1.eta(), p1.phi()); - const int idx2 = unrolledIndex(p2.eta(), p2.phi()); - const float y2_pAp = protonRapidity(p2); - const int idxY1 = unrolledIndexY(y1_pAp, p1.phi()); - const int idxY2 = unrolledIndexY(y2_pAp, p2.phi()); - if (idx1 >= 0 && idx2 >= 0) { - hRho2_pAp_pT015toMaxDefined->Fill(idx1, idx2); + for (auto const& a : protonInfo) { + for (auto const& b : antiProtonInfo) { + const float qinvPAp = computeQinv(a.px, a.py, a.pz, a.E, b.px, b.py, b.pz, b.E); + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_pAp_Before_qinvCut"), qinvPAp); + if (failsQinvCut(qinvPAp)) { + continue; } - if (idxY1 >= 0 && idxY2 >= 0) { - hRho2_pAp_y_pT015toMaxDefined->Fill(idxY1, idxY2); + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_pAp_After_qinvCut"), qinvPAp); + if (cFillEtaSpace.value && a.idxEta >= 0 && b.idxEta >= 0) { + hRho2_pAp_pT015toMaxDefined->Fill(a.idxEta, b.idxEta); + } + if (a.idxY >= 0 && b.idxY >= 0) { + hRho2_pAp_y_pT015toMaxDefined->Fill(a.idxY, b.idxY); + } + if (cs) { + fillIdx(cs->pAp, a.idxEta, b.idxEta); + fillIdx(cs->pAp_y, a.idxY, b.idxY); } } } - for (auto const& p1 : selectedPrimAntiProtons) { - const float y1_App = protonRapidity(p1); - for (auto const& p2 : selectedPrimProtons) { - const int idx1 = unrolledIndex(p1.eta(), p1.phi()); - const int idx2 = unrolledIndex(p2.eta(), p2.phi()); - const float y2_App = protonRapidity(p2); - const int idxY1 = unrolledIndexY(y1_App, p1.phi()); - const int idxY2 = unrolledIndexY(y2_App, p2.phi()); - if (idx1 >= 0 && idx2 >= 0) { - hRho2_App_pT015toMaxDefined->Fill(idx1, idx2); + for (auto const& a : antiProtonInfo) { + for (auto const& b : protonInfo) { + const float qinvApp = computeQinv(a.px, a.py, a.pz, a.E, b.px, b.py, b.pz, b.E); + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_App_Before_qinvCut"), qinvApp); + if (failsQinvCut(qinvApp)) { + continue; } - if (idxY1 >= 0 && idxY2 >= 0) { - hRho2_App_y_pT015toMaxDefined->Fill(idxY1, idxY2); + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_App_After_qinvCut"), qinvApp); + if (cFillEtaSpace.value && a.idxEta >= 0 && b.idxEta >= 0) { + hRho2_App_pT015toMaxDefined->Fill(a.idxEta, b.idxEta); + } + if (a.idxY >= 0 && b.idxY >= 0) { + hRho2_App_y_pT015toMaxDefined->Fill(a.idxY, b.idxY); + } + if (cs) { + fillIdx(cs->App, a.idxEta, b.idxEta); + fillIdx(cs->App_y, a.idxY, b.idxY); } } } - for (auto const& p1 : selectedPrimAntiProtons) { - const float y1_ApAp = protonRapidity(p1); - for (auto const& p2 : selectedPrimAntiProtons) { - if (p1.index() == p2.index()) { + for (auto const& a : antiProtonInfo) { + for (auto const& b : antiProtonInfo) { + if (a.gid == b.gid) { continue; - } // CHANGED from globalIndex() - const int idx1 = unrolledIndex(p1.eta(), p1.phi()); - const int idx2 = unrolledIndex(p2.eta(), p2.phi()); - const float y2_ApAp = protonRapidity(p2); - const int idxY1 = unrolledIndexY(y1_ApAp, p1.phi()); - const int idxY2 = unrolledIndexY(y2_ApAp, p2.phi()); - if (idx1 >= 0 && idx2 >= 0) { - hRho2_ApAp_pT015toMaxDefined->Fill(idx1, idx2); } - if (idxY1 >= 0 && idxY2 >= 0) { - hRho2_ApAp_y_pT015toMaxDefined->Fill(idxY1, idxY2); + const float qinvApAp = computeQinv(a.px, a.py, a.pz, a.E, b.px, b.py, b.pz, b.E); + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_ApAp_Before_qinvCut"), qinvApAp); + if (failsQinvCut(qinvApAp)) { + continue; + } + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_ApAp_After_qinvCut"), qinvApAp); + if (cFillEtaSpace.value && a.idxEta >= 0 && b.idxEta >= 0) { + hRho2_ApAp_pT015toMaxDefined->Fill(a.idxEta, b.idxEta); + } + if (a.idxY >= 0 && b.idxY >= 0) { + hRho2_ApAp_y_pT015toMaxDefined->Fill(a.idxY, b.idxY); + } + if (cs) { + fillIdx(cs->ApAp, a.idxEta, b.idxEta); + fillIdx(cs->ApAp_y, a.idxY, b.idxY); } } } @@ -2609,7 +2920,7 @@ struct LambdaProtonBalanceFunction { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_Before_qinvCut"), qinvLP); } // QA3/SplitTrackQA: q_inv Before and After cut - if (qinvLP > kQinvCutLP) { + if (!failsQinvCut(qinvLP)) { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_After_qinvCut"), qinvLP); } // QA3/SplitTrackQA: close-pair block for daughter-overlap diagnosed split tracks @@ -2633,16 +2944,28 @@ struct LambdaProtonBalanceFunction { const float yP = protonRapidity(primProton); const int idxYL = unrolledIndexY(yL, v0.phi()); const int idxYP = unrolledIndexY(yP, primProton.phi()); - // Physics pair correlations (rho2 / pT / pair-count): q_inv cut not applied to rho2 + // Physics pair correlations (rho2 / pT / pair-count): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (failsQinvCut(qinvLP)) { + continue; + } + registryCorrelationQA.fill(HIST("QA3/Kstar/h1f_kstar_Lp"), + computeKstar(v0.px(), v0.py(), v0.pz(), kMassLambda, + primProton.px(), primProton.py(), primProton.pz(), kMassProton)); if (idxLambda >= 0 && idxPrimP >= 0) { if (bin >= 0) { hPtPrimProton_Lambda[bin]->Fill(primProton.pt()); } - hRho2_Lp_pT015toMaxDefined->Fill(idxLambda, idxPrimP); + if (cFillEtaSpace.value) { + hRho2_Lp_pT015toMaxDefined->Fill(idxLambda, idxPrimP); + } } if (idxYL >= 0 && idxYP >= 0) { hRho2_Lp_y_pT015toMaxDefined->Fill(idxYL, idxYP); } + if (cs) { + fillIdx(cs->Lp, idxLambda, idxPrimP); + fillIdx(cs->Lp_y, idxYL, idxYP); + } ++nPairs_Lambda_PrimProton; } for (auto const& primAntiProton : selectedPrimAntiProtons) { @@ -2660,7 +2983,7 @@ struct LambdaProtonBalanceFunction { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_Before_qinvCut"), qinvLAp); } // QA3/SplitTrackQA: q_inv Before and After cut - if (qinvLAp > kQinvCutLP) { + if (!failsQinvCut(qinvLAp)) { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_After_qinvCut"), qinvLAp); } // QA3/RawPairDensity: Lambda-antiproton → same LP histogram @@ -2677,27 +3000,39 @@ struct LambdaProtonBalanceFunction { const float yAp = protonRapidity(primAntiProton); const int idxYL2 = unrolledIndexY(yL2, v0.phi()); const int idxYAp = unrolledIndexY(yAp, primAntiProton.phi()); - // Physics pair correlations (rho2 / pT / pair-count): q_inv cut not applied to rho2 + // Physics pair correlations (rho2 / pT / pair-count): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (failsQinvCut(qinvLAp)) { + continue; + } + registryCorrelationQA.fill(HIST("QA3/Kstar/h1f_kstar_LAp"), + computeKstar(v0.px(), v0.py(), v0.pz(), kMassLambda, + primAntiProton.px(), primAntiProton.py(), primAntiProton.pz(), kMassProton)); if (idxLambda >= 0 && idxPrimPbar >= 0) { if (bin >= 0) { hPtPrimAntiProton_Lambda[bin]->Fill(primAntiProton.pt()); } - hRho2_LAp_pT015toMaxDefined->Fill(idxLambda, idxPrimPbar); + if (cFillEtaSpace.value) { + hRho2_LAp_pT015toMaxDefined->Fill(idxLambda, idxPrimPbar); + } } if (idxYL2 >= 0 && idxYAp >= 0) { hRho2_LAp_y_pT015toMaxDefined->Fill(idxYL2, idxYAp); } + if (cs) { + fillIdx(cs->LAp, idxLambda, idxPrimPbar); + fillIdx(cs->LAp_y, idxYL2, idxYAp); + } ++nPairs_Lambda_PrimAntiProton; } // ── Autocorrelation diagnostic: primary proton vs Lambda daughter proton── // Lambda proton daughter = v0PosDau (positive track, identified as proton // by |tpcNSigmaPr| < PProtonTPCNsigma, already in scope above). - // Loop over ALL selected primary protons — no daughter-track veto applied - // intentionally (the purpose is to DETECT the autocorrelation). + // Loop over ALL selected primary protons. NOTE: selectedPrimProtons is already + // cleaned by the V0-daughter veto, so the same-track case cannot occur here; + // this only checks for residual proximity correlations (e.g. undetected feed-down). // Fills inclusive h2f_dEta_dPhi for all pairs and - // h2f_dEta_dPhi_nonSameTrack for pairs where the primary proton is not - // the Lambda positive daughter. + // h2f_dEta_dPhi_nonSameTrack for every pair in this cleaned sample. { const float etaDau = v0PosDau.eta(); const float phiDau = v0PosDau.phi(); @@ -2776,7 +3111,7 @@ struct LambdaProtonBalanceFunction { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_Before_qinvCut"), qinvALp); } // QA3/SplitTrackQA: q_inv Before and After cut - if (qinvALp > kQinvCutLP) { + if (!failsQinvCut(qinvALp)) { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_After_qinvCut"), qinvALp); } // QA3/RawPairDensity: AntiLambda-proton → same LP histogram @@ -2793,16 +3128,28 @@ struct LambdaProtonBalanceFunction { const float yP2 = protonRapidity(primProton); const int idxYAL = unrolledIndexY(yAL, v0.phi()); const int idxYP2 = unrolledIndexY(yP2, primProton.phi()); - // Physics pair correlations (rho2 / pT / pair-count): q_inv cut not applied to rho2 + // Physics pair correlations (rho2 / pT / pair-count): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (failsQinvCut(qinvALp)) { + continue; + } + registryCorrelationQA.fill(HIST("QA3/Kstar/h1f_kstar_ALp"), + computeKstar(v0.px(), v0.py(), v0.pz(), kMassLambda, + primProton.px(), primProton.py(), primProton.pz(), kMassProton)); if (idxAL >= 0 && idxPrimP >= 0) { if (bin >= 0) { hPtPrimProton_AntiLambda[bin]->Fill(primProton.pt()); } - hRho2_ALp_pT015toMaxDefined->Fill(idxAL, idxPrimP); + if (cFillEtaSpace.value) { + hRho2_ALp_pT015toMaxDefined->Fill(idxAL, idxPrimP); + } } if (idxYAL >= 0 && idxYP2 >= 0) { hRho2_ALp_y_pT015toMaxDefined->Fill(idxYAL, idxYP2); } + if (cs) { + fillIdx(cs->ALp, idxAL, idxPrimP); + fillIdx(cs->ALp_y, idxYAL, idxYP2); + } ++nPairs_AntiLambda_PrimProton; } for (auto const& primAntiProton : selectedPrimAntiProtons) { @@ -2820,7 +3167,7 @@ struct LambdaProtonBalanceFunction { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_Before_qinvCut"), qinvALAp); } // QA3/SplitTrackQA: q_inv Before and After cut - if (qinvALAp > kQinvCutLP) { + if (!failsQinvCut(qinvALAp)) { registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LP_After_qinvCut"), qinvALAp); } // QA3/SplitTrackQA: close-pair block for daughter-overlap diagnosed split tracks @@ -2844,16 +3191,28 @@ struct LambdaProtonBalanceFunction { const float yAp2 = protonRapidity(primAntiProton); const int idxYAL2 = unrolledIndexY(yAL2, v0.phi()); const int idxYAp2 = unrolledIndexY(yAp2, primAntiProton.phi()); - // Physics pair correlations (rho2 / pT / pair-count): q_inv cut not applied to rho2 + // Physics pair correlations (rho2 / pT / pair-count): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (failsQinvCut(qinvALAp)) { + continue; + } + registryCorrelationQA.fill(HIST("QA3/Kstar/h1f_kstar_ALAp"), + computeKstar(v0.px(), v0.py(), v0.pz(), kMassLambda, + primAntiProton.px(), primAntiProton.py(), primAntiProton.pz(), kMassProton)); if (idxAL2 >= 0 && idxPrimPb >= 0) { if (bin >= 0) { hPtPrimAntiProton_AntiLambda[bin]->Fill(primAntiProton.pt()); } - hRho2_ALAp_pT015toMaxDefined->Fill(idxAL2, idxPrimPb); + if (cFillEtaSpace.value) { + hRho2_ALAp_pT015toMaxDefined->Fill(idxAL2, idxPrimPb); + } } if (idxYAL2 >= 0 && idxYAp2 >= 0) { hRho2_ALAp_y_pT015toMaxDefined->Fill(idxYAL2, idxYAp2); } + if (cs) { + fillIdx(cs->ALAp, idxAL2, idxPrimPb); + fillIdx(cs->ALAp_y, idxYAL2, idxYAp2); + } ++nPairs_AntiLambda_PrimAntiProton; } @@ -2881,9 +3240,10 @@ struct LambdaProtonBalanceFunction { // ── Combo 4: AntiLambda daughter antiproton ↔ primary antiproton ─ // AntiLambda neg-daughter = v0NegDau (charge −1, identified as // antiproton). Primary antiproton = selectedPrimAntiProtons (charge −1). - // Fills inclusive h2f_dEta_dPhi for all pairs and - // h2f_dEta_dPhi_nonSameTrack for pairs where the primary antiproton is - // not the AntiLambda negative daughter. + // Fills inclusive h2f_dEta_dPhi for all pairs and h2f_dEta_dPhi_nonSameTrack + // for every pair in this cleaned sample (selectedPrimAntiProtons is already + // veto-cleaned, so the primary antiproton can never be the AntiLambda + // negative daughter; the nonSameTrack histogram will equal the inclusive one). { const float etaDauAL4 = v0NegDau.eta(); const float phiDauAL4 = v0NegDau.phi(); @@ -2951,21 +3311,26 @@ struct LambdaProtonBalanceFunction { const float Ev2 = std::sqrt(v2pmag * v2pmag + kMassLambda * kMassLambda); const float qinvLL = computeQinv(v1.px(), v1.py(), v1.pz(), Ev1, v2.px(), v2.py(), v2.pz(), Ev2); registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_Before_qinvCut"), qinvLL); - if (qinvLL > kQinvCutLP) { - registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvLL); + if (failsQinvCut(qinvLL)) { + continue; } + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvLL); } const int idx1 = unrolledIndex(v1.eta(), v1.phi()); const int idx2 = unrolledIndex(v2.eta(), v2.phi()); const int idxY1 = unrolledIndexY(yv1L, v1.phi()); const int idxY2 = unrolledIndexY(v2.rapidity(1), v2.phi()); - // Physics pair correlations (rho2): q_inv cut not applied to rho2 - if (idx1 >= 0 && idx2 >= 0) { + // Physics pair correlations (rho2): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (cFillEtaSpace.value && idx1 >= 0 && idx2 >= 0) { hRho2_LL_pT015toMaxDefined->Fill(idx1, idx2); } if (idxY1 >= 0 && idxY2 >= 0) { hRho2_LL_y_pT015toMaxDefined->Fill(idxY1, idxY2); } + if (cs) { + fillIdx(cs->LL, idx1, idx2); + fillIdx(cs->LL_y, idxY1, idxY2); + } } } // LAL @@ -3000,21 +3365,26 @@ struct LambdaProtonBalanceFunction { const float Ev2L = std::sqrt(v2pmagL * v2pmagL + kMassLambda * kMassLambda); const float qinvLAL = computeQinv(v1.px(), v1.py(), v1.pz(), Ev1L, v2.px(), v2.py(), v2.pz(), Ev2L); registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_Before_qinvCut"), qinvLAL); - if (qinvLAL > kQinvCutLP) { - registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvLAL); + if (failsQinvCut(qinvLAL)) { + continue; } + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvLAL); } const int idx1 = unrolledIndex(v1.eta(), v1.phi()); const int idx2 = unrolledIndex(v2.eta(), v2.phi()); const int idxY1 = unrolledIndexY(yv1LAL, v1.phi()); const int idxY2 = unrolledIndexY(v2.rapidity(2), v2.phi()); - // Physics pair correlations (rho2): q_inv cut not applied to rho2 - if (idx1 >= 0 && idx2 >= 0) { + // Physics pair correlations (rho2): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (cFillEtaSpace.value && idx1 >= 0 && idx2 >= 0) { hRho2_LAL_pT015toMaxDefined->Fill(idx1, idx2); } if (idxY1 >= 0 && idxY2 >= 0) { hRho2_LAL_y_pT015toMaxDefined->Fill(idxY1, idxY2); } + if (cs) { + fillIdx(cs->LAL, idx1, idx2); + fillIdx(cs->LAL_y, idxY1, idxY2); + } } } // ALL @@ -3049,21 +3419,26 @@ struct LambdaProtonBalanceFunction { const float Ev2AL = std::sqrt(v2pmagAL * v2pmagAL + kMassLambda * kMassLambda); const float qinvALL = computeQinv(v1.px(), v1.py(), v1.pz(), Ev1AL, v2.px(), v2.py(), v2.pz(), Ev2AL); registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_Before_qinvCut"), qinvALL); - if (qinvALL > kQinvCutLP) { - registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvALL); + if (failsQinvCut(qinvALL)) { + continue; } + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvALL); } const int idx1 = unrolledIndex(v1.eta(), v1.phi()); const int idx2 = unrolledIndex(v2.eta(), v2.phi()); const int idxY1 = unrolledIndexY(yv1ALL, v1.phi()); const int idxY2 = unrolledIndexY(v2.rapidity(1), v2.phi()); - // Physics pair correlations (rho2): q_inv cut not applied to rho2 - if (idx1 >= 0 && idx2 >= 0) { + // Physics pair correlations (rho2): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (cFillEtaSpace.value && idx1 >= 0 && idx2 >= 0) { hRho2_ALL_pT015toMaxDefined->Fill(idx1, idx2); } if (idxY1 >= 0 && idxY2 >= 0) { hRho2_ALL_y_pT015toMaxDefined->Fill(idxY1, idxY2); } + if (cs) { + fillIdx(cs->ALL, idx1, idx2); + fillIdx(cs->ALL_y, idxY1, idxY2); + } } } // ALAL @@ -3101,21 +3476,26 @@ struct LambdaProtonBalanceFunction { const float Ev2AL2 = std::sqrt(v2pmagAL2 * v2pmagAL2 + kMassLambda * kMassLambda); const float qinvALAL = computeQinv(v1.px(), v1.py(), v1.pz(), Ev1AL2, v2.px(), v2.py(), v2.pz(), Ev2AL2); registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_Before_qinvCut"), qinvALAL); - if (qinvALAL > kQinvCutLP) { - registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvALAL); + if (failsQinvCut(qinvALAL)) { + continue; } + registryCorrelationQA.fill(HIST("QA3/SplitTrackQA/h1f_qinv_LL_After_qinvCut"), qinvALAL); } const int idx1 = unrolledIndex(v1.eta(), v1.phi()); const int idx2 = unrolledIndex(v2.eta(), v2.phi()); const int idxY1 = unrolledIndexY(yv1ALAL, v1.phi()); const int idxY2 = unrolledIndexY(v2.rapidity(2), v2.phi()); - // Physics pair correlations (rho2): q_inv cut not applied to rho2 - if (idx1 >= 0 && idx2 >= 0) { + // Physics pair correlations (rho2): q_inv cut applied (pairs with q_inv <= kQinvCutLP are rejected above) + if (cFillEtaSpace.value && idx1 >= 0 && idx2 >= 0) { hRho2_ALAL_pT015toMaxDefined->Fill(idx1, idx2); } if (idxY1 >= 0 && idxY2 >= 0) { hRho2_ALAL_y_pT015toMaxDefined->Fill(idxY1, idxY2); } + if (cs) { + fillIdx(cs->ALAL, idx1, idx2); + fillIdx(cs->ALAL_y, idxY1, idxY2); + } } } // ───────────────────────────────────────────────────────────────────── @@ -3145,6 +3525,12 @@ struct LambdaProtonBalanceFunction { LOG(info) << "Total proton candidates after veto : " << totalAfter; LOG(info) << "Total removed by veto : " << totalRemoved; LOG(info) << Form("Fraction removed : %.6f", fracRemoved); + const double fracRemovedAp = (runTotalAntiPBeforeVeto > 0) + ? static_cast(runTotalAntiPRemovedVeto) / static_cast(runTotalAntiPBeforeVeto) + : 0.0; + LOG(info) << "Total antiproton candidates before veto: " << runTotalAntiPBeforeVeto; + LOG(info) << "Total antiproton removed by veto : " << runTotalAntiPRemovedVeto; + LOG(info) << Form("Antiproton fraction removed : %.6f", fracRemovedAp); LOG(info) << "==============================================="; LOG(info) << ""; } @@ -3155,6 +3541,3 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } - -// What i did here is to change the eta acceptance from 0.8 to 1.0 for now for QA purposes, but later for final analysis we will change it back to 0.8. So please ignore the changes related to maxEta and qaEtaAxis for now. I have kept the maxEta as 1.0f so that it can be used for track acceptance in the code, but we will change it to 0.8f later for final analysis. The same goes for qaEtaAxis, I have set it to -1.0f to 1.0f for now, but we will change it to -0.8f to 0.8f later for final analysis. -// Also we previously gave 0.8 rapidity cut for lambda and anti-lambda, but now we have changed it to 1.0 for now for QA purposes, but later for final analysis we will change it back to 0.8. So please ignore the changes related to rapidity cuts for now.