From 60763c6aa6753c7d3a58ee6c235bc8670df58264 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 3 Nov 2026 22:11:49 +0100 Subject: [PATCH 1/6] Fix: gate init of builders --- .../femtoProducerDerivedToDerived.cxx | 67 +++++++++++++++++-- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx index 2eca98b293c..a4f1020df72 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -213,12 +213,67 @@ struct FemtoProducerDerivedToDerived { LOG(fatal) << "Exactly one process function must be activated (got " << activeProcesses << ")."; } - builders.trackBuilder.init(confTrackBuilder); - builders.v0Builder.init(confV0Builder); - builders.cascadeBuilder.init(confCascadeBuilder); - builders.kinkBuilder.init(confKinkBuilder); - builders.resonanceBuilder.init(confResonanceBuilder); - builders.mcBuilder.init(confMcBuilder); + // which builders the currently active process function actually exercises -- + // only those need their limit configuration validated (see e.g. TrackBuilderDerivedToDerived::init()); + // an unused builder is free to keep its (possibly all-zero) default limits + const bool needsTrackBuilder = + doprocessTracks || doprocessTracksWithMass || doprocessTracksWithFitVars || + doprocessTracksLambdas || doprocessTracksWithMassLambdas || doprocessTracksWithFitVarsLambdas || + doprocessTracksXis || doprocessTracksWithFitVarsXis || + doprocessTracksOmegas || doprocessTracksWithFitVarsOmegas || + doprocessTracksK0shorts || doprocessTracksWithFitVarsK0shorts || + doprocessTracksSigma || doprocessTracksSigmaPlus || doprocessTracksSigmaPlusExtended || + doprocessTracksSigmaPlusPcm || doprocessTracksSigmaPlusPcmExtended || + doprocessTracksRho0 || doprocessTracksPhi || + doprocessTracksMc || doprocessTracksSigmaMc || doprocessTracksSigmaPlusMc || + doprocessTracksSigmaPlusExtendedMc || doprocessTracksSigmaPlusPcmMc || doprocessTracksSigmaPlusPcmExtendedMc; + + const bool needsV0Builder = + doprocessTracksLambdas || doprocessTracksWithMassLambdas || doprocessTracksWithFitVarsLambdas || + doprocessLambdas || + doprocessTracksK0shorts || doprocessTracksWithFitVarsK0shorts || + doprocessLambdasXis; + + const bool needsCascadeBuilder = + doprocessTracksXis || doprocessTracksWithFitVarsXis || + doprocessTracksOmegas || doprocessTracksWithFitVarsOmegas || + doprocessLambdasXis; + + const bool needsKinkBuilder = + doprocessTracksSigma || doprocessTracksSigmaPlus || doprocessTracksSigmaPlusExtended || + doprocessTracksSigmaPlusPcm || doprocessTracksSigmaPlusPcmExtended || + doprocessTracksSigmaMc || doprocessTracksSigmaPlusMc || doprocessTracksSigmaPlusExtendedMc || + doprocessTracksSigmaPlusPcmMc || doprocessTracksSigmaPlusPcmExtendedMc; + + const bool needsResonanceBuilder = doprocessTracksRho0 || doprocessTracksPhi; + + const bool needsMcBuilder = + doprocessTracksMc || doprocessTracksSigmaMc || doprocessTracksSigmaPlusMc || + doprocessTracksSigmaPlusExtendedMc || doprocessTracksSigmaPlusPcmMc || doprocessTracksSigmaPlusPcmExtendedMc; + + // skip init() entirely for builders the active process doesn't touch: their limit + // members default to 0 and are only ever read by the collisionHasTooFew*/process* + // methods that the active process also doesn't call, so leaving them uninitialized + // (i.e. at their 0 default) is harmless -- this also sidesteps each builder's "all + // limits are 0" fatal check, which would otherwise fire for an unrelated species + if (needsTrackBuilder) { + builders.trackBuilder.init(confTrackBuilder); + } + if (needsV0Builder) { + builders.v0Builder.init(confV0Builder); + } + if (needsCascadeBuilder) { + builders.cascadeBuilder.init(confCascadeBuilder); + } + if (needsKinkBuilder) { + builders.kinkBuilder.init(confKinkBuilder); + } + if (needsResonanceBuilder) { + builders.resonanceBuilder.init(confResonanceBuilder); + } + if (needsMcBuilder) { + builders.mcBuilder.init(confMcBuilder); + } } // process functions From 100223cdce6da65b0d0bf94c1635b109aa084928 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 3 Nov 2026 22:12:22 +0100 Subject: [PATCH 2/6] Feat: add PID histograms --- PWGCF/Femto/Core/pairBuilder.h | 16 +- PWGCF/Femto/Core/trackBuilder.h | 2 + PWGCF/Femto/Core/trackHistManager.h | 189 +++++++++++++++------- PWGCF/Femto/Tasks/femtoCascadeQa.cxx | 2 +- PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx | 6 +- PWGCF/Femto/Tasks/femtoTrackQa.cxx | 2 +- PWGCF/Femto/Tasks/femtoV0Qa.cxx | 2 +- 7 files changed, 150 insertions(+), 69 deletions(-) diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index a2c46bbb875..dd157bbb0ae 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -91,9 +91,7 @@ class PairTrackTrackBuilder std::map> const& trackHistSpec2, std::map> const& pairHistSpec, std::map> const& cprHistSpec, - std::map> const& pairCleanerHistSpec, - int puritySlotMask1 = 1, - int puritySlotMask2 = 1) + std::map> const& pairCleanerHistSpec) { // check if correlate the same tracks or not @@ -108,8 +106,8 @@ class PairTrackTrackBuilder if (mSameSpecies) { mTrackCleaner1.init(confTrackCleaner1); - mTrackHistManagerSe1.template init(registry, trackHistSpec1, confTrackSelection1, puritySlotMask1); - mTrackHistManagerMe1.template init(registry, trackHistSpec1, confTrackSelection1, puritySlotMask1); + mTrackHistManagerSe1.template init(registry, trackHistSpec1, confTrackSelection1); + mTrackHistManagerMe1.template init(registry, trackHistSpec1, confTrackSelection1); mPairHistManagerSe.setMass(confTrackSelection1.pdgCodeAbs.value, confTrackSelection1.pdgCodeAbs.value); mPairHistManagerSe.setCharge(confTrackSelection1.chargeAbs.value, confTrackSelection1.chargeAbs.value); @@ -121,10 +119,10 @@ class PairTrackTrackBuilder } else { mTrackCleaner1.init(confTrackCleaner1); mTrackCleaner2.init(confTrackCleaner2); - mTrackHistManagerSe1.template init(registry, trackHistSpec1, confTrackSelection1, puritySlotMask1); - mTrackHistManagerSe2.template init(registry, trackHistSpec2, confTrackSelection2, puritySlotMask2); - mTrackHistManagerMe1.template init(registry, trackHistSpec1, confTrackSelection1, puritySlotMask1); - mTrackHistManagerMe2.template init(registry, trackHistSpec2, confTrackSelection2, puritySlotMask2); + mTrackHistManagerSe1.template init(registry, trackHistSpec1, confTrackSelection1); + mTrackHistManagerSe2.template init(registry, trackHistSpec2, confTrackSelection2); + mTrackHistManagerMe1.template init(registry, trackHistSpec1, confTrackSelection1); + mTrackHistManagerMe2.template init(registry, trackHistSpec2, confTrackSelection2); mPairHistManagerSe.setMass(confTrackSelection1.pdgCodeAbs.value, confTrackSelection2.pdgCodeAbs.value); mPairHistManagerSe.setCharge(confTrackSelection1.chargeAbs.value, confTrackSelection2.chargeAbs.value); diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index 9acba874559..16bff2aad52 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -157,6 +157,8 @@ struct ConfTrackSelection : public o2::framework::ConfigurableGroup { o2::framework::Configurable rejectionMaskHighMomentum{"rejectionMaskHighMomentum", 0ul, "Bitmask for rejections above momentum threshold"}; // momentum threshold for PID usage o2::framework::Configurable pidThres{"pidThres", 1.2f, "Momentum threshold for using TPCTOF/TOF pid for tracks with large momentum (GeV/c)"}; + // which species slot this selection corresponds to in the packed purity tables (FitVars only) + o2::framework::Configurable puritySlotMask{"puritySlotMask", 1, "Bitmask (bit N = slot N) selecting which purity slot to plot, read off hPuritySlotAssignment in the producer output."}; }; // Define unique prefixes as constexpr string literals diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h index 82fcbbd26de..22d82f72d56 100644 --- a/PWGCF/Femto/Core/trackHistManager.h +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -121,6 +121,22 @@ enum TrackHist { kTpctofDeuteron, kTpctofTriton, kTpctofHelium, + // momentum vs tpc vs its pid (uncombined, orthogonal nSigma axes -- lets one cut on both at once) + kTpcVsItsElectron, + kTpcVsItsPion, + kTpcVsItsKaon, + kTpcVsItsProton, + kTpcVsItsDeuteron, + kTpcVsItsTriton, + kTpcVsItsHelium, + // momentum vs tpc vs tof pid (uncombined, orthogonal nSigma axes -- lets one cut on both at once) + kTpcVsTofElectron, + kTpcVsTofPion, + kTpcVsTofKaon, + kTpcVsTofProton, + kTpcVsTofDeuteron, + kTpcVsTofTriton, + kTpcVsTofHelium, // purity (species picked at runtime via puritySlotMask, see hPuritySlotAssignment) kItsPurity, kTpcPurity, @@ -161,7 +177,6 @@ struct ConfTrackBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; o2::framework::ConfigurableAxis mass{"mass", {{200, 0.f, 2.f}}, "Mass (if enabled, plot TOF mass, otherwise PDG mass)"}; o2::framework::ConfigurableAxis pdgCodes{"pdgCodes", {{8001, -4000.5, 4000.5}}, "MC ONLY: PDG codes of selected tracks"}; - o2::framework::Configurable puritySlotMask{"puritySlotMask", 1, "Bitmask (bit N = slot N) selecting which purity slot to plot, read off hPuritySlotAssignment in the producer output."}; o2::framework::ConfigurableAxis purityNSigma{"purityNSigma", {{3000, -15, 15}}, "nSigma decoded from the packed purity tables (species picked via puritySlotMask); signed, for the raw Its/Tpc/Tof values"}; o2::framework::ConfigurableAxis purityNSigmaComb{"purityNSigmaComb", {{2000, 0, 20}}, "Combined nSigma (hypot of two raw values); always non-negative, for Tpc+Its/Tpc+Tof"}; o2::framework::ConfigurableAxis fractionDcaXy{"fractionDcaXy", {{300, -0.3, 0.3}}, "DCA_xy (fraction estimation, needs FTrackDcas joined)"}; @@ -229,13 +244,13 @@ struct ConfTrackQaBinning : o2::framework::ConfigurableGroup { std::string prefix = Prefix; o2::framework::Configurable momentumType{"momentumType", static_cast(modes::MomentumType::kPAtPv), "Momentum on x-axis (0->Pt, 1->P at PV, 2->P at TPC inner wall)"}; o2::framework::Configurable plot2d{"plot2d", true, "Generate various 2D QA plots"}; - o2::framework::Configurable plotElectronPid{"plotElectronPid", true, "Generate plots for Electron PID"}; - o2::framework::Configurable plotPionPid{"plotPionPid", true, "Generate plots for Pion PID"}; - o2::framework::Configurable plotKaonPid{"plotKaonPid", true, "Generate plots for Kaon PID"}; + o2::framework::Configurable plotElectronPid{"plotElectronPid", false, "Generate plots for Electron PID"}; + o2::framework::Configurable plotPionPid{"plotPionPid", false, "Generate plots for Pion PID"}; + o2::framework::Configurable plotKaonPid{"plotKaonPid", false, "Generate plots for Kaon PID"}; o2::framework::Configurable plotProtonPid{"plotProtonPid", true, "Generate plots for Proton PID"}; - o2::framework::Configurable plotDeuteronPid{"plotDeuteronPid", true, "Generate plots for Deuteron PID"}; - o2::framework::Configurable plotTritonPid{"plotTritonPid", true, "Generate plots for Triton PID"}; - o2::framework::Configurable plotHeliumPid{"plotHeliumPid", true, "Generate plots for Helium PID"}; + o2::framework::Configurable plotDeuteronPid{"plotDeuteronPid", false, "Generate plots for Deuteron PID"}; + o2::framework::Configurable plotTritonPid{"plotTritonPid", false, "Generate plots for Triton PID"}; + o2::framework::Configurable plotHeliumPid{"plotHeliumPid", false, "Generate plots for Helium PID"}; o2::framework::Configurable plotOrigins{"plotOrigins", true, "MC ONLY: Plot pt vs DCAxy vs DCAz for different particle origins"}; o2::framework::Configurable> pdgCodesForMothersOfSecondary{"pdgCodesForMothersOfSecondary", {3122}, "MC ONLY: PDG codes of mothers of secondaries (Max 3 will be considered)"}; o2::framework::ConfigurableAxis itsCluster{"itsCluster", {{8, -0.5, 7.5}}, "ITS cluster"}; @@ -411,6 +426,20 @@ constexpr std::array, kTrackHistLast> {kTpctofDeuteron, o2::framework::HistType::kTH2F, "hTpctofPidDeuteron", "TPC+TOF PID Deuteron; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,de}^{2}+n#sigma_{TOF,de}^{2}}"}, {kTpctofTriton, o2::framework::HistType::kTH2F, "hTpctofPidTriton", "TPC+TOF PID Triton; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,tr}^{2}+n#sigma_{TOF,tr}^{2}}"}, {kTpctofHelium, o2::framework::HistType::kTH2F, "hTpctofPidHelium", "TPC+TOF PID Helium; p (GeV/#it{c}) ; #sqrt{n#sigma_{TPC,he}^{2}+n#sigma_{TOF,he}^{2}}"}, + {kTpcVsItsElectron, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidElectron", "TPC vs ITS PID Electron; p (GeV/#it{c}) ; n#sigma_{TPC,el} ; n#sigma_{ITS,el}"}, + {kTpcVsItsPion, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidPion", "TPC vs ITS PID Pion; p (GeV/#it{c}) ; n#sigma_{TPC,pi} ; n#sigma_{ITS,pi}"}, + {kTpcVsItsKaon, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidKaon", "TPC vs ITS PID Kaon; p (GeV/#it{c}) ; n#sigma_{TPC,ka} ; n#sigma_{ITS,ka}"}, + {kTpcVsItsProton, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidProton", "TPC vs ITS PID Proton; p (GeV/#it{c}) ; n#sigma_{TPC,pr} ; n#sigma_{ITS,pr}"}, + {kTpcVsItsDeuteron, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidDeuteron", "TPC vs ITS PID Deuteron; p (GeV/#it{c}) ; n#sigma_{TPC,de} ; n#sigma_{ITS,de}"}, + {kTpcVsItsTriton, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidTriton", "TPC vs ITS PID Triton; p (GeV/#it{c}) ; n#sigma_{TPC,tr} ; n#sigma_{ITS,tr}"}, + {kTpcVsItsHelium, o2::framework::HistType::kTHnSparseF, "hTpcVsItsPidHelium", "TPC vs ITS PID Helium; p (GeV/#it{c}) ; n#sigma_{TPC,he} ; n#sigma_{ITS,he}"}, + {kTpcVsTofElectron, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidElectron", "TPC vs TOF PID Electron; p (GeV/#it{c}) ; n#sigma_{TPC,el} ; n#sigma_{TOF,el}"}, + {kTpcVsTofPion, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidPion", "TPC vs TOF PID Pion; p (GeV/#it{c}) ; n#sigma_{TPC,pi} ; n#sigma_{TOF,pi}"}, + {kTpcVsTofKaon, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidKaon", "TPC vs TOF PID Kaon; p (GeV/#it{c}) ; n#sigma_{TPC,ka} ; n#sigma_{TOF,ka}"}, + {kTpcVsTofProton, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidProton", "TPC vs TOF PID Proton; p (GeV/#it{c}) ; n#sigma_{TPC,pr} ; n#sigma_{TOF,pr}"}, + {kTpcVsTofDeuteron, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidDeuteron", "TPC vs TOF PID Deuteron; p (GeV/#it{c}) ; n#sigma_{TPC,de} ; n#sigma_{TOF,de}"}, + {kTpcVsTofTriton, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidTriton", "TPC vs TOF PID Triton; p (GeV/#it{c}) ; n#sigma_{TPC,tr} ; n#sigma_{TOF,tr}"}, + {kTpcVsTofHelium, o2::framework::HistType::kTHnSparseF, "hTpcVsTofPidHelium", "TPC vs TOF PID Helium; p (GeV/#it{c}) ; n#sigma_{TPC,he} ; n#sigma_{TOF,he}"}, {kItsPurity, o2::framework::HistType::kTH2F, "hItsPurity", "ITS purity nSigma (species picked via puritySlotMask); p_{T} (GeV/#it{c}) ; n#sigma_{ITS}"}, {kTpcPurity, o2::framework::HistType::kTH2F, "hTpcPurity", "TPC purity nSigma (species picked via puritySlotMask); p_{T} (GeV/#it{c}) ; n#sigma_{TPC}"}, {kTofPurity, o2::framework::HistType::kTH2F, "hTofPurity", "TOF purity nSigma (species picked via puritySlotMask); p_{T} (GeV/#it{c}) ; n#sigma_{TOF}"}, @@ -517,7 +546,21 @@ constexpr std::array, kTrackHistLast> {kTpctofProton, {(confQa).p, (confQa).tpctofProton}}, \ {kTpctofDeuteron, {(confQa).p, (confQa).tpctofDeuteron}}, \ {kTpctofTriton, {(confQa).p, (confQa).tpctofTriton}}, \ - {kTpctofHelium, {(confQa).p, (confQa).tpctofHelium}}, + {kTpctofHelium, {(confQa).p, (confQa).tpctofHelium}}, \ + {kTpcVsItsElectron, {(confQa).p, (confQa).tpcElectron, (confQa).itsElectron}}, \ + {kTpcVsItsPion, {(confQa).p, (confQa).tpcPion, (confQa).itsPion}}, \ + {kTpcVsItsKaon, {(confQa).p, (confQa).tpcKaon, (confQa).itsKaon}}, \ + {kTpcVsItsProton, {(confQa).p, (confQa).tpcProton, (confQa).itsProton}}, \ + {kTpcVsItsDeuteron, {(confQa).p, (confQa).tpcDeuteron, (confQa).itsDeuteron}}, \ + {kTpcVsItsTriton, {(confQa).p, (confQa).tpcTriton, (confQa).itsTriton}}, \ + {kTpcVsItsHelium, {(confQa).p, (confQa).tpcHelium, (confQa).itsHelium}}, \ + {kTpcVsTofElectron, {(confQa).p, (confQa).tpcElectron, (confQa).tofElectron}}, \ + {kTpcVsTofPion, {(confQa).p, (confQa).tpcPion, (confQa).tofPion}}, \ + {kTpcVsTofKaon, {(confQa).p, (confQa).tpcKaon, (confQa).tofKaon}}, \ + {kTpcVsTofProton, {(confQa).p, (confQa).tpcProton, (confQa).tofProton}}, \ + {kTpcVsTofDeuteron, {(confQa).p, (confQa).tpcDeuteron, (confQa).tofDeuteron}}, \ + {kTpcVsTofTriton, {(confQa).p, (confQa).tpcTriton, (confQa).tofTriton}}, \ + {kTpcVsTofHelium, {(confQa).p, (confQa).tpcHelium, (confQa).tofHelium}}, // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TRACK_HIST_MC_MAP(conf) \ @@ -664,31 +707,24 @@ class TrackHistManager TrackHistManager() = default; ~TrackHistManager() = default; - // init for analysis and mc + // init for analysis, qa, mc and fitvars -- from a selection config object (track-track pairs, + // triplets, standalone QA task's own species). puritySlotMask lives on ConfTrackSelection + // itself (it picks which species slot in the packed purity tables this selection corresponds + // to), so it travels along with the selection object instead of needing its own parameter at + // every layer between the task and here. template void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, - T const& ConfTrackSelection, - int puritySlotMask = 1) + T const& ConfTrackSelection) { - mHistogramRegistry = registry; - mAbsCharge = std::abs(ConfTrackSelection.chargeAbs.value); - mPdgCode = std::abs(ConfTrackSelection.pdgCodeAbs.value) * ConfTrackSelection.chargeSign.value; - mPuritySlotMask = puritySlotMask; - if constexpr (isFlagSet(mode, modes::Mode::kReco)) { - this->initAnalysis(Specs); - } - if constexpr (isFlagSet(mode, modes::Mode::kQa)) { - this->initQa(Specs); - } - if constexpr (isFlagSet(mode, modes::Mode::kMc)) { - this->initMc(Specs); - } - if constexpr (isFlagSet(mode, modes::Mode::kFitVars)) { - this->template initFitVars(Specs); - } + this->template initCommon(registry, Specs, + std::abs(ConfTrackSelection.chargeAbs.value), + std::abs(ConfTrackSelection.pdgCodeAbs.value) * ConfTrackSelection.chargeSign.value, + ConfTrackSelection.puritySlotMask.value); } + // same, from raw charge/pdg ints (V0/cascade/resonance daughter sub-managers, which have no + // selection config object of their own -- the parent builder already applied the selection) template void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, @@ -696,24 +732,10 @@ class TrackHistManager int ChargeSign, int PdgCodeAbs) { - mHistogramRegistry = registry; - mAbsCharge = std::abs(ChargeAbs); - mPdgCode = std::abs(PdgCodeAbs) * ChargeSign; - if constexpr (isFlagSet(mode, modes::Mode::kReco)) { - this->initAnalysis(Specs); - } - if constexpr (isFlagSet(mode, modes::Mode::kQa)) { - this->initQa(Specs); - } - if constexpr (isFlagSet(mode, modes::Mode::kMc)) { - this->initMc(Specs); - } - if constexpr (isFlagSet(mode, modes::Mode::kFitVars)) { - this->template initFitVars(Specs); - } + this->template initCommon(registry, Specs, std::abs(ChargeAbs), std::abs(PdgCodeAbs) * ChargeSign, 1); } - // init for analysis and qa and mc + // same as above, but also configure the QA-only optional histograms (species PID toggles, plot2d, ...) template void init(o2::framework::HistogramRegistry* registry, std::map> const& Specs, @@ -746,7 +768,7 @@ class TrackHistManager this->fillQa(track); } if constexpr (isFlagSet(mode, modes::Mode::kFitVars)) { - this->fillFitVars(track); + this->template fillFitVars(track); } } @@ -763,11 +785,36 @@ class TrackHistManager this->template fillMc(track, col, mcParticles, mcMothers, mcPartonicMothers); } if constexpr (isFlagSet(mode, modes::Mode::kFitVars)) { - this->fillFitVars(track); + this->template fillFitVars(track); } } private: + // shared dispatch for all init() overloads above -- the only thing that differs between them + // is how mAbsCharge/mPdgCode/mPuritySlotMask get computed + template + void initCommon(o2::framework::HistogramRegistry* registry, + std::map> const& Specs, + int absCharge, int pdgCode, int puritySlotMask) + { + mHistogramRegistry = registry; + mAbsCharge = absCharge; + mPdgCode = pdgCode; + mPuritySlotMask = puritySlotMask; + if constexpr (isFlagSet(mode, modes::Mode::kReco)) { + this->initAnalysis(Specs); + } + if constexpr (isFlagSet(mode, modes::Mode::kQa)) { + this->initQa(Specs); + } + if constexpr (isFlagSet(mode, modes::Mode::kMc)) { + this->initMc(Specs); + } + if constexpr (isFlagSet(mode, modes::Mode::kFitVars)) { + this->template initFitVars(Specs); + } + } + template void enableOptionalHistograms(T const& ConfBinningQa) { @@ -804,16 +851,22 @@ class TrackHistManager } // purity (packed nSigma tables) and fraction (DCA) -- only called when mode carries kFitVars, - // which also implies the track type actually has the relevant tables joined + // which also implies the track type actually has the relevant tables joined. + // Purity itself is skipped in QA mode: the QA task already has full per-species PID + // (Its/Tpc/Tof/Tpcits/Tpctof/TpcVsIts/TpcVsTof in PID/), so the puritySlotMask-selected, + // single-species Purity histograms would be pure redundancy there -- they only earn their + // keep in the pair task, where there is no per-species breakdown to fall back on. template void initFitVars(std::map> const& Specs) { std::string fitVarsDir = std::string(prefix) + std::string(FitVarsDir); - mHistogramRegistry->add(fitVarsDir + getHistNameV2(kItsPurity, HistTable), getHistDesc(kItsPurity, HistTable), getHistType(kItsPurity, HistTable), {Specs.at(kItsPurity)}); - mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTpcPurity, HistTable), getHistDesc(kTpcPurity, HistTable), getHistType(kTpcPurity, HistTable), {Specs.at(kTpcPurity)}); - mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTofPurity, HistTable), getHistDesc(kTofPurity, HistTable), getHistType(kTofPurity, HistTable), {Specs.at(kTofPurity)}); - mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTpcitsPurity, HistTable), getHistDesc(kTpcitsPurity, HistTable), getHistType(kTpcitsPurity, HistTable), {Specs.at(kTpcitsPurity)}); - mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTpctofPurity, HistTable), getHistDesc(kTpctofPurity, HistTable), getHistType(kTpctofPurity, HistTable), {Specs.at(kTpctofPurity)}); + if constexpr (!isFlagSet(mode, modes::Mode::kQa)) { + mHistogramRegistry->add(fitVarsDir + getHistNameV2(kItsPurity, HistTable), getHistDesc(kItsPurity, HistTable), getHistType(kItsPurity, HistTable), {Specs.at(kItsPurity)}); + mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTpcPurity, HistTable), getHistDesc(kTpcPurity, HistTable), getHistType(kTpcPurity, HistTable), {Specs.at(kTpcPurity)}); + mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTofPurity, HistTable), getHistDesc(kTofPurity, HistTable), getHistType(kTofPurity, HistTable), {Specs.at(kTofPurity)}); + mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTpcitsPurity, HistTable), getHistDesc(kTpcitsPurity, HistTable), getHistType(kTpcitsPurity, HistTable), {Specs.at(kTpcitsPurity)}); + mHistogramRegistry->add(fitVarsDir + getHistNameV2(kTpctofPurity, HistTable), getHistDesc(kTpctofPurity, HistTable), getHistType(kTpctofPurity, HistTable), {Specs.at(kTpctofPurity)}); + } mHistogramRegistry->add(fitVarsDir + getHistNameV2(kFractionDca, HistTable), getHistDesc(kFractionDca, HistTable), getHistType(kFractionDca, HistTable), {Specs.at(kFractionDca)}); // per-origin truth-split fraction-DCA templates; need MC truth, so only booked when the mode @@ -900,6 +953,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofElectron, Specs); this->addPidHistogram(pidDir, kTpcitsElectron, Specs); this->addPidHistogram(pidDir, kTpctofElectron, Specs); + this->addPidHistogram(pidDir, kTpcVsItsElectron, Specs); + this->addPidHistogram(pidDir, kTpcVsTofElectron, Specs); } if (mPlotPionPid) { @@ -908,6 +963,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofPion, Specs); this->addPidHistogram(pidDir, kTpcitsPion, Specs); this->addPidHistogram(pidDir, kTpctofPion, Specs); + this->addPidHistogram(pidDir, kTpcVsItsPion, Specs); + this->addPidHistogram(pidDir, kTpcVsTofPion, Specs); } if (mPlotKaonPid) { @@ -916,6 +973,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofKaon, Specs); this->addPidHistogram(pidDir, kTpcitsKaon, Specs); this->addPidHistogram(pidDir, kTpctofKaon, Specs); + this->addPidHistogram(pidDir, kTpcVsItsKaon, Specs); + this->addPidHistogram(pidDir, kTpcVsTofKaon, Specs); } if (mPlotProtonPid) { @@ -924,6 +983,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofProton, Specs); this->addPidHistogram(pidDir, kTpcitsProton, Specs); this->addPidHistogram(pidDir, kTpctofProton, Specs); + this->addPidHistogram(pidDir, kTpcVsItsProton, Specs); + this->addPidHistogram(pidDir, kTpcVsTofProton, Specs); } if (mPlotDeuteronPid) { @@ -932,6 +993,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofDeuteron, Specs); this->addPidHistogram(pidDir, kTpcitsDeuteron, Specs); this->addPidHistogram(pidDir, kTpctofDeuteron, Specs); + this->addPidHistogram(pidDir, kTpcVsItsDeuteron, Specs); + this->addPidHistogram(pidDir, kTpcVsTofDeuteron, Specs); } if (mPlotTritonPid) { @@ -940,6 +1003,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofTriton, Specs); this->addPidHistogram(pidDir, kTpcitsTriton, Specs); this->addPidHistogram(pidDir, kTpctofTriton, Specs); + this->addPidHistogram(pidDir, kTpcVsItsTriton, Specs); + this->addPidHistogram(pidDir, kTpcVsTofTriton, Specs); } if (mPlotHeliumPid) { @@ -948,6 +1013,8 @@ class TrackHistManager this->addPidHistogram(pidDir, kTofHelium, Specs); this->addPidHistogram(pidDir, kTpcitsHelium, Specs); this->addPidHistogram(pidDir, kTpctofHelium, Specs); + this->addPidHistogram(pidDir, kTpcVsItsHelium, Specs); + this->addPidHistogram(pidDir, kTpcVsTofHelium, Specs); } } @@ -1005,11 +1072,11 @@ class TrackHistManager // joined on T, independently of the other; mPuritySlotMask picks the species slot (one bit set, // e.g. from cutculator reading hPuritySlotAssignment), everything is filled unconditionally // once that slot is decoded -- no momentum-regime selection, the analyst picks the right - // combination/range downstream - template + // combination/range downstream. Purity itself is skipped in QA mode, mirroring initFitVars. + template void fillFitVars(T const& track) { - if constexpr (requires(T t) { t.itsNSigmaSlot0(); }) { + if constexpr (!isFlagSet(mode, modes::Mode::kQa) && requires(T t) { t.itsNSigmaSlot0(); }) { float itsNSigma = 0.f; float tpcNSigma = 0.f; float tofNSigma = 0.f; @@ -1109,6 +1176,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofElectron, HistTable)), momentum, track.tofNSigmaEl()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsElectron, HistTable)), momentum, track.tpcitsNSigmaEl()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofElectron, HistTable)), momentum, track.tpctofNSigmaEl()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsElectron, HistTable)), momentum, track.tpcNSigmaEl(), track.itsNSigmaEl()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofElectron, HistTable)), momentum, track.tpcNSigmaEl(), track.tofNSigmaEl()); } if (mPlotPionPid) { @@ -1117,6 +1186,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofPion, HistTable)), momentum, track.tofNSigmaPi()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsPion, HistTable)), momentum, track.tpcitsNSigmaPi()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofPion, HistTable)), momentum, track.tpctofNSigmaPi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsPion, HistTable)), momentum, track.tpcNSigmaPi(), track.itsNSigmaPi()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofPion, HistTable)), momentum, track.tpcNSigmaPi(), track.tofNSigmaPi()); } if (mPlotKaonPid) { @@ -1125,6 +1196,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofKaon, HistTable)), momentum, track.tofNSigmaKa()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsKaon, HistTable)), momentum, track.tpcitsNSigmaKa()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofKaon, HistTable)), momentum, track.tpctofNSigmaKa()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsKaon, HistTable)), momentum, track.tpcNSigmaKa(), track.itsNSigmaKa()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofKaon, HistTable)), momentum, track.tpcNSigmaKa(), track.tofNSigmaKa()); } if (mPlotProtonPid) { @@ -1133,6 +1206,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofProton, HistTable)), momentum, track.tofNSigmaPr()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsProton, HistTable)), momentum, track.tpcitsNSigmaPr()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofProton, HistTable)), momentum, track.tpctofNSigmaPr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsProton, HistTable)), momentum, track.tpcNSigmaPr(), track.itsNSigmaPr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofProton, HistTable)), momentum, track.tpcNSigmaPr(), track.tofNSigmaPr()); } if (mPlotDeuteronPid) { @@ -1141,6 +1216,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofDeuteron, HistTable)), momentum, track.tofNSigmaDe()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsDeuteron, HistTable)), momentum, track.tpcitsNSigmaDe()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofDeuteron, HistTable)), momentum, track.tpctofNSigmaDe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsDeuteron, HistTable)), momentum, track.tpcNSigmaDe(), track.itsNSigmaDe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofDeuteron, HistTable)), momentum, track.tpcNSigmaDe(), track.tofNSigmaDe()); } if (mPlotTritonPid) { @@ -1149,6 +1226,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofTriton, HistTable)), momentum, track.tofNSigmaTr()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsTriton, HistTable)), momentum, track.tpcitsNSigmaTr()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofTriton, HistTable)), momentum, track.tpctofNSigmaTr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsTriton, HistTable)), momentum, track.tpcNSigmaTr(), track.itsNSigmaTr()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofTriton, HistTable)), momentum, track.tpcNSigmaTr(), track.tofNSigmaTr()); } if (mPlotHeliumPid) { @@ -1157,6 +1236,8 @@ class TrackHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTofHelium, HistTable)), momentum, track.tofNSigmaHe()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcitsHelium, HistTable)), momentum, track.tpcitsNSigmaHe()); mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpctofHelium, HistTable)), momentum, track.tpctofNSigmaHe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsItsHelium, HistTable)), momentum, track.tpcNSigmaHe(), track.itsNSigmaHe()); + mHistogramRegistry->fill(HIST(prefix) + HIST(PidDir) + HIST(getHistName(kTpcVsTofHelium, HistTable)), momentum, track.tpcNSigmaHe(), track.tofNSigmaHe()); } } diff --git a/PWGCF/Femto/Tasks/femtoCascadeQa.cxx b/PWGCF/Femto/Tasks/femtoCascadeQa.cxx index fee88a038c6..78b8ae337dc 100644 --- a/PWGCF/Femto/Tasks/femtoCascadeQa.cxx +++ b/PWGCF/Femto/Tasks/femtoCascadeQa.cxx @@ -51,7 +51,7 @@ struct FemtoCascadeQa { using FemtoXis = o2::soa::Join; using FemtoOmegas = o2::soa::Join; - using FemtoTracks = o2::soa::Join; + using FemtoTracks = o2::soa::Join; using FemtoXisWithLabel = o2::soa::Join; using FemtoOmegasWithLabel = o2::soa::Join; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx index 0b3299d8895..660f368891a 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx @@ -65,7 +65,7 @@ struct FemtoPairTrackTrack { // for analysis which require particles at high pt, add tof mass so sidebands can be used using FemtoTracksWithMass = o2::soa::Join; - // opt-in: adds the packed purity tables (nSigma, see TrackBinning1/2.puritySlotMask) and FTrackDcas + // opt-in: adds the packed purity tables (nSigma, see TrackSelection1/2.puritySlotMask) and FTrackDcas // (fraction estimation) for the FitVars histograms. Needs the producer's // TrackTables.produceItsPurity/produceTpcPurity/produceTofPurity/produceTrackDcas enabled. using FemtoTracksWithFitVars = o2::soa::Join; @@ -173,7 +173,7 @@ struct FemtoPairTrackTrack { trackHistSpec1 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning1); trackHistSpec2 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning2); pairHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec, confTrackBinning1.puritySlotMask.value, confTrackBinning2.puritySlotMask.value); + pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec); } else if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); trackHistSpec1 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning1); @@ -185,7 +185,7 @@ struct FemtoPairTrackTrack { trackHistSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning1); trackHistSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning2); pairHistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec, confTrackBinning1.puritySlotMask.value, confTrackBinning2.puritySlotMask.value); + pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec); } hRegistry.print(); }; diff --git a/PWGCF/Femto/Tasks/femtoTrackQa.cxx b/PWGCF/Femto/Tasks/femtoTrackQa.cxx index c247afdb75c..c3dc0898145 100644 --- a/PWGCF/Femto/Tasks/femtoTrackQa.cxx +++ b/PWGCF/Femto/Tasks/femtoTrackQa.cxx @@ -53,7 +53,7 @@ struct FemtoTrackQa { using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; - using FemtoTracks = o2::soa::Join; + using FemtoTracks = o2::soa::Join; using FemtoTracksWithLabel = o2::soa::Join; diff --git a/PWGCF/Femto/Tasks/femtoV0Qa.cxx b/PWGCF/Femto/Tasks/femtoV0Qa.cxx index 083f5bcc849..4ae00099140 100644 --- a/PWGCF/Femto/Tasks/femtoV0Qa.cxx +++ b/PWGCF/Femto/Tasks/femtoV0Qa.cxx @@ -52,7 +52,7 @@ struct FemtoV0Qa { using FemtoLambdas = o2::soa::Join; using FemtoK0shorts = o2::soa::Join; - using FemtoTracks = o2::soa::Join; + using FemtoTracks = o2::soa::Join; using FemtoLambdasWithLabel = o2::soa::Join; using FemtoK0shortsWithLabel = o2::soa::Join; From d38ef5050e09b2b1944f73974c83a221c26eb1ab Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Tue, 3 Nov 2026 23:05:20 +0100 Subject: [PATCH 3/6] Fix: fix binning of kinematic variable --- PWGCF/Femto/Core/closePairRejection.h | 34 +++++---- PWGCF/Femto/Core/closeTripletRejection.h | 21 +++--- PWGCF/Femto/Core/histManager.h | 14 ++++ PWGCF/Femto/Core/modes.h | 17 +++++ PWGCF/Femto/Core/pairCleaner.h | 22 +++--- PWGCF/Femto/Core/pairHistManager.h | 12 ++-- PWGCF/Femto/Core/trackHistManager.h | 8 +-- PWGCF/Femto/Core/tripletCleaner.h | 8 +-- PWGCF/Femto/Core/tripletHistManager.h | 89 +++++++++--------------- 9 files changed, 119 insertions(+), 106 deletions(-) diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h index 67c1e92f532..d7d8b320171 100644 --- a/PWGCF/Femto/Core/closePairRejection.h +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -17,6 +17,7 @@ #define PWGCF_FEMTO_CORE_CLOSEPAIRREJECTION_H_ #include "PWGCF/Femto/Core/histManager.h" +#include "PWGCF/Femto/Core/modes.h" #include "Common/Core/RecoDecay.h" @@ -61,7 +62,8 @@ enum CprHist { // template configurable group for Cpr // DefaultCutAverage: default of cutAverage (e.g. false for pairs of generated particles, where no detector effects are present) -template +// DefaultKinematicVariable: default of kinematicVariable (e.g. Q3 for triplets, kstar for pairs) +template struct ConfCpr : o2::framework::ConfigurableGroup { std::string prefix = std::string(Prefix); o2::framework::Configurable cutAverage{"cutAverage", DefaultCutAverage, "Apply CPR if the average deta-dphistar is below the configured values"}; @@ -71,6 +73,7 @@ struct ConfCpr : o2::framework::ConfigurableGroup { o2::framework::Configurable plotAverage{"plotAverage", true, "Plot average deta dphi distribution"}; o2::framework::Configurable plotAngularCorrelation{"plotAngularCorrelation", false, "Plot angular correlation of particles (eta1 vs eta2 & phi1 vs phi2)"}; o2::framework::Configurable plotKinematic{"plotKinematic", true, "Plot kinematic (kstar/Q3) distribution of blocked pairs/triplets"}; + o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(DefaultKinematicVariable), "Type of kinematic variable (0->kstar, 1->kT, 2->mT, 3->Q3) reported by the kinematic plot"}; o2::framework::Configurable detaMax{"detaMax", 0.01f, "Maximium deta"}; o2::framework::Configurable dphistarMax{"dphistarMax", 0.01f, "Maximum dphistar"}; o2::framework::Configurable detaCenter{"detaCenter", 0.f, "Center of deta cut"}; @@ -241,6 +244,7 @@ class CloseTrackRejection mPlotAngularCorrelation = confCpr.plotAngularCorrelation.value; mPlotKinematic = confCpr.plotKinematic.value; + mKinematicVariable = static_cast(confCpr.kinematicVariable.value); if (confCpr.seed.value >= 0) { uint64_t randomSeed = 0; @@ -259,7 +263,8 @@ class CloseTrackRejection mHistogramRegistry = registry; if (mPlotKinematic) { - mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kKinematic, HistTable), getHistDesc(kKinematic, HistTable), getHistType(kKinematic, HistTable), {specs.at(kKinematic)}); + std::string kinematicDesc = histmanager::replaceFirstAxisTitle(getHistDesc(kKinematic, HistTable), modes::kinematicVariableToAxisTitle(mKinematicVariable)); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kKinematic, HistTable), kinematicDesc.c_str(), getHistType(kKinematic, HistTable), {specs.at(kKinematic)}); } if (mPlotAverage) { @@ -301,9 +306,9 @@ class CloseTrackRejection bool isClose = mUseEpisoidalCut ? isClosePairEpisoidalCut() : isClosePairRectengularCut(); if (isClose) { - fillBlocked(pairHistManager.getKinematic()); + fillBlocked(pairHistManager.getKinematic(mKinematicVariable)); } else { - fillPassed(pairHistManager.getKinematic()); + fillPassed(pairHistManager.getKinematic(mKinematicVariable)); } return isClose; @@ -493,6 +498,7 @@ class CloseTrackRejection bool mPlotAverage = false; bool mPlotAngularCorrelation = false; bool mPlotKinematic = false; + modes::KinematicVariable mKinematicVariable = modes::KinematicVariable::kKstar; float mKinematicMin = -1.f; float mKinematicMax = -1.f; @@ -531,10 +537,10 @@ template class ClosePairRejectionTrackTrack { public: - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr, + T1 const& confCpr, int absChargeTrack1, int absChargeTrack2) { @@ -597,10 +603,10 @@ template class ClosePairRejectionTrackV0 // can also be used for any particle type that has pos/neg daughters, like resonances { public: - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr, + T1 const& confCpr, int absChargeTrack) { mCtr.init(registry, specs, confCpr, absChargeTrack, 1); @@ -719,10 +725,10 @@ template class ClosePairRejectionTrackKink { public: - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr, + T1 const& confCpr, int absChargeTrack) { mCtr.init(registry, specs, confCpr, absChargeTrack, 1); @@ -753,10 +759,10 @@ template class ClosePairRejectionTrackTwoPhotonResonance { public: - template + template void init(o2::framework::HistogramRegistry* /*registry*/, std::map> const& /*specs*/, - T const& /*confCpr*/, + T1 const& /*confCpr*/, int /*absChargeTrack*/) { } @@ -774,10 +780,10 @@ template class ClosePairRejectionMcParticleMcParticle { public: - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr) + T1 const& confCpr) { mCtr.init(registry, specs, confCpr, 1, 1); mCtr.setMagField(confCpr.magField.value); diff --git a/PWGCF/Femto/Core/closeTripletRejection.h b/PWGCF/Femto/Core/closeTripletRejection.h index 3a2ad4c6847..919b7553cc9 100644 --- a/PWGCF/Femto/Core/closeTripletRejection.h +++ b/PWGCF/Femto/Core/closeTripletRejection.h @@ -31,11 +31,12 @@ constexpr const char PrefixCtrTrackTrackV0[] = "CtrTrackTrackV0"; constexpr const char PrefixCtrTrackTrackCascade[] = "CtrTrackTrackCascade"; constexpr const char PrefixCtrMcParticleMcParticleMcParticle[] = "CtrMcParticleMcParticleMcParticle"; -using ConfCtrTrackTrackTrack = closepairrejection::ConfCpr; -using ConfCtrTrackTrackV0 = closepairrejection::ConfCpr; -using ConfCtrTrackTrackCascade = closepairrejection::ConfCpr; +// Q3 (not kstar) is the natural kinematic variable for triplets, so it is the default here +using ConfCtrTrackTrackTrack = closepairrejection::ConfCpr; +using ConfCtrTrackTrackV0 = closepairrejection::ConfCpr; +using ConfCtrTrackTrackCascade = closepairrejection::ConfCpr; // generated particles, no cut by default (close triplet rejection corrects a detector effect) -using ConfCtrMcParticleMcParticleMcParticle = closepairrejection::ConfCpr; +using ConfCtrMcParticleMcParticleMcParticle = closepairrejection::ConfCpr; // directory names constexpr char PrefixTrack1Track2Se[] = "CPR_Track1Track2/SE/"; @@ -81,10 +82,10 @@ class CloseTripletRejectionTrackTrackTrack CloseTripletRejectionTrackTrackTrack() = default; ~CloseTripletRejectionTrackTrackTrack() = default; - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr, + T1 const& confCpr, int absChargeTrack1, int absChargeTrack2, int absChargeTrack3) @@ -128,10 +129,10 @@ class CloseTripletRejectionTrackTrackV0 CloseTripletRejectionTrackTrackV0() = default; ~CloseTripletRejectionTrackTrackV0() = default; - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr, + T1 const& confCpr, int absChargeTrack1, int absChargeTrack2) { @@ -225,10 +226,10 @@ class CloseTripletRejectionMcParticleMcParticleMcParticle CloseTripletRejectionMcParticleMcParticleMcParticle() = default; ~CloseTripletRejectionMcParticleMcParticleMcParticle() = default; - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& specs, - T const& confCpr) + T1 const& confCpr) { mCtr12.init(registry, specs, confCpr); mCtr23.init(registry, specs, confCpr); diff --git a/PWGCF/Femto/Core/histManager.h b/PWGCF/Femto/Core/histManager.h index a0070a08f9f..a5f2aeb6175 100644 --- a/PWGCF/Femto/Core/histManager.h +++ b/PWGCF/Femto/Core/histManager.h @@ -85,5 +85,19 @@ constexpr const char* getHistDesc(EnumType variable, const ArrayType& array) return it != array.end() ? it->histdesc.data() : ""; } + +// Replace the x-axis segment of a "title; x axis; y axis[; z axis...]" histogram description +// with newTitle. Used to patch a static HistTable description at runtime once the actual axis +// quantity (e.g. which momentum type, which kinematic variable) is resolved from a Configurable. +inline std::string replaceFirstAxisTitle(std::string_view desc, std::string_view newTitle) +{ + std::string result(desc); + const auto first = result.find(';'); + const auto second = (first == std::string::npos) ? std::string::npos : result.find(';', first + 1); + if (second != std::string::npos) { + result.replace(first + 1, second - first - 1, " " + std::string(newTitle) + " "); + } + return result; +} } // namespace o2::analysis::femto::histmanager #endif // PWGCF_FEMTO_CORE_HISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/modes.h b/PWGCF/Femto/Core/modes.h index 1f4b9d16b3d..1920096a835 100644 --- a/PWGCF/Femto/Core/modes.h +++ b/PWGCF/Femto/Core/modes.h @@ -282,5 +282,22 @@ enum class KinematicVariable : o2::analysis::femto::datatypes::KinematicVariable kKinematicVariableLast = 4 }; +/// axis title for the kinematic variable plotted by CPR / pair- and triplet-cleaner QA histograms +constexpr const char* kinematicVariableToAxisTitle(KinematicVariable type) +{ + switch (type) { + case KinematicVariable::kKstar: + return "k* (GeV/#it{c})"; + case KinematicVariable::kKt: + return "k_{T} (GeV/#it{c})"; + case KinematicVariable::kMt: + return "m_{T} (GeV/#it{c}^{2})"; + case KinematicVariable::kQ3: + return "Q_{3} (GeV/#it{c})"; + default: + return "kinematic variable (GeV/#it{c})"; + } +} + }; // namespace o2::analysis::femto::modes #endif // PWGCF_FEMTO_CORE_MODES_H_ diff --git a/PWGCF/Femto/Core/pairCleaner.h b/PWGCF/Femto/Core/pairCleaner.h index e8655f0ab3b..358ba59962f 100644 --- a/PWGCF/Femto/Core/pairCleaner.h +++ b/PWGCF/Femto/Core/pairCleaner.h @@ -102,6 +102,9 @@ class BasePairCleaner BasePairCleaner() = default; virtual ~BasePairCleaner() = default; + // pairCuts is the pair/triplet histogram manager's own ConfPairCuts/ConfTripletCuts group, which + // carries this cleaner's own kinematicVariable Configurable (independent from CPR's and from + // whatever the pair/triplet histogram manager itself may be plotting elsewhere). template void init(o2::framework::HistogramRegistry* registry, T1 const& specs, @@ -122,7 +125,9 @@ class BasePairCleaner mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kStats, HistTable), getHistDesc(kStats, HistTable), getHistType(kStats, HistTable), {axisStats}); mHistogramRegistry->get(HIST(prefix) + HIST(histmanager::getHistName(kStats, HistTable)))->GetXaxis()->SetBinLabel(1, "All analyzed reco pairs"); mHistogramRegistry->get(HIST(prefix) + HIST(histmanager::getHistName(kStats, HistTable)))->GetXaxis()->SetBinLabel(2, "All blocked reco pairs"); - mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kKinematic, HistTable), getHistDesc(kKinematic, HistTable), getHistType(kKinematic, HistTable), {specs.at(kKinematic)}); + mKinematicVariable = static_cast(pairCuts.kinematicVariable.value); + std::string kinematicDesc = histmanager::replaceFirstAxisTitle(getHistDesc(kKinematic, HistTable), modes::kinematicVariableToAxisTitle(mKinematicVariable)); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kKinematic, HistTable), kinematicDesc.c_str(), getHistType(kKinematic, HistTable), {specs.at(kKinematic)}); } protected: @@ -206,6 +211,7 @@ class BasePairCleaner bool mMixPairsWithCommonAncestor = false; bool mMixPairsWithNonCommonAncestor = false; + modes::KinematicVariable mKinematicVariable = modes::KinematicVariable::kKstar; private: // require both particles to originate from the same partonic mother @@ -253,7 +259,7 @@ class TrackTrackPairCleaner : public BasePairCleaner this->fillAll(); bool isClean = this->isCleanParticlePair(track1, track2); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -294,7 +300,7 @@ class V0V0PairCleaner : public BasePairCleaner // also works for particl this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && this->isCleanParticlePair(posDaughter1, negDaughter2) && this->isCleanParticlePair(negDaughter1, posDaughter2); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -331,7 +337,7 @@ class TrackV0PairCleaner : public BasePairCleaner // also works for part auto negDaughter = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); bool isClean = this->isCleanParticlePair(posDaughter, track) && this->isCleanParticlePair(negDaughter, track); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -367,7 +373,7 @@ class TrackKinkPairCleaner : public BasePairCleaner auto chaDaughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); bool isClean = this->isCleanParticlePair(chaDaughter, track); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -405,7 +411,7 @@ class TrackCascadePairCleaner : public BasePairCleaner auto negDaughter = trackTable.rawIteratorAt(cascade.negDauId() - trackTable.offset()); bool isClean = this->isCleanParticlePair(bachelor, track) && this->isCleanParticlePair(posDaughter, track) && this->isCleanParticlePair(negDaughter, track); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -443,7 +449,7 @@ class TrackLcPairCleaner : public BasePairCleaner auto prong2 = trackTable.rawIteratorAt(lc.prong2DauId() - trackTable.offset()); bool isClean = this->isCleanParticlePair(prong0, track) && this->isCleanParticlePair(prong1, track) && this->isCleanParticlePair(prong2, track); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -478,7 +484,7 @@ class McParticleMcParticlePairCleaner : public BasePairCleaner this->fillAll(); bool isClean = this->isCleanParticlePair(particle1, particle2); if (!isClean) { - this->fillBlocked(pairHistManager.getKinematic()); + this->fillBlocked(pairHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 5d227b7500d..b6bb3ca1942 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -249,7 +249,6 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis dalitzM12{"dalitzM12", {{100, 0, 10}}, "Mass12 binning of darlitz plot"}; o2::framework::ConfigurableAxis dalitzM13{"dalitzM13", {{100, 0, 10}}, "Mass13 binning of darlitz plot"}; o2::framework::Configurable transverseMassType{"transverseMassType", static_cast(modes::TransverseMassType::kAveragePdgMass), "Type of transverse mass (0-> Average Pdg Mass, 1-> Reduced Pdg Mass, 2-> Mt from combined 4 vector)"}; - o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(modes::KinematicVariable::kKstar), "Type of kinematic variable (0->kstar, 1->kT, 2->mT) for PC and CPR plots"}; o2::framework::ConfigurableAxis binningDeltaEta{"binningDeltaEta", {{35, -1.6, 1.6}}, "Delta eta"}; o2::framework::ConfigurableAxis binningDeltaPhi{"binningDeltaPhi", {{35, -o2::constants::math::PIHalf, 3 * o2::constants::math::PIHalf}}, "Delta phi"}; o2::framework::Configurable plotBertschPratt{"plotBertschPratt", false, "(Reco/Mc) Enable 1D projections and 3D (q_out, q_side, q_long) Bertsch-Pratt histograms in LCMS"}; @@ -282,6 +281,7 @@ struct ConfPairCuts : o2::framework::ConfigurableGroup { o2::framework::Configurable mixOnlyCommonAncestor{"mixOnlyCommonAncestor", false, "Require pair to have common ancestor (in the same event)"}; o2::framework::Configurable mixOnlyNonCommonAncestor{"mixOnlyNonCommonAncestor", false, "Require pair to have non-common ancestor (in the same event)"}; o2::framework::Configurable useMotherAsAncestor{"useMotherAsAncestor", false, "Use the first ancestor (i.e. the direct mother) instead of the partonic mother when requiring (non-)common ancestry"}; + o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(modes::KinematicVariable::kKstar), "Type of kinematic variable (0->kstar, 1->kT, 2->mT) reported by the pair-cleaner kinematic plot"}; }; // the enum gives the correct index in the array @@ -667,9 +667,6 @@ class PairHistManager // transverse mass type mMtType = static_cast(ConfPairBinning.transverseMassType.value); - // kinematic variable - mKinematicVariable = static_cast(ConfPairBinning.kinematicVariable.value); - // values for cuts mKstarMin = ConfPairCuts.kstarMin.value; mKstarMax = ConfPairCuts.kstarMax.value; @@ -943,9 +940,11 @@ class PairHistManager } } - float getKinematic() const + // kinematicVariable is supplied by the caller (CPR/pair cleaner), each of which carries its own + // Configurable for it -- this manager has no opinion of its own on which variable to report + float getKinematic(modes::KinematicVariable kinematicVariable) const { - switch (mKinematicVariable) { + switch (kinematicVariable) { case modes::KinematicVariable::kKstar: return mKstar; break; @@ -1614,7 +1613,6 @@ class PairHistManager double mPdgMassNegDau2 = 0; modes::TransverseMassType mMtType = modes::TransverseMassType::kAveragePdgMass; - modes::KinematicVariable mKinematicVariable = modes::KinematicVariable::kKstar; int mAbsCharge1 = 1; int mAbsCharge2 = 1; diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h index 22d82f72d56..66e4fe3fab3 100644 --- a/PWGCF/Femto/Core/trackHistManager.h +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -1022,13 +1022,7 @@ class TrackHistManager /// with the one matching the configured momentum type void addPidHistogram(std::string const& pidDir, TrackHist hist, std::map> const& Specs) { - // descriptions have the form "title; x axis ; y axis" - std::string desc(getHistDesc(hist, HistTable)); - const auto first = desc.find(';'); - const auto second = (first == std::string::npos) ? std::string::npos : desc.find(';', first + 1); - if (second != std::string::npos) { - desc.replace(first + 1, second - first - 1, " " + std::string(modes::momentumTypeToAxisTitle(mMomentumType)) + " "); - } + std::string desc = histmanager::replaceFirstAxisTitle(getHistDesc(hist, HistTable), modes::momentumTypeToAxisTitle(mMomentumType)); mHistogramRegistry->add(pidDir + getHistNameV2(hist, HistTable), desc.c_str(), getHistType(hist, HistTable), {Specs.at(hist)}); } diff --git a/PWGCF/Femto/Core/tripletCleaner.h b/PWGCF/Femto/Core/tripletCleaner.h index 85a89c77ff9..1c7f42f4cce 100644 --- a/PWGCF/Femto/Core/tripletCleaner.h +++ b/PWGCF/Femto/Core/tripletCleaner.h @@ -44,7 +44,7 @@ class TrackTrackTrackTripletCleaner : public paircleaner::BasePairCleanerisCleanParticlePair(track2, track3) && this->isCleanParticlePair(track1, track3); if (!isClean) { - this->fillBlocked(tripletHistManager.getKinematic()); + this->fillBlocked(tripletHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -90,7 +90,7 @@ class TrackTrackV0TripletCleaner : public paircleaner::BasePairCleaner this->isCleanParticlePair(track2, posDaughter) && this->isCleanParticlePair(track2, negDaughter); if (!isClean) { - this->fillBlocked(tripletHistManager.getKinematic()); + this->fillBlocked(tripletHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -139,7 +139,7 @@ class TrackTrackCascadeTripletCleaner : public paircleaner::BasePairCleanerisCleanParticlePair(track2, negDaughter) && this->isCleanParticlePair(track2, bachelor); if (!isClean) { - this->fillBlocked(tripletHistManager.getKinematic()); + this->fillBlocked(tripletHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } @@ -182,7 +182,7 @@ class McParticleMcParticleMcParticleTripletCleaner : public paircleaner::BasePai this->isCleanParticlePair(particle2, particle3) && this->isCleanParticlePair(particle1, particle3); if (!isClean) { - this->fillBlocked(tripletHistManager.getKinematic()); + this->fillBlocked(tripletHistManager.getKinematic(this->mKinematicVariable)); } return isClean; } diff --git a/PWGCF/Femto/Core/tripletHistManager.h b/PWGCF/Femto/Core/tripletHistManager.h index 7ffc306308c..b7eadec7642 100644 --- a/PWGCF/Femto/Core/tripletHistManager.h +++ b/PWGCF/Femto/Core/tripletHistManager.h @@ -44,9 +44,8 @@ namespace o2::analysis::femto::triplethistmanager enum TripletHist { // standard 1D kQ3, - kMt, // average mt of all pairs in the triplet - // kstar betweeen single particles - kKstar12, + kMt, // average mt of all pairs in the triplet + kKstar12, // kstar between single particles, always computed kKstar13, kKstar23, // standard 2D @@ -125,7 +124,6 @@ struct ConfTripletBinning : o2::framework::ConfigurableGroup { std::string prefix = std::string("TripletBinning"); o2::framework::Configurable plot1D{"plot1D", true, "Enable 1D histograms"}; o2::framework::Configurable plot2D{"plot2D", true, "Enable 2D histograms"}; - o2::framework::Configurable plotKstar{"plotKstar", false, "Enable kstar histograms"}; o2::framework::Configurable plotPt1VsPt2VsPt3{"plotPt1VsPt2VsPt3", false, "Enable 3D histogram (Pt1 vs Pt2 vs Pt3)"}; o2::framework::Configurable plotQ3VsPt1VsPt2VsPt3{"plotQ3VsPt1VsPt2VsPt3", false, "Enable 4D histogram (Q3 vs Pt1 vs Pt2 vs Pt3)"}; o2::framework::Configurable plotQ3VsMtVsMult{"plotQ3VsMtVsMult", false, "Enable 3D histogram (Q3 vs Mt vs Mult)"}; @@ -145,7 +143,6 @@ struct ConfTripletBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis mass2{"mass2", {{100, 0, 2}}, "Mass binning for particle 2 (if particle has mass getter, otherwise PDG mass)"}; o2::framework::ConfigurableAxis mass3{"mass3", {{100, 0, 2}}, "Mass binning for particle 3 (if particle has mass getter, otherwise PDG mass)"}; o2::framework::Configurable transverseMassType{"transverseMassType", static_cast(modes::TransverseMassType::kAveragePdgMass), "Type of transverse mass (0-> Average Pdg Mass, 1-> Reduced Pdg Mass, 2-> Mt from combined 4 vector)"}; - o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(modes::KinematicVariable::kQ3), "Type of kinematic variable (2->mT, 3->Q3) for PC and CPR plots"}; }; struct ConfTripletCuts : o2::framework::ConfigurableGroup { @@ -163,6 +160,7 @@ struct ConfTripletCuts : o2::framework::ConfigurableGroup { o2::framework::Configurable mixOnlyCommonAncestor{"mixOnlyCommonAncestor", false, "Require pair to have common ancestor (in the same event)"}; o2::framework::Configurable mixOnlyNonCommonAncestor{"mixOnlyNonCommonAncestor", false, "Require pair to have non-common ancestor (in the same event)"}; o2::framework::Configurable useMotherAsAncestor{"useMotherAsAncestor", false, "Use the first ancestor (i.e. the direct mother) instead of the partonic mother when requiring (non-)common ancestry"}; + o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(modes::KinematicVariable::kQ3), "Type of kinematic variable (2->mT, 3->Q3) reported by the triplet-cleaner kinematic plot"}; }; // the enum gives the correct index in the array @@ -337,7 +335,6 @@ class TripletHistManager // transverse mass type mMtType = static_cast(ConfTripletBinning.transverseMassType.value); - mKinematicVariable = static_cast(ConfTripletBinning.kinematicVariable.value); // values for cuts mQ3Min = ConfTripletCuts.q3Min.value; @@ -351,7 +348,6 @@ class TripletHistManager mKstar23Min = ConfTripletCuts.kstar23Min.value; mKstar23Max = ConfTripletCuts.kstar23Max.value; - mPlotKstar = ConfTripletBinning.plotKstar.value; mPlotPt1VsPt2VsPt3 = ConfTripletBinning.plotPt1VsPt2VsPt3.value; mPlotQ3VsPt1VsPt2VsPt3 = ConfTripletBinning.plotQ3VsPt1VsPt2VsPt3.value; mPlotQ3VsMtVsMult = ConfTripletBinning.plotQ3VsMtVsMult.value; @@ -360,14 +356,6 @@ class TripletHistManager mPlotQ3VsMtVsPt1VsPt2VsPt3VsMultVsCent = ConfTripletBinning.plotQ3VsMtVsPt1VsPt2VsPt3VsMultVsCent.value; mPlotQ3VsKstar12VsKstar13VsKstar23VsPt1VsPt2VsPt3 = ConfTripletBinning.plotQ3VsKstar12VsKstar13VsKstar23VsPt1VsPt2VsPt3.value; - // kstar12/13/23 are only computed on demand (they cost 3 extra femtomath::getKstar() calls per - // triplet); anything that needs the value -- the 1D plots, the 7D histogram, or a cut -- - // must be OR'ed in here, otherwise it silently stays at its default of 0 - mRequireKstar = mPlotKstar || mPlotQ3VsKstar12VsKstar13VsKstar23VsPt1VsPt2VsPt3 || - mKstar12Min > 0.f || mKstar12Max > 0.f || - mKstar13Min > 0.f || mKstar13Max > 0.f || - mKstar23Min > 0.f || mKstar23Max > 0.f; - mPairCorrelationQa = ConfMixing.enablePairCorrelationQa.value; mEventMixingQa = ConfMixing.enableEventMixingQa.value; @@ -417,11 +405,9 @@ class TripletHistManager // set Q3 mQ3 = femtomath::getQ3(mParticle1, mParticle2, mParticle3); - if (mRequireKstar) { - mKstar12 = femtomath::getKstar(mParticle1, mParticle2); - mKstar13 = femtomath::getKstar(mParticle1, mParticle3); - mKstar23 = femtomath::getKstar(mParticle2, mParticle3); - } + mKstar12 = femtomath::getKstar(mParticle1, mParticle2); + mKstar13 = femtomath::getKstar(mParticle1, mParticle3); + mKstar23 = femtomath::getKstar(mParticle2, mParticle3); // if one of the particles has a mass getter, we cache the value for the filling later if constexpr (utils::HasMass) { @@ -470,14 +456,12 @@ class TripletHistManager mMt = mTrueMt; mQ3 = mTrueQ3; - if (mRequireKstar) { - mTrueKstar12 = femtomath::getKstar(mTrueParticle1, mTrueParticle2); - mTrueKstar13 = femtomath::getKstar(mTrueParticle1, mTrueParticle3); - mTrueKstar23 = femtomath::getKstar(mTrueParticle2, mTrueParticle3); - mKstar12 = mTrueKstar12; - mKstar13 = mTrueKstar13; - mKstar23 = mTrueKstar23; - } + mTrueKstar12 = femtomath::getKstar(mTrueParticle1, mTrueParticle2); + mTrueKstar13 = femtomath::getKstar(mTrueParticle1, mTrueParticle3); + mTrueKstar23 = femtomath::getKstar(mTrueParticle2, mTrueParticle3); + mKstar12 = mTrueKstar12; + mKstar13 = mTrueKstar13; + mKstar23 = mTrueKstar23; } // same event: one (truth) collision for true mult/cent @@ -597,9 +581,15 @@ class TripletHistManager } } - float getKinematic() const + // kinematicVariable is supplied by the caller (CPR/triplet cleaner), each of which carries its + // own Configurable for it -- this manager has no opinion of its own on which variable to report. + // kstar has no single value for a triplet, so kKstar reports the average of the three pair kstars. + float getKinematic(modes::KinematicVariable kinematicVariable) const { - switch (mKinematicVariable) { + switch (kinematicVariable) { + case modes::KinematicVariable::kKstar: + return (mKstar12 + mKstar13 + mKstar23) / 3.f; + break; case modes::KinematicVariable::kMt: return mMt; break; @@ -673,6 +663,9 @@ class TripletHistManager if (mPlot1d) { mHistogramRegistry->add(analysisDir + getHistNameV2(kQ3, HistTable), getHistDesc(kQ3, HistTable), getHistType(kQ3, HistTable), {Specs.at(kQ3)}); mHistogramRegistry->add(analysisDir + getHistNameV2(kMt, HistTable), getHistDesc(kMt, HistTable), getHistType(kMt, HistTable), {Specs.at(kMt)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar12, HistTable), getHistDesc(kKstar12, HistTable), getHistType(kKstar12, HistTable), {Specs.at(kKstar12)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar13, HistTable), getHistDesc(kKstar13, HistTable), getHistType(kKstar13, HistTable), {Specs.at(kKstar13)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar23, HistTable), getHistDesc(kKstar23, HistTable), getHistType(kKstar23, HistTable), {Specs.at(kKstar23)}); } if (mPlot2d) { mHistogramRegistry->add(analysisDir + getHistNameV2(kPt1VsQ3, HistTable), getHistDesc(kPt1VsQ3, HistTable), getHistType(kPt1VsQ3, HistTable), {Specs.at(kPt1VsQ3)}); @@ -684,12 +677,6 @@ class TripletHistManager // TODO: implement histograms differential im mass of the particles } - if (mPlotKstar) { - mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar12, HistTable), getHistDesc(kKstar12, HistTable), getHistType(kKstar12, HistTable), {Specs.at(kKstar12)}); - mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar13, HistTable), getHistDesc(kKstar13, HistTable), getHistType(kKstar13, HistTable), {Specs.at(kKstar13)}); - mHistogramRegistry->add(analysisDir + getHistNameV2(kKstar23, HistTable), getHistDesc(kKstar23, HistTable), getHistType(kKstar23, HistTable), {Specs.at(kKstar23)}); - } - if (mPlotPt1VsPt2VsPt3) { mHistogramRegistry->add(analysisDir + getHistNameV2(kPt1VsPt2VsPt3, HistTable), getHistDesc(kPt1VsPt2VsPt3, HistTable), getHistType(kPt1VsPt2VsPt3, HistTable), {Specs.at(kPt1VsPt2VsPt3)}); } @@ -743,7 +730,7 @@ class TripletHistManager } } - // pure mc-truth triplet (kMc without kReco) — reuses the mPlot1d/mPlot2d/mPlotKstar flags, + // pure mc-truth triplet (kMc without kReco) — reuses the mPlot1d/mPlot2d flags, // since these are histogram-content flags, not mode flags void initMcTruth(std::map> const& Specs) { @@ -751,6 +738,9 @@ class TripletHistManager if (mPlot1d) { mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3, HistTable), getHistDesc(kTrueQ3, HistTable), getHistType(kTrueQ3, HistTable), {Specs.at(kTrueQ3)}); mHistogramRegistry->add(mcDir + getHistNameV2(kTrueMt, HistTable), getHistDesc(kTrueMt, HistTable), getHistType(kTrueMt, HistTable), {Specs.at(kTrueMt)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar12, HistTable), getHistDesc(kTrueKstar12, HistTable), getHistType(kTrueKstar12, HistTable), {Specs.at(kTrueKstar12)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar13, HistTable), getHistDesc(kTrueKstar13, HistTable), getHistType(kTrueKstar13, HistTable), {Specs.at(kTrueKstar13)}); + mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar23, HistTable), getHistDesc(kTrueKstar23, HistTable), getHistType(kTrueKstar23, HistTable), {Specs.at(kTrueKstar23)}); } if (mPlot2d) { mHistogramRegistry->add(mcDir + getHistNameV2(kTruePt1VsTrueQ3, HistTable), getHistDesc(kTruePt1VsTrueQ3, HistTable), getHistType(kTruePt1VsTrueQ3, HistTable), {Specs.at(kTruePt1VsTrueQ3)}); @@ -760,11 +750,6 @@ class TripletHistManager mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3VsTrueMult, HistTable), getHistDesc(kTrueQ3VsTrueMult, HistTable), getHistType(kTrueQ3VsTrueMult, HistTable), {Specs.at(kTrueQ3VsTrueMult)}); mHistogramRegistry->add(mcDir + getHistNameV2(kTrueQ3VsTrueCent, HistTable), getHistDesc(kTrueQ3VsTrueCent, HistTable), getHistType(kTrueQ3VsTrueCent, HistTable), {Specs.at(kTrueQ3VsTrueCent)}); } - if (mPlotKstar) { - mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar12, HistTable), getHistDesc(kTrueKstar12, HistTable), getHistType(kTrueKstar12, HistTable), {Specs.at(kTrueKstar12)}); - mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar13, HistTable), getHistDesc(kTrueKstar13, HistTable), getHistType(kTrueKstar13, HistTable), {Specs.at(kTrueKstar13)}); - mHistogramRegistry->add(mcDir + getHistNameV2(kTrueKstar23, HistTable), getHistDesc(kTrueKstar23, HistTable), getHistType(kTrueKstar23, HistTable), {Specs.at(kTrueKstar23)}); - } } void fillMcTruth() @@ -772,6 +757,9 @@ class TripletHistManager if (mPlot1d) { mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3, HistTable)), mTrueQ3); mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueMt, HistTable)), mTrueMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar12, HistTable)), mTrueKstar12); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar13, HistTable)), mTrueKstar13); + mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar23, HistTable)), mTrueKstar23); } if (mPlot2d) { mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTruePt1VsTrueQ3, HistTable)), mTrueParticle1.Pt(), mTrueQ3); @@ -781,11 +769,6 @@ class TripletHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3VsTrueMult, HistTable)), mTrueQ3, mTrueMult); mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueQ3VsTrueCent, HistTable)), mTrueQ3, mTrueCent); } - if (mPlotKstar) { - mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar12, HistTable)), mTrueKstar12); - mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar13, HistTable)), mTrueKstar13); - mHistogramRegistry->fill(HIST(prefix) + HIST(McDir) + HIST(getHistName(kTrueKstar23, HistTable)), mTrueKstar23); - } } void fillAnalysis() @@ -793,6 +776,9 @@ class TripletHistManager if (mPlot1d) { mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQ3, HistTable)), mQ3); mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kMt, HistTable)), mMt); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar12, HistTable)), mKstar12); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar13, HistTable)), mKstar13); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar23, HistTable)), mKstar23); } if (mPlot2d) { mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt1VsQ3, HistTable)), mParticle1.Pt(), mQ3); @@ -803,12 +789,6 @@ class TripletHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQ3VsCent, HistTable)), mQ3, mCent); } - if (mPlotKstar) { - mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar12, HistTable)), mKstar12); - mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar13, HistTable)), mKstar13); - mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kKstar23, HistTable)), mKstar23); - } - if (mPlotPt1VsPt2VsPt3) { mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kPt1VsPt2VsPt3, HistTable)), mParticle1.Pt(), mParticle2.Pt(), mParticle3.Pt()); } @@ -857,7 +837,6 @@ class TripletHistManager double mPdgMass3 = 0.; modes::TransverseMassType mMtType = modes::TransverseMassType::kAveragePdgMass; - modes::KinematicVariable mKinematicVariable = modes::KinematicVariable::kQ3; int mAbsCharge1 = 1; int mAbsCharge2 = 1; @@ -906,8 +885,6 @@ class TripletHistManager bool mPlot1d = true; bool mPlot2d = true; - bool mPlotKstar = false; - bool mRequireKstar = false; bool mPlotPt1VsPt2VsPt3 = false; bool mPlotQ3VsPt1VsPt2VsPt3 = false; bool mPlotQ3VsMtVsMult = false; From 5d4c5a4ecbf0782ee4b4851325ff44e15638bff3 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Wed, 4 Nov 2026 07:03:42 +0100 Subject: [PATCH 4/6] Fix: reset track map once per DF, not per collision --- PWGCF/Femto/Core/trackBuilder.h | 13 + PWGCF/Femto/TableProducer/femtoProducer.cxx | 438 +++++++++++------- .../femtoProducerDerivedToDerived.cxx | 349 ++++++++------ 3 files changed, 487 insertions(+), 313 deletions(-) diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index 16bff2aad52..3e703ddd94e 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -763,6 +763,19 @@ class TrackBuilder if (!mProduceTracks && !mProduceLiteTracks) { return false; } + // getDaughterIndex() already checks indexMap and skips calling fillTrack() when the track is + // already present, so reaching this point with an existing entry only happens via the direct + // standalone-track path (fillTracks()/fillMcTracks()). Two distinct causes land here: the track + // was already registered as someone's daughter before its own collision was processed, or the + // track is itself associated with more than one collision and was already filled for an earlier + // one. Either way, keep the earlier row rather than writing a duplicate; its mask/fillType + // reflects whichever collision/role filled it first, not necessarily this one. + if (utils::getIndex(track.globalIndex(), indexMap)) { + LOG(warn) << "Track " << track.globalIndex() << " was already filled (as a daughter, or under another " + << "collision it is associated with); skipping the duplicate standalone fill. Its mask/fillType " + << "reflects whichever fill happened first, not necessarily this collision's selection."; + return true; + } int64_t lastIndex = 0; if (mProduceTracks) { trackProducts.producedTracks(collisionBuilder.collisionIndex(), diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 4b1082941ca..711183d7327 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -103,22 +103,26 @@ using Run3McGenParticles = o2::aod::McParticles; struct FemtoProducer { - // all Preslice declarations, grouped into a single data member (see o2::framework::PresliceGroup's - // own doc comment) to stay well under the 100-direct-data-member cap on task structs + // all Preslice declarations, grouped into a single data member struct : public o2::framework::PresliceGroup { o2::framework::Preslice perMcCollision = o2::aod::mcparticle::mcCollisionId; + o2::framework::Preslice perColTracks = o2::aod::track::collisionId; o2::framework::Preslice perColRecoTracks = o2::aod::track::collisionId; + o2::framework::Preslice perColV0s = o2::aod::v0data::collisionId; o2::framework::Preslice perColRecoV0s = o2::aod::v0data::collisionId; o2::framework::Preslice perColRecoPCMPhotons = o2::aod::v0photonkf::collisionId; + o2::framework::Preslice perColCascades = o2::aod::cascdata::collisionId; o2::framework::Preslice perColRecoCascades = o2::aod::cascdata::collisionId; o2::framework::Preslice perColRecoKinks = o2::aod::kinkcand::collisionId; + o2::framework::Preslice perColSigmaPlusPcms = o2::aod::sigmapluscand::collisionId; o2::framework::Preslice perColRecoSigmaPlusPcms = o2::aod::sigmapluscand::collisionId; + o2::framework::Preslice perColD0s = o2::aod::hf_cand::collisionId; o2::framework::Preslice perColRecoD0s = o2::aod::hf_cand::collisionId; + o2::framework::Preslice perColLcs = o2::aod::hf_cand::collisionId; o2::framework::Preslice perColRecoLcs = o2::aod::hf_cand::collisionId; } preslices; - // plain builder helper objects, grouped into a single data member (not Configurable/Partition/ - // Preslice/Produces, so the framework never needs to discover them individually -- free to nest) + // plain builder helper objects, grouped into a single data member struct { collisionbuilder::CollisionBuilder collisionBuilder; trackbuilder::TrackBuilder trackBuilder; @@ -443,16 +447,19 @@ struct FemtoProducer { } // processing tracks + // NOTE: trackBuilder.reset() is NOT called here. It must happen exactly once per dataframe + // (in the calling processTracksXXX/processTracksXXXMc function, before the reco-collision + // loop), not once per collision, so that fillTrack()'s "protect against double filling" dedup + // (indexMap) can actually catch a track referenced from more than one collision in the same + // dataframe instead of being wiped before it gets the chance. template void processTracks(T1 const& col, T2 const& tracksWithItsPid) { - builders.trackBuilder.reset(tracksWithItsPid); builders.trackBuilder.fillTracks(col, builders.collisionBuilder, collisionBuilderProducts, tracksWithItsPid, trackBuilderProducts); } template void processMcTracks(T1 const& col, T2 const& mcCols, T3 const& tracks, T4 const& tracksWithItsPid, T5 const& mcParticles) { - builders.trackBuilder.reset(tracksWithItsPid); builders.trackBuilder.fillMcTracks(col, builders.collisionBuilder, collisionBuilderProducts, mcCols, tracks, tracksWithItsPid, trackBuilderProducts, mcParticles, builders.mcBuilder, mcProducts); } @@ -553,163 +560,211 @@ struct FemtoProducer { // process functions - data // ========================================================================== - void processTracksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); } PROCESS_SWITCH(FemtoProducer, processTracksRun3pp, "Provide tracks", true); - void processTracksRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + void processTracksRun3PbPb(rawinputs::Run3PbPbCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); } PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPb, "Provide tracks in PbPb collisions", false); - void processTracksRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape::iterator const& col, + void processTracksRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); } PROCESS_SWITCH(FemtoProducer, processTracksRun3PbPbWithEventShape, "Provide tracks in PbPb collisions with event shape information", false); - void processTracksV0sRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksV0sRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); } PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3pp, "Provide tracks and v0s", false); - void processTracksPhotonsRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksPhotonsRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, o2::aod::V0PhotonsKF const& photons, o2::aod::V0Legs const& v0legs) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + // V0PhotonsKF/V0Legs carry a plain CollisionId column (not a framework index column), so they + // are not auto-grouped by the DPL binder and must be sliced manually, same as EMPhotonFilter.cxx + auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); + processPhotons(col, photonsThisCol, v0legs); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - // V0PhotonsKF/V0Legs carry a plain CollisionId column (not a framework index column), so they - // are not auto-grouped by the DPL binder and must be sliced manually, same as EMPhotonFilter.cxx - auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); - processPhotons(col, photonsThisCol, v0legs); } PROCESS_SWITCH(FemtoProducer, processTracksPhotonsRun3pp, "Provide tracks and PCM photons", false); - void processTracksPhotonsRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + void processTracksPhotonsRun3PbPb(rawinputs::Run3PbPbCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, o2::aod::V0PhotonsKF const& photons, o2::aod::V0Legs const& v0legs) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); + processPhotons(col, photonsThisCol, v0legs); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); - processPhotons(col, photonsThisCol, v0legs); } PROCESS_SWITCH(FemtoProducer, processTracksPhotonsRun3PbPb, "Provide tracks and PCM photons in PbPb collisions", false); - void processTracksV0sRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + void processTracksV0sRun3PbPb(rawinputs::Run3PbPbCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); } PROCESS_SWITCH(FemtoProducer, processTracksV0sRun3PbPb, "Provide tracks and v0s in PbPb collisions", false); - void processTracksV0sCascadesRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksV0sCascadesRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s, rawinputs::Run3Cascades const& cascades) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); + auto cascadesThisCol = cascades.sliceBy(preslices.perColCascades, col.globalIndex()); + processCascades(col, tracksThisCol, cascadesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); - processCascades(col, tracks, cascades); } PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3pp, "Provide tracks, v0s and cascades", false); - void processTracksV0sCascadesRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + void processTracksV0sCascadesRun3PbPb(rawinputs::Run3PbPbCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s, rawinputs::Run3Cascades const& cascades) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); + auto cascadesThisCol = cascades.sliceBy(preslices.perColCascades, col.globalIndex()); + processCascades(col, tracksThisCol, cascadesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); - processCascades(col, tracks, cascades); } PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3PbPb, "Provide tracks, v0s and cascades in PbPb collisions", false); - void processTracksV0sCascadesRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape::iterator const& col, + void processTracksV0sCascadesRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s, rawinputs::Run3Cascades const& cascades) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); + auto cascadesThisCol = cascades.sliceBy(preslices.perColCascades, col.globalIndex()); + processCascades(col, tracksThisCol, cascadesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); - processCascades(col, tracks, cascades); } PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesRun3PbPbWithEventShape, "Provide tracks, v0s and cascades in PbPb collisions with event shape information", false); - void processTracksV0sCascadesPhotonsRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape::iterator const& col, + void processTracksV0sCascadesPhotonsRun3PbPbWithEventShape(rawinputs::Run3PbPbCollisionsWithEventShape const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s, @@ -717,71 +772,94 @@ struct FemtoProducer { o2::aod::V0PhotonsKF const& photons, o2::aod::V0Legs const& v0legs) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); + auto cascadesThisCol = cascades.sliceBy(preslices.perColCascades, col.globalIndex()); + processCascades(col, tracksThisCol, cascadesThisCol); + // V0PhotonsKF/V0Legs carry a plain CollisionId column (not a framework index column), so they + // are not auto-grouped by the DPL binder and must be sliced manually, same as EMPhotonFilter.cxx + auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); + processPhotons(col, photonsThisCol, v0legs); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); - processCascades(col, tracks, cascades); - // V0PhotonsKF/V0Legs carry a plain CollisionId column (not a framework index column), so they - // are not auto-grouped by the DPL binder and must be sliced manually, same as EMPhotonFilter.cxx - auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); - processPhotons(col, photonsThisCol, v0legs); } PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesPhotonsRun3PbPbWithEventShape, "Provide tracks, v0s, cascades and PCM photons in PbPb collisions with event shape information", false); - void processTracksKinksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksKinksRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Kinks const& kinks) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto kinksThisCol = kinks.sliceBy(preslices.perColRecoKinks, col.globalIndex()); + processKinks(col, tracksThisCol, kinksThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processKinks(col, tracks, kinks); } PROCESS_SWITCH(FemtoProducer, processTracksKinksRun3pp, "Provide tracks and kinks", false); - void processTracksSigmaPlusPcmsRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksSigmaPlusPcmsRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3SigmaPlusPcms const& sigmaPlusPcms) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto sigmaPlusPcmsThisCol = sigmaPlusPcms.sliceBy(preslices.perColSigmaPlusPcms, col.globalIndex()); + processSigmaPlusPcms(col, tracksThisCol, sigmaPlusPcmsThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processSigmaPlusPcms(col, tracks, sigmaPlusPcms); } PROCESS_SWITCH(FemtoProducer, processTracksSigmaPlusPcmsRun3pp, "Provide tracks and sigma plus reconstructed with a PCM photon", false); - void processTracksV0sCascadesKinksRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksV0sCascadesKinksRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s, rawinputs::Run3Cascades const& cascades, rawinputs::Run3Kinks const& kinks) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); + auto cascadesThisCol = cascades.sliceBy(preslices.perColCascades, col.globalIndex()); + processCascades(col, tracksThisCol, cascadesThisCol); + auto kinksThisCol = kinks.sliceBy(preslices.perColRecoKinks, col.globalIndex()); + processKinks(col, tracksThisCol, kinksThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); - processCascades(col, tracks, cascades); - processKinks(col, tracks, kinks); } PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesKinksRun3pp, "Provide tracks, v0s, cascades and kinks", false); - void processTracksV0sCascadesKinksPhotonsRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksV0sCascadesKinksPhotonsRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Vzeros const& v0s, @@ -790,49 +868,66 @@ struct FemtoProducer { o2::aod::V0PhotonsKF const& photons, o2::aod::V0Legs const& v0legs) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto v0sThisCol = v0s.sliceBy(preslices.perColV0s, col.globalIndex()); + processV0s(col, tracksThisCol, v0sThisCol); + auto cascadesThisCol = cascades.sliceBy(preslices.perColCascades, col.globalIndex()); + processCascades(col, tracksThisCol, cascadesThisCol); + auto kinksThisCol = kinks.sliceBy(preslices.perColRecoKinks, col.globalIndex()); + processKinks(col, tracksThisCol, kinksThisCol); + // V0PhotonsKF/V0Legs carry a plain CollisionId column (not a framework index column), so they + // are not auto-grouped by the DPL binder and must be sliced manually, same as EMPhotonFilter.cxx + auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); + processPhotons(col, photonsThisCol, v0legs); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processV0s(col, tracks, v0s); - processCascades(col, tracks, cascades); - processKinks(col, tracks, kinks); - // V0PhotonsKF/V0Legs carry a plain CollisionId column (not a framework index column), so they - // are not auto-grouped by the DPL binder and must be sliced manually, same as EMPhotonFilter.cxx - auto photonsThisCol = photons.sliceBy(preslices.perColRecoPCMPhotons, col.globalIndex()); - processPhotons(col, photonsThisCol, v0legs); } PROCESS_SWITCH(FemtoProducer, processTracksV0sCascadesKinksPhotonsRun3pp, "Provide tracks, v0s, cascades, kinks and PCM photons", false); - void processTracksD0sRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksD0sRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3D0s const& candidates) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto candidatesThisCol = candidates.sliceBy(preslices.perColD0s, col.globalIndex()); + processD0s(col, tracksThisCol, candidatesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processD0s(col, tracks, candidates); } PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3pp, "Provide tracks and D0s", false); - void processTracksD0sRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + void processTracksD0sRun3PbPb(rawinputs::Run3PbPbCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3D0s const& candidates) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto candidatesThisCol = candidates.sliceBy(preslices.perColD0s, col.globalIndex()); + processD0s(col, tracksThisCol, candidatesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processD0s(col, tracks, candidates); } PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPb, "Provide tracks and D0s in PbPb collisions", false); @@ -843,10 +938,10 @@ struct FemtoProducer { // does no auto-grouping. Tables that are iterated over (tracks, v0s, cascades, // kinks) are sliced per collision; the full track table is passed alongside so // the v0/cascade/kink builders can resolve their daughter indices. - // These functions own the per-timeframe reset of the mc builder maps (once, before the - // reco-collision loop, in both pass-through and lazy-fill mode); processMcCollisions never - // resets them itself, since it runs once per reco collision and the dedup maps have to - // survive across all reco collisions in the timeframe. + // These functions own the per-timeframe reset of the mc builder maps AND of trackBuilder + // (once, before the reco-collision loop, in both pass-through and lazy-fill mode); neither + // processMcCollisions nor processMcTracks resets them, since they run once per reco collision + // and the dedup maps have to survive across all reco collisions in the timeframe. // ========================================================================== void processTracksRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, @@ -856,6 +951,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -879,6 +975,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -903,6 +1000,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -930,6 +1028,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -958,6 +1057,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -989,6 +1089,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1019,6 +1120,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1046,6 +1148,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1074,6 +1177,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1104,6 +1208,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1131,6 +1236,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1150,33 +1256,43 @@ struct FemtoProducer { } PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPbMc, "Provide reconstructed and generated tracks and D0s in PbPb collisions", false); - void processTracksLcsRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + void processTracksLcsRun3pp(rawinputs::Run3PpCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Lcs const& candidates) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto candidatesThisCol = candidates.sliceBy(preslices.perColLcs, col.globalIndex()); + processLcs(col, tracksThisCol, candidatesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processLcs(col, tracks, candidates); } PROCESS_SWITCH(FemtoProducer, processTracksLcsRun3pp, "Provide tracks and Lcs", false); - void processTracksLcsRun3PbPb(rawinputs::Run3PbPbCollisions::iterator const& col, + void processTracksLcsRun3PbPb(rawinputs::Run3PbPbCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3FullPidTracks const& tracks, rawinputs::Run3Lcs const& candidates) { - if (!processCollisions(col, bcs, tracks)) { - return; + builders.trackBuilder.reset(tracks); + for (auto const& col : cols) { + auto tracksThisCol = tracks.sliceBy(preslices.perColTracks, col.globalIndex()); + if (!processCollisions(col, bcs, tracksThisCol)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processTracks(col, tracksWithItsPid); + auto candidatesThisCol = candidates.sliceBy(preslices.perColLcs, col.globalIndex()); + processLcs(col, tracksThisCol, candidatesThisCol); } - auto tracksWithItsPid = o2::soa::Attach(tracks); - processTracks(col, tracksWithItsPid); - processLcs(col, tracks, candidates); } PROCESS_SWITCH(FemtoProducer, processTracksLcsRun3PbPb, "Provide tracks and Lcs in PbPb collisions", false); @@ -1188,6 +1304,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } @@ -1215,6 +1332,7 @@ struct FemtoProducer { rawinputs::Run3McGenParticles const& mcParticles) { builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); if (builders.mcBuilder.isPassThrough()) { builders.mcBuilder.fillMcPassThrough(mcCols, mcParticles, preslices.perMcCollision, mcProducts); } diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx index a4f1020df72..c7c560e0f8e 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -277,258 +277,297 @@ struct FemtoProducerDerivedToDerived { } // process functions - void processTracks(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks) + void processTracks(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracks, "Process tracks", true); - void processTracksWithMass(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithMass const& tracks) + void processTracksWithMass(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithMass const& tracks) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithMass, "Process tracks with mass", false); - void processTracksWithFitVars(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithFitVars const& tracks) + void processTracksWithFitVars(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithFitVars const& tracks) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithFitVars, "Process tracks, carrying through FitVars tables", false); - void processTracksLambdas(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoLambdas const& lambdas) + void processTracksLambdas(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoLambdas const& lambdas) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksLambdas, "Process lambdas and tracks", false); - void processTracksWithMassLambdas(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithMass const& tracks, femtotables::FemtoLambdas const& lambdas) + void processTracksWithMassLambdas(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithMass const& tracks, femtotables::FemtoLambdas const& lambdas) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache) || builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache) || builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithMassLambdas, "Process lambdas and tracks with mass", false); - void processTracksWithFitVarsLambdas(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoLambdas const& lambdas) + void processTracksWithFitVarsLambdas(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoLambdas const& lambdas) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithFitVarsLambdas, "Process lambdas and tracks, carrying through FitVars tables", false); - void processLambdas(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoLambdas const& lambdas) + void processLambdas(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoLambdas const& lambdas) { - if (builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processLambdas, "Process lambdas only (produced track table contains daughers only)", false); - void processTracksXis(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoXis const& xis) + void processTracksXis(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoXis const& xis) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.cascadeBuilder.processXis(col, xis, tracks, xiPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.cascadeBuilder.processXis(col, xis, tracks, xiPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksXis, "Process tracks and xis", false); - void processTracksWithFitVarsXis(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoXis const& xis) + void processTracksWithFitVarsXis(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoXis const& xis) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.cascadeBuilder.processXis(col, xis, tracks, xiPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.cascadeBuilder.processXis(col, xis, tracks, xiPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithFitVarsXis, "Process tracks and xis, carrying through FitVars tables", false); - void processTracksOmegas(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoOmegas const& omegas) + void processTracksOmegas(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoOmegas const& omegas) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewOmegas(col, omegas, omegaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.cascadeBuilder.processOmegas(col, omegas, tracks, omegaPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewOmegas(col, omegas, omegaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.cascadeBuilder.processOmegas(col, omegas, tracks, omegaPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksOmegas, "Process tracks and omegas", false); - void processTracksWithFitVarsOmegas(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoOmegas const& omegas) + void processTracksWithFitVarsOmegas(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoOmegas const& omegas) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewOmegas(col, omegas, omegaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.cascadeBuilder.processOmegas(col, omegas, tracks, omegaPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.cascadeBuilder.collisionHasTooFewOmegas(col, omegas, omegaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.cascadeBuilder.processOmegas(col, omegas, tracks, omegaPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithFitVarsOmegas, "Process tracks and omegas, carrying through FitVars tables", false); - void processTracksK0shorts(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoK0shorts const& k0shorts) + void processTracksK0shorts(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoK0shorts const& k0shorts) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksK0shorts, "Process k0short and tracks", false); - void processTracksWithFitVarsK0shorts(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoK0shorts const& k0shorts) + void processTracksWithFitVarsK0shorts(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracksWithFitVars const& tracks, femtotables::FemtoK0shorts const& k0shorts) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache) || builders.v0Builder.collisionHasTooFewK0shorts(col, k0shorts, k0shortPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackWithFitVarsPartition1, trackWithFitVarsPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.v0Builder.processK0shorts(col, k0shorts, tracks, k0shortPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithFitVarsK0shorts, "Process k0short and tracks, carrying through FitVars tables", false); - void processTracksSigma(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigma const& sigma) + void processTracksSigma(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigma const& sigma) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigma(col, sigma, sigmaPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.kinkBuilder.processSigma(col, sigma, tracks, sigmaPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigma(col, sigma, sigmaPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.kinkBuilder.processSigma(col, sigma, tracks, sigmaPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksSigma, "Process sigma and tracks", false); - void processTracksSigmaPlus(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlus const& sigmaplus) + void processTracksSigmaPlus(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlus const& sigmaplus) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, sigmaPlusPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, sigmaPlusPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksSigmaPlus, "Process sigmaPlus and tracks", false); - void processTracksSigmaPlusExtended(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlusExtended const& sigmaplus) + void processTracksSigmaPlusExtended(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlusExtended const& sigmaplus) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, sigmaPlusExtendedPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusExtendedPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, sigmaPlusExtendedPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusExtendedPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksSigmaPlusExtended, "Process sigmaPlus (with SigmaPlusExtras) and tracks", false); - void processTracksSigmaPlusPcm(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlusPcm const& sigmapluspcm) + void processTracksSigmaPlusPcm(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlusPcm const& sigmapluspcm) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlusPcm(col, sigmapluspcm, sigmaPlusPcmPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.kinkBuilder.processSigmaPlusPcm(col, sigmapluspcm, tracks, sigmaPlusPcmPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlusPcm(col, sigmapluspcm, sigmaPlusPcmPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.kinkBuilder.processSigmaPlusPcm(col, sigmapluspcm, tracks, sigmaPlusPcmPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksSigmaPlusPcm, "Process sigmaPlusPcm (with SigmaPlusPcmMlScores, selected on the BDT score) and tracks", false); - void processTracksSigmaPlusPcmExtended(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlusPcmExtended const& sigmapluspcm) + void processTracksSigmaPlusPcmExtended(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoSigmaPlusPcmExtended const& sigmapluspcm) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlusPcm(col, sigmapluspcm, sigmaPlusPcmExtendedPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.kinkBuilder.processSigmaPlusPcm(col, sigmapluspcm, tracks, sigmaPlusPcmExtendedPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlusPcm(col, sigmapluspcm, sigmaPlusPcmExtendedPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.kinkBuilder.processSigmaPlusPcm(col, sigmapluspcm, tracks, sigmaPlusPcmExtendedPartition, builders.trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksSigmaPlusPcmExtended, "Process sigmaPlusPcm (with SigmaPlusPcmMlScores and SigmaPlusPcmExtras, selected on the BDT score) and tracks", false); - void processTracksRho0(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoRho0s const& rho0s) + void processTracksRho0(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoRho0s const& rho0s) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.resonanceBuilder.collisionHasTooFewRho0s(col, rho0s, rho0Partition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.resonanceBuilder.processRho0s(col, rho0s, tracks, rho0Partition, builders.trackBuilder, cache, resonanceBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.resonanceBuilder.collisionHasTooFewRho0s(col, rho0s, rho0Partition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.resonanceBuilder.processRho0s(col, rho0s, tracks, rho0Partition, builders.trackBuilder, cache, resonanceBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksRho0, "Process rho0 and tracks", false); - void processTracksPhi(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoPhis const& phis) + void processTracksPhi(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoPhis const& phis) { - if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.resonanceBuilder.collisionHasTooFewPhis(col, phis, phiPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); - builders.resonanceBuilder.processPhis(col, phis, tracks, phiPartition, builders.trackBuilder, cache, resonanceBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, trackPartition1, trackPartition2, cache) || builders.resonanceBuilder.collisionHasTooFewPhis(col, phis, phiPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.trackBuilder.processTracks(col, tracks, trackPartition1, trackPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + builders.resonanceBuilder.processPhis(col, phis, tracks, phiPartition, builders.trackBuilder, cache, resonanceBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksPhi, "Process phi and tracks", false); - void processLambdasXis(femtotables::FilteredFemtoCollision const& col, femtotables::FemtoTracks const& tracks, femtotables::FemtoLambdas const& lambdas, femtotables::FemtoXis const& xis) + void processLambdasXis(femtotables::FilteredFemtoCollisions const& cols, femtotables::FemtoTracks const& tracks, femtotables::FemtoLambdas const& lambdas, femtotables::FemtoXis const& xis) { - if (builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache) || builders.cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { - return; - } builders.trackBuilder.reset(tracks); - builders.collisionBuilder.processCollision(col, collisionBuilderProducts); - builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); - builders.cascadeBuilder.processXis(col, xis, tracks, xiPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + for (auto const& col : cols) { + if (builders.v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache) || builders.cascadeBuilder.collisionHasTooFewXis(col, xis, xiPartition, cache)) { + continue; + } + builders.collisionBuilder.processCollision(col, collisionBuilderProducts); + builders.v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, builders.trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + builders.cascadeBuilder.processXis(col, xis, tracks, xiPartition, builders.trackBuilder, cache, cascadeBuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processLambdasXis, "Process lambdas and xis", false); // mc processing - // // NOTE: unlike the other process functions, this one subscribes to the full - // collision table and iterates manually. The MC index maps are keyed by source - // global index and must live for the whole dataframe void processTracksMc(femtotables::FilteredFemtoMcCollisions const& cols, femtotables::FemtoMcTracks const& tracks, o2::aod::FMcCols const& mcCols, @@ -538,13 +577,12 @@ struct FemtoProducerDerivedToDerived { { // once per dataframe builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); for (auto const& col : cols) { if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache)) { continue; } - // track indexMap is per collision by construction, so it resets here - builders.trackBuilder.reset(tracks); builders.collisionBuilder.processCollision(col, collisionBuilderProducts); builders.mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); builders.trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, @@ -562,13 +600,14 @@ struct FemtoProducerDerivedToDerived { o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { + // once per dataframe builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); for (auto const& col : cols) { if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigma(col, sigma, mcSigmaPartition, cache)) { continue; } - builders.trackBuilder.reset(tracks); builders.collisionBuilder.processCollision(col, collisionBuilderProducts); builders.mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); builders.trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, @@ -588,13 +627,14 @@ struct FemtoProducerDerivedToDerived { o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { + // once per dataframe builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); for (auto const& col : cols) { if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, mcSigmaPlusPartition, cache)) { continue; } - builders.trackBuilder.reset(tracks); builders.collisionBuilder.processCollision(col, collisionBuilderProducts); builders.mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); builders.trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, @@ -614,13 +654,14 @@ struct FemtoProducerDerivedToDerived { o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { + // once per dataframe builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); for (auto const& col : cols) { if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlus(col, sigmaplus, mcSigmaPlusExtendedPartition, cache)) { continue; } - builders.trackBuilder.reset(tracks); builders.collisionBuilder.processCollision(col, collisionBuilderProducts); builders.mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); builders.trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, @@ -640,13 +681,14 @@ struct FemtoProducerDerivedToDerived { o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { + // once per dataframe builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); for (auto const& col : cols) { if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlusPcm(col, sigmapluspcm, mcSigmaPlusPcmPartition, cache)) { continue; } - builders.trackBuilder.reset(tracks); builders.collisionBuilder.processCollision(col, collisionBuilderProducts); builders.mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); builders.trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, @@ -666,13 +708,14 @@ struct FemtoProducerDerivedToDerived { o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { + // once per dataframe builders.mcBuilder.reset(mcCols, mcParticles); + builders.trackBuilder.reset(tracks); for (auto const& col : cols) { if (builders.trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache) || builders.kinkBuilder.collisionHasTooFewSigmaPlusPcm(col, sigmapluspcm, mcSigmaPlusPcmExtendedPartition, cache)) { continue; } - builders.trackBuilder.reset(tracks); builders.collisionBuilder.processCollision(col, collisionBuilderProducts); builders.mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); builders.trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, From 44e4fc5728c7a1d3b076b8e3acbd265dd02ada05 Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Wed, 4 Nov 2026 08:19:07 +0100 Subject: [PATCH 5/6] Fix: add missing header --- PWGCF/Femto/Core/closeTripletRejection.h | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGCF/Femto/Core/closeTripletRejection.h b/PWGCF/Femto/Core/closeTripletRejection.h index 919b7553cc9..a3e2f1b8cc7 100644 --- a/PWGCF/Femto/Core/closeTripletRejection.h +++ b/PWGCF/Femto/Core/closeTripletRejection.h @@ -17,6 +17,7 @@ #define PWGCF_FEMTO_CORE_CLOSETRIPLETREJECTION_H_ #include "PWGCF/Femto/Core/closePairRejection.h" +#include "PWGCF/Femto/Core/modes.h" #include #include From 3f2b53159883e57061e6c23fd0bc05e718e6132c Mon Sep 17 00:00:00 2001 From: Anton Riedel Date: Wed, 4 Nov 2026 08:30:29 +0100 Subject: [PATCH 6/6] Feat: reuse functionality from reco decay --- PWGCF/Femto/Core/mcBuilder.h | 41 +++++++++--------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index c0f61d477f5..8cde761ad01 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -673,25 +673,11 @@ class McBuilder if (!mcParticle.has_mothers()) { return -1; } - auto motherIds = mcParticle.mothersIds(); - // adapted these checks from MCUtils in PWGEM - const int defaultMotherSize = 2; - std::vector allMotherIds; - if (motherIds.size() == defaultMotherSize && motherIds[1] > motherIds[0]) { - // keep for now, might be needed later - // && ((80 < std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) && std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) < 90) || (100 < std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) && std::abs(o2::mcgenstatus::getGenStatusCode(p.statusCode())) < 110))) { - // Pythia: mother range - for (int i = motherIds[0]; i <= motherIds[1]; i++) { - allMotherIds.push_back(i); - } - } else { - // Otherwise just use them as given - for (const int& id : motherIds) { - allMotherIds.push_back(id); - } - } + // RecoDecay::getOrderedMotherIds() implements the Pythia mother-id-range expansion (gated on the particle's gen status code) + std::vector allMotherIds; + RecoDecay::getOrderedMotherIds(mcParticle, allMotherIds, /*searchUpToQuark=*/true); // Loop over all mothers - for (const int& i : allMotherIds) { + for (const int64_t& i : allMotherIds) { if (i < 0 || i >= mcParticles.size()) { continue; @@ -722,19 +708,12 @@ class McBuilder if (!current.has_mothers()) { break; } - auto motherIds = current.mothersIds(); - int nextIndex = -1; - const int defaultMotherSize = 2; - if (motherIds.size() == defaultMotherSize && motherIds[1] > motherIds[0]) { - nextIndex = motherIds[0]; - } else { - for (const int& id : motherIds) { - if (id >= 0 && id < mcParticles.size()) { - nextIndex = id; - break; - } - } - } + // RecoDecay::getOrderedMotherIds() implements the Pythia mother-id-range expansion (gated on + // the particle's gen status code). This function only ever follows a single branch upward, + // so just the first ordered id is used. + std::vector motherIdsOrdered; + RecoDecay::getOrderedMotherIds(current, motherIdsOrdered, /*searchUpToQuark=*/true); + int64_t nextIndex = motherIdsOrdered.empty() ? -1 : motherIdsOrdered.front(); if (nextIndex < 0 || nextIndex >= mcParticles.size()) { break;