From 00bcf187b7bca1864e592193a2b50c2057ab5b87 Mon Sep 17 00:00:00 2001 From: spolitan Date: Thu, 19 Jun 2025 17:38:35 +0200 Subject: [PATCH 01/13] [PWGCF] Adding V0s and Phi cases in filter2Prong processing --- PWGCF/DataModel/CorrelationsDerived.h | 5 +- PWGCF/TableProducer/filter2Prong.cxx | 293 ++++++++++++++++++++++++-- 2 files changed, 275 insertions(+), 23 deletions(-) diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index c6b96b77466..efc0ccc7a41 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -123,7 +123,10 @@ enum ParticleDecay { D0barToKPi, JPsiToEE, JPsiToMuMu, - Generic2Prong, + PhiToKK, + K0stoPiPi, + LambdatoPPi, + AntiLambdatoPiP }; } // namespace cf2prongtrack DECLARE_SOA_TABLE(CF2ProngTracks, "AOD", "CF2PRONGTRACK", //! Reduced track table diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 2ee72e9b923..f632908287e 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -16,6 +16,8 @@ #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "Common/DataModel/PIDResponseITS.h" + #include "Framework/ASoAHelpers.h" #include "Framework/AnalysisDataModel.h" #include "Framework/AnalysisTask.h" @@ -49,6 +51,41 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass (GeV)") O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") + O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") + O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") + O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") + O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") + O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") + O2_DEFINE_CONFIGURABLE(cMinV0DCAPr, float, 0.1, "Min V0 proton DCA") + O2_DEFINE_CONFIGURABLE(cMinV0DCAPi, float, 0.1, "Min V0 pion DCA") + O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") + O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") + O2_DEFINE_CONFIGURABLE(ITSPIDNsigma, float, 3.0, "PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") + O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") + O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") + O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") + O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") + O2_DEFINE_CONFIGURABLE(massOmegaMin, float, 1.5, "Minimum mass for omega") + O2_DEFINE_CONFIGURABLE(massOmegaMax, float, 1.8, "Maximum mass for omega") + O2_DEFINE_CONFIGURABLE(interactionRateMin, float, -1, "Minimum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(interactionRateMax, float, 1.e20, "Maximum interaction rate (kHz)") + O2_DEFINE_CONFIGURABLE(radiusMax, float, 2.3, "Maximum decay radius (cm)") + O2_DEFINE_CONFIGURABLE(radiusMin, float, 0.0, "Minimum decay radius (cm)") + O2_DEFINE_CONFIGURABLE(cosPaMin, float, 0.98, "Minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMax, float, 0.2, "Maximum DCA among the V0 daughters (cm)") + O2_DEFINE_CONFIGURABLE(dcaV0ToPvMax, float, 0.2, "Maximum DCA of the V0 from the primary vertex (cm)") + O2_DEFINE_CONFIGURABLE(cosPaV0Min, float, 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays") + O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0, float, 0.12, "Minimum Armenteros' qt for K0") + O2_DEFINE_CONFIGURABLE(qtArmenterosMaxForLambda, float, 0.12, "Minimum Armenteros' qt for (anti)Lambda") + O2_DEFINE_CONFIGURABLE(ConfV0Rap, float, 0.5, "Store rapidity of v0") + O2_DEFINE_CONFIGURABLE(cMaxLambdaLifeTime, float, 30, "Store Lambda lifetime") + O2_DEFINE_CONFIGURABLE(cMaxK0sLifeTime, float, 30, "Store K0s lifetime") + O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "flag for applying deep angle") + O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") + O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") + O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.1, "Cut based on track from momentum difference") + HfHelper hfHelper; Produces output2ProngTracks; Produces output2ProngTrackmls; @@ -166,37 +203,249 @@ struct Filter2Prong { } PROCESS_SWITCH(Filter2Prong, processMC, "Process MC 2-prong daughters", false); - // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + template + bool selectionPair(const T1& candidate1, const T2& candidate2) + { + double pt1, pt2, pz1, pz2, p1, p2, angle; + pt1 = candidate1.pt(); + pt2 = candidate2.pt(); + pz1 = candidate1.pz(); + pz2 = candidate2.pz(); + p1 = candidate1.p(); + p2 = candidate2.p(); + angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + if (isDeepAngle && angle < cfgDeepAngle) { + return false; + } + return true; + } + + template + bool isFakeKaon(T const& track) + { + const auto pglobal = track.p(); + const auto ptpc = track.tpcInnerParam(); + if (TMath::Abs(pglobal - ptpc) > ConfFakeKaonCut) { + return true; + } + return false; + } + + template + bool isSelectedV0AsK0s(Collision const& collision, const V0Cand& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + float CtauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0; + + if (v0.mK0Short() < massK0Min || v0.mK0Short() > massK0Max) { + return false; + } + if (v0.qtarm() < qtArmenterosMinForK0) { + return false; + } + if (v0.v0radius() > radiusMax) { + return false; + } + if (v0.v0radius() < radiusMin) { + return false; + } + if (v0.v0cosPA() < cosPaMin) { + return false; + } + if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + return false; + } + if (v0.dcav0topv() > dcaV0ToPvMax) { + return false; + } + if (std::abs(CtauK0s) > cMaxK0sLifeTime) { + return false; + } + if (std::abs(v0.yK0Short()) > ConfV0Rap) { + return false; + } + if (((std::abs(posTrack.tpcNSigmaPi()) > ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > ConfDaughPIDCuts))) { + return false; + } + if ((TMath::Abs(v0.dcapostopv()) < cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + return true; + } + + template + bool isSelectedV0AsLambda(Collision const& collision, const V0Cand& v0, int pid /*0: lambda, 1: antilambda*/) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + float CtauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda; + + if ((v0.mLambda() < massLambdaMin || v0.mLambda() > massLambdaMax) && + (v0.mAntiLambda() < massLambdaMin || v0.mAntiLambda() > massLambdaMax)) { + return false; + } + if (v0.qtarm() > qtArmenterosMaxForLambda) { + return false; + } + if (v0.v0radius() > radiusMax) { + return false; + } + if (v0.v0radius() < radiusMin) { + return false; + } + if (v0.v0cosPA() < cosPaMin) { + return false; + } + if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + return false; + } + if (v0.dcav0topv() > dcaV0ToPvMax) { + return false; + } + if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < cMinV0DCAPr || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPi)) { + return false; + } + if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPr)) { + return false; + } + if (pid == 0 && ((std::abs(posTrack.tpcNSigmaPr()) > ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > ConfDaughPIDCuts))) { + return false; + } + if (pid == 1 && ((std::abs(posTrack.tpcNSigmaPi()) > ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > ConfDaughPIDCuts))) { + return false; + } + if (std::abs(CtauLambda) > cMaxLambdaLifeTime) { + return false; + } + if (std::abs(v0.yLambda()) > ConfV0Rap) { + return false; + } + return true; + } + + template + bool isV0TrackSelected(const T1& v0) + { + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + if (!posTrack.hasTPC() || !negTrack.hasTPC()) { + return false; + } + if (posTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin) { + return false; + } + if (posTrack.tpcCrossedRowsOverFindableCls() < 0.8 || negTrack.tpcCrossedRowsOverFindableCls() < 0.8) { + return false; + } + if (std::abs(v0.positiveeta()) > etaTrackMax || std::abs(v0.negativeeta()) > etaTrackMax) { + return false; + } + if (v0.positivept() < ptTrackMin || v0.negativept() < ptTrackMin) { + return false; + } + return true; + } + + // Processing data for invariant mass analysis for 2-prong tracks, including V0s (K0s, Lambdas, Anti-Lambdas) and Phi mesons using PIDTrack = soa::Join; - void processDataInvMass(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, PIDTrack const& tracks) + void processDataInvMass(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, PIDTrack const& tracks, aod::V0Datas const& V0s) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) return; // rejected collision - for (const auto& cftrack1 : cftracks) { - const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); - if (p1.sign() != 1) - continue; - if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) - continue; - for (const auto& cftrack2 : cftracks) { - if (cftrack2.globalIndex() == cftrack1.globalIndex()) + + o2::aod::ITSResponse itsResponse; + + if (cfgDoPhi) { // Process Phi mesons + for (const auto& cftrack1 : cftracks) { // Loop over first track + const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); + + if (p1.sign() != 1) // Only consider positive tracks continue; - const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); - if (p2.sign() != -1) + if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) // Check if the track passes PID condition continue; - if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) + if (ITSPIDSelection && p1.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < ITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + if (removefaketrack && isFakeKaon(p1)) { // Check if the track is a fake kaon continue; - ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); - ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); - ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; - if (s.pt() < cfgImCutPt || s.M() < cfgImMinInvMass || s.M() > cfgImMaxInvMass) + } + + for (const auto& cftrack2 : cftracks) { // Loop over second track + if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one + continue; + + const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); + if (p2.sign() != -1) // Only consider negative tracks + continue; + if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) // Check if the track passes PID condition + continue; + if (ITSPIDSelection && p2.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < ITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + if (!selectionPair(p1, p2)) { + continue; + } + if (removefaketrack && isFakeKaon(p2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); + ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); + ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; + if (s.pt() < cfgImCutPt || s.M() < cfgImMinInvMass || s.M() > cfgImMaxInvMass) + continue; + + float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKK); + } // end of loop over second track + } // end of loop over first track + } // end of processing Phi mesons + + if (cfgDoV0) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas) + for (const auto& v0 : V0s) { // Loop over V0 candidates + if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs continue; + } - float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); - output2ProngTracks(cfcollisions.begin().globalIndex(), - cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::Generic2Prong); - } - } + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + + auto v0Type = 0; + double massV0 = 0.0; + if (isSelectedV0AsK0s(collision, v0)) { // candidate is K0s + SETBIT(v0Type, aod::cf2prongtrack::K0stoPiPi); + + output2ProngTracks(cfcollisions.begin().globalIndex(), + posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), v0Type); + + continue; // candidate is K0s, skip to next V0 candidate + } + + bool LambdaTag = isSelectedV0AsLambda(collision, v0, 0); + bool aLambdaTag = isSelectedV0AsLambda(collision, v0, 1); + if (!LambdaTag && !aLambdaTag) { // neither Lambda nor Anti-Lambda + continue; + } + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) + if (LambdaTag) { // candidate is Lambda + SETBIT(v0Type, aod::cf2prongtrack::LambdatoPPi); + massV0 = v0.mLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, v0Type); + } else if (aLambdaTag) { // candidate is Anti-lambda + SETBIT(v0Type, aod::cf2prongtrack::AntiLambdatoPiP); + massV0 = v0.mAntiLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, v0Type); + } // end of Lambda and Anti-Lambda processing + } // end of loop over V0 candidates + } // end of processing V0 candidates } PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); }; // struct From c77d98b7230be7643be9c0b14efa530765199e38 Mon Sep 17 00:00:00 2001 From: spolitan Date: Fri, 20 Jun 2025 15:43:47 +0200 Subject: [PATCH 02/13] Adding possibility to store Pr PID in CFtracks --- PWGCF/DataModel/CorrelationsDerived.h | 5 +++- PWGCF/TableProducer/filterCorrelations.cxx | 35 ++++++++++++---------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index efc0ccc7a41..3b7535705e9 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -70,12 +70,15 @@ DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign (positive, negative) +DECLARE_SOA_COLUMN(TPCNsigmaPr, tpcNsigmaPr, float); //! TPC n-sigma for proton +DECLARE_SOA_COLUMN(TOFNsigmaPr, tofNsigmaPr, float); //! TOF n-sigma for proton } // namespace cftrack DECLARE_SOA_TABLE(CFTracks, "AOD", "CFTRACK", //! Reduced track table o2::soa::Index<>, cftrack::CFCollisionId, cftrack::Pt, cftrack::Eta, cftrack::Phi, - cftrack::Sign, track::TrackType); + cftrack::Sign, track::TrackType, + cftrack::TPCNsigmaPr, cftrack::TOFNsigmaPr); DECLARE_SOA_TABLE(CFTrackLabels, "AOD", "CFTRACKLABEL", //! Labels for reduced track table cftrack::CFMcParticleId); using CFTrack = CFTracks::iterator; diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 7d5e0b17c38..d27dfa0432a 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -8,23 +8,23 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include +#include "PWGCF/DataModel/CorrelationsDerived.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" #include "Framework/O2DatabasePDGPlugin.h" - +#include "Framework/runDataProcessing.h" #include "MathUtils/detail/TypeTruncation.h" -#include "PWGCF/DataModel/CorrelationsDerived.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/Centrality.h" - #include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -66,6 +66,7 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)") O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs to enable successive filtering tasks") O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics)") + O2_DEFINE_CONFIGURABLE(cfgStorePid, bool, false, "Store PID information for tracks (TPC and TOF n-sigma for protons)") O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)") O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, {}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only.") // needed for some neutral particles @@ -75,7 +76,7 @@ struct FilterCF { // TODO how to have this in the second task? For now they are copied Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt); - Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); + Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); Filter mcCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; @@ -155,7 +156,7 @@ struct FilterCF { return 0; } - void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) { if (cfgVerbosity > 0) { LOGF(info, "processData: Tracks for collision: %d | Vertex: %.1f (%d) | INT7: %d | Multiplicity: %.1f", tracks.size(), collision.posZ(), collision.flags(), collision.sel7(), collision.multiplicity()); @@ -172,7 +173,11 @@ struct FilterCF { outputCollRefs(collision.globalIndex()); for (auto& track : tracks) { - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); + if (cfgStorePid) { + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), track.tpcNsigmaPr(), track.tofNsigmaPr()); + } else { + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), -999.0f, -999.0f); + } if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -287,7 +292,7 @@ struct FilterCF { } } outputTracks(outputCollisions.lastIndex(), - truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track)); + truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track), -999.0f, -999.0f); outputTrackLabels(mcParticleId); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -326,7 +331,7 @@ struct MultiplicitySelector { O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt); - Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); + Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); void init(InitContext&) { From 8d9b971bd0363f746fb0344f0ebe8f20d021d1e1 Mon Sep 17 00:00:00 2001 From: spolitan Date: Mon, 23 Jun 2025 09:14:57 +0200 Subject: [PATCH 03/13] Update cf tables with pid information --- PWGCF/DataModel/CorrelationsDerived.h | 7 +-- PWGCF/TableProducer/filter2Prong.cxx | 73 +++++++++++++++------- PWGCF/TableProducer/filterCorrelations.cxx | 16 ++--- 3 files changed, 61 insertions(+), 35 deletions(-) diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index 3b7535705e9..032e4fa0a2d 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -70,15 +70,14 @@ DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign (positive, negative) -DECLARE_SOA_COLUMN(TPCNsigmaPr, tpcNsigmaPr, float); //! TPC n-sigma for proton -DECLARE_SOA_COLUMN(TOFNsigmaPr, tofNsigmaPr, float); //! TOF n-sigma for proton +DECLARE_SOA_COLUMN(NsigmaTPCPr, nsigmatpcpr, float); //! nsigma tpc proton +DECLARE_SOA_COLUMN(NsigmaTOFPr, nsigmatofpr, float); //! nsigma tpc proton } // namespace cftrack DECLARE_SOA_TABLE(CFTracks, "AOD", "CFTRACK", //! Reduced track table o2::soa::Index<>, cftrack::CFCollisionId, cftrack::Pt, cftrack::Eta, cftrack::Phi, - cftrack::Sign, track::TrackType, - cftrack::TPCNsigmaPr, cftrack::TOFNsigmaPr); + cftrack::Sign, track::TrackType, cftrack::NsigmaTPCPr, cftrack::NsigmaTOFPr); DECLARE_SOA_TABLE(CFTrackLabels, "AOD", "CFTRACKLABEL", //! Labels for reduced track table cftrack::CFMcParticleId); using CFTrack = CFTracks::iterator; diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index f632908287e..574c74268d3 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -44,13 +44,9 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgYMax, float, -1.0f, "Maximum candidate rapidity") O2_DEFINE_CONFIGURABLE(cfgImPart1Mass, float, o2::constants::physics::MassKPlus, "Daughter particle 1 mass in GeV") O2_DEFINE_CONFIGURABLE(cfgImPart2Mass, float, o2::constants::physics::MassKMinus, "Daughter particle 2 mass in GeV") - O2_DEFINE_CONFIGURABLE(cfgImPart1PID, int, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") - O2_DEFINE_CONFIGURABLE(cfgImPart2PID, int, o2::track::PID::Kaon, "PID of daughter particle 2 (O2 PID ID)") O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass (GeV)") O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass (GeV)") - O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") - O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") @@ -85,6 +81,10 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.1, "Cut based on track from momentum difference") + O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 3, "nsigma tpc") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 3, "nsigma tof") + O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.0, "TOF beta") + O2_DEFINE_CONFIGURABLE(isTOFOnly, bool, false, "flag to select kaon with only TOF condition") HfHelper hfHelper; Produces output2ProngTracks; @@ -101,12 +101,11 @@ struct Filter2Prong { template using HasMLProb = decltype(std::declval().mlProbD0()); - std::unique_ptr sigmaFormula; + using PIDTrack = soa::Join; + using ResoV0s = aod::V0Datas; void init(InitContext&) { - if (doprocessDataInvMass) - sigmaFormula = std::make_unique("sigmaFormula", cfgImSigmaFormula.value.c_str()); } template @@ -242,13 +241,10 @@ struct Filter2Prong { if (v0.mK0Short() < massK0Min || v0.mK0Short() > massK0Max) { return false; } - if (v0.qtarm() < qtArmenterosMinForK0) { - return false; - } - if (v0.v0radius() > radiusMax) { + if ((v0.qtarm() / std::abs(v0.alpha())) < qtArmenterosMinForK0) { return false; } - if (v0.v0radius() < radiusMin) { + if (v0.v0radius() > radiusMax || v0.v0radius() < radiusMin) { return false; } if (v0.v0cosPA() < cosPaMin) { @@ -287,13 +283,7 @@ struct Filter2Prong { (v0.mAntiLambda() < massLambdaMin || v0.mAntiLambda() > massLambdaMax)) { return false; } - if (v0.qtarm() > qtArmenterosMaxForLambda) { - return false; - } - if (v0.v0radius() > radiusMax) { - return false; - } - if (v0.v0radius() < radiusMin) { + if (v0.v0radius() > radiusMax || v0.v0radius() < radiusMin) { return false; } if (v0.v0cosPA() < cosPaMin) { @@ -350,8 +340,28 @@ struct Filter2Prong { return true; } - // Processing data for invariant mass analysis for 2-prong tracks, including V0s (K0s, Lambdas, Anti-Lambdas) and Phi mesons - using PIDTrack = soa::Join; + template + bool selectionPID(const T& candidate) + { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + return false; + } + + template + bool selectionPID2(const T& candidate) + { + if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { + return true; + } + return false; + } + + // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. void processDataInvMass(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, PIDTrack const& tracks, aod::V0Datas const& V0s) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) @@ -362,11 +372,18 @@ struct Filter2Prong { if (cfgDoPhi) { // Process Phi mesons for (const auto& cftrack1 : cftracks) { // Loop over first track const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); - if (p1.sign() != 1) // Only consider positive tracks continue; - if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) // Check if the track passes PID condition + /*if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) + { + continue; + }*/ + if (!isTOFOnly && !selectionPID(p1)) { + continue; + } + if (isTOFOnly && !selectionPID2(p1)) { continue; + } if (ITSPIDSelection && p1.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < ITSPIDNsigma.value)) { // Check ITS PID condition continue; } @@ -381,8 +398,16 @@ struct Filter2Prong { const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); if (p2.sign() != -1) // Only consider negative tracks continue; - if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) // Check if the track passes PID condition + /*if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) + { + continue; + }*/ + if (!isTOFOnly && !selectionPID(p2)) { continue; + } + if (isTOFOnly && !selectionPID2(p2)) { + continue; + } if (ITSPIDSelection && p2.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < ITSPIDNsigma.value)) { // Check ITS PID condition continue; } diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index d27dfa0432a..64cc6874461 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -9,6 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -66,9 +68,9 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)") O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs to enable successive filtering tasks") O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics)") - O2_DEFINE_CONFIGURABLE(cfgStorePid, bool, false, "Store PID information for tracks (TPC and TOF n-sigma for protons)") O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)") O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, {}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only.") // needed for some neutral particles + O2_DEFINE_CONFIGURABLE(fillproton, bool, true, "flag to fill proton nsigma") // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -156,6 +158,7 @@ struct FilterCF { return 0; } + // void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) { if (cfgVerbosity > 0) { @@ -173,11 +176,10 @@ struct FilterCF { outputCollRefs(collision.globalIndex()); for (auto& track : tracks) { - if (cfgStorePid) { - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), track.tpcNsigmaPr(), track.tofNsigmaPr()); - } else { - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), -999.0f, -999.0f); - } + if (fillproton) + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), track.tpcNSigmaPr(), track.tofNSigmaPr()); + else + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), -999.99, -999.99); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -292,7 +294,7 @@ struct FilterCF { } } outputTracks(outputCollisions.lastIndex(), - truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track), -999.0f, -999.0f); + truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track), -999.99, -999.99); outputTrackLabels(mcParticleId); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); From 06f8546a84219c0f8fa3bde948dc1664eae01eaa Mon Sep 17 00:00:00 2001 From: spolitan Date: Mon, 23 Jun 2025 09:44:24 +0200 Subject: [PATCH 04/13] Add momentum dependent pid sel in cf tracks --- PWGCF/TableProducer/filter2Prong.cxx | 66 +++++++++++++--------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 574c74268d3..ebe291b9738 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -44,9 +44,13 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgYMax, float, -1.0f, "Maximum candidate rapidity") O2_DEFINE_CONFIGURABLE(cfgImPart1Mass, float, o2::constants::physics::MassKPlus, "Daughter particle 1 mass in GeV") O2_DEFINE_CONFIGURABLE(cfgImPart2Mass, float, o2::constants::physics::MassKMinus, "Daughter particle 2 mass in GeV") + // O2_DEFINE_CONFIGURABLE(cfgImPart1PID, int, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") + // O2_DEFINE_CONFIGURABLE(cfgImPart2PID, int, o2::track::PID::Kaon, "PID of daughter particle 2 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, 1, "Use mommentum dependent PID for Phi meson") O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass (GeV)") O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass (GeV)") + // O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") @@ -104,8 +108,12 @@ struct Filter2Prong { using PIDTrack = soa::Join; using ResoV0s = aod::V0Datas; + // std::unique_ptr sigmaFormula; + void init(InitContext&) { + // if (doprocessDataInvMass) + // sigmaFormula = std::make_unique("sigmaFormula", cfgImSigmaFormula.value.c_str()); } template @@ -343,20 +351,22 @@ struct Filter2Prong { template bool selectionPID(const T& candidate) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { - return true; - } - if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { - return true; - } - return false; - } - - template - bool selectionPID2(const T& candidate) - { - if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && TMath::Abs(candidate.tofNSigmaKa()) < nsigmaCutTOF) { - return true; + if (cfgMomDepPID) { + if (candidate.p() < 0.5) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } + } else if (!cfgMomDepPID) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + return true; + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + return true; + } } return false; } @@ -372,52 +382,38 @@ struct Filter2Prong { if (cfgDoPhi) { // Process Phi mesons for (const auto& cftrack1 : cftracks) { // Loop over first track const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); - if (p1.sign() != 1) // Only consider positive tracks - continue; - /*if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) - { - continue; - }*/ - if (!isTOFOnly && !selectionPID(p1)) { + if (p1.sign() != 1) { continue; } - if (isTOFOnly && !selectionPID2(p1)) { + if (ITSPIDSelection && p1.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < ITSPIDNsigma.value)) { // Check ITS PID condition continue; } - if (ITSPIDSelection && p1.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < ITSPIDNsigma.value)) { // Check ITS PID condition + if (!selectionPID(p1)) { continue; } if (removefaketrack && isFakeKaon(p1)) { // Check if the track is a fake kaon continue; } - for (const auto& cftrack2 : cftracks) { // Loop over second track if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one continue; const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); - if (p2.sign() != -1) // Only consider negative tracks - continue; - /*if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) - { - continue; - }*/ - if (!isTOFOnly && !selectionPID(p2)) { + if (p2.sign() != -1) { continue; } - if (isTOFOnly && !selectionPID2(p2)) { + if (!selectionPID(p2)) { continue; } if (ITSPIDSelection && p2.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < ITSPIDNsigma.value)) { // Check ITS PID condition continue; } - if (!selectionPair(p1, p2)) { + if (removefaketrack && isFakeKaon(p2)) { // Check if the track is a fake kaon continue; } - if (removefaketrack && isFakeKaon(p2)) { + if (!selectionPair(p1, p2)) { continue; } - ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; From eeca237b281d82a732715089b4faeece0a6f03f8 Mon Sep 17 00:00:00 2001 From: spolitan Date: Mon, 23 Jun 2025 10:04:57 +0200 Subject: [PATCH 05/13] Minor fix --- PWGCF/TableProducer/filter2Prong.cxx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index ebe291b9738..551b6b9ba9c 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -44,13 +44,9 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgYMax, float, -1.0f, "Maximum candidate rapidity") O2_DEFINE_CONFIGURABLE(cfgImPart1Mass, float, o2::constants::physics::MassKPlus, "Daughter particle 1 mass in GeV") O2_DEFINE_CONFIGURABLE(cfgImPart2Mass, float, o2::constants::physics::MassKMinus, "Daughter particle 2 mass in GeV") - // O2_DEFINE_CONFIGURABLE(cfgImPart1PID, int, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") - // O2_DEFINE_CONFIGURABLE(cfgImPart2PID, int, o2::track::PID::Kaon, "PID of daughter particle 2 (O2 PID ID)") - O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, 1, "Use mommentum dependent PID for Phi meson") O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass (GeV)") O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass (GeV)") - // O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") @@ -62,6 +58,7 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") O2_DEFINE_CONFIGURABLE(ITSPIDNsigma, float, 3.0, "PID nsigma for ITS") O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") + O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, true, "Use momentum dependent PID cuts for V0s") O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") @@ -108,12 +105,8 @@ struct Filter2Prong { using PIDTrack = soa::Join; using ResoV0s = aod::V0Datas; - // std::unique_ptr sigmaFormula; - void init(InitContext&) { - // if (doprocessDataInvMass) - // sigmaFormula = std::make_unique("sigmaFormula", cfgImSigmaFormula.value.c_str()); } template @@ -394,6 +387,7 @@ struct Filter2Prong { if (removefaketrack && isFakeKaon(p1)) { // Check if the track is a fake kaon continue; } + for (const auto& cftrack2 : cftracks) { // Loop over second track if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one continue; @@ -414,6 +408,7 @@ struct Filter2Prong { if (!selectionPair(p1, p2)) { continue; } + ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; From ba947fd01553ac0a994ea049843da794b2be2073 Mon Sep 17 00:00:00 2001 From: spolitan Date: Wed, 25 Jun 2025 22:46:12 +0200 Subject: [PATCH 06/13] Adding pid info in cf tracktype and splitting V0s and Phi filter from general 2 prong --- PWGCF/DataModel/CorrelationsDerived.h | 5 +- PWGCF/TableProducer/filter2Prong.cxx | 266 +++++++++++++-------- PWGCF/TableProducer/filterCorrelations.cxx | 78 +++++- 3 files changed, 232 insertions(+), 117 deletions(-) diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index 032e4fa0a2d..5f79a78e974 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -70,14 +70,12 @@ DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle DECLARE_SOA_COLUMN(Sign, sign, int8_t); //! Sign (positive, negative) -DECLARE_SOA_COLUMN(NsigmaTPCPr, nsigmatpcpr, float); //! nsigma tpc proton -DECLARE_SOA_COLUMN(NsigmaTOFPr, nsigmatofpr, float); //! nsigma tpc proton } // namespace cftrack DECLARE_SOA_TABLE(CFTracks, "AOD", "CFTRACK", //! Reduced track table o2::soa::Index<>, cftrack::CFCollisionId, cftrack::Pt, cftrack::Eta, cftrack::Phi, - cftrack::Sign, track::TrackType, cftrack::NsigmaTPCPr, cftrack::NsigmaTOFPr); + cftrack::Sign, track::TrackType); DECLARE_SOA_TABLE(CFTrackLabels, "AOD", "CFTRACKLABEL", //! Labels for reduced track table cftrack::CFMcParticleId); using CFTrack = CFTracks::iterator; @@ -125,6 +123,7 @@ enum ParticleDecay { D0barToKPi, JPsiToEE, JPsiToMuMu, + Generic2Prong, PhiToKK, K0stoPiPi, LambdatoPPi, diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 551b6b9ba9c..5af560dc7a0 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -44,48 +44,56 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgYMax, float, -1.0f, "Maximum candidate rapidity") O2_DEFINE_CONFIGURABLE(cfgImPart1Mass, float, o2::constants::physics::MassKPlus, "Daughter particle 1 mass in GeV") O2_DEFINE_CONFIGURABLE(cfgImPart2Mass, float, o2::constants::physics::MassKMinus, "Daughter particle 2 mass in GeV") + O2_DEFINE_CONFIGURABLE(cfgImPart1PID, int, o2::track::PID::Kaon, "PID of daughter particle 1 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgImPart2PID, int, o2::track::PID::Kaon, "PID of daughter particle 2 (O2 PID ID)") + O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, 1, "Use mommentum dependent PID for Phi meson") O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") - O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass (GeV)") - O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass (GeV)") - O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") - O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") - O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") - O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") - O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") - O2_DEFINE_CONFIGURABLE(cMinV0DCAPr, float, 0.1, "Min V0 proton DCA") - O2_DEFINE_CONFIGURABLE(cMinV0DCAPi, float, 0.1, "Min V0 pion DCA") - O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") - O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") - O2_DEFINE_CONFIGURABLE(ITSPIDNsigma, float, 3.0, "PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") - O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, true, "Use momentum dependent PID cuts for V0s") - O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") - O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") - O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") - O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") - O2_DEFINE_CONFIGURABLE(massOmegaMin, float, 1.5, "Minimum mass for omega") - O2_DEFINE_CONFIGURABLE(massOmegaMax, float, 1.8, "Maximum mass for omega") - O2_DEFINE_CONFIGURABLE(interactionRateMin, float, -1, "Minimum interaction rate (kHz)") - O2_DEFINE_CONFIGURABLE(interactionRateMax, float, 1.e20, "Maximum interaction rate (kHz)") - O2_DEFINE_CONFIGURABLE(radiusMax, float, 2.3, "Maximum decay radius (cm)") - O2_DEFINE_CONFIGURABLE(radiusMin, float, 0.0, "Minimum decay radius (cm)") - O2_DEFINE_CONFIGURABLE(cosPaMin, float, 0.98, "Minimum cosine of pointing angle") - O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMax, float, 0.2, "Maximum DCA among the V0 daughters (cm)") - O2_DEFINE_CONFIGURABLE(dcaV0ToPvMax, float, 0.2, "Maximum DCA of the V0 from the primary vertex (cm)") - O2_DEFINE_CONFIGURABLE(cosPaV0Min, float, 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays") - O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0, float, 0.12, "Minimum Armenteros' qt for K0") - O2_DEFINE_CONFIGURABLE(qtArmenterosMaxForLambda, float, 0.12, "Minimum Armenteros' qt for (anti)Lambda") - O2_DEFINE_CONFIGURABLE(ConfV0Rap, float, 0.5, "Store rapidity of v0") - O2_DEFINE_CONFIGURABLE(cMaxLambdaLifeTime, float, 30, "Store Lambda lifetime") - O2_DEFINE_CONFIGURABLE(cMaxK0sLifeTime, float, 30, "Store K0s lifetime") - O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "flag for applying deep angle") - O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") - O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") - O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.1, "Cut based on track from momentum difference") - O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 3, "nsigma tpc") - O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 3, "nsigma tof") - O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.0, "TOF beta") - O2_DEFINE_CONFIGURABLE(isTOFOnly, bool, false, "flag to select kaon with only TOF condition") + O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.98f, "Minimum invariant mass for generic 2 prong") + O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass for generic 2 prong") + O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") + struct : ConfigurableGroup{ + O2_DEFINE_CONFIGURABLE(cfgImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)") + O2_DEFINE_CONFIGURABLE(cfgImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)") + O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") + O2_DEFINE_CONFIGURABLE(cfgITSclusterPhiMeson, int, 5, "Minimum number of ITS cluster for phi meson track") + O2_DEFINE_CONFIGURABLE(cfgTPCCrossedRowsPhiMeson, int, 80, "Minimum number of TPC Crossed Rows for phi meson track") + O2_DEFINE_CONFIGURABLE(cfgCutDCAxyPhiMeson, float, 0.1, "Maximum DCAxy for phi meson track") + O2_DEFINE_CONFIGURABLE(cfgCutDCAzPhiMeson, float, 0.1, "Maximum DCAz for phi meson track") + O2_DEFINE_CONFIGURABLE(cfgCutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track") + O2_DEFINE_CONFIGURABLE(cfgCutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track") + O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") + // O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") // already present in strangeness builder + // dca pos and neg already prsent in strangeness builder + // O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") + O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") + O2_DEFINE_CONFIGURABLE(cMinV0DCAPr, float, 0.1, "Min V0 proton DCA") + O2_DEFINE_CONFIGURABLE(cMinV0DCAPi, float, 0.1, "Min V0 pion DCA") + O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") + O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") + O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") + O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") + O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") + O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") + O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") + // O2_DEFINE_CONFIGURABLE(radiusMax, float, 2.3, "Maximum decay radius (cm)") // already present in strangeness builder + // O2_DEFINE_CONFIGURABLE(radiusMin, float, 0.0, "Minimum decay radius (cm)") // already present in strangeness builder + // O2_DEFINE_CONFIGURABLE(cosPaMin, float, 0.98, "Minimum cosine of pointing angle") // already present in strangeness builder + // O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMax, float, 0.2, "Maximum DCA among the V0 daughters (cm)") // already present in strangeness builder + O2_DEFINE_CONFIGURABLE(dcaV0ToPvMax, float, 0.2, "Maximum DCA of the V0 from the primary vertex (cm)") + O2_DEFINE_CONFIGURABLE(cosPaV0Min, float, 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays") + O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0, float, 0.12, "Minimum Armenteros' qt for K0") + O2_DEFINE_CONFIGURABLE(ConfV0Rap, float, 0.5, "Store rapidity of v0") + O2_DEFINE_CONFIGURABLE(cMaxLambdaLifeTime, float, 30, "Store Lambda lifetime") + O2_DEFINE_CONFIGURABLE(cMaxK0sLifeTime, float, 30, "Store K0s lifetime") + O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "flag for applying deep angle") + O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") + O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") + O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") + O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") + O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.5, "TOF beta")} grpphiV0; HfHelper hfHelper; Produces output2ProngTracks; @@ -102,11 +110,15 @@ struct Filter2Prong { template using HasMLProb = decltype(std::declval().mlProbD0()); - using PIDTrack = soa::Join; + using PIDTrack = soa::Join; using ResoV0s = aod::V0Datas; + std::unique_ptr sigmaFormula; + void init(InitContext&) { + if (doprocessDataInvMass) + sigmaFormula = std::make_unique("sigmaFormula", cfgImSigmaFormula.value.c_str()); } template @@ -203,6 +215,15 @@ struct Filter2Prong { } PROCESS_SWITCH(Filter2Prong, processMC, "Process MC 2-prong daughters", false); + template + bool selectionTrack(const T& candidate) + { + if (candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() >= grpphiV0.cfgITSclusterPhiMeson && candidate.tpcNClsCrossedRows() > grpphiV0.cfgTPCCrossedRowsPhiMeson && std::abs(candidate.dcaXY()) <= grpphiV0.cfgCutDCAxyPhiMeson && std::abs(candidate.dcaZ()) <= grpphiV0.cfgCutDCAzPhiMeson && std::abs(candidate.eta()) <= grpphiV0.cfgCutEtaPhiMeson && candidate.pt() >= grpphiV0.cfgCutPTPhiMeson) { + return true; + } + return false; + } + template bool selectionPair(const T1& candidate1, const T2& candidate2) { @@ -214,18 +235,18 @@ struct Filter2Prong { p1 = candidate1.p(); p2 = candidate2.p(); angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); - if (isDeepAngle && angle < cfgDeepAngle) { + if (grpphiV0.isDeepAngle && angle < grpphiV0.cfgDeepAngle) { return false; } return true; } template - bool isFakeKaon(T const& track) + bool isFakeTrack(T const& track) { const auto pglobal = track.p(); const auto ptpc = track.tpcInnerParam(); - if (TMath::Abs(pglobal - ptpc) > ConfFakeKaonCut) { + if (TMath::Abs(pglobal - ptpc) > grpphiV0.ConfFakeKaonCut) { return true; } return false; @@ -239,34 +260,34 @@ struct Filter2Prong { float CtauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0; - if (v0.mK0Short() < massK0Min || v0.mK0Short() > massK0Max) { - return false; - } - if ((v0.qtarm() / std::abs(v0.alpha())) < qtArmenterosMinForK0) { + if (v0.mK0Short() < grpphiV0.massK0Min || v0.mK0Short() > grpphiV0.massK0Max) { return false; } - if (v0.v0radius() > radiusMax || v0.v0radius() < radiusMin) { + if ((v0.qtarm() / std::abs(v0.alpha())) < grpphiV0.qtArmenterosMinForK0) { return false; } - if (v0.v0cosPA() < cosPaMin) { + // if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { + // return false; + // } + // if (v0.v0cosPA() < grpphiV0.cosPaMin) { + // return false; + //} + // if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { + // return false; + //} + if (v0.dcav0topv() > grpphiV0.dcaV0ToPvMax) { return false; } - if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + if (std::abs(CtauK0s) > grpphiV0.cMaxK0sLifeTime) { return false; } - if (v0.dcav0topv() > dcaV0ToPvMax) { + if (std::abs(v0.yK0Short()) > grpphiV0.ConfV0Rap) { return false; } - if (std::abs(CtauK0s) > cMaxK0sLifeTime) { + if (((std::abs(posTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts))) { return false; } - if (std::abs(v0.yK0Short()) > ConfV0Rap) { - return false; - } - if (((std::abs(posTrack.tpcNSigmaPi()) > ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > ConfDaughPIDCuts))) { - return false; - } - if ((TMath::Abs(v0.dcapostopv()) < cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPi)) { + if ((TMath::Abs(v0.dcapostopv()) < grpphiV0.cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < grpphiV0.cMinV0DCAPi)) { return false; } return true; @@ -280,38 +301,38 @@ struct Filter2Prong { float CtauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda; - if ((v0.mLambda() < massLambdaMin || v0.mLambda() > massLambdaMax) && - (v0.mAntiLambda() < massLambdaMin || v0.mAntiLambda() > massLambdaMax)) { - return false; - } - if (v0.v0radius() > radiusMax || v0.v0radius() < radiusMin) { - return false; - } - if (v0.v0cosPA() < cosPaMin) { - return false; - } - if (v0.dcaV0daughters() > dcaV0DaughtersMax) { + if ((v0.mLambda() < grpphiV0.massLambdaMin || v0.mLambda() > grpphiV0.massLambdaMax) && + (v0.mAntiLambda() < grpphiV0.massLambdaMin || v0.mAntiLambda() > grpphiV0.massLambdaMax)) { return false; } - if (v0.dcav0topv() > dcaV0ToPvMax) { + // if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { + // return false; + // } + // if (v0.v0cosPA() < grpphiV0.cosPaMin) { + // return false; + //} + // if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { + // return false; + //} + if (v0.dcav0topv() > grpphiV0.dcaV0ToPvMax) { return false; } - if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < cMinV0DCAPr || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPi)) { + if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < grpphiV0.cMinV0DCAPr || TMath::Abs(v0.dcanegtopv()) < grpphiV0.cMinV0DCAPi)) { return false; } - if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < cMinV0DCAPr)) { + if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < grpphiV0.cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < grpphiV0.cMinV0DCAPr)) { return false; } - if (pid == 0 && ((std::abs(posTrack.tpcNSigmaPr()) > ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > ConfDaughPIDCuts))) { + if (pid == 0 && ((std::abs(posTrack.tpcNSigmaPr()) > grpphiV0.ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts))) { return false; } - if (pid == 1 && ((std::abs(posTrack.tpcNSigmaPi()) > ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > ConfDaughPIDCuts))) { + if (pid == 1 && ((std::abs(posTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > grpphiV0.ConfDaughPIDCuts))) { return false; } - if (std::abs(CtauLambda) > cMaxLambdaLifeTime) { + if (std::abs(CtauLambda) > grpphiV0.cMaxLambdaLifeTime) { return false; } - if (std::abs(v0.yLambda()) > ConfV0Rap) { + if (std::abs(v0.yLambda()) > grpphiV0.ConfV0Rap) { return false; } return true; @@ -326,16 +347,16 @@ struct Filter2Prong { if (!posTrack.hasTPC() || !negTrack.hasTPC()) { return false; } - if (posTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < tpcNClsCrossedRowsTrackMin) { - return false; - } + // if (posTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin) { + // return false; + // } if (posTrack.tpcCrossedRowsOverFindableCls() < 0.8 || negTrack.tpcCrossedRowsOverFindableCls() < 0.8) { return false; } - if (std::abs(v0.positiveeta()) > etaTrackMax || std::abs(v0.negativeeta()) > etaTrackMax) { - return false; - } - if (v0.positivept() < ptTrackMin || v0.negativept() < ptTrackMin) { + // if (std::abs(v0.positiveeta()) > grpphiV0.etaTrackMax || std::abs(v0.negativeeta()) > grpphiV0.etaTrackMax) { + // return false; + // } + if (v0.positivept() < grpphiV0.ptTrackMin || v0.negativept() < grpphiV0.ptTrackMin) { return false; } return true; @@ -346,18 +367,18 @@ struct Filter2Prong { { if (cfgMomDepPID) { if (candidate.p() < 0.5) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpphiV0.nsigmaCutTPC) { return true; - } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpphiV0.nsigmaCutTOF && candidate.beta() > grpphiV0.cfgCutTOFBeta) { return true; } - } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpphiV0.nsigmaCutTOF && candidate.beta() > grpphiV0.cfgCutTOFBeta) { return true; } } else if (!cfgMomDepPID) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < nsigmaCutTPC) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpphiV0.nsigmaCutTPC) { return true; - } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < nsigmaCutTOF && candidate.beta() > cfgCutTOFBeta) { + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpphiV0.nsigmaCutTOF && candidate.beta() > grpphiV0.cfgCutTOFBeta) { return true; } } @@ -365,26 +386,62 @@ struct Filter2Prong { } // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. - void processDataInvMass(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, PIDTrack const& tracks, aod::V0Datas const& V0s) + void processDataInvMass(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + for (const auto& cftrack1 : cftracks) { + const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); + if (p1.sign() != 1) + continue; + if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart1PID, p1), o2::aod::pidutils::tofNSigma(cfgImPart1PID, p1)) <= 0.0f) + continue; + for (const auto& cftrack2 : cftracks) { + if (cftrack2.globalIndex() == cftrack1.globalIndex()) + continue; + const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); + if (p2.sign() != -1) + continue; + if (sigmaFormula->Eval(o2::aod::pidutils::tpcNSigma(cfgImPart2PID, p2), o2::aod::pidutils::tofNSigma(cfgImPart2PID, p2)) <= 0.0f) + continue; + ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); + ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); + ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; + if (s.pt() < cfgImCutPt || s.M() < cfgImMinInvMass || s.M() > cfgImMaxInvMass) + continue; + + float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::Generic2Prong); + } + } + } + PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); + + // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + void processDataPhiV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks, aod::V0Datas const& V0s) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) return; // rejected collision o2::aod::ITSResponse itsResponse; - if (cfgDoPhi) { // Process Phi mesons + if (grpphiV0.cfgDoPhi) { // Process Phi mesons for (const auto& cftrack1 : cftracks) { // Loop over first track const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); if (p1.sign() != 1) { continue; } - if (ITSPIDSelection && p1.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < ITSPIDNsigma.value)) { // Check ITS PID condition + if (!selectionTrack(p1)) { + continue; + } + if (grpphiV0.ITSPIDSelection && p1.p() < grpphiV0.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpphiV0.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpphiV0.highITSPIDNsigma.value)) { // Check ITS PID condition continue; } if (!selectionPID(p1)) { continue; } - if (removefaketrack && isFakeKaon(p1)) { // Check if the track is a fake kaon + if (grpphiV0.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon continue; } @@ -396,13 +453,16 @@ struct Filter2Prong { if (p2.sign() != -1) { continue; } + if (!selectionTrack(p2)) { + continue; + } if (!selectionPID(p2)) { continue; } - if (ITSPIDSelection && p2.p() < ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > -ITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < ITSPIDNsigma.value)) { // Check ITS PID condition + if (grpphiV0.ITSPIDSelection && p2.p() < grpphiV0.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpphiV0.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpphiV0.highITSPIDNsigma.value)) { // Check ITS PID condition continue; } - if (removefaketrack && isFakeKaon(p2)) { // Check if the track is a fake kaon + if (grpphiV0.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon continue; } if (!selectionPair(p1, p2)) { @@ -412,9 +472,9 @@ struct Filter2Prong { ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; - if (s.pt() < cfgImCutPt || s.M() < cfgImMinInvMass || s.M() > cfgImMaxInvMass) + if (s.M() < grpphiV0.cfgImMinInvMassPhiMeson || s.M() > grpphiV0.cfgImMaxInvMassPhiMeson) { continue; - + } float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); output2ProngTracks(cfcollisions.begin().globalIndex(), cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKK); @@ -422,7 +482,7 @@ struct Filter2Prong { } // end of loop over first track } // end of processing Phi mesons - if (cfgDoV0) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas) + if (grpphiV0.cfgDoV0) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas) for (const auto& v0 : V0s) { // Loop over V0 candidates if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs continue; @@ -454,7 +514,8 @@ struct Filter2Prong { massV0 = v0.mLambda(); output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), v0.pt(), v0.eta(), v0.phi(), massV0, v0Type); - } else if (aLambdaTag) { // candidate is Anti-lambda + } + if (aLambdaTag) { // candidate is Anti-lambda SETBIT(v0Type, aod::cf2prongtrack::AntiLambdatoPiP); massV0 = v0.mAntiLambda(); output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), @@ -463,7 +524,8 @@ struct Filter2Prong { } // end of loop over V0 candidates } // end of processing V0 candidates } - PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); + PROCESS_SWITCH(Filter2Prong, processDataPhiV0, "Process data PhiV0 candidates with invariant mass method", false); + }; // struct WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 64cc6874461..ab528ddfb9a 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -14,6 +14,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/TrackSelectionTables.h" #include "Framework/ASoAHelpers.h" @@ -52,7 +53,8 @@ struct FilterCF { enum TrackSelectionCuts : uint8_t { kTrackSelected = BIT(0), kITS5Clusters = BIT(1), - kTPC90CrossedRows = BIT(2) + kTPC90CrossedRows = BIT(2), + kPIDProton = BIT(3) }; // Configuration @@ -70,7 +72,13 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics)") O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)") O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, {}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only.") // needed for some neutral particles - O2_DEFINE_CONFIGURABLE(fillproton, bool, true, "flag to fill proton nsigma") + O2_DEFINE_CONFIGURABLE(nsigmaCutTPCProton, float, 3, "proton nsigma TPC") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOFProton, float, 3, "proton nsigma TOF") + O2_DEFINE_CONFIGURABLE(ITSProtonselection, bool, false, "flag for ITS proton nsigma selection") + O2_DEFINE_CONFIGURABLE(nsigmaCutITSProton, float, 3, "proton nsigma ITS") + O2_DEFINE_CONFIGURABLE(dcaselection, bool, false, "flag for applying dca selection on tracks") + O2_DEFINE_CONFIGURABLE(dcaxymax, float, 0.1f, "dcaxy of tracks") + O2_DEFINE_CONFIGURABLE(dcazmax, float, 0.1f, "dcaz of tracks") // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -131,8 +139,36 @@ struct FilterCF { return false; } + template + bool selectionPIDProton(const T& candidate) + { + o2::aod::ITSResponse itsResponse; + + if (ITSProtonselection && candidate.pt() <= 0.6 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { + return false; + } + if (ITSProtonselection && candidate.pt() > 0.6 && candidate.pt() <= 0.8 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { + return false; + } + + if (candidate.hasTOF()) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { + return true; + } + if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFProton) { + return true; + } + } + if (!candidate.hasTOF()) { + if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { + return true; + } + } + return false; + } + template - uint8_t getTrackType(TTrack& track) + uint8_t getTrackType(TTrack& track, bool isprot) { if (cfgTrackSelection == 0) { if (track.isGlobalTrack()) { @@ -153,13 +189,27 @@ struct FilterCF { } } return trackType; + } else if (cfgTrackSelection == 2) { + uint8_t trackType = 0; + if (track.isGlobalTrack()) { + trackType |= kTrackSelected; + if (track.itsNCls() >= 5) { + trackType |= kITS5Clusters; + } + if (track.tpcNClsCrossedRows() >= 90) { + trackType |= kTPC90CrossedRows; + } + if (isprot) { + trackType |= kPIDProton; + } + } + return trackType; } LOGF(fatal, "Invalid setting for cfgTrackSelection: %d", cfgTrackSelection.value); return 0; } - // void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) - void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) { if (cfgVerbosity > 0) { LOGF(info, "processData: Tracks for collision: %d | Vertex: %.1f (%d) | INT7: %d | Multiplicity: %.1f", tracks.size(), collision.posZ(), collision.flags(), collision.sel7(), collision.multiplicity()); @@ -174,12 +224,17 @@ struct FilterCF { if (cfgTransientTables) outputCollRefs(collision.globalIndex()); - + Bool_t isproton = false; for (auto& track : tracks) { - if (fillproton) - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), track.tpcNSigmaPr(), track.tofNSigmaPr()); - else - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track), -999.99, -999.99); + if (selectionPIDProton(track)) { + isproton = true; + } + if (dcaselection && std::abs(track.dcaXY()) > dcaxymax) + continue; + if (dcaselection && std::abs(track.dcaZ()) > dcazmax) + continue; + + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track, isproton)); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -293,8 +348,7 @@ struct FilterCF { LOGP(fatal, "processMC: Track {} is referring to a MC particle which we do not store {} {} (reco flag {})", track.index(), track.mcParticleId(), mcParticleId, static_cast(mcReconstructedCache[track.mcParticleId()])); } } - outputTracks(outputCollisions.lastIndex(), - truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track), -999.99, -999.99); + outputTracks(outputCollisions.lastIndex(), truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track, false)); outputTrackLabels(mcParticleId); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); From 5aed3dbf8017c834d24460875a563da5f3cf6926 Mon Sep 17 00:00:00 2001 From: spolitan Date: Thu, 26 Jun 2025 09:37:14 +0200 Subject: [PATCH 07/13] cleaning code and removing commented lines --- PWGCF/TableProducer/filter2Prong.cxx | 111 ++++++++++----------- PWGCF/TableProducer/filterCorrelations.cxx | 10 +- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 5af560dc7a0..9083f678ff9 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -62,38 +62,37 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgCutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track") O2_DEFINE_CONFIGURABLE(cfgCutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track") O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") - // O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") // already present in strangeness builder - // dca pos and neg already prsent in strangeness builder - // O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") - O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") - O2_DEFINE_CONFIGURABLE(cMinV0DCAPr, float, 0.1, "Min V0 proton DCA") - O2_DEFINE_CONFIGURABLE(cMinV0DCAPi, float, 0.1, "Min V0 pion DCA") - O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") - O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") - O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") - O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") - O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") - O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") - O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") - // O2_DEFINE_CONFIGURABLE(radiusMax, float, 2.3, "Maximum decay radius (cm)") // already present in strangeness builder - // O2_DEFINE_CONFIGURABLE(radiusMin, float, 0.0, "Minimum decay radius (cm)") // already present in strangeness builder - // O2_DEFINE_CONFIGURABLE(cosPaMin, float, 0.98, "Minimum cosine of pointing angle") // already present in strangeness builder - // O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMax, float, 0.2, "Maximum DCA among the V0 daughters (cm)") // already present in strangeness builder - O2_DEFINE_CONFIGURABLE(dcaV0ToPvMax, float, 0.2, "Maximum DCA of the V0 from the primary vertex (cm)") - O2_DEFINE_CONFIGURABLE(cosPaV0Min, float, 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays") - O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0, float, 0.12, "Minimum Armenteros' qt for K0") - O2_DEFINE_CONFIGURABLE(ConfV0Rap, float, 0.5, "Store rapidity of v0") - O2_DEFINE_CONFIGURABLE(cMaxLambdaLifeTime, float, 30, "Store Lambda lifetime") - O2_DEFINE_CONFIGURABLE(cMaxK0sLifeTime, float, 30, "Store K0s lifetime") - O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "flag for applying deep angle") - O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") - O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") - O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") - O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") - O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") - O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.5, "TOF beta")} grpphiV0; + O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") + O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") + O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") + O2_DEFINE_CONFIGURABLE(cMinV0DCAPr, float, 0.1, "Min V0 proton DCA") + O2_DEFINE_CONFIGURABLE(cMinV0DCAPi, float, 0.1, "Min V0 pion DCA") + O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") + O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") + O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") + O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") + O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") + O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") + O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") + O2_DEFINE_CONFIGURABLE(radiusMax, float, 2.3, "Maximum decay radius (cm)") + O2_DEFINE_CONFIGURABLE(radiusMin, float, 0.0, "Minimum decay radius (cm)") + O2_DEFINE_CONFIGURABLE(cosPaMin, float, 0.98, "Minimum cosine of pointing angle") + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMax, float, 0.2, "Maximum DCA among the V0 daughters (cm)") + O2_DEFINE_CONFIGURABLE(dcaV0ToPvMax, float, 0.2, "Maximum DCA of the V0 from the primary vertex (cm)") + O2_DEFINE_CONFIGURABLE(cosPaV0Min, float, 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays") + O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0, float, 0.12, "Minimum Armenteros' qt for K0") + O2_DEFINE_CONFIGURABLE(ConfV0Rap, float, 0.5, "Store rapidity of v0") + O2_DEFINE_CONFIGURABLE(cMaxLambdaLifeTime, float, 30, "Store Lambda lifetime") + O2_DEFINE_CONFIGURABLE(cMaxK0sLifeTime, float, 30, "Store K0s lifetime") + O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "flag for applying deep angle") + O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") + O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") + O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") + O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") + O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.5, "TOF beta")} grpphiV0; HfHelper hfHelper; Produces output2ProngTracks; @@ -266,15 +265,15 @@ struct Filter2Prong { if ((v0.qtarm() / std::abs(v0.alpha())) < grpphiV0.qtArmenterosMinForK0) { return false; } - // if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { - // return false; - // } - // if (v0.v0cosPA() < grpphiV0.cosPaMin) { - // return false; - //} - // if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { - // return false; - //} + if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { + return false; + } + if (v0.v0cosPA() < grpphiV0.cosPaMin) { + return false; + } + if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { + return false; + } if (v0.dcav0topv() > grpphiV0.dcaV0ToPvMax) { return false; } @@ -305,15 +304,15 @@ struct Filter2Prong { (v0.mAntiLambda() < grpphiV0.massLambdaMin || v0.mAntiLambda() > grpphiV0.massLambdaMax)) { return false; } - // if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { - // return false; - // } - // if (v0.v0cosPA() < grpphiV0.cosPaMin) { - // return false; - //} - // if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { - // return false; - //} + if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { + return false; + } + if (v0.v0cosPA() < grpphiV0.cosPaMin) { + return false; + } + if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { + return false; + } if (v0.dcav0topv() > grpphiV0.dcaV0ToPvMax) { return false; } @@ -347,15 +346,15 @@ struct Filter2Prong { if (!posTrack.hasTPC() || !negTrack.hasTPC()) { return false; } - // if (posTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin) { - // return false; - // } + if (posTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin) { + return false; + } if (posTrack.tpcCrossedRowsOverFindableCls() < 0.8 || negTrack.tpcCrossedRowsOverFindableCls() < 0.8) { return false; } - // if (std::abs(v0.positiveeta()) > grpphiV0.etaTrackMax || std::abs(v0.negativeeta()) > grpphiV0.etaTrackMax) { - // return false; - // } + if (std::abs(v0.positiveeta()) > grpphiV0.etaTrackMax || std::abs(v0.negativeeta()) > grpphiV0.etaTrackMax) { + return false; + } if (v0.positivept() < grpphiV0.ptTrackMin || v0.negativept() < grpphiV0.ptTrackMin) { return false; } diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index ab528ddfb9a..593208bd94b 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -79,6 +79,8 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(dcaselection, bool, false, "flag for applying dca selection on tracks") O2_DEFINE_CONFIGURABLE(dcaxymax, float, 0.1f, "dcaxy of tracks") O2_DEFINE_CONFIGURABLE(dcazmax, float, 0.1f, "dcaz of tracks") + O2_DEFINE_CONFIGURABLE(itsnclusters, int, 5, "minimum number of ITS clusters for tracks") + O2_DEFINE_CONFIGURABLE(tpcncrossedrows, int, 80, "minimum number of TPC crossed rows for tracks") // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -181,10 +183,10 @@ struct FilterCF { uint8_t trackType = 0; if (track.isGlobalTrack()) { trackType |= kTrackSelected; - if (track.itsNCls() >= 5) { + if (track.itsNCls() >= itsnclusters) { trackType |= kITS5Clusters; } - if (track.tpcNClsCrossedRows() >= 90) { + if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { trackType |= kTPC90CrossedRows; } } @@ -193,10 +195,10 @@ struct FilterCF { uint8_t trackType = 0; if (track.isGlobalTrack()) { trackType |= kTrackSelected; - if (track.itsNCls() >= 5) { + if (track.itsNCls() >= itsnclusters) { trackType |= kITS5Clusters; } - if (track.tpcNClsCrossedRows() >= 90) { + if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { trackType |= kTPC90CrossedRows; } if (isprot) { From e9c2b0dcb9c2f2ac00c75b765ba4422ade01045a Mon Sep 17 00:00:00 2001 From: spolitan Date: Thu, 26 Jun 2025 09:39:47 +0200 Subject: [PATCH 08/13] cleaning code --- PWGCF/TableProducer/filter2Prong.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 9083f678ff9..15b806a0524 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -417,7 +417,7 @@ struct Filter2Prong { } PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); - // Generic 2-prong invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. void processDataPhiV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks, aod::V0Datas const& V0s) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) From 6080e47f01acc85772c255e8a0bc59d486ad431c Mon Sep 17 00:00:00 2001 From: spolitan Date: Mon, 30 Jun 2025 15:31:06 +0200 Subject: [PATCH 09/13] Implementing Sourav and Jan comments --- PWGCF/TableProducer/filter2Prong.cxx | 184 ++++++++++----------- PWGCF/TableProducer/filterCorrelations.cxx | 60 ++++--- 2 files changed, 128 insertions(+), 116 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 15b806a0524..89a42fc47c6 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -48,51 +48,58 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgImPart2PID, int, o2::track::PID::Kaon, "PID of daughter particle 2 (O2 PID ID)") O2_DEFINE_CONFIGURABLE(cfgMomDepPID, bool, 1, "Use mommentum dependent PID for Phi meson") O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") - O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.98f, "Minimum invariant mass for generic 2 prong") + O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass for generic 2 prong") O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass for generic 2 prong") O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") + + struct : ConfigurableGroup{ + O2_DEFINE_CONFIGURABLE(DoV0, bool, true, "Store V0s information") + O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") + O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") + O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") + O2_DEFINE_CONFIGURABLE(minV0DCAPr, float, 0.1, "Min V0 proton DCA") + O2_DEFINE_CONFIGURABLE(minV0DCAPiLambda, float, 0.1, "Min V0 pion DCA for lambda") + O2_DEFINE_CONFIGURABLE(minV0DCAPiK0s, float, 0.1, "Min V0 pion DCA for K0s") + O2_DEFINE_CONFIGURABLE(daughPIDCuts, float, 4.0, "PID nsigma for V0s") + O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") + O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") + O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") + O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") + O2_DEFINE_CONFIGURABLE(radiusMaxLambda, float, 2.3, "Maximum decay radius (cm) for lambda") + O2_DEFINE_CONFIGURABLE(radiusMinLambda, float, 0.0, "Minimum decay radius (cm) for lambda") + O2_DEFINE_CONFIGURABLE(radiusMaxK0s, float, 2.3, "Maximum decay radius (cm) for K0s") + O2_DEFINE_CONFIGURABLE(radiusMinK0s, float, 0.0, "Minimum decay radius (cm) for K0s") + O2_DEFINE_CONFIGURABLE(cosPaMinLambda, float, 0.98, "Minimum cosine of pointing angle for lambda") + O2_DEFINE_CONFIGURABLE(cosPaMinK0s, float, 0.98, "Minimum cosine of pointing angle for K0s") + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxLambda, float, 0.2, "Maximum DCA among the V0 daughters (cm) for lambda") + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxK0s, float, 0.2, "Maximum DCA among the V0 daughters (cm) for K0s") + O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0s, float, 0.12, "Minimum Armenteros' qt for K0s") + O2_DEFINE_CONFIGURABLE(maxLambdaLifeTime, float, 30, "Maximum lambda lifetime (in cm)") + O2_DEFINE_CONFIGURABLE(maxK0sLifeTime, float, 30, "Maximum K0s lifetime (in cm)") + } grpV0; + struct : ConfigurableGroup{ - O2_DEFINE_CONFIGURABLE(cfgImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)") - O2_DEFINE_CONFIGURABLE(cfgImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)") - O2_DEFINE_CONFIGURABLE(cfgDoPhi, bool, false, "Store phi information") - O2_DEFINE_CONFIGURABLE(cfgITSclusterPhiMeson, int, 5, "Minimum number of ITS cluster for phi meson track") - O2_DEFINE_CONFIGURABLE(cfgTPCCrossedRowsPhiMeson, int, 80, "Minimum number of TPC Crossed Rows for phi meson track") - O2_DEFINE_CONFIGURABLE(cfgCutDCAxyPhiMeson, float, 0.1, "Maximum DCAxy for phi meson track") - O2_DEFINE_CONFIGURABLE(cfgCutDCAzPhiMeson, float, 0.1, "Maximum DCAz for phi meson track") - O2_DEFINE_CONFIGURABLE(cfgCutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track") - O2_DEFINE_CONFIGURABLE(cfgCutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track") - O2_DEFINE_CONFIGURABLE(cfgDoV0, bool, true, "Store V0s candidates") - O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") - O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") - O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") - O2_DEFINE_CONFIGURABLE(cMinV0DCAPr, float, 0.1, "Min V0 proton DCA") - O2_DEFINE_CONFIGURABLE(cMinV0DCAPi, float, 0.1, "Min V0 pion DCA") - O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") - O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") - O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(ConfDaughPIDCuts, float, 4.0, "PID nsigma for V0s") - O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") - O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") - O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") - O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") - O2_DEFINE_CONFIGURABLE(radiusMax, float, 2.3, "Maximum decay radius (cm)") - O2_DEFINE_CONFIGURABLE(radiusMin, float, 0.0, "Minimum decay radius (cm)") - O2_DEFINE_CONFIGURABLE(cosPaMin, float, 0.98, "Minimum cosine of pointing angle") - O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMax, float, 0.2, "Maximum DCA among the V0 daughters (cm)") - O2_DEFINE_CONFIGURABLE(dcaV0ToPvMax, float, 0.2, "Maximum DCA of the V0 from the primary vertex (cm)") - O2_DEFINE_CONFIGURABLE(cosPaV0Min, float, 0.95, "Minimum cosine of pointing angle for V0 stemming from cascade decays") - O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0, float, 0.12, "Minimum Armenteros' qt for K0") - O2_DEFINE_CONFIGURABLE(ConfV0Rap, float, 0.5, "Store rapidity of v0") - O2_DEFINE_CONFIGURABLE(cMaxLambdaLifeTime, float, 30, "Store Lambda lifetime") - O2_DEFINE_CONFIGURABLE(cMaxK0sLifeTime, float, 30, "Store K0s lifetime") - O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "flag for applying deep angle") - O2_DEFINE_CONFIGURABLE(cfgDeepAngle, float, 0.04, "deep angle cut") - O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "flag to remove fake kaon") - O2_DEFINE_CONFIGURABLE(ConfFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") - O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") - O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") - O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.5, "TOF beta")} grpphiV0; + O2_DEFINE_CONFIGURABLE(DoPhi, bool, false, "Store Phi information") + O2_DEFINE_CONFIGURABLE(ImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)") + O2_DEFINE_CONFIGURABLE(ImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)") + O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") + O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") + O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(ITSclusterPhiMeson, int, 5, "Minimum number of ITS cluster for phi meson track") + O2_DEFINE_CONFIGURABLE(TPCCrossedRowsPhiMeson, int, 80, "Minimum number of TPC Crossed Rows for phi meson track") + O2_DEFINE_CONFIGURABLE(cutDCAxyPhiMeson, float, 0.1, "Maximum DCAxy for phi meson track") + O2_DEFINE_CONFIGURABLE(cutDCAzPhiMeson, float, 0.1, "Maximum DCAz for phi meson track") + O2_DEFINE_CONFIGURABLE(cutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track") + O2_DEFINE_CONFIGURABLE(cutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track") + O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "Flag for applying deep angle") + O2_DEFINE_CONFIGURABLE(deepAngle, float, 0.04, "Deep angle cut") + O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") + O2_DEFINE_CONFIGURABLE(cutTOFBeta, float, 0.5, "TOF beta") + O2_DEFINE_CONFIGURABLE(confFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") + O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "Flag to remove fake kaon") + } grpPhi; HfHelper hfHelper; Produces output2ProngTracks; @@ -217,7 +224,7 @@ struct Filter2Prong { template bool selectionTrack(const T& candidate) { - if (candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() >= grpphiV0.cfgITSclusterPhiMeson && candidate.tpcNClsCrossedRows() > grpphiV0.cfgTPCCrossedRowsPhiMeson && std::abs(candidate.dcaXY()) <= grpphiV0.cfgCutDCAxyPhiMeson && std::abs(candidate.dcaZ()) <= grpphiV0.cfgCutDCAzPhiMeson && std::abs(candidate.eta()) <= grpphiV0.cfgCutEtaPhiMeson && candidate.pt() >= grpphiV0.cfgCutPTPhiMeson) { + if (candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() >= grpPhi.ITSclusterPhiMeson && candidate.tpcNClsCrossedRows() > grpPhi.TPCCrossedRowsPhiMeson && std::abs(candidate.dcaXY()) <= grpPhi.cutDCAxyPhiMeson && std::abs(candidate.dcaZ()) <= grpPhi.cutDCAzPhiMeson && std::abs(candidate.eta()) <= grpPhi.cutEtaPhiMeson && candidate.pt() >= grpPhi.cutPTPhiMeson) { return true; } return false; @@ -234,7 +241,7 @@ struct Filter2Prong { p1 = candidate1.p(); p2 = candidate2.p(); angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); - if (grpphiV0.isDeepAngle && angle < grpphiV0.cfgDeepAngle) { + if (grpPhi.isDeepAngle && angle < grpPhi.deepAngle) { return false; } return true; @@ -245,7 +252,7 @@ struct Filter2Prong { { const auto pglobal = track.p(); const auto ptpc = track.tpcInnerParam(); - if (TMath::Abs(pglobal - ptpc) > grpphiV0.ConfFakeKaonCut) { + if (TMath::Abs(pglobal - ptpc) > grpPhi.confFakeKaonCut) { return true; } return false; @@ -259,34 +266,28 @@ struct Filter2Prong { float CtauK0s = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0; - if (v0.mK0Short() < grpphiV0.massK0Min || v0.mK0Short() > grpphiV0.massK0Max) { - return false; - } - if ((v0.qtarm() / std::abs(v0.alpha())) < grpphiV0.qtArmenterosMinForK0) { + if (v0.mK0Short() < grpV0.massK0Min || v0.mK0Short() > grpV0.massK0Max) { return false; } - if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { + if ((v0.qtarm() / std::abs(v0.alpha())) < grpV0.qtArmenterosMinForK0s) { return false; } - if (v0.v0cosPA() < grpphiV0.cosPaMin) { + if (v0.v0radius() > grpV0.radiusMaxK0s || v0.v0radius() < grpV0.radiusMinK0s) { return false; } - if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { + if (v0.v0cosPA() < grpV0.cosPaMinK0s) { return false; } - if (v0.dcav0topv() > grpphiV0.dcaV0ToPvMax) { + if (v0.dcaV0daughters() > grpV0.dcaV0DaughtersMaxK0s) { return false; } - if (std::abs(CtauK0s) > grpphiV0.cMaxK0sLifeTime) { + if (std::abs(CtauK0s) > grpV0.maxK0sLifeTime) { return false; } - if (std::abs(v0.yK0Short()) > grpphiV0.ConfV0Rap) { + if (((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts))) { return false; } - if (((std::abs(posTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts))) { - return false; - } - if ((TMath::Abs(v0.dcapostopv()) < grpphiV0.cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < grpphiV0.cMinV0DCAPi)) { + if ((TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiK0s || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPiK0s)) { return false; } return true; @@ -300,38 +301,32 @@ struct Filter2Prong { float CtauLambda = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda; - if ((v0.mLambda() < grpphiV0.massLambdaMin || v0.mLambda() > grpphiV0.massLambdaMax) && - (v0.mAntiLambda() < grpphiV0.massLambdaMin || v0.mAntiLambda() > grpphiV0.massLambdaMax)) { - return false; - } - if (v0.v0radius() > grpphiV0.radiusMax || v0.v0radius() < grpphiV0.radiusMin) { + if ((v0.mLambda() < grpV0.massLambdaMin || v0.mLambda() > grpV0.massLambdaMax) && + (v0.mAntiLambda() < grpV0.massLambdaMin || v0.mAntiLambda() > grpV0.massLambdaMax)) { return false; } - if (v0.v0cosPA() < grpphiV0.cosPaMin) { + if (v0.v0radius() > grpV0.radiusMaxLambda || v0.v0radius() < grpV0.radiusMinLambda) { return false; } - if (v0.dcaV0daughters() > grpphiV0.dcaV0DaughtersMax) { + if (v0.v0cosPA() < grpV0.cosPaMinLambda) { return false; } - if (v0.dcav0topv() > grpphiV0.dcaV0ToPvMax) { + if (v0.dcaV0daughters() > grpV0.dcaV0DaughtersMaxLambda) { return false; } - if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < grpphiV0.cMinV0DCAPr || TMath::Abs(v0.dcanegtopv()) < grpphiV0.cMinV0DCAPi)) { + if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPr || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPiLambda)) { return false; } - if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < grpphiV0.cMinV0DCAPi || TMath::Abs(v0.dcanegtopv()) < grpphiV0.cMinV0DCAPr)) { + if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiLambda || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPr)) { return false; } - if (pid == 0 && ((std::abs(posTrack.tpcNSigmaPr()) > grpphiV0.ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts))) { + if (pid == 0 && ((std::abs(posTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts))) { return false; } - if (pid == 1 && ((std::abs(posTrack.tpcNSigmaPi()) > grpphiV0.ConfDaughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > grpphiV0.ConfDaughPIDCuts))) { + if (pid == 1 && ((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts))) { return false; } - if (std::abs(CtauLambda) > grpphiV0.cMaxLambdaLifeTime) { - return false; - } - if (std::abs(v0.yLambda()) > grpphiV0.ConfV0Rap) { + if (std::abs(CtauLambda) > grpV0.maxLambdaLifeTime) { return false; } return true; @@ -346,16 +341,16 @@ struct Filter2Prong { if (!posTrack.hasTPC() || !negTrack.hasTPC()) { return false; } - if (posTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < grpphiV0.tpcNClsCrossedRowsTrackMin) { + if (posTrack.tpcNClsCrossedRows() < grpV0.tpcNClsCrossedRowsTrackMin || negTrack.tpcNClsCrossedRows() < grpV0.tpcNClsCrossedRowsTrackMin) { return false; } if (posTrack.tpcCrossedRowsOverFindableCls() < 0.8 || negTrack.tpcCrossedRowsOverFindableCls() < 0.8) { return false; } - if (std::abs(v0.positiveeta()) > grpphiV0.etaTrackMax || std::abs(v0.negativeeta()) > grpphiV0.etaTrackMax) { + if (std::abs(v0.positiveeta()) > grpV0.etaTrackMax || std::abs(v0.negativeeta()) > grpV0.etaTrackMax) { return false; } - if (v0.positivept() < grpphiV0.ptTrackMin || v0.negativept() < grpphiV0.ptTrackMin) { + if (v0.positivept() < grpV0.ptTrackMin || v0.negativept() < grpV0.ptTrackMin) { return false; } return true; @@ -366,18 +361,18 @@ struct Filter2Prong { { if (cfgMomDepPID) { if (candidate.p() < 0.5) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpphiV0.nsigmaCutTPC) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpPhi.nsigmaCutTPC) { return true; - } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpphiV0.nsigmaCutTOF && candidate.beta() > grpphiV0.cfgCutTOFBeta) { + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { return true; } - } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpphiV0.nsigmaCutTOF && candidate.beta() > grpphiV0.cfgCutTOFBeta) { + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { return true; } } else if (!cfgMomDepPID) { - if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpphiV0.nsigmaCutTPC) { + if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpPhi.nsigmaCutTPC) { return true; - } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpphiV0.nsigmaCutTOF && candidate.beta() > grpphiV0.cfgCutTOFBeta) { + } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { return true; } } @@ -425,7 +420,7 @@ struct Filter2Prong { o2::aod::ITSResponse itsResponse; - if (grpphiV0.cfgDoPhi) { // Process Phi mesons + if (grpPhi.DoPhi) { // Process Phi mesons for (const auto& cftrack1 : cftracks) { // Loop over first track const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); if (p1.sign() != 1) { @@ -434,13 +429,13 @@ struct Filter2Prong { if (!selectionTrack(p1)) { continue; } - if (grpphiV0.ITSPIDSelection && p1.p() < grpphiV0.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpphiV0.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpphiV0.highITSPIDNsigma.value)) { // Check ITS PID condition + if (grpPhi.ITSPIDSelection && p1.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition continue; } if (!selectionPID(p1)) { continue; } - if (grpphiV0.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon + if (grpPhi.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon continue; } @@ -458,10 +453,10 @@ struct Filter2Prong { if (!selectionPID(p2)) { continue; } - if (grpphiV0.ITSPIDSelection && p2.p() < grpphiV0.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpphiV0.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpphiV0.highITSPIDNsigma.value)) { // Check ITS PID condition + if (grpPhi.ITSPIDSelection && p2.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition continue; } - if (grpphiV0.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon + if (grpPhi.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon continue; } if (!selectionPair(p1, p2)) { @@ -471,7 +466,7 @@ struct Filter2Prong { ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; - if (s.M() < grpphiV0.cfgImMinInvMassPhiMeson || s.M() > grpphiV0.cfgImMaxInvMassPhiMeson) { + if (s.M() < grpPhi.ImMinInvMassPhiMeson || s.M() > grpPhi.ImMaxInvMassPhiMeson) { continue; } float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); @@ -481,7 +476,7 @@ struct Filter2Prong { } // end of loop over first track } // end of processing Phi mesons - if (grpphiV0.cfgDoV0) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas) + if (grpV0.DoV0) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas) for (const auto& v0 : V0s) { // Loop over V0 candidates if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs continue; @@ -492,21 +487,20 @@ struct Filter2Prong { auto v0Type = 0; double massV0 = 0.0; + + // K0s if (isSelectedV0AsK0s(collision, v0)) { // candidate is K0s SETBIT(v0Type, aod::cf2prongtrack::K0stoPiPi); output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), v0Type); - - continue; // candidate is K0s, skip to next V0 candidate } + // Lambda and Anti-Lambda bool LambdaTag = isSelectedV0AsLambda(collision, v0, 0); bool aLambdaTag = isSelectedV0AsLambda(collision, v0, 1); - if (!LambdaTag && !aLambdaTag) { // neither Lambda nor Anti-Lambda - continue; - } + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) if (LambdaTag) { // candidate is Lambda SETBIT(v0Type, aod::cf2prongtrack::LambdatoPPi); diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 593208bd94b..8cf4030b419 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -26,6 +26,7 @@ #include +#include // required for is_detected #include using namespace o2; @@ -53,8 +54,11 @@ struct FilterCF { enum TrackSelectionCuts : uint8_t { kTrackSelected = BIT(0), kITS5Clusters = BIT(1), - kTPC90CrossedRows = BIT(2), - kPIDProton = BIT(3) + kTPCCrossedRows = BIT(2), + }; + + enum PIDCuts : uint8_t { + kPIDProton = BIT(1) }; // Configuration @@ -69,7 +73,7 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(cfgMaxOcc, int, 3000, "maximum occupancy selection") O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)") O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs to enable successive filtering tasks") - O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics)") + O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics | 2 = Run 3 with proton pid selection)") O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)") O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, {}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only.") // needed for some neutral particles O2_DEFINE_CONFIGURABLE(nsigmaCutTPCProton, float, 3, "proton nsigma TPC") @@ -141,6 +145,8 @@ struct FilterCF { return false; } + using TrackType = soa::Filtered>; + template bool selectionPIDProton(const T& candidate) { @@ -168,9 +174,24 @@ struct FilterCF { } return false; } + /* + template + using HasProtonPID = decltype(selectionPIDProton(std::declval())); + */ + template + struct HasProtonPID : std::false_type { + }; - template - uint8_t getTrackType(TTrack& track, bool isprot) + template + struct HasProtonPID().tpcNSigmaPr()), + decltype(std::declval().tofNSigmaPr()), + decltype(std::declval().hasTOF())>> + : std::true_type { + }; + + template + uint8_t getTrackType(const TTrack& track) { if (cfgTrackSelection == 0) { if (track.isGlobalTrack()) { @@ -187,26 +208,27 @@ struct FilterCF { trackType |= kITS5Clusters; } if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { - trackType |= kTPC90CrossedRows; + trackType |= kTPCCrossedRows; } } return trackType; } else if (cfgTrackSelection == 2) { uint8_t trackType = 0; if (track.isGlobalTrack()) { - trackType |= kTrackSelected; if (track.itsNCls() >= itsnclusters) { - trackType |= kITS5Clusters; - } - if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { - trackType |= kTPC90CrossedRows; - } - if (isprot) { - trackType |= kPIDProton; + if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { + if constexpr (HasProtonPID::value) { + if (selectionPIDProton(track)) { + trackType |= kPIDProton; + } + } + } } } return trackType; } + + LOGF(fatal, "Invalid setting for cfgTrackSelection: %d", cfgTrackSelection.value); return 0; } @@ -226,17 +248,13 @@ struct FilterCF { if (cfgTransientTables) outputCollRefs(collision.globalIndex()); - Bool_t isproton = false; for (auto& track : tracks) { - if (selectionPIDProton(track)) { - isproton = true; - } if (dcaselection && std::abs(track.dcaXY()) > dcaxymax) continue; if (dcaselection && std::abs(track.dcaZ()) > dcazmax) continue; - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track, isproton)); + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -251,7 +269,7 @@ struct FilterCF { Preslice perCollision = aod::track::collisionId; void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, soa::Join const& allCollisions, - soa::Filtered> const& tracks, + soa::Filtered> const& tracks, aod::BCsWithTimestamps const&) { mcReconstructedCache.reserve(allParticles.size()); @@ -350,7 +368,7 @@ struct FilterCF { LOGP(fatal, "processMC: Track {} is referring to a MC particle which we do not store {} {} (reco flag {})", track.index(), track.mcParticleId(), mcParticleId, static_cast(mcReconstructedCache[track.mcParticleId()])); } } - outputTracks(outputCollisions.lastIndex(), truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track, false)); + outputTracks(outputCollisions.lastIndex(), truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track)); outputTrackLabels(mcParticleId); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); From 5c536540660cb16610f0c6bcbec3910e84b63ac9 Mon Sep 17 00:00:00 2001 From: spolitan Date: Fri, 4 Jul 2025 17:06:15 +0200 Subject: [PATCH 10/13] Implementing Jan comments --- PWGCF/TableProducer/filter2Prong.cxx | 18 ++++------ PWGCF/TableProducer/filterCorrelations.cxx | 39 ++++++++++++++-------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 89a42fc47c6..e50c3ca92a6 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -484,17 +484,13 @@ struct Filter2Prong { const auto& posTrack = v0.template posTrack_as(); const auto& negTrack = v0.template negTrack_as(); - - auto v0Type = 0; double massV0 = 0.0; // K0s if (isSelectedV0AsK0s(collision, v0)) { // candidate is K0s - SETBIT(v0Type, aod::cf2prongtrack::K0stoPiPi); - - output2ProngTracks(cfcollisions.begin().globalIndex(), + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), - v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), v0Type); + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPi); } // Lambda and Anti-Lambda @@ -503,16 +499,14 @@ struct Filter2Prong { // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) if (LambdaTag) { // candidate is Lambda - SETBIT(v0Type, aod::cf2prongtrack::LambdatoPPi); - massV0 = v0.mLambda(); + massV0 = v0.mLambda(); output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), - v0.pt(), v0.eta(), v0.phi(), massV0, v0Type); + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdatoPPi); } if (aLambdaTag) { // candidate is Anti-lambda - SETBIT(v0Type, aod::cf2prongtrack::AntiLambdatoPiP); - massV0 = v0.mAntiLambda(); + massV0 = v0.mAntiLambda(); output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), - v0.pt(), v0.eta(), v0.phi(), massV0, v0Type); + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdatoPiP); } // end of Lambda and Anti-Lambda processing } // end of loop over V0 candidates } // end of processing V0 candidates diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 8cf4030b419..51b87fe3b2f 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -51,13 +51,13 @@ using CFMultiplicity = CFMultiplicities::iterator; struct FilterCF { Service pdg; - enum TrackSelectionCuts : uint8_t { + enum TrackSelectionCuts1 : uint8_t { kTrackSelected = BIT(0), kITS5Clusters = BIT(1), kTPCCrossedRows = BIT(2), }; - enum PIDCuts : uint8_t { + enum TrackSelectionCuts2 : uint8_t { kPIDProton = BIT(1) }; @@ -80,9 +80,8 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(nsigmaCutTOFProton, float, 3, "proton nsigma TOF") O2_DEFINE_CONFIGURABLE(ITSProtonselection, bool, false, "flag for ITS proton nsigma selection") O2_DEFINE_CONFIGURABLE(nsigmaCutITSProton, float, 3, "proton nsigma ITS") - O2_DEFINE_CONFIGURABLE(dcaselection, bool, false, "flag for applying dca selection on tracks") - O2_DEFINE_CONFIGURABLE(dcaxymax, float, 0.1f, "dcaxy of tracks") - O2_DEFINE_CONFIGURABLE(dcazmax, float, 0.1f, "dcaz of tracks") + O2_DEFINE_CONFIGURABLE(dcaxymax, float, 999.f, "maximum dcaxy of tracks") + O2_DEFINE_CONFIGURABLE(dcazmax, float, 999.f, "maximum dcaz of tracks") O2_DEFINE_CONFIGURABLE(itsnclusters, int, 5, "minimum number of ITS clusters for tracks") O2_DEFINE_CONFIGURABLE(tpcncrossedrows, int, 80, "minimum number of TPC crossed rows for tracks") @@ -174,10 +173,7 @@ struct FilterCF { } return false; } - /* - template - using HasProtonPID = decltype(selectionPIDProton(std::declval())); - */ + template struct HasProtonPID : std::false_type { }; @@ -233,7 +229,11 @@ struct FilterCF { return 0; } - void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + /// \brief Templetized process data for a given collision and its associated tracks + /// \param collision The collision object containing information about the collision + /// \param tracks The collection of tracks associated with the collision + template + void processDataT(const C1& collision, const T1& tracks) { if (cfgVerbosity > 0) { LOGF(info, "processData: Tracks for collision: %d | Vertex: %.1f (%d) | INT7: %d | Multiplicity: %.1f", tracks.size(), collision.posZ(), collision.flags(), collision.sel7(), collision.multiplicity()); @@ -243,16 +243,16 @@ struct FilterCF { return; } - auto bc = collision.bc_as(); + auto bc = collision.template bc_as(); outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp()); if (cfgTransientTables) outputCollRefs(collision.globalIndex()); for (auto& track : tracks) { - if (dcaselection && std::abs(track.dcaXY()) > dcaxymax) - continue; - if (dcaselection && std::abs(track.dcaZ()) > dcazmax) + if ((std::abs(track.dcaXY()) > dcaxymax) || (std::abs(track.dcaZ()) > dcazmax)) { continue; + } + outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); if (cfgTransientTables) @@ -262,8 +262,19 @@ struct FilterCF { etaphi->Fill(collision.multiplicity(), track.eta(), track.phi()); } } + + void processData(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + { + processDataT(collision, tracks); + } PROCESS_SWITCH(FilterCF, processData, "Process data", true); + void processDataPid(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, soa::Filtered> const& tracks) + { + processDataT(collision, tracks); + } + PROCESS_SWITCH(FilterCF, processDataPid, "Process data with PID", false); + // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions Preslice perMcCollision = aod::mcparticle::mcCollisionId; Preslice perCollision = aod::track::collisionId; From 7c2a7a8afaf823214fad4b74b4304d768c0cafba Mon Sep 17 00:00:00 2001 From: spolitan Date: Mon, 7 Jul 2025 15:56:54 +0200 Subject: [PATCH 11/13] Implementing Jasper comments --- PWGCF/TableProducer/filter2Prong.cxx | 193 +++++++++++---------- PWGCF/TableProducer/filterCorrelations.cxx | 55 ++++-- 2 files changed, 138 insertions(+), 110 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index e50c3ca92a6..63c88e52c63 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -36,6 +36,10 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::math_utils::detail; +enum LambdaPid { kLambda = 0, + kAntiLambda + }; + // #define FLOAT_PRECISION 0xFFFFFFF0 #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; @@ -50,10 +54,9 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgImCutPt, float, 0.2f, "Minimal pT for candidates") O2_DEFINE_CONFIGURABLE(cfgImMinInvMass, float, 0.95f, "Minimum invariant mass for generic 2 prong") O2_DEFINE_CONFIGURABLE(cfgImMaxInvMass, float, 1.07f, "Maximum invariant mass for generic 2 prong") - O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") + O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && abs(x) < 3.0) || (z >= 0.5 && abs(x) < 2.5 && abs(y) < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") struct : ConfigurableGroup{ - O2_DEFINE_CONFIGURABLE(DoV0, bool, true, "Store V0s information") O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") @@ -79,7 +82,6 @@ struct Filter2Prong { } grpV0; struct : ConfigurableGroup{ - O2_DEFINE_CONFIGURABLE(DoPhi, bool, false, "Store Phi information") O2_DEFINE_CONFIGURABLE(ImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)") O2_DEFINE_CONFIGURABLE(ImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)") O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") @@ -293,8 +295,8 @@ struct Filter2Prong { return true; } - template - bool isSelectedV0AsLambda(Collision const& collision, const V0Cand& v0, int pid /*0: lambda, 1: antilambda*/) + template + bool isSelectedV0AsLambda(Collision const& collision, const V0Cand& v0) { const auto& posTrack = v0.template posTrack_as(); const auto& negTrack = v0.template negTrack_as(); @@ -314,18 +316,19 @@ struct Filter2Prong { if (v0.dcaV0daughters() > grpV0.dcaV0DaughtersMaxLambda) { return false; } - if (pid == 0 && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPr || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPiLambda)) { - return false; - } - if (pid == 1 && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiLambda || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPr)) { + if (pid == LambdaPid::kLambda && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPr || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPiLambda)) { return false; } - if (pid == 0 && ((std::abs(posTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts))) { - return false; - } - if (pid == 1 && ((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts))) { + if (pid == LambdaPid::kAntiLambda && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiLambda || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPr)) { return false; } + if (pid == LambdaPid::kLambda && ((std::abs(posTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts))) + { + return false; + } + if (pid == LambdaPid::kAntiLambda && ((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts))) { + return false; + } if (std::abs(CtauLambda) > grpV0.maxLambdaLifeTime) { return false; } @@ -369,7 +372,7 @@ struct Filter2Prong { } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { return true; } - } else if (!cfgMomDepPID) { + } else { if (!candidate.hasTOF() && TMath::Abs(candidate.tpcNSigmaKa()) < grpPhi.nsigmaCutTPC) { return true; } else if (candidate.hasTOF() && TMath::Sqrt(candidate.tpcNSigmaKa() * candidate.tpcNSigmaKa() + candidate.tofNSigmaKa() * candidate.tofNSigmaKa()) < grpPhi.nsigmaCutTOF && candidate.beta() > grpPhi.cutTOFBeta) { @@ -413,105 +416,111 @@ struct Filter2Prong { PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. - void processDataPhiV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks, aod::V0Datas const& V0s) + void processDataV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks, aod::V0Datas const& V0s) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + + o2::aod::ITSResponse itsResponse; + + for (const auto& v0 : V0s) { // Loop over V0 candidates + if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs + continue; + } + + const auto& posTrack = v0.template posTrack_as(); + const auto& negTrack = v0.template negTrack_as(); + double massV0 = 0.0; + + // K0s + if (isSelectedV0AsK0s(collision, v0)) { // candidate is K0s + output2ProngTracks(cfcollisions.begin().globalIndex(), + posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPi); + } + + // Lambda and Anti-Lambda + bool LambdaTag = isSelectedV0AsLambda(collision, v0); + bool aLambdaTag = isSelectedV0AsLambda(collision, v0); + + // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) + if (LambdaTag) { // candidate is Lambda + massV0 = v0.mLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdatoPPi); + } + if (aLambdaTag) { // candidate is Anti-lambda + massV0 = v0.mAntiLambda(); + output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), + v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdatoPiP); + } // end of Lambda and Anti-Lambda processing + } // end of loop over V0 candidates + } + PROCESS_SWITCH(Filter2Prong, processDataV0, "Process data V0 candidates with invariant mass method", false); + + // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. + void processDataPhi(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) return; // rejected collision o2::aod::ITSResponse itsResponse; - if (grpPhi.DoPhi) { // Process Phi mesons - for (const auto& cftrack1 : cftracks) { // Loop over first track - const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); - if (p1.sign() != 1) { + for (const auto& cftrack1 : cftracks) { // Loop over first track + const auto& p1 = tracks.iteratorAt(cftrack1.trackId() - tracks.begin().globalIndex()); + if (p1.sign() != 1) { + continue; + } + if (!selectionTrack(p1)) { + continue; + } + if (grpPhi.ITSPIDSelection && p1.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition + continue; + } + if (!selectionPID(p1)) { + continue; + } + if (grpPhi.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon + continue; + } + + for (const auto& cftrack2 : cftracks) { // Loop over second track + if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one continue; - } - if (!selectionTrack(p1)) { + + const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); + if (p2.sign() != -1) { continue; } - if (grpPhi.ITSPIDSelection && p1.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p1) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p1) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition + if (!selectionTrack(p2)) { continue; } - if (!selectionPID(p1)) { + if (!selectionPID(p2)) { continue; } - if (grpPhi.removefaketrack && isFakeTrack(p1)) { // Check if the track is a fake kaon + if (grpPhi.ITSPIDSelection && p2.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition continue; } - - for (const auto& cftrack2 : cftracks) { // Loop over second track - if (cftrack2.globalIndex() == cftrack1.globalIndex()) // Skip if it's the same track as the first one - continue; - - const auto& p2 = tracks.iteratorAt(cftrack2.trackId() - tracks.begin().globalIndex()); - if (p2.sign() != -1) { - continue; - } - if (!selectionTrack(p2)) { - continue; - } - if (!selectionPID(p2)) { - continue; - } - if (grpPhi.ITSPIDSelection && p2.p() < grpPhi.ITSPIDPthreshold.value && !(itsResponse.nSigmaITS(p2) > grpPhi.lowITSPIDNsigma.value && itsResponse.nSigmaITS(p2) < grpPhi.highITSPIDNsigma.value)) { // Check ITS PID condition - continue; - } - if (grpPhi.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon - continue; - } - if (!selectionPair(p1, p2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); - ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); - ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; - if (s.M() < grpPhi.ImMinInvMassPhiMeson || s.M() > grpPhi.ImMaxInvMassPhiMeson) { - continue; - } - float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); - output2ProngTracks(cfcollisions.begin().globalIndex(), - cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKK); - } // end of loop over second track - } // end of loop over first track - } // end of processing Phi mesons - - if (grpV0.DoV0) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas) - for (const auto& v0 : V0s) { // Loop over V0 candidates - if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs + if (grpPhi.removefaketrack && isFakeTrack(p2)) { // Check if the track is a fake kaon continue; } - - const auto& posTrack = v0.template posTrack_as(); - const auto& negTrack = v0.template negTrack_as(); - double massV0 = 0.0; - - // K0s - if (isSelectedV0AsK0s(collision, v0)) { // candidate is K0s - output2ProngTracks(cfcollisions.begin().globalIndex(), - posTrack.globalIndex(), negTrack.globalIndex(), - v0.pt(), v0.eta(), v0.phi(), v0.mK0Short(), aod::cf2prongtrack::K0stoPiPi); + if (!selectionPair(p1, p2)) { + continue; } - // Lambda and Anti-Lambda - bool LambdaTag = isSelectedV0AsLambda(collision, v0, 0); - bool aLambdaTag = isSelectedV0AsLambda(collision, v0, 1); - - // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis) - if (LambdaTag) { // candidate is Lambda - massV0 = v0.mLambda(); - output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), - v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::LambdatoPPi); + ROOT::Math::PtEtaPhiMVector vec1(p1.pt(), p1.eta(), p1.phi(), cfgImPart1Mass); + ROOT::Math::PtEtaPhiMVector vec2(p2.pt(), p2.eta(), p2.phi(), cfgImPart2Mass); + ROOT::Math::PtEtaPhiMVector s = vec1 + vec2; + if (s.M() < grpPhi.ImMinInvMassPhiMeson || s.M() > grpPhi.ImMaxInvMassPhiMeson) { + continue; } - if (aLambdaTag) { // candidate is Anti-lambda - massV0 = v0.mAntiLambda(); - output2ProngTracks(cfcollisions.begin().globalIndex(), posTrack.globalIndex(), negTrack.globalIndex(), - v0.pt(), v0.eta(), v0.phi(), massV0, aod::cf2prongtrack::AntiLambdatoPiP); - } // end of Lambda and Anti-Lambda processing - } // end of loop over V0 candidates - } // end of processing V0 candidates + float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); + output2ProngTracks(cfcollisions.begin().globalIndex(), + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKK); + } // end of loop over second track + } // end of loop over first track } - PROCESS_SWITCH(Filter2Prong, processDataPhiV0, "Process data PhiV0 candidates with invariant mass method", false); + PROCESS_SWITCH(Filter2Prong, processDataPhi, "Process data Phi candidates with invariant mass method", false); }; // struct diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 51b87fe3b2f..2191370a09a 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -165,8 +165,7 @@ struct FilterCF { if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFProton) { return true; } - } - if (!candidate.hasTOF()) { + } else { if (std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { return true; } @@ -210,16 +209,10 @@ struct FilterCF { return trackType; } else if (cfgTrackSelection == 2) { uint8_t trackType = 0; - if (track.isGlobalTrack()) { - if (track.itsNCls() >= itsnclusters) { - if (track.tpcNClsCrossedRows() >= tpcncrossedrows) { - if constexpr (HasProtonPID::value) { - if (selectionPIDProton(track)) { - trackType |= kPIDProton; - } - } + if constexpr (HasProtonPID::value) { + if (track.isGlobalTrack() && (track.itsNCls() >= itsnclusters) && (track.tpcNClsCrossedRows() >= tpcncrossedrows) && selectionPIDProton(track)) { + trackType |= kPIDProton; } - } } return trackType; } @@ -275,13 +268,18 @@ struct FilterCF { } PROCESS_SWITCH(FilterCF, processDataPid, "Process data with PID", false); - // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions - Preslice perMcCollision = aod::mcparticle::mcCollisionId; - Preslice perCollision = aod::track::collisionId; - void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, - soa::Join const& allCollisions, - soa::Filtered> const& tracks, - aod::BCsWithTimestamps const&) + /// \brief Process MC data for a given set of MC collisions and associated particles and tracks + /// \param mcCollisions The collection of MC collisions + /// \param allParticles The collection of all MC particles + /// \param allCollisions The collection of all collisions, joined with MC collision labels and + /// event selections + /// \param tracks The collection of tracks, filtered by selection criteria + /// \param bcs The collection of bunch crossings with timestamps + template + void processMCT(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + soa::Join const& allCollisions, + T1 const& tracks, + aod::BCsWithTimestamps const&) { mcReconstructedCache.reserve(allParticles.size()); mcParticleLabelsCache.reserve(allParticles.size()); @@ -389,8 +387,29 @@ struct FilterCF { } } } + + // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions + Preslice perMcCollision = aod::mcparticle::mcCollisionId; + Preslice perCollision = aod::track::collisionId; + void processMC(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + soa::Join const& allCollisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const& bcs) + { + processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); + } PROCESS_SWITCH(FilterCF, processMC, "Process MC", false); + // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions + void processMCPid(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, + soa::Join const& allCollisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const& bcs) + { + processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); + } + PROCESS_SWITCH(FilterCF, processMCPid, "Process MC with PID", false); + void processMCGen(aod::McCollisions::iterator const& mcCollision, aod::McParticles const& particles) { float multiplicity = 0.0f; From 52e29628342e8926d675620a457b15d09b9f1548 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Mon, 7 Jul 2025 13:57:33 +0000 Subject: [PATCH 12/13] Please consider the following formatting changes --- PWGCF/TableProducer/filter2Prong.cxx | 101 ++++++++++----------- PWGCF/TableProducer/filterCorrelations.cxx | 18 ++-- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 63c88e52c63..1cb86cd121a 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -38,7 +38,7 @@ using namespace o2::math_utils::detail; enum LambdaPid { kLambda = 0, kAntiLambda - }; +}; // #define FLOAT_PRECISION 0xFFFFFFF0 #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; @@ -57,51 +57,49 @@ struct Filter2Prong { O2_DEFINE_CONFIGURABLE(cfgImSigmaFormula, std::string, "(z < 0.5 && abs(x) < 3.0) || (z >= 0.5 && abs(x) < 2.5 && abs(y) < 3.0)", "pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)") struct : ConfigurableGroup{ - O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") - O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") - O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") - O2_DEFINE_CONFIGURABLE(minV0DCAPr, float, 0.1, "Min V0 proton DCA") - O2_DEFINE_CONFIGURABLE(minV0DCAPiLambda, float, 0.1, "Min V0 pion DCA for lambda") - O2_DEFINE_CONFIGURABLE(minV0DCAPiK0s, float, 0.1, "Min V0 pion DCA for K0s") - O2_DEFINE_CONFIGURABLE(daughPIDCuts, float, 4.0, "PID nsigma for V0s") - O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") - O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") - O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") - O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") - O2_DEFINE_CONFIGURABLE(radiusMaxLambda, float, 2.3, "Maximum decay radius (cm) for lambda") - O2_DEFINE_CONFIGURABLE(radiusMinLambda, float, 0.0, "Minimum decay radius (cm) for lambda") - O2_DEFINE_CONFIGURABLE(radiusMaxK0s, float, 2.3, "Maximum decay radius (cm) for K0s") - O2_DEFINE_CONFIGURABLE(radiusMinK0s, float, 0.0, "Minimum decay radius (cm) for K0s") - O2_DEFINE_CONFIGURABLE(cosPaMinLambda, float, 0.98, "Minimum cosine of pointing angle for lambda") - O2_DEFINE_CONFIGURABLE(cosPaMinK0s, float, 0.98, "Minimum cosine of pointing angle for K0s") - O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxLambda, float, 0.2, "Maximum DCA among the V0 daughters (cm) for lambda") - O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxK0s, float, 0.2, "Maximum DCA among the V0 daughters (cm) for K0s") - O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0s, float, 0.12, "Minimum Armenteros' qt for K0s") - O2_DEFINE_CONFIGURABLE(maxLambdaLifeTime, float, 30, "Maximum lambda lifetime (in cm)") - O2_DEFINE_CONFIGURABLE(maxK0sLifeTime, float, 30, "Maximum K0s lifetime (in cm)") - } grpV0; - + O2_DEFINE_CONFIGURABLE(tpcNClsCrossedRowsTrackMin, float, 70, "Minimum number of crossed rows in TPC") + O2_DEFINE_CONFIGURABLE(etaTrackMax, float, 0.8, "Maximum pseudorapidity") + O2_DEFINE_CONFIGURABLE(ptTrackMin, float, 0.1, "Minimum transverse momentum") + O2_DEFINE_CONFIGURABLE(minV0DCAPr, float, 0.1, "Min V0 proton DCA") + O2_DEFINE_CONFIGURABLE(minV0DCAPiLambda, float, 0.1, "Min V0 pion DCA for lambda") + O2_DEFINE_CONFIGURABLE(minV0DCAPiK0s, float, 0.1, "Min V0 pion DCA for K0s") + O2_DEFINE_CONFIGURABLE(daughPIDCuts, float, 4.0, "PID nsigma for V0s") + O2_DEFINE_CONFIGURABLE(massK0Min, float, 0.4, "Minimum mass for K0") + O2_DEFINE_CONFIGURABLE(massK0Max, float, 0.6, "Maximum mass for K0") + O2_DEFINE_CONFIGURABLE(massLambdaMin, float, 1.0, "Minimum mass for lambda") + O2_DEFINE_CONFIGURABLE(massLambdaMax, float, 1.3, "Maximum mass for lambda") + O2_DEFINE_CONFIGURABLE(radiusMaxLambda, float, 2.3, "Maximum decay radius (cm) for lambda") + O2_DEFINE_CONFIGURABLE(radiusMinLambda, float, 0.0, "Minimum decay radius (cm) for lambda") + O2_DEFINE_CONFIGURABLE(radiusMaxK0s, float, 2.3, "Maximum decay radius (cm) for K0s") + O2_DEFINE_CONFIGURABLE(radiusMinK0s, float, 0.0, "Minimum decay radius (cm) for K0s") + O2_DEFINE_CONFIGURABLE(cosPaMinLambda, float, 0.98, "Minimum cosine of pointing angle for lambda") + O2_DEFINE_CONFIGURABLE(cosPaMinK0s, float, 0.98, "Minimum cosine of pointing angle for K0s") + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxLambda, float, 0.2, "Maximum DCA among the V0 daughters (cm) for lambda") + O2_DEFINE_CONFIGURABLE(dcaV0DaughtersMaxK0s, float, 0.2, "Maximum DCA among the V0 daughters (cm) for K0s") + O2_DEFINE_CONFIGURABLE(qtArmenterosMinForK0s, float, 0.12, "Minimum Armenteros' qt for K0s") + O2_DEFINE_CONFIGURABLE(maxLambdaLifeTime, float, 30, "Maximum lambda lifetime (in cm)") + O2_DEFINE_CONFIGURABLE(maxK0sLifeTime, float, 30, "Maximum K0s lifetime (in cm)")} grpV0; + struct : ConfigurableGroup{ - O2_DEFINE_CONFIGURABLE(ImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)") - O2_DEFINE_CONFIGURABLE(ImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)") - O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") - O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") - O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") - O2_DEFINE_CONFIGURABLE(ITSclusterPhiMeson, int, 5, "Minimum number of ITS cluster for phi meson track") - O2_DEFINE_CONFIGURABLE(TPCCrossedRowsPhiMeson, int, 80, "Minimum number of TPC Crossed Rows for phi meson track") - O2_DEFINE_CONFIGURABLE(cutDCAxyPhiMeson, float, 0.1, "Maximum DCAxy for phi meson track") - O2_DEFINE_CONFIGURABLE(cutDCAzPhiMeson, float, 0.1, "Maximum DCAz for phi meson track") - O2_DEFINE_CONFIGURABLE(cutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track") - O2_DEFINE_CONFIGURABLE(cutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track") - O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "Flag for applying deep angle") - O2_DEFINE_CONFIGURABLE(deepAngle, float, 0.04, "Deep angle cut") - O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") - O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") - O2_DEFINE_CONFIGURABLE(cutTOFBeta, float, 0.5, "TOF beta") - O2_DEFINE_CONFIGURABLE(confFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") - O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "Flag to remove fake kaon") - } grpPhi; + O2_DEFINE_CONFIGURABLE(ImMinInvMassPhiMeson, float, 0.98f, "Minimum invariant mass Phi meson (GeV)") + O2_DEFINE_CONFIGURABLE(ImMaxInvMassPhiMeson, float, 1.07f, "Maximum invariant mass Phi meson (GeV)") + O2_DEFINE_CONFIGURABLE(ITSPIDSelection, bool, true, "PID ITS") + O2_DEFINE_CONFIGURABLE(ITSPIDPthreshold, float, 1.0, "Momentum threshold for ITS PID (GeV/c) (only used if ITSPIDSelection is true)") + O2_DEFINE_CONFIGURABLE(lowITSPIDNsigma, float, 3.0, "lower cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(highITSPIDNsigma, float, 3.0, "higher cut on PID nsigma for ITS") + O2_DEFINE_CONFIGURABLE(ITSclusterPhiMeson, int, 5, "Minimum number of ITS cluster for phi meson track") + O2_DEFINE_CONFIGURABLE(TPCCrossedRowsPhiMeson, int, 80, "Minimum number of TPC Crossed Rows for phi meson track") + O2_DEFINE_CONFIGURABLE(cutDCAxyPhiMeson, float, 0.1, "Maximum DCAxy for phi meson track") + O2_DEFINE_CONFIGURABLE(cutDCAzPhiMeson, float, 0.1, "Maximum DCAz for phi meson track") + O2_DEFINE_CONFIGURABLE(cutEtaPhiMeson, float, 0.8, "Maximum eta for phi meson track") + O2_DEFINE_CONFIGURABLE(cutPTPhiMeson, float, 0.15, "Maximum pt for phi meson track") + O2_DEFINE_CONFIGURABLE(isDeepAngle, bool, true, "Flag for applying deep angle") + O2_DEFINE_CONFIGURABLE(deepAngle, float, 0.04, "Deep angle cut") + O2_DEFINE_CONFIGURABLE(nsigmaCutTPC, float, 2.5, "nsigma tpc") + O2_DEFINE_CONFIGURABLE(nsigmaCutTOF, float, 2.5, "nsigma tof") + O2_DEFINE_CONFIGURABLE(cutTOFBeta, float, 0.5, "TOF beta") + O2_DEFINE_CONFIGURABLE(confFakeKaonCut, float, 0.15, "Cut based on track from momentum difference") + O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "Flag to remove fake kaon")} grpPhi; HfHelper hfHelper; Produces output2ProngTracks; @@ -322,13 +320,12 @@ struct Filter2Prong { if (pid == LambdaPid::kAntiLambda && (TMath::Abs(v0.dcapostopv()) < grpV0.minV0DCAPiLambda || TMath::Abs(v0.dcanegtopv()) < grpV0.minV0DCAPr)) { return false; } - if (pid == LambdaPid::kLambda && ((std::abs(posTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts))) - { - return false; - } + if (pid == LambdaPid::kLambda && ((std::abs(posTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts))) { + return false; + } if (pid == LambdaPid::kAntiLambda && ((std::abs(posTrack.tpcNSigmaPi()) > grpV0.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > grpV0.daughPIDCuts))) { - return false; - } + return false; + } if (std::abs(CtauLambda) > grpV0.maxLambdaLifeTime) { return false; } @@ -516,7 +513,7 @@ struct Filter2Prong { } float phi = RecoDecay::constrainAngle(s.Phi(), 0.0f); output2ProngTracks(cfcollisions.begin().globalIndex(), - cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKK); + cftrack1.globalIndex(), cftrack2.globalIndex(), s.pt(), s.eta(), phi, s.M(), aod::cf2prongtrack::PhiToKK); } // end of loop over second track } // end of loop over first track } diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 2191370a09a..572e4c6c886 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -91,7 +91,7 @@ struct FilterCF { // TODO how to have this in the second task? For now they are copied Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt); - Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); + Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); Filter mcCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; @@ -172,7 +172,7 @@ struct FilterCF { } return false; } - + template struct HasProtonPID : std::false_type { }; @@ -211,13 +211,12 @@ struct FilterCF { uint8_t trackType = 0; if constexpr (HasProtonPID::value) { if (track.isGlobalTrack() && (track.itsNCls() >= itsnclusters) && (track.tpcNClsCrossedRows() >= tpcncrossedrows) && selectionPIDProton(track)) { - trackType |= kPIDProton; - } + trackType |= kPIDProton; + } } return trackType; } - LOGF(fatal, "Invalid setting for cfgTrackSelection: %d", cfgTrackSelection.value); return 0; } @@ -246,7 +245,6 @@ struct FilterCF { continue; } - outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); if (cfgTransientTables) outputTrackRefs(collision.globalIndex(), track.globalIndex()); @@ -402,9 +400,9 @@ struct FilterCF { // NOTE not filtering collisions here because in that case there can be tracks referring to MC particles which are not part of the selected MC collisions void processMCPid(aod::McCollisions const& mcCollisions, aod::McParticles const& allParticles, - soa::Join const& allCollisions, - soa::Filtered> const& tracks, - aod::BCsWithTimestamps const& bcs) + soa::Join const& allCollisions, + soa::Filtered> const& tracks, + aod::BCsWithTimestamps const& bcs) { processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); } @@ -437,7 +435,7 @@ struct MultiplicitySelector { O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt); - Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); + Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); void init(InitContext&) { From 0937d757ef62652176169ce09dbbd639240bf525 Mon Sep 17 00:00:00 2001 From: spolitan Date: Mon, 7 Jul 2025 18:47:10 +0200 Subject: [PATCH 13/13] fixing unused variable issue --- PWGCF/TableProducer/filter2Prong.cxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx index 1cb86cd121a..105d4d25871 100644 --- a/PWGCF/TableProducer/filter2Prong.cxx +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -413,13 +413,11 @@ struct Filter2Prong { PROCESS_SWITCH(Filter2Prong, processDataInvMass, "Process data generic 2-prong candidates with invariant mass method", false); // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. - void processDataV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks, aod::V0Datas const& V0s) + void processDataV0(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const&, aod::V0Datas const& V0s) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) return; // rejected collision - o2::aod::ITSResponse itsResponse; - for (const auto& v0 : V0s) { // Loop over V0 candidates if (!isV0TrackSelected(v0)) { // Quality selection for V0 prongs continue; @@ -456,7 +454,7 @@ struct Filter2Prong { PROCESS_SWITCH(Filter2Prong, processDataV0, "Process data V0 candidates with invariant mass method", false); // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now. - void processDataPhi(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks) + void processDataPhi(aod::Collisions::iterator const&, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, Filter2Prong::PIDTrack const& tracks) { if (cfcollisions.size() <= 0 || cftracks.size() <= 0) return; // rejected collision