diff --git a/PWGHF/HFC/DataModel/CorrelationTables.h b/PWGHF/HFC/DataModel/CorrelationTables.h index 9b2f725515a..02ffed0b9c4 100644 --- a/PWGHF/HFC/DataModel/CorrelationTables.h +++ b/PWGHF/HFC/DataModel/CorrelationTables.h @@ -227,6 +227,7 @@ DECLARE_SOA_COLUMN(PiNsigmTOF, piNsigmTOF, float); //! A DECLARE_SOA_COLUMN(MCandHadron, mCandHadron, float); //! Invariant mass of Lc/Sc+Hadron combined system DECLARE_SOA_COLUMN(PtCombined, ptCombined, float); //! Transverse momentum of combined Lc+Hadron system DECLARE_SOA_COLUMN(MV0, mV0, float); //! Invariant mass of V0 +DECLARE_SOA_COLUMN(MV0Ref, mV0Ref, float); //! Invariant mass of reflected V0 } // namespace hf_correlation_lc_hadron DECLARE_SOA_TABLE(PtLcFromScHPair, "AOD", "PTLCSCHPAIR", //! Sc-->Lc pT for paired Sc-proton @@ -259,9 +260,9 @@ DECLARE_SOA_TABLE(CandHadronInvMass, "AOD", "CANDHIMASS", //! Lc-Hadron mass aod::hf_correlation_lc_hadron::MCandHadron, aod::hf_correlation_lc_hadron::PtCombined); DECLARE_SOA_TABLE(PairedV0InvMass, "AOD", "PAIRV0IMASS", //! invarient mass of v0 which paired with charm candidates - aod::hf_correlation_lc_hadron::MV0); + aod::hf_correlation_lc_hadron::MV0, aod::hf_correlation_lc_hadron::MV0Ref); DECLARE_SOA_TABLE(V0InvMass, "AOD", "V0IMASS", //! invarient mass of v0 - aod::hf_correlation_lc_hadron::MV0); + aod::hf_correlation_lc_hadron::MV0, aod::hf_correlation_lc_hadron::MV0Ref); DECLARE_SOA_TABLE(LcHadronRecoInfo, "AOD", "LCHRECOINFO", //! Lc-Hadrons pairs Reconstructed Informations aod::hf_correlation_lc_hadron::MLc, diff --git a/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx index 2818dc75f98..6e148bc6c9e 100644 --- a/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorLcScHadrons.cxx @@ -26,6 +26,7 @@ #include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/HFC/Utils/utilsCorrelations.h" #include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/CCDB/EventSelectionParams.h" @@ -63,6 +64,7 @@ #include #include #include +#include #include using namespace o2; @@ -335,6 +337,9 @@ struct HfCorrelatorLcScHadrons { Produces entryPairedV0InvMass; Produces entryV0InvMass; + SliceCache cache; + Service pdg{}; + struct : ConfigurableGroup { Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; @@ -375,34 +380,16 @@ struct HfCorrelatorLcScHadrons { Configurable cfgDaughPrPtMin{"cfgDaughPrPtMin", 0.3, "min. pT Daughter Proton"}; Configurable cfgDaughPiPtMax{"cfgDaughPiPtMax", 10., "max. pT Daughter Pion"}; Configurable cfgDaughPiPtMin{"cfgDaughPiPtMin", 0.3, "min. pT Daughter Pion"}; - Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 3., "max. TPCnSigma Proton"}; - Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 2., "max. TPCnSigma Pion"}; - Configurable cfgDaughPIDCutsTOFPi{"cfgDaughPIDCutsTOFPi", 2., "max. TOFnSigma Pion"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 2.5, "max. TPCnSigma Proton"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 2.5, "max. TPCnSigma Pion"}; + Configurable cfgDaughPIDCutsTOFPi{"cfgDaughPIDCutsTOFPi", 2.5, "max. TOFnSigma Pion"}; + Configurable cfgDaughPIDCutsTOFPr{"cfgDaughPIDCutsTOFPr", 2.5, "max. TOFnSigma Pion"}; Configurable cfgHypMassWindow{"cfgHypMassWindow", 0.1, "single lambda mass selection"}; Configurable cfgIsCorrCollMatchV0{"cfgIsCorrCollMatchV0", true, "check if daughter and mother collision are same"}; Configurable cfgCalDataDrivenEffPr{"cfgCalDataDrivenEffPr", false, "calculate data driven efficiency of proton using Lambda"}; + Configurable calEffV0{"calEffV0", false, "calculate lambda0 efficiency"}; } cfgV0; - SliceCache cache; - Service pdg{}; - int8_t chargeCand = 3; - int8_t signSoftPion = 0; - int leadingIndex = 0; - int poolBin = 0; - int poolBinLc = 0; - bool correlationStatus = false; - bool isPrompt = false; - bool isNonPrompt = false; - bool isSignal = false; - static constexpr int8_t ChargeScPlusPlus{2}; - static constexpr int8_t ChargeZero{0}; - static constexpr int8_t AssignedChargeSc0{1}; // to distinguish sc0 from anti-sc0, charge set to +1 and -1 - - TRandom3* rnd = new TRandom3(0); - // std::vector outputMl = {-1., -1., -1.}; - std::vector outputMlPKPi = {-1., -1., -1.}; - std::vector outputMlPiKP = {-1., -1., -1.}; - // Event Mixing for the Data Mode // using SelCollisionsWithSc = soa::Join; using SelCollisions = soa::Filtered>; @@ -424,6 +411,9 @@ struct HfCorrelatorLcScHadrons { using TracksData = soa::Filtered>; // trackFilter applied using TracksWithMc = soa::Filtered>; // trackFilter applied + template + using HasStrangeTOFinV0 = decltype(std::declval().tofNSigmaLaPr()); + // Filters for ME Filter collisionFilter = aod::hf_selection_lc_collision::lcSel == true; Filter lcFilter = ((o2::aod::hf_track_index::hfflag & static_cast(1 << aod::hf_cand_3prong::DecayType::LcToPKPi)) != static_cast(0)) && (aod::hf_sel_candidate_lc::isSelLcToPKPi >= cfgCharmCand.selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= cfgCharmCand.selectionFlagLc); @@ -447,8 +437,24 @@ struct HfCorrelatorLcScHadrons { ConfigurableAxis binsNSigmas{"binsNSigmas", {4000, -500., 500.}, "n#sigma"}; BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; - HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + int8_t chargeCand = 3; + int8_t signSoftPion = 0; + int leadingIndex = 0; + int poolBin = 0; + int poolBinLc = 0; + bool correlationStatus = false; + bool isPrompt = false; + bool isNonPrompt = false; + bool isSignal = false; + static constexpr int8_t ChargeScPlusPlus{2}; + static constexpr int8_t ChargeZero{0}; + static constexpr int8_t AssignedChargeSc0{1}; // to distinguish sc0 from anti-sc0, charge set to +1 and -1 + TRandom3 rnd{0}; + std::vector outputMlPKPi = {-1., -1., -1.}; + std::vector outputMlPiKP = {-1., -1., -1.}; + void init(InitContext&) { AxisSpec axisCandMass = {binsCandMass, "inv. mass (p K #pi) (GeV/#it{c}^{2})"}; @@ -576,31 +582,64 @@ struct HfCorrelatorLcScHadrons { return y; } - template - bool isSelectedV0Daughter(T const& track, int pid) + template + bool isSelectedV0Daughter(Tracktype const& track, V0Type v0, int pid) { - // if (!track.isGlobalTrackWoDCA()) - // return false; - if (std::abs(pid) == kProton && std::abs(track.tpcNSigmaPr()) > cfgV0.cfgDaughPIDCutsTPCPr) { - return false; - } - if (std::abs(pid) == kPiPlus && (std::abs(track.tpcNSigmaPi()) > cfgV0.cfgDaughPIDCutsTPCPi || std::abs(track.tofNSigmaPi()) > cfgV0.cfgDaughPIDCutsTOFPi)) { - return false; - } if (std::abs(track.eta()) > cfgCharmCand.etaTrackMax) { return false; } - if (std::abs(pid) == kProton && track.pt() > cfgV0.cfgDaughPrPtMax) { - return false; - } - if (std::abs(pid) == kProton && track.pt() < cfgV0.cfgDaughPrPtMin) { - return false; - } - if (std::abs(pid) == kPiPlus && track.pt() > cfgV0.cfgDaughPiPtMax) { - return false; + // --------------------------------------------------------- + // 1. Proton PID Selection + // --------------------------------------------------------- + if (std::abs(pid) == kProton) { + bool passTOF = false; + + if (track.pt() > cfgV0.cfgDaughPrPtMax || track.pt() < cfgV0.cfgDaughPrPtMin) { + return false; + } + if (track.hasTOF()) { + if constexpr (std::experimental::is_detected::value) { + // pid > 0: Proton from Lambda (LaPr) + // pid < 0: Antiproton from Anti-Lambda (ALaPr) + double strangeTOF = (pid > 0) ? v0.tofNSigmaLaPr() : v0.tofNSigmaALaPr(); + passTOF = std::abs(strangeTOF) > cfgV0.cfgDaughPIDCutsTOFPr; + } else { + // if strange TOF is unavailable + passTOF = std::abs(track.tofNSigmaPr()) > cfgV0.cfgDaughPIDCutsTOFPr; + } + } + + if ((std::abs(track.tpcNSigmaPr()) > cfgV0.cfgDaughPIDCutsTPCPr) || passTOF) { + return false; + } } - if (std::abs(pid) == kPiPlus && track.pt() < cfgV0.cfgDaughPiPtMin) { - return false; + + // --------------------------------------------------------- + // 2. Pion PID Selection + // --------------------------------------------------------- + if (std::abs(pid) == kPiPlus) { + bool passTOF = false; + + if (track.pt() > cfgV0.cfgDaughPiPtMax || track.pt() < cfgV0.cfgDaughPiPtMin) { + return false; + } + + if (track.hasTOF()) { + if constexpr (std::experimental::is_detected::value) { + // A pion can belong to either a Lambda/Anti-Lambda decay or a K0s decay. + // We evaluate both applicable hypotheses based on charge sign and pick the best match. + double tofLa = (pid > 0) ? v0.tofNSigmaALaPi() : v0.tofNSigmaLaPi(); + + passTOF = tofLa > cfgV0.cfgDaughPIDCutsTOFPi; + } else { + // Fallback to standard track TOF + passTOF = std::abs(track.tofNSigmaPi()) > cfgV0.cfgDaughPIDCutsTOFPi; + } + } + + if ((std::abs(track.tpcNSigmaPi()) > cfgV0.cfgDaughPIDCutsTPCPi) || passTOF) { + return false; + } } return true; @@ -628,92 +667,6 @@ struct HfCorrelatorLcScHadrons { template void fillV0HistogramsWithLc(CollisionType const& collision, V0 const& v0s, TrackType const& tracks, CandsLcType const& candidates, aod::McParticles const* mcParticles = nullptr) { - if (cfgV0.cfgCalDataDrivenEffPr) { - for (const auto& v0 : v0s) { - auto posTrackV0 = v0.template posTrack_as(); - auto negTrackV0 = v0.template negTrack_as(); - if (cfgV0.cfgIsCorrCollMatchV0 && ((v0.collisionId() != posTrackV0.collisionId()) || (v0.collisionId() != negTrackV0.collisionId()))) { - continue; - } - - if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { - entryHadron(v0.mLambda(), posTrackV0.eta(), posTrackV0.pt() * posTrackV0.sign(), 0, 0, v0.pt()); - entryTrkPID(posTrackV0.tpcNSigmaPr(), posTrackV0.tpcNSigmaKa(), posTrackV0.tpcNSigmaPi(), posTrackV0.tofNSigmaPr(), posTrackV0.tofNSigmaKa(), posTrackV0.tofNSigmaPi()); - - if (isSelectedV0Daughter(posTrackV0, kProton) && isSelectedV0Daughter(negTrackV0, kPiPlus)) { - registry.fill(HIST("hV0Lambda"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - registry.fill(HIST("hV0LambdaRefl"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - - registry.fill(HIST("hTPCnSigmaPr"), posTrackV0.pt(), posTrackV0.tpcNSigmaPr()); - if (posTrackV0.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPr"), posTrackV0.pt(), posTrackV0.tofNSigmaPr()); - } - - if (passPIDSelection(posTrackV0, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRej"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - - registry.fill(HIST("hTPCnSigmaPrPiKRej"), posTrackV0.pt(), posTrackV0.tpcNSigmaPr()); - if (posTrackV0.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPrPiKRej"), posTrackV0.pt(), posTrackV0.tofNSigmaPr()); - } - } - } - } - if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { - entryHadron(v0.mAntiLambda(), negTrackV0.eta(), negTrackV0.pt() * negTrackV0.sign(), 0, 0, v0.pt()); - entryTrkPID(negTrackV0.tpcNSigmaPr(), negTrackV0.tpcNSigmaKa(), negTrackV0.tpcNSigmaPi(), negTrackV0.tofNSigmaPr(), negTrackV0.tofNSigmaKa(), negTrackV0.tofNSigmaPi()); - - if (isSelectedV0Daughter(negTrackV0, kProton) && isSelectedV0Daughter(posTrackV0, kPiPlus)) { - registry.fill(HIST("hV0Lambda"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - registry.fill(HIST("hV0LambdaRefl"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - - registry.fill(HIST("hTPCnSigmaPr"), negTrackV0.pt(), negTrackV0.tpcNSigmaPr()); - if (negTrackV0.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPr"), negTrackV0.pt(), negTrackV0.tofNSigmaPr()); - } - if (passPIDSelection(negTrackV0, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRej"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - - registry.fill(HIST("hTPCnSigmaPrPiKRej"), negTrackV0.pt(), negTrackV0.tpcNSigmaPr()); - if (negTrackV0.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPrPiKRej"), negTrackV0.pt(), negTrackV0.tofNSigmaPr()); - } - } - } - } - if constexpr (IsMcRec) { - if (!v0.has_mcParticle() || !posTrackV0.has_mcParticle() || !negTrackV0.has_mcParticle()) { - continue; - } - auto v0Mc = v0.mcParticle(); - auto posTrack = posTrackV0.mcParticle(); - auto negTrack = negTrackV0.mcParticle(); - - if (std::abs(v0Mc.pdgCode()) == kLambda0) { - if (std::abs(posTrack.pdgCode()) == kProton) { - registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - - if (passPIDSelection(posTrackV0, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - } - } - if (std::abs(negTrack.pdgCode()) == kProton) { - registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - - if (passPIDSelection(negTrackV0, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), negTrackV0.pt()); - registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mLambda(), v0.pt(), posTrackV0.pt()); - } - } - } - } - } - } int nTracks = 0; float efficiencyWeightCand = 1.; @@ -726,7 +679,7 @@ struct HfCorrelatorLcScHadrons { } if (cfgCharmCand.eventFractionToAnalyze > 0) { - if (rnd->Uniform(0, 1) > cfgCharmCand.eventFractionToAnalyze) { + if (rnd.Uniform(0, 1) > cfgCharmCand.eventFractionToAnalyze) { skipMixedEventTableFilling = true; } } @@ -878,7 +831,7 @@ struct HfCorrelatorLcScHadrons { // Process Lambda (proton-pion) if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { - if (isSelectedV0Daughter(posTrackV0, kProton) && isSelectedV0Daughter(negTrackV0, kPiPlus)) { + if (isSelectedV0Daughter(posTrackV0, v0, kProton) && isSelectedV0Daughter(negTrackV0, v0, kPiMinus)) { if (selLcPKPi) { fillCorrelationTable(cfgCharmCand.fillTrkPID, v0, candidate, outputMlPKPi, poolBin, correlationStatus, yCand, chargeCand, 0, massCandPKPi, *mcParticles); @@ -890,7 +843,7 @@ struct HfCorrelatorLcScHadrons { if (countCand == 1) { if (!skipMixedEventTableFilling) { entryHadron(v0.phi(), v0.eta(), v0.pt() * v0Lambda, poolBin, gCollisionId, timeStamp); - entryV0InvMass(v0.mLambda()); + entryV0InvMass(v0.mLambda(), v0.mAntiLambda()); registry.fill(HIST("hTracksBin"), poolBin); } } @@ -899,7 +852,7 @@ struct HfCorrelatorLcScHadrons { // Process anti-Lambda (anti-proton-pion) if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { - if (isSelectedV0Daughter(negTrackV0, kProton) && isSelectedV0Daughter(posTrackV0, kPiPlus)) { + if (isSelectedV0Daughter(negTrackV0, v0, kProtonBar) && isSelectedV0Daughter(posTrackV0, v0, kPiPlus)) { if (selLcPKPi) { fillCorrelationTable(cfgCharmCand.fillTrkPID, v0, candidate, outputMlPKPi, poolBin, correlationStatus, yCand, chargeCand, 0, massCandPKPi, *mcParticles); @@ -910,7 +863,7 @@ struct HfCorrelatorLcScHadrons { if (countCand == 1) { if (!skipMixedEventTableFilling) { entryHadron(v0.phi(), v0.eta(), v0.pt() * v0AntiLambda, poolBin, gCollisionId, timeStamp); - entryV0InvMass(v0.mAntiLambda()); + entryV0InvMass(v0.mAntiLambda(), v0.mLambda()); registry.fill(HIST("hTracksBin"), poolBin); } } @@ -963,6 +916,160 @@ struct HfCorrelatorLcScHadrons { registry.fill(HIST("hPtTracksVsSignGen"), track.pt(), chargeTrack / (std::abs(chargeTrack))); } } + + // ======================================== + // Efficiency calculation block + // ======================================== + template + void fillEffV0(V0 const& v0s, + TrackType const&, + aod::McParticles const& mcParticles) + { + // Data-driven efficiency calculation for protons using Lambda + for (const auto& v0 : v0s) { + auto const& trackV0Pos = v0.template posTrack_as(); + auto const& trackV0Neg = v0.template negTrack_as(); + if (cfgV0.cfgIsCorrCollMatchV0 && ((v0.collisionId() != trackV0Pos.collisionId()) || (v0.collisionId() != trackV0Neg.collisionId()))) { + continue; + } + + // Process Lambda (proton + pion) + if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + entryHadron(v0.mLambda(), trackV0Pos.eta(), trackV0Pos.pt() * trackV0Pos.sign(), 0, 0, v0.pt()); + entryTrkPID(trackV0Pos.tpcNSigmaPr(), trackV0Pos.tpcNSigmaKa(), trackV0Pos.tpcNSigmaPi(), trackV0Pos.tofNSigmaPr(), trackV0Pos.tofNSigmaKa(), trackV0Pos.tofNSigmaPi()); + + if (isSelectedV0Daughter(trackV0Pos, v0, kProton) && isSelectedV0Daughter(trackV0Neg, v0, kPiMinus)) { + registry.fill(HIST("hV0Lambda"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hV0LambdaRefl"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hTPCnSigmaPr"), trackV0Pos.pt(), trackV0Pos.tpcNSigmaPr()); + + if (trackV0Pos.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPr"), trackV0Pos.pt(), trackV0Pos.tofNSigmaPr()); + } + + if (passPIDSelection(trackV0Pos, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRej"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hTPCnSigmaPrPiKRej"), trackV0Pos.pt(), trackV0Pos.tpcNSigmaPr()); + if (trackV0Pos.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPrPiKRej"), trackV0Pos.pt(), trackV0Pos.tofNSigmaPr()); + } + } + } + } + + if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + entryHadron(v0.mAntiLambda(), trackV0Neg.eta(), trackV0Neg.pt() * trackV0Neg.sign(), 0, 0, v0.pt()); + entryTrkPID(trackV0Neg.tpcNSigmaPr(), trackV0Neg.tpcNSigmaKa(), trackV0Neg.tpcNSigmaPi(), trackV0Neg.tofNSigmaPr(), trackV0Neg.tofNSigmaKa(), trackV0Neg.tofNSigmaPi()); + + if (isSelectedV0Daughter(trackV0Neg, v0, kProtonBar) && isSelectedV0Daughter(trackV0Pos, v0, kPiPlus)) { + registry.fill(HIST("hV0Lambda"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hV0LambdaRefl"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hTPCnSigmaPr"), trackV0Neg.pt(), trackV0Neg.tpcNSigmaPr()); + + if (trackV0Neg.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPr"), trackV0Neg.pt(), trackV0Neg.tofNSigmaPr()); + } + + if (passPIDSelection(trackV0Neg, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRej"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hTPCnSigmaPrPiKRej"), trackV0Neg.pt(), trackV0Neg.tpcNSigmaPr()); + if (trackV0Neg.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPrPiKRej"), trackV0Neg.pt(), trackV0Neg.tofNSigmaPr()); + } + } + } + } + + // MC-Reco specific V0 matching + if constexpr (IsMc) { + if (!v0.has_mcParticle() || !trackV0Pos.has_mcParticle() || !trackV0Neg.has_mcParticle()) { + continue; + } + auto const& v0Mc = v0.mcParticle(); + auto const& partV0Pos = trackV0Pos.mcParticle(); + auto const& partV0Neg = trackV0Neg.mcParticle(); + + if (v0Mc.pdgCode() == kLambda0) { + registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + if (cfgV0.calEffV0 && v0Mc.isPhysicalPrimary() && v0Mc.producedByGenerator()) { + registry.fill(HIST("hV0PrimLambdaMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + registry.fill(HIST("hV0PrimLambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + } + + if (passPIDSelection(trackV0Pos, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + } + } + if (v0Mc.pdgCode() == kLambda0Bar) { + registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + + if (cfgV0.calEffV0 && v0Mc.isPhysicalPrimary() && v0Mc.producedByGenerator()) { + registry.fill(HIST("hV0PrimLambdaMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + registry.fill(HIST("hV0PrimLambdaReflMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + } + if (passPIDSelection(trackV0Neg, cfgCharmCand.trkPIDspecies, cfgCharmCand.pidTPCMax, cfgCharmCand.pidTOFMax, cfgCharmCand.tofPIDThreshold, cfgCharmCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + } + } + } + } + + if constexpr (IsMc) { + if (cfgV0.calEffV0) { + + for (const auto& particle : mcParticles) { + + if (std::abs(particle.pdgCode()) != kLambda0) { + continue; + } + + if (std::abs(particle.y()) > cfgCharmCand.yCandMax) { + continue; + } + if (!particle.isPhysicalPrimary() || !particle.producedByGenerator()) { + continue; + } + + auto daughterParts = particle.daughters_as(); + const int8_t nDaughtersV0 = 2; + + if (daughterParts.size() != nDaughtersV0) { + continue; + } + + for (const auto& currentDaughter : daughterParts) { + + if (std::abs(currentDaughter.eta()) > cfgCharmCand.etaTrackMax) { + continue; + } + + if (std::abs(currentDaughter.pdgCode()) == kProton) { + + if (currentDaughter.pt() > cfgV0.cfgDaughPrPtMax || currentDaughter.pt() < cfgV0.cfgDaughPrPtMin) { + continue; + } + + } else if (std::abs(currentDaughter.pdgCode()) == kPiPlus) { + if (currentDaughter.pt() > cfgV0.cfgDaughPiPtMax || currentDaughter.pt() < cfgV0.cfgDaughPiPtMin) { + continue; + } + + } else { + continue; + } + } + registry.fill(HIST("hV0PtPrimLambdaMcGen"), particle.pt()); + } + } + } + } + template void fillCorrelationTable(bool trkPidFill, AssocType const& assoc, CandType const& candidate, const std::vector& outMl, int binPool, int8_t correlStatus, @@ -978,12 +1085,12 @@ struct HfCorrelatorLcScHadrons { if constexpr (LambdaPart == 1) { massCandHadron = calculateInvMass(candidate, assoc, massCand, assoc.mLambda()); - entryPairedV0InvMass(assoc.mLambda()); + entryPairedV0InvMass(assoc.mLambda(), assoc.mAntiLambda()); signAssoc = 1; yAssoc = assoc.yLambda(); } else if constexpr (LambdaPart == -1) { massCandHadron = calculateInvMass(candidate, assoc, massCand, assoc.mAntiLambda()); - entryPairedV0InvMass(assoc.mAntiLambda()); + entryPairedV0InvMass(assoc.mAntiLambda(), assoc.mLambda()); signAssoc = -1; // Note: Ensure signAssoc vs assoc.signAssoc is consistent yAssoc = assoc.yLambda(); } else { @@ -1054,7 +1161,7 @@ struct HfCorrelatorLcScHadrons { } if (cfgCharmCand.eventFractionToAnalyze > 0) { - if (rnd->Uniform(0, 1) > cfgCharmCand.eventFractionToAnalyze) { + if (rnd.Uniform(0, 1) > cfgCharmCand.eventFractionToAnalyze) { skipMixedEventTableFilling = true; } } @@ -1741,7 +1848,7 @@ struct HfCorrelatorLcScHadrons { // Updated processDataLambdaV0 to include Lc candidates void processDataLambdaV0(SelCollisions::iterator const& collision, TracksData const& tracks, - aod::V0Datas const& v0s, + soa::Join const& v0s, CandsLcDataFiltered const& candidates, aod::BCsWithTimestamps const&) { @@ -1751,13 +1858,22 @@ struct HfCorrelatorLcScHadrons { void processMcLambdaV0(SelCollisions::iterator const& collision, TracksWithMc const& tracks, - soa::Join const& v0s, + soa::Join const& v0s, CandsLcMcRecFiltered const& candidates, aod::McParticles const& mcParticles) { fillV0HistogramsWithLc(collision, v0s, tracks, candidates, &mcParticles); } PROCESS_SWITCH(HfCorrelatorLcScHadrons, processMcLambdaV0, "Mc process for v0 lambda with Lc", false); + + void processLambda0EffCal(SelCollisions::iterator const&, + TracksWithMc const& tracks, + soa::Join const& v0s, + aod::McParticles const& mcParticles) + { + fillEffV0(v0s, tracks, mcParticles); + } + PROCESS_SWITCH(HfCorrelatorLcScHadrons, processLambda0EffCal, "Mc process for lambda0", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx index 5a8816ccba5..ba25f043366 100644 --- a/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorXicHadrons.cxx @@ -408,30 +408,22 @@ struct HfCorrelatorXicHadrons { Configurable cfgDaughPrPtMin{"cfgDaughPrPtMin", 0.3f, "min. pT daughter proton"}; Configurable cfgDaughPiPtMax{"cfgDaughPiPtMax", 10.f, "max. pT daughter pion"}; Configurable cfgDaughPiPtMin{"cfgDaughPiPtMin", 0.3f, "min. pT daughter pion"}; - Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 3.f, "max. TPC nSigma proton"}; - Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 2.f, "max. TPC nSigma pion"}; - Configurable cfgDaughPIDCutsTOFPi{"cfgDaughPIDCutsTOFPi", 2.f, "max. TOF nSigma pion"}; + Configurable cfgDaughPIDCutsTPCPr{"cfgDaughPIDCutsTPCPr", 2.5f, "max. TPC nSigma proton"}; + Configurable cfgDaughPIDCutsTPCPi{"cfgDaughPIDCutsTPCPi", 2.5f, "max. TPC nSigma pion"}; + Configurable cfgDaughPIDCutsTOFPi{"cfgDaughPIDCutsTOFPi", 2.5f, "max. TOF nSigma pion"}; + Configurable cfgDaughPIDCutsTOFPr{"cfgDaughPIDCutsTOFPr", 2.5f, "max. TOF nSigma pion"}; Configurable cfgHypMassWindow{"cfgHypMassWindow", 0.1f, "single lambda mass selection"}; Configurable cfgIsCorrCollMatchV0{"cfgIsCorrCollMatchV0", true, "check if daughter and mother collision are same"}; Configurable cfgCalDataDrivenEffPr{"cfgCalDataDrivenEffPr", false, "calculate data driven efficiency of proton using Lambda"}; + Configurable calEffV0{"calEffV0", false, "calculate lambda0 efficiency"}; } cfgV0; SliceCache cache; Service pdg{}; - int8_t chargeCand = 3; - int leadingIndex = 0; - int poolBin = 0; - int poolBinXic = 0; - bool correlationStatus = false; - bool isPrompt = false; - bool isNonPrompt = false; - bool isSignal = false; - TRandom3 rnd{0}; - std::vector outputMlXic = {-1., -1., -1.}; // Event Mixing for the Data Mode using SelCollisions = soa::Filtered>; - using SelCollisionsMc = soa::Filtered>; // collisionFilter applied + using SelCollisionsMc = soa::Filtered>; // XicPlus data using CandsXicPlusData = soa::Join; @@ -452,10 +444,13 @@ struct HfCorrelatorXicHadrons { using McCollisionsSel = soa::Filtered>; using McParticlesSel = soa::Filtered; - // Tracks used in Data and MC + // Tracks using TracksData = soa::Filtered>; using TracksWithMc = soa::Filtered>; + template + using HasStrangeTOFinV0 = decltype(std::declval().tofNSigmaLaPr()); + Filter collisionFilter = aod::hf_selection_lc_collision::lcSel == true; Filter trackFilter = (nabs(aod::track::eta) < cfgXicCand.etaTrackMax) && (nabs(aod::track::pt) > cfgXicCand.ptTrackMin) && (nabs(aod::track::dcaXY) < cfgXicCand.dcaXYTrackMax) && (nabs(aod::track::dcaZ) < cfgXicCand.dcaZTrackMax); Filter xicPlusFilter = aod::hf_sel_candidate_xic::isSelXicToXiPiPi >= cfgXicCand.selectionFlagXic; @@ -480,9 +475,19 @@ struct HfCorrelatorXicHadrons { ConfigurableAxis binsNSigmas{"binsNSigmas", {4000, -500., 500.}, "n#sigma"}; BinningType corrBinning{{binsZVtx, binsMultiplicity}, true}; - HistogramRegistry registry{"registry"}; + int8_t chargeCand = 3; + int leadingIndex = 0; + int poolBin = 0; + int poolBinXic = 0; + bool correlationStatus = false; + bool isPrompt = false; + bool isNonPrompt = false; + bool isSignal = false; + TRandom3 rnd{0}; + std::vector outputMlXic = {-1., -1., -1.}; + void init(InitContext&) { // XicPlus mass axes @@ -588,8 +593,11 @@ struct HfCorrelatorXicHadrons { registry.add("hV0LambdaReflPiKRej", "V0 Lambda reflected candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); registry.add("hV0LambdaMcRec", "McRec V0 Lambda candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); registry.add("hV0LambdaReflMcRec", "McRec V0 Lambda reflected candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0PrimLambdaMcRec", "McRec V0 Lambda candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0PrimLambdaReflMcRec", "McRec V0 Lambda reflected candidates;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); registry.add("hV0LambdaPiKRejMcRec", "McRec V0 Lambda candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); registry.add("hV0LambdaReflPiKRejMcRec", "McRec V0 Lambda reflected candidates with #pi K rejection;inv. mass (p #pi) (GeV/#it{c}^{2});GeV/#it{c};GeV/#it{c}", {HistType::kTH3F, {{axisMassV0}, {axisPtV0}, {axisPtHadron}}}); + registry.add("hV0PtPrimLambdaMcGen", "Mcgen V0 Lambda candidates;GeV/#it{c}", {HistType::kTH1F, {{axisPtV0}}}); corrBinning = {{binsZVtx, binsMultiplicity}, true}; } @@ -624,135 +632,233 @@ struct HfCorrelatorXicHadrons { } } - template - bool isSelectedV0Daughter(T const& track, int pid) + template + bool isSelectedV0Daughter(Tracktype const& track, V0Type v0, int pid) { - if (std::abs(pid) == kProton && std::abs(track.tpcNSigmaPr()) > cfgV0.cfgDaughPIDCutsTPCPr) { - return false; - } - if (std::abs(pid) == kPiPlus && (std::abs(track.tpcNSigmaPi()) > cfgV0.cfgDaughPIDCutsTPCPi || std::abs(track.tofNSigmaPi()) > cfgV0.cfgDaughPIDCutsTOFPi)) { - return false; - } if (std::abs(track.eta()) > cfgXicCand.etaTrackMax) { return false; } - if (std::abs(pid) == kProton && track.pt() > cfgV0.cfgDaughPrPtMax) { - return false; - } - if (std::abs(pid) == kProton && track.pt() < cfgV0.cfgDaughPrPtMin) { - return false; - } - if (std::abs(pid) == kPiPlus && track.pt() > cfgV0.cfgDaughPiPtMax) { - return false; + // --------------------------------------------------------- + // 1. Proton PID Selection + // --------------------------------------------------------- + if (std::abs(pid) == kProton) { + bool passTOF = false; + + if (track.pt() > cfgV0.cfgDaughPrPtMax || track.pt() < cfgV0.cfgDaughPrPtMin) { + return false; + } + if (track.hasTOF()) { + if constexpr (std::experimental::is_detected::value) { + // pid > 0: Proton from Lambda (LaPr) + // pid < 0: Antiproton from Anti-Lambda (ALaPr) + double strangeTOF = (pid > 0) ? v0.tofNSigmaLaPr() : v0.tofNSigmaALaPr(); + passTOF = std::abs(strangeTOF) > cfgV0.cfgDaughPIDCutsTOFPr; + } else { + // if strange TOF is unavailable + passTOF = std::abs(track.tofNSigmaPr()) > cfgV0.cfgDaughPIDCutsTOFPr; + } + } + + if ((std::abs(track.tpcNSigmaPr()) > cfgV0.cfgDaughPIDCutsTPCPr) || passTOF) { + return false; + } } - if (std::abs(pid) == kPiPlus && track.pt() < cfgV0.cfgDaughPiPtMin) { - return false; + + // --------------------------------------------------------- + // 2. Pion PID Selection + // --------------------------------------------------------- + if (std::abs(pid) == kPiPlus) { + bool passTOF = false; + + if (track.pt() > cfgV0.cfgDaughPiPtMax || track.pt() < cfgV0.cfgDaughPiPtMin) { + return false; + } + + if (track.hasTOF()) { + if constexpr (std::experimental::is_detected::value) { + // A pion can belong to either a Lambda/Anti-Lambda decay or a K0s decay. + // We evaluate both applicable hypotheses based on charge sign and pick the best match. + double tofLa = (pid > 0) ? v0.tofNSigmaALaPi() : v0.tofNSigmaLaPi(); + + passTOF = tofLa > cfgV0.cfgDaughPIDCutsTOFPi; + } else { + // Fallback to standard track TOF + passTOF = std::abs(track.tofNSigmaPi()) > cfgV0.cfgDaughPIDCutsTOFPi; + } + } + + if ((std::abs(track.tpcNSigmaPi()) > cfgV0.cfgDaughPIDCutsTPCPi) || passTOF) { + return false; + } } return true; } - // ============================================================================ - // SAME EVENT WITH V0 LAMBDA PROCESSING - // ============================================================================ - - template - void doSameEventWithV0(CollisionType const& collision, - V0 const& v0s, - TrackType const& tracks, - CandsXics const& candidates, - aod::McParticles const* mcParticles = nullptr) + // ======================================== + // Efficiency calculation block + // ======================================== + template + void fillEffV0(V0 const& v0s, + TrackType const&, + aod::McParticles const& mcParticles) { // Data-driven efficiency calculation for protons using Lambda - if (cfgV0.cfgCalDataDrivenEffPr) { - for (const auto& v0 : v0s) { - auto const& trackV0Pos = v0.template posTrack_as(); - auto const& trackV0Neg = v0.template negTrack_as(); - if (cfgV0.cfgIsCorrCollMatchV0 && ((v0.collisionId() != trackV0Pos.collisionId()) || (v0.collisionId() != trackV0Neg.collisionId()))) { - continue; - } + for (const auto& v0 : v0s) { + auto const& trackV0Pos = v0.template posTrack_as(); + auto const& trackV0Neg = v0.template negTrack_as(); + if (cfgV0.cfgIsCorrCollMatchV0 && ((v0.collisionId() != trackV0Pos.collisionId()) || (v0.collisionId() != trackV0Neg.collisionId()))) { + continue; + } - // Process Lambda (proton + pion) - if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { - entryHadron(v0.mLambda(), trackV0Pos.eta(), trackV0Pos.pt() * trackV0Pos.sign(), 0, 0, v0.pt()); - entryTrkPID(trackV0Pos.tpcNSigmaPr(), trackV0Pos.tpcNSigmaKa(), trackV0Pos.tpcNSigmaPi(), trackV0Pos.tofNSigmaPr(), trackV0Pos.tofNSigmaKa(), trackV0Pos.tofNSigmaPi()); + // Process Lambda (proton + pion) + if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { + entryHadron(v0.mLambda(), trackV0Pos.eta(), trackV0Pos.pt() * trackV0Pos.sign(), 0, 0, v0.pt()); + entryTrkPID(trackV0Pos.tpcNSigmaPr(), trackV0Pos.tpcNSigmaKa(), trackV0Pos.tpcNSigmaPi(), trackV0Pos.tofNSigmaPr(), trackV0Pos.tofNSigmaKa(), trackV0Pos.tofNSigmaPi()); - if (isSelectedV0Daughter(trackV0Pos, kProton) && isSelectedV0Daughter(trackV0Neg, kPiPlus)) { - registry.fill(HIST("hV0Lambda"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - registry.fill(HIST("hV0LambdaRefl"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - registry.fill(HIST("hTPCnSigmaPr"), trackV0Pos.pt(), trackV0Pos.tpcNSigmaPr()); + if (isSelectedV0Daughter(trackV0Pos, v0, kProton) && isSelectedV0Daughter(trackV0Neg, v0, kPiMinus)) { + registry.fill(HIST("hV0Lambda"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hV0LambdaRefl"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hTPCnSigmaPr"), trackV0Pos.pt(), trackV0Pos.tpcNSigmaPr()); - if (trackV0Pos.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPr"), trackV0Pos.pt(), trackV0Pos.tofNSigmaPr()); - } + if (trackV0Pos.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPr"), trackV0Pos.pt(), trackV0Pos.tofNSigmaPr()); + } - if (passPIDSelection(trackV0Pos, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRej"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - registry.fill(HIST("hTPCnSigmaPrPiKRej"), trackV0Pos.pt(), trackV0Pos.tpcNSigmaPr()); - if (trackV0Pos.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPrPiKRej"), trackV0Pos.pt(), trackV0Pos.tofNSigmaPr()); - } + if (passPIDSelection(trackV0Pos, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRej"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hTPCnSigmaPrPiKRej"), trackV0Pos.pt(), trackV0Pos.tpcNSigmaPr()); + if (trackV0Pos.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPrPiKRej"), trackV0Pos.pt(), trackV0Pos.tofNSigmaPr()); } } } + } - if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { - entryHadron(v0.mAntiLambda(), trackV0Neg.eta(), trackV0Neg.pt() * trackV0Neg.sign(), 0, 0, v0.pt()); - entryTrkPID(trackV0Neg.tpcNSigmaPr(), trackV0Neg.tpcNSigmaKa(), trackV0Neg.tpcNSigmaPi(), trackV0Neg.tofNSigmaPr(), trackV0Neg.tofNSigmaKa(), trackV0Neg.tofNSigmaPi()); + if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { + entryHadron(v0.mAntiLambda(), trackV0Neg.eta(), trackV0Neg.pt() * trackV0Neg.sign(), 0, 0, v0.pt()); + entryTrkPID(trackV0Neg.tpcNSigmaPr(), trackV0Neg.tpcNSigmaKa(), trackV0Neg.tpcNSigmaPi(), trackV0Neg.tofNSigmaPr(), trackV0Neg.tofNSigmaKa(), trackV0Neg.tofNSigmaPi()); + + if (isSelectedV0Daughter(trackV0Neg, v0, kProtonBar) && isSelectedV0Daughter(trackV0Pos, v0, kPiPlus)) { + registry.fill(HIST("hV0Lambda"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hV0LambdaRefl"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hTPCnSigmaPr"), trackV0Neg.pt(), trackV0Neg.tpcNSigmaPr()); - if (isSelectedV0Daughter(trackV0Neg, kProton) && isSelectedV0Daughter(trackV0Neg, kPiPlus)) { - registry.fill(HIST("hV0Lambda"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - registry.fill(HIST("hV0LambdaRefl"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - registry.fill(HIST("hTPCnSigmaPr"), trackV0Neg.pt(), trackV0Neg.tpcNSigmaPr()); + if (trackV0Neg.hasTOF()) { + registry.fill(HIST("hTOFnSigmaPr"), trackV0Neg.pt(), trackV0Neg.tofNSigmaPr()); + } + if (passPIDSelection(trackV0Neg, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRej"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); + registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + registry.fill(HIST("hTPCnSigmaPrPiKRej"), trackV0Neg.pt(), trackV0Neg.tpcNSigmaPr()); if (trackV0Neg.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPr"), trackV0Neg.pt(), trackV0Neg.tofNSigmaPr()); + registry.fill(HIST("hTOFnSigmaPrPiKRej"), trackV0Neg.pt(), trackV0Neg.tofNSigmaPr()); } + } + } + } - if (passPIDSelection(trackV0Neg, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRej"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - registry.fill(HIST("hV0LambdaReflPiKRej"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - registry.fill(HIST("hTPCnSigmaPrPiKRej"), trackV0Neg.pt(), trackV0Neg.tpcNSigmaPr()); - if (trackV0Neg.hasTOF()) { - registry.fill(HIST("hTOFnSigmaPrPiKRej"), trackV0Neg.pt(), trackV0Neg.tofNSigmaPr()); - } - } + // MC-Reco specific V0 matching + if constexpr (IsMc) { + if (!v0.has_mcParticle() || !trackV0Pos.has_mcParticle() || !trackV0Neg.has_mcParticle()) { + continue; + } + auto const& v0Mc = v0.mcParticle(); + auto const& partV0Pos = trackV0Pos.mcParticle(); + auto const& partV0Neg = trackV0Neg.mcParticle(); + + if (v0Mc.pdgCode() == kLambda0) { + registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + if (cfgV0.calEffV0 && v0Mc.isPhysicalPrimary() && v0Mc.producedByGenerator()) { + registry.fill(HIST("hV0PrimLambdaMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + registry.fill(HIST("hV0PrimLambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + } + + if (passPIDSelection(trackV0Pos, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); } } + if (v0Mc.pdgCode() == kLambda0Bar) { + registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); - // MC-Reco specific V0 matching - if constexpr (IsMcRec) { - if (!v0.has_mcParticle() || !trackV0Pos.has_mcParticle() || !trackV0Neg.has_mcParticle()) { + if (cfgV0.calEffV0 && v0Mc.isPhysicalPrimary() && v0Mc.producedByGenerator()) { + registry.fill(HIST("hV0PrimLambdaMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + registry.fill(HIST("hV0PrimLambdaReflMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + } + if (passPIDSelection(trackV0Neg, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { + registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), partV0Neg.pt()); + registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mLambda(), v0.pt(), partV0Pos.pt()); + } + } + } + } + + if constexpr (IsMc) { + if (cfgV0.calEffV0) { + + for (const auto& particle : mcParticles) { + + if (std::abs(particle.pdgCode()) != kLambda0) { continue; } - auto const& v0Mc = v0.mcParticle(); - auto const& partV0Pos = trackV0Pos.mcParticle(); - auto const& partV0Neg = trackV0Neg.mcParticle(); - - if (std::abs(v0Mc.pdgCode()) == kLambda0) { - if (std::abs(partV0Pos.pdgCode()) == kProton) { - registry.fill(HIST("hV0LambdaMcRec"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - registry.fill(HIST("hV0LambdaReflMcRec"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - - if (passPIDSelection(trackV0Pos, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - } + + if (std::abs(particle.y()) > cfgXicCand.yCandMax) { + continue; + } + if (!particle.isPhysicalPrimary() || !particle.producedByGenerator()) { + continue; + } + + auto daughterParts = particle.daughters_as(); + const int8_t nDaughtersV0 = 2; + + if (daughterParts.size() != nDaughtersV0) { + continue; + } + + for (const auto& currentDaughter : daughterParts) { + + if (std::abs(currentDaughter.eta()) > cfgXicCand.etaTrackMax) { + continue; } - if (std::abs(partV0Neg.pdgCode()) == kProton) { - registry.fill(HIST("hV0LambdaMcRec"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - registry.fill(HIST("hV0LambdaReflMcRec"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); - if (passPIDSelection(trackV0Neg, cfgXicCand.trkPIDspecies, cfgXicCand.pidTPCMax, cfgXicCand.pidTOFMax, cfgXicCand.tofPIDThreshold, cfgXicCand.forceTOF)) { - registry.fill(HIST("hV0LambdaPiKRejMcRec"), v0.mAntiLambda(), v0.pt(), trackV0Neg.pt()); - registry.fill(HIST("hV0LambdaReflPiKRejMcRec"), v0.mLambda(), v0.pt(), trackV0Pos.pt()); + if (std::abs(currentDaughter.pdgCode()) == kProton) { + + if (currentDaughter.pt() > cfgV0.cfgDaughPrPtMax || currentDaughter.pt() < cfgV0.cfgDaughPrPtMin) { + continue; + } + + } else if (std::abs(currentDaughter.pdgCode()) == kPiPlus) { + if (currentDaughter.pt() > cfgV0.cfgDaughPiPtMax || currentDaughter.pt() < cfgV0.cfgDaughPiPtMin) { + continue; } + + } else { + continue; } } + registry.fill(HIST("hV0PtPrimLambdaMcGen"), particle.pt()); } } } + } + + // ============================================================================ + // SAME EVENT WITH V0 LAMBDA PROCESSING + // ============================================================================ + + template + void doSameEventWithV0(CollisionType const& collision, + V0 const& v0s, + TrackType const& tracks, + CandsXics const& candidates, + aod::McParticles const* mcParticles = nullptr) + { // Main Xic-Lambda correlation loop int nTracks = 0; @@ -899,7 +1005,7 @@ struct HfCorrelatorXicHadrons { // Process Lambda (proton-pion) if (std::abs(o2::constants::physics::MassLambda - v0.mLambda()) < cfgV0.cfgHypMassWindow) { - if (isSelectedV0Daughter(trackV0Pos, kProton) && isSelectedV0Daughter(trackV0Neg, kPiPlus)) { + if (isSelectedV0Daughter(trackV0Pos, v0, kProton) && isSelectedV0Daughter(trackV0Neg, v0, kPiMinus)) { if (selXicCand) { fillCorrelationTable(cfgXicCand.fillTrkPID, v0, ptCand, etaCand, phiCand, outputMlXic, poolBin, correlationStatus, yCand, massCand, *mcParticles); @@ -908,7 +1014,7 @@ struct HfCorrelatorXicHadrons { if (countCand == 1) { if (!skipMixedEventTableFilling) { entryHadron(v0.phi(), v0.eta(), v0.pt() * static_cast(V0LambdaType::Lambda), poolBin, gCollisionId, timeStamp); - entryV0InvMass(v0.mLambda()); + entryV0InvMass(v0.mLambda(), v0.mAntiLambda()); registry.fill(HIST("hTracksBin"), poolBin); } } @@ -917,7 +1023,7 @@ struct HfCorrelatorXicHadrons { // Process anti-Lambda (anti-proton-pion) if (std::abs(o2::constants::physics::MassLambda - v0.mAntiLambda()) < cfgV0.cfgHypMassWindow) { - if (isSelectedV0Daughter(trackV0Neg, kProton) && isSelectedV0Daughter(trackV0Pos, kPiPlus)) { + if (isSelectedV0Daughter(trackV0Neg, v0, kProtonBar) && isSelectedV0Daughter(trackV0Pos, v0, kPiPlus)) { if (selXicCand) { fillCorrelationTable(cfgXicCand.fillTrkPID, v0, ptCand, etaCand, phiCand, outputMlXic, poolBin, correlationStatus, yCand, massCand, *mcParticles); @@ -926,7 +1032,7 @@ struct HfCorrelatorXicHadrons { if (countCand == 1) { if (!skipMixedEventTableFilling) { entryHadron(v0.phi(), v0.eta(), v0.pt() * static_cast(V0LambdaType::AntiLambda), poolBin, gCollisionId, timeStamp); - entryV0InvMass(v0.mAntiLambda()); + entryV0InvMass(v0.mAntiLambda(), v0.mLambda()); registry.fill(HIST("hTracksBin"), poolBin); } } @@ -997,14 +1103,14 @@ struct HfCorrelatorXicHadrons { if constexpr (LambdaType == V0LambdaType::Lambda) { // Lambda massPart2 = assoc.mLambda(); - entryPairedV0InvMass(assoc.mLambda()); + entryPairedV0InvMass(assoc.mLambda(), assoc.mAntiLambda()); signAssoc = V0LambdaType::Lambda; yAssoc = assoc.yLambda(); } else if constexpr (LambdaType == V0LambdaType::AntiLambda) { // AntiLambda massPart2 = assoc.mAntiLambda(); signAssoc = V0LambdaType::AntiLambda; yAssoc = assoc.yLambda(); - entryPairedV0InvMass(assoc.mLambda()); + entryPairedV0InvMass(assoc.mAntiLambda(), assoc.mLambda()); } else { // Regular track massPart2 = getMassFromPdg(cfgXicCand.particlePdg); signAssoc = assoc.sign(); @@ -1351,14 +1457,14 @@ struct HfCorrelatorXicHadrons { auto const& trackV0Neg = assocParticle.template negTrack_as(); if (std::abs(o2::constants::physics::MassLambda - assocParticle.mLambda()) < cfgV0.cfgHypMassWindow) { - if (isSelectedV0Daughter(trackV0Pos, kProton) && isSelectedV0Daughter(trackV0Neg, kPiPlus)) { + if (isSelectedV0Daughter(trackV0Pos, assocParticle, kProton) && isSelectedV0Daughter(trackV0Neg, assocParticle, kPiPlus)) { fillCorrelationTable(cfgXicCand.fillTrkPID, assocParticle, ptCand, etaCand, phiCand, outputMlXic, poolBin, correlationStatus, yCand, massCand, *mcParticles); } } if (std::abs(o2::constants::physics::MassLambda - assocParticle.mAntiLambda()) < cfgV0.cfgHypMassWindow) { - if (isSelectedV0Daughter(trackV0Neg, kProton) && isSelectedV0Daughter(trackV0Pos, kPiPlus)) { + if (isSelectedV0Daughter(trackV0Neg, assocParticle, -kProton) && isSelectedV0Daughter(trackV0Pos, assocParticle, -kPiPlus)) { fillCorrelationTable(cfgXicCand.fillTrkPID, assocParticle, ptCand, etaCand, phiCand, outputMlXic, poolBin, correlationStatus, yCand, massCand, *mcParticles); } } @@ -1589,6 +1695,16 @@ struct HfCorrelatorXicHadrons { } PROCESS_SWITCH(HfCorrelatorXicHadrons, processMcRecXic0V0, "Mc process for v0 lambda with Xic0", false); + /// MC Reco processing: Xic0 with V0 Lambda + void processV0McRec(SelCollisions::iterator const&, + TracksWithMc const& tracks, + soa::Join const& v0s, + aod::McParticles const& mcParticles) + { + fillEffV0(v0s, tracks, mcParticles); + } + PROCESS_SWITCH(HfCorrelatorXicHadrons, processV0McRec, "Mc process for v0 lambda", false); + // ============================================================================ // MIXED EVENT PROCESS FUNCTIONS // ============================================================================