From eec1c66231f08b58cfd27e6e8b37406d34d1e964 Mon Sep 17 00:00:00 2001 From: Prottay Das Date: Thu, 2 Jul 2026 19:33:34 +0200 Subject: [PATCH 1/2] updated table producer with PID bit masks --- PWGLF/TableProducer/Resonances/phiflow.cxx | 262 +++++++++++++++++---- 1 file changed, 222 insertions(+), 40 deletions(-) diff --git a/PWGLF/TableProducer/Resonances/phiflow.cxx b/PWGLF/TableProducer/Resonances/phiflow.cxx index 84708fde922..a7b52f5359e 100644 --- a/PWGLF/TableProducer/Resonances/phiflow.cxx +++ b/PWGLF/TableProducer/Resonances/phiflow.cxx @@ -95,16 +95,12 @@ struct phiflow { Configurable usePID{"usePID", true, "Flag for using PID selection for kaon meson track"}; Configurable nsigmaCutTPCKaMeson{"nsigmaCutTPCKaMeson", 3.0, "Maximum nsigma cut TPC for kaon meson track"}; Configurable nsigmaCutTOFKaMeson{"nsigmaCutTOFKaMeson", 3.0, "Maximum nsigma cut TOF for kaon meson track"}; - Configurable cutTOFBetaKaMeson{"cutTOFBetaKaMeson", 1.0, "Maximum beta cut for kaon meson track"}; + Configurable cutTOFBetaKaMeson{"cutTOFBetaKaMeson", 0.5f, "Maximum beta cut for kaon meson track"}; + Configurable pSwitchPID{"pSwitchPID", 0.5f, "pT switch for pT-dependent kaon PID"}; + Configurable pSwitchAsymPID{"pSwitchAsymPID", 0.7f, "Momentum switch for asymmetric kaon PID"}; + Configurable applyTOFAsymPID{"applyTOFAsymPID", true, "Apply TOF requirement in PID7"}; } grpKaon; - enum KaonPidBits : uint8_t { - kPID1 = 1u << 0, // selectionPID - kPID2 = 1u << 1, // selectionPID2 - kPID3 = 1u << 2, // selectionPID3 - kPID4 = 1u << 3 // selectionPID4 - }; - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; RCTFlagsChecker rctChecker; void init(o2::framework::InitContext&) @@ -129,46 +125,75 @@ struct phiflow { candidate.pt() >= grpKaon.cutPTKaMeson; } + enum KaonPidBits : uint8_t { + kPID1 = 1u << 0, // TOF-availability-dependent rectangular PID + kPID2 = 1u << 1, // TOF-availability-dependent circular PID + kPID3 = 1u << 2, // pT-dependent circular PID + kPID4 = 1u << 3, // pT-dependent rectangular PID, phi-v2-like + kPID5 = 1u << 4, // TOF-only PID + kPID6 = 1u << 5, // Momentum-dependent asymmetric TOF PID + kPID7 = 1u << 6 // Optional-TOF asymmetric PID + }; + template bool selectionPID(const T& candidate) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < grpKaon.nsigmaCutTPCKaMeson) { - return true; + const float nTPC = candidate.tpcNSigmaKa(); + + // No TOF hit: TPC-only PID at all pT. + if (!candidate.hasTOF()) { + return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; } - if (candidate.hasTOF() && candidate.beta() > grpKaon.cutTOFBetaKaMeson && std::abs(candidate.tpcNSigmaKa()) < grpKaon.nsigmaCutTPCKaMeson && std::abs(candidate.tofNSigmaKa()) < grpKaon.nsigmaCutTOFKaMeson) { - return true; + + // TOF hit: require beta, TPC PID, and TOF PID. + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; } - return false; + + return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson && + std::abs(candidate.tofNSigmaKa()) < grpKaon.nsigmaCutTOFKaMeson; } template bool selectionPID2(const T& candidate) { - if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < grpKaon.nsigmaCutTPCKaMeson) { - return true; + const float nTPC = candidate.tpcNSigmaKa(); + + // No TOF hit: TPC-only PID at all pT. + if (!candidate.hasTOF()) { + return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; } - if (candidate.hasTOF() && candidate.beta() > grpKaon.cutTOFBetaKaMeson && std::sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpKaon.nsigmaCutTOFKaMeson) { - return true; + + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; } - return false; + + const float nTOF = candidate.tofNSigmaKa(); + const float nCombined = std::sqrt(nTPC * nTPC + nTOF * nTOF); + + return nCombined < grpKaon.nsigmaCutTOFKaMeson; } template bool selectionPID3(const T& candidate) { - constexpr float pSwitch = 0.5f; - const float pt = candidate.pt(); const float nTPC = candidate.tpcNSigmaKa(); - if (pt < pSwitch && !candidate.hasTOF()) { + // Low pT: TPC-only. TOF is ignored even if present. + if (pt < grpKaon.pSwitchPID) { return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; } + // High pT: TOF is mandatory. if (!candidate.hasTOF()) { return false; } + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; + } + const float nTOF = candidate.tofNSigmaKa(); const float nCombined = std::sqrt(nTPC * nTPC + nTOF * nTOF); @@ -178,19 +203,23 @@ struct phiflow { template bool selectionPID4(const T& candidate) { - constexpr float pSwitch = 0.5f; - const float pt = candidate.pt(); const float nTPC = candidate.tpcNSigmaKa(); - if (pt < pSwitch) { + // Low pT: TPC-only. TOF is ignored even if present. + if (pt < grpKaon.pSwitchPID) { return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; } + // High pT: TOF is mandatory. if (!candidate.hasTOF()) { return false; } + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; + } + const float nTOF = candidate.tofNSigmaKa(); return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson && @@ -198,23 +227,167 @@ struct phiflow { } template - uint8_t kaonPidMask(const T& trk) + bool selectionPID5(const T& candidate) { - uint8_t m = 0; + // This matches the TOF-only selection from the other task. + if (!candidate.hasTOF()) { + return false; + } - if (selectionPID(trk)) { - m |= kPID1; + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; } - if (selectionPID2(trk)) { - m |= kPID2; + + return std::abs(candidate.tofNSigmaKa()) < + grpKaon.nsigmaCutTOFKaMeson; + } + + template + bool selectionPID6(const T& candidate) + { + const float p = candidate.p(); + const float nTPC = candidate.tpcNSigmaKa(); + + // This follows selectionPIDpTdependent2 from the other task. + // Note: it uses total momentum p, not transverse momentum pT. + if (p < grpKaon.pSwitchAsymPID) { + return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; + } + + if (!candidate.hasTOF()) { + return false; } - if (selectionPID3(trk)) { - m |= kPID3; + + if (std::abs(nTPC) >= grpKaon.nsigmaCutTPCKaMeson) { + return false; } - if (selectionPID4(trk)) { - m |= kPID4; + + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; + } + + const float nTOF = candidate.tofNSigmaKa(); + + if (p < 1.6f) { + return nTOF > -5.0f && nTOF < 10.0f; + } + + if (p < 2.0f) { + return nTOF > -3.0f && nTOF < 10.0f; + } + + if (p < 2.5f) { + return nTOF > -3.0f && nTOF < 6.0f; + } + + if (p < 4.0f) { + return nTOF > -2.5f && nTOF < 4.0f; + } + + if (p < 5.0f) { + return nTOF > -4.0f && nTOF < 3.0f; + } + + if (p < 6.0f) { + return nTOF > -4.0f && nTOF < 2.5f; } - return m; + + return nTOF > -3.0f && nTOF < 3.0f; + } + + template + bool selectionPID7(const T& candidate) + { + const float p = candidate.p(); + const float nTPC = candidate.tpcNSigmaKa(); + + // This follows selectionPID22 from the other task. + // If TOF is disabled, use only the TPC kaon selection. + if (!grpKaon.applyTOFAsymPID) { + return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; + } + + // No TOF hit: allow TPC-only PID at all momenta. + if (!candidate.hasTOF()) { + return std::abs(nTPC) < grpKaon.nsigmaCutTPCKaMeson; + } + + // For tracks with TOF, asymmetric TOF selection starts above p = 0.5. + if (p <= 0.5f) { + return false; + } + + if (std::abs(nTPC) >= grpKaon.nsigmaCutTPCKaMeson) { + return false; + } + + if (candidate.beta() <= grpKaon.cutTOFBetaKaMeson) { + return false; + } + + const float nTOF = candidate.tofNSigmaKa(); + + if (p < 1.6f) { + return nTOF > -5.0f && nTOF < 10.0f; + } + + if (p < 2.0f) { + return nTOF > -3.0f && nTOF < 10.0f; + } + + if (p < 2.5f) { + return nTOF > -3.0f && nTOF < 6.0f; + } + + if (p < 4.0f) { + return nTOF > -2.5f && nTOF < 4.0f; + } + + if (p < 5.0f) { + return nTOF > -4.0f && nTOF < 3.0f; + } + + if (p < 6.0f) { + return nTOF > -4.0f && nTOF < 2.5f; + } + + return nTOF > -3.0f && nTOF < 3.0f; + } + + template + uint8_t kaonPidMask(const T& track) + { + uint8_t mask = 0; + + if (selectionPID(track)) { + mask |= kPID1; + } + + if (selectionPID2(track)) { + mask |= kPID2; + } + + if (selectionPID3(track)) { + mask |= kPID3; + } + + if (selectionPID4(track)) { + mask |= kPID4; + } + + if (selectionPID5(track)) { + mask |= kPID5; + } + + if (selectionPID6(track)) { + mask |= kPID6; + } + + if (selectionPID7(track)) { + mask |= kPID7; + } + + return mask; } struct StoredKaon { @@ -249,6 +422,12 @@ struct phiflow { histos.fill(HIST("hEvtSelInfo"), 0.5); + if (!collision.triggereventsp()) { + return; + } + + histos.fill(HIST("hEvtSelInfo"), 1.5); + if (!((!rctCut.requireRCTFlagChecker || rctChecker(collision)) && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && @@ -261,7 +440,8 @@ struct phiflow { return; } - histos.fill(HIST("hEvtSelInfo"), 1.5); + histos.fill(HIST("hEvtSelInfo"), 2.5); + histos.fill(HIST("hCent"), centrality); std::vector selectedKaons; @@ -290,7 +470,7 @@ struct phiflow { const float nSigmaITS1 = itsResponse.nSigmaITS(track1); - if (grpKaon.itsPIDSelection && + if (grpKaon.itsPIDSelection && track1.p() < 1.0 && (nSigmaITS1 <= grpKaon.lowITSPIDNsigma || nSigmaITS1 >= grpKaon.highITSPIDNsigma)) { continue; @@ -327,7 +507,7 @@ struct phiflow { const float nSigmaITS2 = itsResponse.nSigmaITS(track2); - if (grpKaon.itsPIDSelection && + if (grpKaon.itsPIDSelection && track2.p() < 1.0 && (nSigmaITS2 <= grpKaon.lowITSPIDNsigma || nSigmaITS2 >= grpKaon.highITSPIDNsigma)) { continue; @@ -353,11 +533,13 @@ struct phiflow { // No selected K+ or K- in this collision: // not writing a reduced event row. + histos.fill(HIST("hEvtSelInfo"), 3.5); + /* if (selectedKaons.empty()) { return; } - - histos.fill(HIST("hEvtSelInfo"), 2.5); + */ + histos.fill(HIST("hEvtSelInfo"), 4.5); kaonEvent(centrality, vz, From 5a56a4ad2a8a4b62a52a8d619275a5ff6e137440 Mon Sep 17 00:00:00 2001 From: Prottay Das Date: Thu, 2 Jul 2026 19:56:07 +0200 Subject: [PATCH 2/2] corrected the include headers --- PWGLF/TableProducer/Resonances/phiflow.cxx | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/PWGLF/TableProducer/Resonances/phiflow.cxx b/PWGLF/TableProducer/Resonances/phiflow.cxx index a7b52f5359e..0fba563e264 100644 --- a/PWGLF/TableProducer/Resonances/phiflow.cxx +++ b/PWGLF/TableProducer/Resonances/phiflow.cxx @@ -27,7 +27,6 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" -#include #include #include #include @@ -41,7 +40,6 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) -#include #include #include #include @@ -428,15 +426,15 @@ struct phiflow { histos.fill(HIST("hEvtSelInfo"), 1.5); - if (!((!rctCut.requireRCTFlagChecker || rctChecker(collision)) && - collision.selection_bit(aod::evsel::kNoSameBunchPileup) && - collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && - (!useNoCollInTimeRangeStandard || - collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) && - collision.sel8() && - (!useGoodITSLayersAll || - collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) && - occupancy < cfgCutOccupancy)) { + if ((rctCut.requireRCTFlagChecker && !rctChecker(collision)) || + !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || + !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || + (useNoCollInTimeRangeStandard && + !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) || + !collision.sel8() || + (useGoodITSLayersAll && + !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) || + occupancy >= cfgCutOccupancy) { return; } @@ -490,7 +488,7 @@ struct phiflow { track1.py(), track1.pz(), +1, - static_cast(track1.globalIndex()), + track1.globalIndex(), mask1}); } @@ -527,7 +525,7 @@ struct phiflow { track2.py(), track2.pz(), -1, - static_cast(track2.globalIndex()), + track2.globalIndex(), mask2}); }