From 225279cda1d3fd6cf507e92b5f24edb8f8a68565 Mon Sep 17 00:00:00 2001 From: ptak Date: Thu, 6 Aug 2026 12:04:49 +0200 Subject: [PATCH 01/11] [PWGCF] Femto: generalize D0 builder naming for upcoming charm hadrons --- PWGCF/Femto/Core/charmHadronBuilder.h | 171 ++++++++++---------- PWGCF/Femto/Core/charmHadronHistManager.h | 10 +- PWGCF/Femto/TableProducer/femtoProducer.cxx | 16 +- 3 files changed, 101 insertions(+), 96 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index 628f392a380..631b13a4b0b 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -44,8 +44,8 @@ namespace o2::analysis::femto::charmhadronbuilder constexpr std::size_t NSizeMLScore{3u}; // filter applied in the producer task -struct ConfD0Filters : o2::framework::ConfigurableGroup { - std::string prefix = std::string("D0Filters"); +struct ConfCharmHadronFilters : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CharmHadronFilters"); // kinematic windows o2::framework::Configurable ptMin{"ptMin", 0.f, "Minimum pT"}; o2::framework::Configurable ptMax{"ptMax", 24.f, "Maximum pT"}; @@ -58,9 +58,9 @@ struct ConfD0Filters : o2::framework::ConfigurableGroup { o2::framework::Configurable yMin{"yMin", -0.8f, "Minimum rapidity"}; o2::framework::Configurable yMax{"yMax", 0.8f, "Maximum rapidity"}; // invariant-mass window - o2::framework::Configurable massMin{"massMin", 1.7f, "Minimum invariant mass for D0"}; - o2::framework::Configurable massMax{"massMax", 2.0f, "Maximum invariant mass for D0"}; - o2::framework::Configurable rejectAmbiguousHypothesis{"rejectAmbiguousHypothesis", false, "Reject candidates selected under both D0 and D0bar hypotheses"}; + o2::framework::Configurable massMin{"massMin", 1.7f, "Minimum invariant mass"}; + o2::framework::Configurable massMax{"massMax", 2.0f, "Maximum invariant mass"}; + o2::framework::Configurable rejectAmbiguousHypothesis{"rejectAmbiguousHypothesis", false, "Reject candidates selected under both particle and antiparticle hypotheses"}; }; // derived selection bits for D0s @@ -82,7 +82,7 @@ struct ConfD0Selection : o2::framework::ConfigurableGroup { o2::framework::Configurable ptMin{"ptMin", 1.f, "Minimum pT"}; o2::framework::Configurable ptMax{"ptMax", 3.f, "Maximum pT"}; // acceptance is applied as a rapidity cut in the builder; the eta/phi windows - // are kept open and exist only to satisfy MAKE_D0_PARTITION + // are kept open and exist only to satisfy macro o2::framework::Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; o2::framework::Configurable etaMax{"etaMax", 0.8f, "Maximum eta"}; o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; @@ -98,28 +98,33 @@ constexpr const char PrefixD0Selection2[] = "D0Selection2"; using ConfD0Selection1 = ConfD0Selection; using ConfD0Selection2 = ConfD0Selection; -/// The different selections for D0s -enum D0Sels { +/// The different selections for charm hadrons. +/// The enum is shared by all species in the family; which bits are actually +/// registered is decided per species in CharmHadronSelection::configure. +enum CharmHadronSels { // topological selections kCpaMin, ///< Min. CPA (cosine pointing angle) kDecayLengthMin, ///< Min. decay length + + // topological selections, 2-prong only (D0) kImpactParameterProductMax, ///< Max. product of prong impact parameters (d0*d0) kCosThetaStarMax, ///< Max. |cos(theta*)| of the decay - kD0SelsMax + kCharmHadronSelsMax }; constexpr char D0SelHistName[] = "hD0Selection"; constexpr char D0barSelHistName[] = "hD0barSelection"; -constexpr char D0SelsName[] = "D0 selection object"; -const std::unordered_map d0SelectionNames = { +constexpr char CharmHadronSelsName[] = "Charm hadron selection object"; +const std::unordered_map charmHadronSelectionNames = { {kCpaMin, "Min. CPA (cosine pointing angle)"}, {kDecayLengthMin, "Min. decay length"}, + {kImpactParameterProductMax, "Max. product of prong impact parameters (d0*d0)"}, {kCosThetaStarMax, "Max. |cos(theta*)| of the decay"}}; -/// enum for all D0 filters (loose kinematic pre-selection, applied before the bit selections) -enum D0Filters { +/// enum for all charm hadron filters (loose kinematic pre-selection, applied before the bit selections). +enum CharmHadronFilters { kDecayChannel, kHypothesis, kPtMin, @@ -133,14 +138,14 @@ enum D0Filters { kMassMin, kMassMax, kRejectAmbiguous, - kD0FiltersMax + kCharmHadronFiltersMax }; constexpr char D0FilterHistName[] = "hD0Filters"; constexpr char D0barFilterHistName[] = "hD0barFilters"; -const std::unordered_map d0FilterNames = { - {kDecayChannel, "D0 -> K pi decay channel"}, - {kHypothesis, "D0/D0bar hypothesis"}, +const std::unordered_map charmHadronFilterNames = { + {kDecayChannel, "Decay channel"}, + {kHypothesis, "Mass hypothesis"}, {kPtMin, "Minimum pT"}, {kPtMax, "Maximum pT"}, {kEtaMin, "Minimum eta"}, @@ -151,14 +156,14 @@ const std::unordered_map d0FilterNames = { {kYMax, "Maximum rapidity"}, {kMassMin, "Minimum invariant mass"}, {kMassMax, "Maximum invariant mass"}, - {kRejectAmbiguous, "Reject ambiguous D0/D0bar hypothesis"}}; + {kRejectAmbiguous, "Reject ambiguous mass hypothesis"}}; template -class D0Selection : public baseselection::BaseSelection +class CharmHadronSelection : public baseselection::BaseSelection { public: - D0Selection() = default; - ~D0Selection() override = default; + CharmHadronSelection() = default; + ~CharmHadronSelection() override = default; template void configure(o2::framework::HistogramRegistry* registry, T1& config, T2& filter) @@ -178,57 +183,57 @@ class D0Selection : public baseselection::BaseSelectionaddSelection(kCpaMin, d0SelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); - this->addSelection(kDecayLengthMin, d0SelectionNames.at(kDecayLengthMin), config.decayLengthMin.value, limits::kLowerLimit, true, true, false); - this->addSelection(kImpactParameterProductMax, d0SelectionNames.at(kImpactParameterProductMax), config.impactParameterProductMax.value, limits::kUpperLimit, true, true, false); - this->addSelection(kCosThetaStarMax, d0SelectionNames.at(kCosThetaStarMax), config.cosThetaStarMax.value, limits::kAbsUpperLimit, true, true, false); + this->addSelection(kCpaMin, charmHadronSelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kDecayLengthMin, charmHadronSelectionNames.at(kDecayLengthMin), config.decayLengthMin.value, limits::kLowerLimit, true, true, false); + this->addSelection(kImpactParameterProductMax, charmHadronSelectionNames.at(kImpactParameterProductMax), config.impactParameterProductMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kCosThetaStarMax, charmHadronSelectionNames.at(kCosThetaStarMax), config.cosThetaStarMax.value, limits::kAbsUpperLimit, true, true, false); this->template setupSelectionHistogram(registry); this->template setupFilterHistogram( registry, { - {d0FilterNames.at(kDecayChannel), 1}, - {d0FilterNames.at(kHypothesis), 1}, - {d0FilterNames.at(kPtMin), mPtMin}, - {d0FilterNames.at(kPtMax), mPtMax}, - {d0FilterNames.at(kEtaMin), mEtaMin}, - {d0FilterNames.at(kEtaMax), mEtaMax}, - {d0FilterNames.at(kPhiMin), mPhiMin}, - {d0FilterNames.at(kPhiMax), mPhiMax}, - {d0FilterNames.at(kYMin), mYMin}, - {d0FilterNames.at(kYMax), mYMax}, - {d0FilterNames.at(kMassMin), mMassMin}, - {d0FilterNames.at(kMassMax), mMassMax}, - {d0FilterNames.at(kRejectAmbiguous), static_cast(mRejectAmbiguousHypothesis)}, + {charmHadronFilterNames.at(kDecayChannel), 1}, + {charmHadronFilterNames.at(kHypothesis), 1}, + {charmHadronFilterNames.at(kPtMin), mPtMin}, + {charmHadronFilterNames.at(kPtMax), mPtMax}, + {charmHadronFilterNames.at(kEtaMin), mEtaMin}, + {charmHadronFilterNames.at(kEtaMax), mEtaMax}, + {charmHadronFilterNames.at(kPhiMin), mPhiMin}, + {charmHadronFilterNames.at(kPhiMax), mPhiMax}, + {charmHadronFilterNames.at(kYMin), mYMin}, + {charmHadronFilterNames.at(kYMax), mYMax}, + {charmHadronFilterNames.at(kMassMin), mMassMin}, + {charmHadronFilterNames.at(kMassMax), mMassMax}, + {charmHadronFilterNames.at(kRejectAmbiguous), static_cast(mRejectAmbiguousHypothesis)}, }); } template - void applySelections(T1 const& d0candidate) + void applySelections(T1 const& candidate) { this->reset(); - this->evaluateObservable(kCpaMin, d0candidate.cpa()); - this->evaluateObservable(kDecayLengthMin, d0candidate.decayLength()); - this->evaluateObservable(kImpactParameterProductMax, d0candidate.impactParameter0() * d0candidate.impactParameter1()); - this->evaluateObservable(kCosThetaStarMax, mHfHelper.cosThetaStarD0(d0candidate)); + this->evaluateObservable(kCpaMin, candidate.cpa()); + this->evaluateObservable(kDecayLengthMin, candidate.decayLength()); + this->evaluateObservable(kImpactParameterProductMax, candidate.impactParameter0() * candidate.impactParameter1()); + this->evaluateObservable(kCosThetaStarMax, mHfHelper.cosThetaStarD0(candidate)); this->template assembleBitmask(); } template - bool checkFilters(const T& d0candidate) const + bool checkFilters(const T& candidate) const { bool pass = true; bool p = false; // decay channel - p = (d0candidate.hfflag() & (1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) != 0; + p = (candidate.hfflag() & (1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) != 0; this->template fillFilter(kDecayChannel, p); pass &= p; if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { - p = d0candidate.isSelD0(); + p = candidate.isSelD0(); } else { - p = d0candidate.isSelD0bar(); + p = candidate.isSelD0bar(); } this->template fillFilter(kHypothesis, p); @@ -236,41 +241,41 @@ class D0Selection : public baseselection::BaseSelectiontemplate fillFilter(kRejectAmbiguous, p); pass &= p; - p = d0candidate.pt() > mPtMin; + p = candidate.pt() > mPtMin; this->template fillFilter(kPtMin, p); pass &= p; - p = d0candidate.pt() < mPtMax; + p = candidate.pt() < mPtMax; this->template fillFilter(kPtMax, p); pass &= p; - p = d0candidate.eta() > mEtaMin; + p = candidate.eta() > mEtaMin; this->template fillFilter(kEtaMin, p); pass &= p; - p = d0candidate.eta() < mEtaMax; + p = candidate.eta() < mEtaMax; this->template fillFilter(kEtaMax, p); pass &= p; - p = d0candidate.phi() > mPhiMin; + p = candidate.phi() > mPhiMin; this->template fillFilter(kPhiMin, p); pass &= p; - p = d0candidate.phi() < mPhiMax; + p = candidate.phi() < mPhiMax; this->template fillFilter(kPhiMax, p); pass &= p; // rapidity if (mUseYCut) { - const float y = mHfHelper.yD0(d0candidate); + const float y = mHfHelper.yD0(candidate); p = y > mYMin; this->template fillFilter(kYMin, p); pass &= p; @@ -310,7 +315,7 @@ class D0Selection : public baseselection::BaseSelection producedD0s; o2::framework::Produces producedD0Masks; @@ -318,8 +323,8 @@ struct CharmHadronBuilderProducts : o2::framework::ProducesGroup { }; // per-table produce switches (-1: auto = produce only if a downstream device subscribes; 0 off; 1 on) -struct ConfD0Tables : o2::framework::ConfigurableGroup { - std::string prefix = std::string("D0Tables"); +struct ConfCharmHadronTables : o2::framework::ConfigurableGroup { + std::string prefix = std::string("CharmHadronTables"); o2::framework::Configurable produceD0s{"produceD0s", -1, "Produce D0s (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceD0Masks{"produceD0Masks", -1, "Produce D0Masks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceD0Extras{"produceD0Extras", -1, "Produce D0Extras (-1: auto; 0 off; 1 on)"}; @@ -335,7 +340,7 @@ class CharmHadronBuilder template void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) { - LOG(info) << "Initialize femto D0 builder..."; + LOG(info) << "Initialize femto charm hadron builder..."; mProduceD0s = utils::enableTable("FD0s_001", table.produceD0s.value, initContext); mProduceD0Masks = utils::enableTable("FD0Masks_001", table.produceD0Masks.value, initContext); mProduceD0Extras = utils::enableTable("FD0Extras_001", table.produceD0Extras.value, initContext); @@ -343,20 +348,20 @@ class CharmHadronBuilder if (mProduceD0s || mProduceD0Masks || mProduceD0Extras) { mFillAnyTable = true; } else { - LOG(info) << "No D0 tables configured, selection object will not be configured..."; + LOG(info) << "No charm hadron tables configured, selection object will not be configured..."; return; } - mD0Selection.configure(registry, config, filter); - mD0Selection.printSelections(D0SelsName); + mCharmHadronSelection.configure(registry, config, filter); + mCharmHadronSelection.printSelections(CharmHadronSelsName); } template - void fillD0Tables(T1& collisionProducts, T2& d0Products, T3 const& candidate, + void fillTables(T1& collisionProducts, T2& charmHadronProducts, T3 const& candidate, float signedPt, float mass, int64_t posDauIndex, int64_t negDauIndex) { if (mProduceD0s) { - d0Products.producedD0s(collisionProducts.producedCollision.lastIndex(), + charmHadronProducts.producedD0s(collisionProducts.producedCollision.lastIndex(), signedPt, candidate.eta(), candidate.phi(), @@ -365,10 +370,10 @@ class CharmHadronBuilder negDauIndex); } if (mProduceD0Masks) { - d0Products.producedD0Masks(mD0Selection.getBitmask()); + charmHadronProducts.producedD0Masks(mCharmHadronSelection.getBitmask()); } if (mProduceD0Extras) { - d0Products.producedD0Extras( + charmHadronProducts.producedD0Extras( candidate.cpa(), candidate.cpaXY(), candidate.decayLength(), @@ -387,8 +392,8 @@ class CharmHadronBuilder } template - void fillD0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, - T5& d0Products, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) + void fillCharmHadrons(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, + T5& charmHadronProducts, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) { if (!mFillAnyTable) { return; @@ -396,11 +401,11 @@ class CharmHadronBuilder int64_t posDauIndex = 0; int64_t negDauIndex = 0; for (const auto& candidate : candidates) { - if (!mD0Selection.checkFilters(candidate)) { + if (!mCharmHadronSelection.checkFilters(candidate)) { continue; } - mD0Selection.applySelections(candidate); - if (!mD0Selection.passesAllRequiredSelections()) { + mCharmHadronSelection.applySelections(candidate); + if (!mCharmHadronSelection.passesAllRequiredSelections()) { continue; } @@ -412,16 +417,16 @@ class CharmHadronBuilder negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { - this->fillD0Tables(collisionProducts, d0Products, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + this->fillTables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); } else { - this->fillD0Tables(collisionProducts, d0Products, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + this->fillTables(collisionProducts, charmHadronProducts, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); } } } template - void fillMcD0s(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& mcCols, T5& trackProducts, - T6& d0Products, T7 const& candidates, T8 const& tracks, T9& trackBuilder, T10 const& mcParticles, T11& mcBuilder, T12& mcProducts) + void fillMcCharmHadrons(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& mcCols, T5& trackProducts, + T6& charmHadronProducts, T7 const& candidates, T8 const& tracks, T9& trackBuilder, T10 const& mcParticles, T11& mcBuilder, T12& mcProducts) { if (!mFillAnyTable) { return; @@ -429,12 +434,12 @@ class CharmHadronBuilder int64_t posDauIndex = 0; int64_t negDauIndex = 0; for (const auto& candidate : candidates) { - if (!mD0Selection.checkFilters(candidate)) { + if (!mCharmHadronSelection.checkFilters(candidate)) { continue; } - mD0Selection.applySelections(candidate); - if (!mD0Selection.passesAllRequiredSelections()) { + mCharmHadronSelection.applySelections(candidate); + if (!mCharmHadronSelection.passesAllRequiredSelections()) { continue; } @@ -446,19 +451,19 @@ class CharmHadronBuilder negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { - this->fillD0Tables(collisionProducts, d0Products, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + this->fillTables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); } else { - this->fillD0Tables(collisionProducts, d0Products, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + this->fillTables(collisionProducts, charmHadronProducts, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); } mcBuilder.template fillMcD0WithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); } } [[nodiscard]] bool fillAnyTable() const { return mFillAnyTable; } - [[nodiscard]] bool isPassThrough() const { return mD0Selection.isPassThrough(); } + [[nodiscard]] bool isPassThrough() const { return mCharmHadronSelection.isPassThrough(); } private: - D0Selection mD0Selection; + CharmHadronSelection mCharmHadronSelection; HfHelper mHfHelper; bool mProduceD0s = false; diff --git a/PWGCF/Femto/Core/charmHadronHistManager.h b/PWGCF/Femto/Core/charmHadronHistManager.h index 544a4273d95..8405da1af43 100644 --- a/PWGCF/Femto/Core/charmHadronHistManager.h +++ b/PWGCF/Femto/Core/charmHadronHistManager.h @@ -86,7 +86,7 @@ enum CharmHadronHist { o2::framework::ConfigurableAxis phi2d{"phi2d", {{200, 0, 1.f * o2::constants::math::TwoPI}}, "Phi for 2D QA"}; template -struct ConfD0Binning : o2::framework::ConfigurableGroup { +struct ConfCharmHadronBinning : o2::framework::ConfigurableGroup { std::string prefix = Prefix; CHARMHADRON_DEFAULT_BINNING(1.7, 2.0) }; @@ -95,11 +95,11 @@ struct ConfD0Binning : o2::framework::ConfigurableGroup { constexpr const char PrefixD0Binning1[] = "D0Binning1"; constexpr const char PrefixD0Binning2[] = "D0Binning2"; -using ConfD0Binning1 = ConfD0Binning; -using ConfD0Binning2 = ConfD0Binning; +using ConfD0Binning1 = ConfCharmHadronBinning; +using ConfD0Binning2 = ConfCharmHadronBinning; template -struct ConfD0QaBinning : o2::framework::ConfigurableGroup { +struct ConfCharmHadronQaBinning : o2::framework::ConfigurableGroup { std::string prefix = Prefix; o2::framework::Configurable plotTopology{"plotTopology", true, "Generate topological QA plots (cpa, decayLength, impactParameterProduct, cosThetaStar)"}; o2::framework::ConfigurableAxis massD0{"massD0", {{200, 1.7, 2.0}}, "Mass of candidates selected as D0"}; @@ -112,7 +112,7 @@ struct ConfD0QaBinning : o2::framework::ConfigurableGroup { }; constexpr const char PrefixD0QaBinning1[] = "D0QaBinning1"; -using ConfD0QaBinning1 = ConfD0QaBinning; +using ConfD0QaBinning1 = ConfCharmHadronQaBinning; // must be in sync with enum CharmHadronHist // the enum gives the correct index in the array diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index f318720d782..841dfba7190 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -132,9 +132,9 @@ struct FemtoProducer { // charm hadron builder charmhadronbuilder::CharmHadronBuilderProducts charmHadronBuilderProducts; - charmhadronbuilder::ConfD0Filters confD0Filters; + charmhadronbuilder::ConfCharmHadronFilters confCharmHadronFilters; charmhadronbuilder::ConfD0Bits confD0Bits; - charmhadronbuilder::ConfD0Tables confD0Tables; + charmhadronbuilder::ConfCharmHadronTables confCharmHadronTables; charmhadronbuilder::CharmHadronBuilder d0Builder; charmhadronbuilder::CharmHadronBuilder d0barBuilder; @@ -191,8 +191,8 @@ struct FemtoProducer { lambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context, trackBuilder); antilambdaBuilder.init(&hRegistry, confLambdaBits, confV0Filters, confV0Tables, context, trackBuilder); - d0Builder.init(&hRegistry, confD0Bits, confD0Filters, confD0Tables, context); - d0barBuilder.init(&hRegistry, confD0Bits, confD0Filters, confD0Tables, context); + d0Builder.init(&hRegistry, confD0Bits, confCharmHadronFilters, confCharmHadronTables, context); + d0barBuilder.init(&hRegistry, confD0Bits, confCharmHadronFilters, confCharmHadronTables, context); sigmaBuilder.init(&hRegistry, confSigmaBits, confKinkFilters, confKinkTables, context, trackBuilder); sigmaPlusBuilder.init(&hRegistry, confSigmaPlusBits, confKinkFilters, confKinkTables, context, trackBuilder); @@ -418,14 +418,14 @@ struct FemtoProducer { template void processD0s(T1 const& col, T2 const& tracks, T3 const& candidates) { - d0Builder.fillD0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); - d0barBuilder.fillD0s(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + d0Builder.fillCharmHadrons(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + d0barBuilder.fillCharmHadrons(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); } template void processMcD0s(T1 const& col, T2 const& mcCols, T3 const& tracks, T4 const& candidates, T5 const& mcParticles) { - d0Builder.fillMcD0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); - d0barBuilder.fillMcD0s(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + d0Builder.fillMcCharmHadrons(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + d0barBuilder.fillMcCharmHadrons(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); } // ========================================================================== From fc028dea2d20497bf81dfaecba9553d1bd187dc3 Mon Sep 17 00:00:00 2001 From: ptak Date: Fri, 7 Aug 2026 09:46:30 +0200 Subject: [PATCH 02/11] [PWGCF] Femto: add Lc data model and selection --- PWGCF/Femto/Core/charmHadronBuilder.h | 107 +++++++++++++++++++++++--- PWGCF/Femto/Core/modes.h | 4 +- PWGCF/Femto/Core/partitions.h | 17 ++++ PWGCF/Femto/DataModel/FemtoTables.h | 69 +++++++++++++++++ 4 files changed, 184 insertions(+), 13 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index 631b13a4b0b..545c45685c9 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -23,6 +23,7 @@ #include "PWGCF/Femto/Core/selectionContainer.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" #include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include @@ -73,6 +74,16 @@ struct ConfD0Bits : o2::framework::ConfigurableGroup { o2::framework::Configurable> cosThetaStarMax{"cosThetaStarMax", {1.f}, "Maximum |cos(theta*)| of the decay"}; }; +// derived selection bits for Lc +struct ConfLcBits : o2::framework::ConfigurableGroup { + std::string prefix = std::string("LcBits"); + o2::framework::Configurable passThrough{"passThrough", false, "If true, all Lcs are passed through. Bits for all selections are stored."}; + o2::framework::Configurable> cpaMin{"cpaMin", {0.9f}, "Minimum cosine of pointing angle"}; + o2::framework::Configurable> decayLengthMin{"decayLengthMin", {0.02f}, "Minimum decay length (cm)"}; + o2::framework::Configurable> chi2PcaMax{"chi2PcaMax", {1.f}, "Maximum sum of distances of the secondary vertex to its prongs (cm)"}; + o2::framework::Configurable> impactParameterProngSqSumMin{"impactParameterProngSqSumMin", {0.f}, "Minimum sum of squared prong impact parameters (cm^2)"}; +}; + // base selection for analysis task for D0s template struct ConfD0Selection : o2::framework::ConfigurableGroup { @@ -93,11 +104,36 @@ struct ConfD0Selection : o2::framework::ConfigurableGroup { o2::framework::Configurable mask{"mask", 0, "Bitmask for D0 selection"}; }; +// base selection for analysis task for Lcs +template +struct ConfLcSelection : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable pdgCodeAbs{"pdgCodeAbs", o2::constants::physics::Pdg::kLambdaCPlus, "PDG code (Lc)"}; + o2::framework::Configurable sign{"sign", 0, "Particle sign (+1: Lc; -1: Lcbar; 0: both)"}; + o2::framework::Configurable ptMin{"ptMin", 1.f, "Minimum pT"}; + o2::framework::Configurable ptMax{"ptMax", 3.f, "Maximum pT"}; + // acceptance is applied as a rapidity cut in the builder; the eta/phi windows + // are kept open and exist only to satisfy the partition macro + o2::framework::Configurable etaMin{"etaMin", -0.8f, "Minimum eta"}; + o2::framework::Configurable etaMax{"etaMax", 0.8f, "Maximum eta"}; + o2::framework::Configurable phiMin{"phiMin", 0.f, "Minimum phi"}; + o2::framework::Configurable phiMax{"phiMax", 1.f * o2::constants::math::TwoPI, "Maximum phi"}; + // signal region; side-bands remain available in the derived data + o2::framework::Configurable massMin{"massMin", 2.24f, "Minimum invariant mass for Lc"}; + o2::framework::Configurable massMax{"massMax", 2.33f, "Maximum invariant mass for Lc"}; + o2::framework::Configurable mask{"mask", 0, "Bitmask for Lc selection"}; +}; + constexpr const char PrefixD0Selection1[] = "D0Selection1"; constexpr const char PrefixD0Selection2[] = "D0Selection2"; using ConfD0Selection1 = ConfD0Selection; using ConfD0Selection2 = ConfD0Selection; +constexpr const char PrefixLcSelection1[] = "LcSelection1"; +constexpr const char PrefixLcSelection2[] = "LcSelection2"; +using ConfLcSelection1 = ConfLcSelection; +using ConfLcSelection2 = ConfLcSelection; + /// The different selections for charm hadrons. /// The enum is shared by all species in the family; which bits are actually /// registered is decided per species in CharmHadronSelection::configure. @@ -110,18 +146,27 @@ enum CharmHadronSels { kImpactParameterProductMax, ///< Max. product of prong impact parameters (d0*d0) kCosThetaStarMax, ///< Max. |cos(theta*)| of the decay + // topological selections, 3-prong only (Lc) + kChi2PcaMax, ///< Max. sum of distances of the secondary vertex to its prongs + kImpactParameterProngSqSumMin, ///< Min. sum of squared prong impact parameters + kCharmHadronSelsMax }; constexpr char D0SelHistName[] = "hD0Selection"; constexpr char D0barSelHistName[] = "hD0barSelection"; constexpr char CharmHadronSelsName[] = "Charm hadron selection object"; +constexpr char LcSelHistName[] = "hLcSelection"; +constexpr char LcBarSelHistName[] = "hLcBarSelection"; const std::unordered_map charmHadronSelectionNames = { {kCpaMin, "Min. CPA (cosine pointing angle)"}, {kDecayLengthMin, "Min. decay length"}, {kImpactParameterProductMax, "Max. product of prong impact parameters (d0*d0)"}, - {kCosThetaStarMax, "Max. |cos(theta*)| of the decay"}}; + {kCosThetaStarMax, "Max. |cos(theta*)| of the decay"}, + + {kChi2PcaMax, "Max. sum of distances of the secondary vertex to its prongs (cm)"}, + {kImpactParameterProngSqSumMin, "Min. sum of squared prong impact parameters (cm^2)"}}; /// enum for all charm hadron filters (loose kinematic pre-selection, applied before the bit selections). enum CharmHadronFilters { @@ -143,6 +188,8 @@ enum CharmHadronFilters { constexpr char D0FilterHistName[] = "hD0Filters"; constexpr char D0barFilterHistName[] = "hD0barFilters"; +constexpr char LcFilterHistName[] = "hLcFilters"; +constexpr char LcBarFilterHistName[] = "hLcBarFilters"; const std::unordered_map charmHadronFilterNames = { {kDecayChannel, "Decay channel"}, {kHypothesis, "Mass hypothesis"}, @@ -158,6 +205,20 @@ const std::unordered_map charmHadronFilterNames {kMassMax, "Maximum invariant mass"}, {kRejectAmbiguous, "Reject ambiguous mass hypothesis"}}; +template +constexpr bool isThreeProng() +{ + return modes::isEqual(hadronType, modes::CharmHadron::kLc) || + modes::isEqual(hadronType, modes::CharmHadron::kLcBar); +} + +template +constexpr bool isParticle() +{ + return modes::isEqual(hadronType, modes::CharmHadron::kD0) || + modes::isEqual(hadronType, modes::CharmHadron::kLc); +} + template class CharmHadronSelection : public baseselection::BaseSelection { @@ -185,8 +246,14 @@ class CharmHadronSelection : public baseselection::BaseSelectionaddSelection(kCpaMin, charmHadronSelectionNames.at(kCpaMin), config.cpaMin.value, limits::kLowerLimit, true, true, false); this->addSelection(kDecayLengthMin, charmHadronSelectionNames.at(kDecayLengthMin), config.decayLengthMin.value, limits::kLowerLimit, true, true, false); - this->addSelection(kImpactParameterProductMax, charmHadronSelectionNames.at(kImpactParameterProductMax), config.impactParameterProductMax.value, limits::kUpperLimit, true, true, false); - this->addSelection(kCosThetaStarMax, charmHadronSelectionNames.at(kCosThetaStarMax), config.cosThetaStarMax.value, limits::kAbsUpperLimit, true, true, false); + + if constexpr (isThreeProng()) { + this->addSelection(kChi2PcaMax, charmHadronSelectionNames.at(kChi2PcaMax), config.chi2PcaMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kImpactParameterProngSqSumMin, charmHadronSelectionNames.at(kImpactParameterProngSqSumMin), config.impactParameterProngSqSumMin.value, limits::kLowerLimit, true, true, false); + } else { + this->addSelection(kImpactParameterProductMax, charmHadronSelectionNames.at(kImpactParameterProductMax), config.impactParameterProductMax.value, limits::kUpperLimit, true, true, false); + this->addSelection(kCosThetaStarMax, charmHadronSelectionNames.at(kCosThetaStarMax), config.cosThetaStarMax.value, limits::kAbsUpperLimit, true, true, false); + } this->template setupSelectionHistogram(registry); this->template setupFilterHistogram( @@ -214,8 +281,14 @@ class CharmHadronSelection : public baseselection::BaseSelectionreset(); this->evaluateObservable(kCpaMin, candidate.cpa()); this->evaluateObservable(kDecayLengthMin, candidate.decayLength()); - this->evaluateObservable(kImpactParameterProductMax, candidate.impactParameter0() * candidate.impactParameter1()); - this->evaluateObservable(kCosThetaStarMax, mHfHelper.cosThetaStarD0(candidate)); + + if constexpr (isThreeProng()) { + this->evaluateObservable(kChi2PcaMax, candidate.chi2PCA()); + this->evaluateObservable(kImpactParameterProngSqSumMin, candidate.impactParameterProngSqSum()); + } else { + this->evaluateObservable(kImpactParameterProductMax, candidate.impactParameter0() * candidate.impactParameter1()); + this->evaluateObservable(kCosThetaStarMax, mHfHelper.cosThetaStarD0(candidate)); + } this->template assembleBitmask(); } @@ -226,24 +299,31 @@ class CharmHadronSelection : public baseselection::BaseSelection()) { + p = (candidate.hfflag() & (1 << o2::aod::hf_cand_3prong::DecayType::LcToPKPi)) != 0; + } else { + p = (candidate.hfflag() & (1 << o2::aod::hf_cand_2prong::DecayType::D0ToPiK)) != 0; + } this->template fillFilter(kDecayChannel, p); pass &= p; if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { p = candidate.isSelD0(); - } else { + } else if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { p = candidate.isSelD0bar(); + } else { // kLc / kLcBar + p = candidate.isSelLcToPKPi() || candidate.isSelLcToPiKP(); } - this->template fillFilter(kHypothesis, p); pass &= p; bool competing = false; if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { competing = candidate.isSelD0bar(); - } else { + } else if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { competing = candidate.isSelD0(); + } else { // Lc / Lcbar: ambiguous means both mass hypotheses passed + competing = candidate.isSelLcToPKPi() && candidate.isSelLcToPiKP(); } p = !mRejectAmbiguousHypothesis || !competing; this->template fillFilter(kRejectAmbiguous, p); @@ -275,7 +355,12 @@ class CharmHadronSelection : public baseselection::BaseSelection()) { + y = mHfHelper.yLc(candidate); + } else { + y = mHfHelper.yD0(candidate); + } p = y > mYMin; this->template fillFilter(kYMin, p); pass &= p; @@ -286,7 +371,7 @@ class CharmHadronSelection : public baseselection::BaseSelectiontemplate fillFilterSummary(pass); - return this->isPassThrough() || pass; + return this->isPassThrough() || pass;ż } [[nodiscard]] float getMassMin() const diff --git a/PWGCF/Femto/Core/modes.h b/PWGCF/Femto/Core/modes.h index 5f41ff42788..57e53837633 100644 --- a/PWGCF/Femto/Core/modes.h +++ b/PWGCF/Femto/Core/modes.h @@ -174,8 +174,8 @@ enum class TwoTrackResonance : o2::analysis::femto::datatypes::TwoTrackResonance enum class CharmHadron : o2::analysis::femto::datatypes::CharmHadronType { kD0, kD0Bar, - kDplus, - kLc + kLc, + kLcBar }; enum class QvecDetector : o2::analysis::femto::datatypes::QvecDetectorType { diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index 68508aa4c70..5706bb9e639 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -179,6 +179,23 @@ (o2::aod::femtobase::stored::mass < (selection).massMax) && \ ncheckbit(o2::aod::femtocharmhadrons::mask, (selection).mask) +// partition for 3-prong charm hadrons +// sign of signedPt encodes particle (+) / antiparticle (-) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define MAKE_CHARM3PRONG_PARTITION(selection) \ + ifnode((selection).sign.node() != 0, \ + ifnode((selection).sign.node() > 0, o2::aod::femtobase::stored::signedPt > 0.f, o2::aod::femtobase::stored::signedPt < 0.f), true) && \ + (nabs(o2::aod::femtobase::stored::signedPt) > (selection).ptMin) && \ + (nabs(o2::aod::femtobase::stored::signedPt) < (selection).ptMax) && \ + (o2::aod::femtobase::stored::eta > (selection).etaMin) && \ + (o2::aod::femtobase::stored::eta < (selection).etaMax) && \ + (o2::aod::femtobase::stored::phi > (selection).phiMin) && \ + (o2::aod::femtobase::stored::phi < (selection).phiMax) && \ + (o2::aod::femtobase::stored::mass > (selection).massMin) && \ + (o2::aod::femtobase::stored::mass < (selection).massMax) && \ + ncheckbit(o2::aod::femtocharmhadrons::mask, (selection).mask) + + // macros for mc collisions (mc only) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define MAKE_MC_COLLISION_FILTER(selection) \ diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index d7aa6003e6d..db94734ce64 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -1146,6 +1146,10 @@ DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CharmHadronMaskTy // daughter links: row indices into the femto track table DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! + prong (pion in D0) DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! - prong (kaon in D0) +// daughter links, 3-prong: row indices into the femto track table. +DECLARE_SOA_INDEX_COLUMN_FULL(Prong0Dau, prong0Dau, int32_t, FTracks, "_Prong0Dau"); //! prong 0 (proton in Lc -> p K pi) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong1Dau, prong1Dau, int32_t, FTracks, "_Prong1Dau"); //! prong 1 (kaon, opposite sign to the mother) +DECLARE_SOA_INDEX_COLUMN_FULL(Prong2Dau, prong2Dau, int32_t, FTracks, "_Prong2Dau"); //! prong 2 (pion in Lc -> p K pi) // QA/debug columns DECLARE_SOA_COLUMN(Cpa, cpa, float); @@ -1154,6 +1158,12 @@ DECLARE_SOA_COLUMN(DecayLength, decayLength, float); DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! d0*d0 of the two prongs DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float); +// QA/debug columns, 3-prong only +DECLARE_SOA_COLUMN(Chi2PCA, chi2PCA, float); //! sum of distances of the secondary vertex to its prongs +DECLARE_SOA_COLUMN(ImpactParameterProngSqSum, impactParameterProngSqSum, float); //! sum of squared prong impact parameters, 3-prong analogue of d0*d0 +DECLARE_SOA_COLUMN(ImpactParameter0, impactParameter0, float); //! impact parameter of prong 0 +DECLARE_SOA_COLUMN(ImpactParameter1, impactParameter1, float); //! impact parameter of prong 1 +DECLARE_SOA_COLUMN(ImpactParameter2, impactParameter2, float); //! impact parameter of prong 2 // ML BDT scores: [0] background, [1] prompt (D0 from c), [2] non-prompt (D0 from b decay) DECLARE_SOA_COLUMN(MlProbD0Bkg, mlProbD0Bkg, float); //! D0 hypothesis: background score DECLARE_SOA_COLUMN(MlProbD0Prompt, mlProbD0Prompt, float); //! D0 hypothesis: prompt score @@ -1163,6 +1173,17 @@ DECLARE_SOA_COLUMN(MlProbD0barPrompt, mlProbD0barPrompt, float); //! D0bar DECLARE_SOA_COLUMN(MlProbD0barNonPrompt, mlProbD0barNonPrompt, float); //! D0bar hypothesis: non-prompt DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int8_t); //! PWGHF selection flag DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int8_t); //! PWGHF selection flag +// ML BDT scores for Lc, both mass hypotheses: [0] background, [1] prompt, [2] non-prompt +DECLARE_SOA_COLUMN(MlProbLcToPKPiBkg, mlProbLcToPKPiBkg, float); //! Lc -> p K pi hypothesis: background score +DECLARE_SOA_COLUMN(MlProbLcToPKPiPrompt, mlProbLcToPKPiPrompt, float); //! Lc -> p K pi hypothesis: prompt score +DECLARE_SOA_COLUMN(MlProbLcToPKPiNonPrompt, mlProbLcToPKPiNonPrompt, float); //! Lc -> p K pi hypothesis: non-prompt score +DECLARE_SOA_COLUMN(MlProbLcToPiKPBkg, mlProbLcToPiKPBkg, float); //! Lc -> pi K p hypothesis: background score +DECLARE_SOA_COLUMN(MlProbLcToPiKPPrompt, mlProbLcToPiKPPrompt, float); //! Lc -> pi K p hypothesis: prompt score +DECLARE_SOA_COLUMN(MlProbLcToPiKPNonPrompt, mlProbLcToPiKPNonPrompt, float); //! Lc -> pi K p hypothesis: non-prompt score +DECLARE_SOA_COLUMN(IsSelLcToPKPi, isSelLcToPKPi, int8_t); //! PWGHF selection flag +DECLARE_SOA_COLUMN(IsSelLcToPiKP, isSelLcToPiKP, int8_t); //! PWGHF selection flag +// mass under the competing hypothesis, following the MassK0short-in-lambda-table pattern +DECLARE_SOA_COLUMN(MassCompetingHypothesis, massCompetingHypothesis, float); //! Lc mass under the hypothesis that was not accepted } // namespace femtocharmhadrons DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0s_001, "FD0", 1, //! femto D0/D0bar (kinematics only) @@ -1206,6 +1227,52 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Extras_001, "FD0EXTRA", 1, //! femto D0 QA femtocharmhadrons::IsSelD0bar); using FD0Extras = FD0Extras_001; +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLcs_001, "FLC", 1, //! femto Lc/Lcbar (kinematics only) + o2::soa::Index<>, + femtobase::stored::FColId, + femtobase::stored::SignedPt, //! sign encodes Lc(+)/Lcbar(-) + femtobase::stored::Eta, + femtobase::stored::Phi, + femtobase::stored::Mass, //! mass of the accepted hypothesis + femtocharmhadrons::Prong0DauId, + femtocharmhadrons::Prong1DauId, + femtocharmhadrons::Prong2DauId, + femtobase::dynamic::Sign, + femtobase::dynamic::Pt, + femtobase::dynamic::P, + femtobase::dynamic::Px, + femtobase::dynamic::Py, + femtobase::dynamic::Pz, + femtobase::dynamic::Theta); +using FLcs = FLcs_001; +using StoredFLcs = StoredFLcs_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLcMasks_001, "FLCMASK", 1, //! femto Lc selection bitmask + femtocharmhadrons::Mask); +using FLcMasks = FLcMasks_001; +using StoredFLcMasks = StoredFLcMasks_001; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLcExtras_001, "FLCEXTRA", 1, //! femto Lc QA / debug + femtocharmhadrons::Cpa, + femtocharmhadrons::CpaXY, + femtocharmhadrons::DecayLength, + femtocharmhadrons::DecayLengthXY, + femtocharmhadrons::Chi2PCA, + femtocharmhadrons::ImpactParameterProngSqSum, + femtocharmhadrons::ImpactParameter0, + femtocharmhadrons::ImpactParameter1, + femtocharmhadrons::ImpactParameter2, + femtocharmhadrons::MassCompetingHypothesis, + femtocharmhadrons::MlProbLcToPKPiBkg, + femtocharmhadrons::MlProbLcToPKPiPrompt, + femtocharmhadrons::MlProbLcToPKPiNonPrompt, + femtocharmhadrons::MlProbLcToPiKPBkg, + femtocharmhadrons::MlProbLcToPiKPPrompt, + femtocharmhadrons::MlProbLcToPiKPNonPrompt, + femtocharmhadrons::IsSelLcToPKPi, // raw PWGHF selection flags + femtocharmhadrons::IsSelLcToPiKP); +using FLcExtras = FLcExtras_001; + // tables for monte carlo namespace femtomccollisions { @@ -1291,6 +1358,8 @@ DECLARE_SOA_TABLE(FK0shortLabels, "AOD", "FK0SHORTLABEL", femtolabels::FMcPartic DECLARE_SOA_TABLE(FD0Labels, "AOD", "FD0LABEL", femtolabels::FMcParticleId); +DECLARE_SOA_TABLE(FLcLabels, "AOD", "FLCLABEL", femtolabels::FMcParticleId); + DECLARE_SOA_TABLE(FSigmaLabels, "AOD", "FSIGMALABEL", femtolabels::FMcParticleId); DECLARE_SOA_TABLE(FSigmaPlusLabels, "AOD", "FSIGMAPLUSLABEL", femtolabels::FMcParticleId); From fd3c9d5197340af907375d82254f4727446fb8f3 Mon Sep 17 00:00:00 2001 From: ptak Date: Tue, 11 Aug 2026 09:15:10 +0200 Subject: [PATCH 03/11] [PWGCF] Femto: fill Lc tables in the charm hadron builder --- PWGCF/Femto/Core/charmHadronBuilder.h | 197 ++++++++++++++++---- PWGCF/Femto/Core/mcBuilder.h | 52 +++++- PWGCF/Femto/TableProducer/femtoProducer.cxx | 110 ++++++++++- 3 files changed, 320 insertions(+), 39 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index 545c45685c9..7ca7bbeec40 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -371,7 +371,7 @@ class CharmHadronSelection : public baseselection::BaseSelectiontemplate fillFilterSummary(pass); - return this->isPassThrough() || pass;ż + return this->isPassThrough() || pass; } [[nodiscard]] float getMassMin() const @@ -405,6 +405,9 @@ struct CharmHadronBuilderProducts : o2::framework::ProducesGroup { o2::framework::Produces producedD0s; o2::framework::Produces producedD0Masks; o2::framework::Produces producedD0Extras; + o2::framework::Produces producedLcs; + o2::framework::Produces producedLcMasks; + o2::framework::Produces producedLcExtras; }; // per-table produce switches (-1: auto = produce only if a downstream device subscribes; 0 off; 1 on) @@ -413,6 +416,9 @@ struct ConfCharmHadronTables : o2::framework::ConfigurableGroup { o2::framework::Configurable produceD0s{"produceD0s", -1, "Produce D0s (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceD0Masks{"produceD0Masks", -1, "Produce D0Masks (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable produceD0Extras{"produceD0Extras", -1, "Produce D0Extras (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLcs{"produceLcs", -1, "Produce Lcs (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLcMasks{"produceLcMasks", -1, "Produce LcMasks (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable produceLcExtras{"produceLcExtras", -1, "Produce LcExtras (-1: auto; 0 off; 1 on)"}; }; template @@ -425,24 +431,43 @@ class CharmHadronBuilder template void init(o2::framework::HistogramRegistry* registry, T1& config, T2& filter, T3& table, T4& initContext) { - LOG(info) << "Initialize femto charm hadron builder..."; - mProduceD0s = utils::enableTable("FD0s_001", table.produceD0s.value, initContext); - mProduceD0Masks = utils::enableTable("FD0Masks_001", table.produceD0Masks.value, initContext); - mProduceD0Extras = utils::enableTable("FD0Extras_001", table.produceD0Extras.value, initContext); - - if (mProduceD0s || mProduceD0Masks || mProduceD0Extras) { + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0) || modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + LOG(info) << "Initialize femto D0 builder..."; + } + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { + LOG(info) << "Initialize femto D0bar builder..."; + } + mProduceD0s = utils::enableTable("FD0s_001", table.produceD0s.value, initContext); + mProduceD0Masks = utils::enableTable("FD0Masks_001", table.produceD0Masks.value, initContext); + mProduceD0Extras = utils::enableTable("FD0Extras_001", table.produceD0Extras.value, initContext); + } + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kLc) || modes::isEqual(hadronType, modes::CharmHadron::kLcBar)) { + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kLc)) { + LOG(info) << "Initialize femto Lc builder..."; + } + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kLcBar)) { + LOG(info) << "Initialize femto Lcbar builder..."; + } + mProduceLcs = utils::enableTable("FLcs_001", table.produceLcs.value, initContext); + mProduceLcMasks = utils::enableTable("FLcMasks_001", table.produceLcMasks.value, initContext); + mProduceLcExtras = utils::enableTable("FLcExtras_001", table.produceLcExtras.value, initContext); + } + if (mProduceD0s || mProduceD0Masks || mProduceD0Extras || + mProduceLcs || mProduceLcMasks || mProduceLcExtras) { mFillAnyTable = true; } else { - LOG(info) << "No charm hadron tables configured, selection object will not be configured..."; + LOG(info) << "No tables configured, Selection object will not be configured..."; + LOG(info) << "Initialization done..."; return; } - mCharmHadronSelection.configure(registry, config, filter); mCharmHadronSelection.printSelections(CharmHadronSelsName); + LOG(info) << "Initialization done..."; } template - void fillTables(T1& collisionProducts, T2& charmHadronProducts, T3 const& candidate, + void fillD0Tables(T1& collisionProducts, T2& charmHadronProducts, T3 const& candidate, float signedPt, float mass, int64_t posDauIndex, int64_t negDauIndex) { if (mProduceD0s) { @@ -476,6 +501,47 @@ class CharmHadronBuilder } } + template + void fillLcTables(T1& collisionProducts, T2& charmHadronProducts, T3 const& candidate, + float signedPt, float mass, float massCompeting, + int64_t protonDauIndex, int64_t kaonDauIndex, int64_t pionDauIndex) + { + if (mProduceLcs) { + charmHadronProducts.producedLcs(collisionProducts.producedCollision.lastIndex(), + signedPt, + candidate.eta(), + candidate.phi(), + mass, + protonDauIndex, + kaonDauIndex, + pionDauIndex); + } + if (mProduceLcMasks) { + charmHadronProducts.producedLcMasks(mCharmHadronSelection.getBitmask()); + } + if (mProduceLcExtras) { + charmHadronProducts.producedLcExtras( + candidate.cpa(), + candidate.cpaXY(), + candidate.decayLength(), + candidate.decayLengthXY(), + candidate.chi2PCA(), + candidate.impactParameterProngSqSum(), + candidate.impactParameter0(), + candidate.impactParameter1(), + candidate.impactParameter2(), + massCompeting, + candidate.mlProbLcToPKPi().size() < NSizeMLScore ? -1.f : candidate.mlProbLcToPKPi()[0], + candidate.mlProbLcToPKPi().size() < NSizeMLScore ? -1.f : candidate.mlProbLcToPKPi()[1], + candidate.mlProbLcToPKPi().size() < NSizeMLScore ? -1.f : candidate.mlProbLcToPKPi()[2], + candidate.mlProbLcToPiKP().size() < NSizeMLScore ? -1.f : candidate.mlProbLcToPiKP()[0], + candidate.mlProbLcToPiKP().size() < NSizeMLScore ? -1.f : candidate.mlProbLcToPiKP()[1], + candidate.mlProbLcToPiKP().size() < NSizeMLScore ? -1.f : candidate.mlProbLcToPiKP()[2], + static_cast(candidate.isSelLcToPKPi()), + static_cast(candidate.isSelLcToPiKP())); + } + } + template void fillCharmHadrons(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& charmHadronProducts, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) @@ -483,8 +549,6 @@ class CharmHadronBuilder if (!mFillAnyTable) { return; } - int64_t posDauIndex = 0; - int64_t negDauIndex = 0; for (const auto& candidate : candidates) { if (!mCharmHadronSelection.checkFilters(candidate)) { continue; @@ -494,17 +558,46 @@ class CharmHadronBuilder continue; } - collisionBuilder.template fillCollision(collisionProducts, col); - - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); - posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, collisionBuilder); - negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0) || modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + + collisionBuilder.template fillCollision(collisionProducts, col); + + int64_t posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, collisionBuilder); + int64_t negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + this->fillD0Tables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + } else { + this->fillD0Tables(collisionProducts, charmHadronProducts, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + } + } - if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { - this->fillTables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); - } else { - this->fillTables(collisionProducts, charmHadronProducts, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kLc) || modes::isEqual(hadronType, modes::CharmHadron::kLcBar)) { + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + auto prong2 = candidate.template prong2_as(); + + // the charge of prong 0 is the charge of the Lc, so the species is decided here + if ((prong0.sign() > 0) != isParticle()) { + continue; + } + + // remap the prong onto the accepted hypothesis so that the proton is always first + bool const isPKPi = candidate.isSelLcToPKPi(); + auto const& protonProng = isPKPi ? prong0 : prong2; + auto const& pionProng = isPKPi ? prong2 : prong0; + float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); + float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); + + collisionBuilder.template fillCollision(collisionProducts, col); + int64_t const protonDauIndex = trackBuilder.template getDaughterIndex(protonProng, trackProducts, collisionBuilder); + int64_t const kaonDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); + int64_t const pionDauIndex = trackBuilder.template getDaughterIndex(pionProng, trackProducts, collisionBuilder); + + float const signedPt = isParticle() ? candidate.pt() : -candidate.pt(); + this->fillLcTables(collisionProducts, charmHadronProducts, candidate, signedPt, mass, massCompeting, protonDauIndex, kaonDauIndex, pionDauIndex); } } } @@ -516,31 +609,62 @@ class CharmHadronBuilder if (!mFillAnyTable) { return; } - int64_t posDauIndex = 0; - int64_t negDauIndex = 0; for (const auto& candidate : candidates) { if (!mCharmHadronSelection.checkFilters(candidate)) { continue; } - + mCharmHadronSelection.applySelections(candidate); if (!mCharmHadronSelection.passesAllRequiredSelections()) { continue; } + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0) || modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + + collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); + + int64_t posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + int64_t negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { + this->fillD0Tables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); + } else { + this->fillD0Tables(collisionProducts, charmHadronProducts, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + } + mcBuilder.template fillMcD0WithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); + } - collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kLc) || modes::isEqual(hadronType, modes::CharmHadron::kLcBar)) { + auto prong0 = candidate.template prong0_as(); + auto prong1 = candidate.template prong1_as(); + auto prong2 = candidate.template prong2_as(); - auto prong0 = candidate.template prong0_as(); - auto prong1 = candidate.template prong1_as(); - posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); - negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + // the charge of prong 0 is the charge of the Lc, so the species is decided here + if ((prong0.sign() > 0) != isParticle()) { + continue; + } - if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { - this->fillTables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); - } else { - this->fillTables(collisionProducts, charmHadronProducts, candidate, -candidate.pt(), mHfHelper.invMassD0barToKPi(candidate), posDauIndex, negDauIndex); + // remap the prongs onto the accepted hypothesis so that the proton is always first + bool const isPKPi = candidate.isSelLcToPKPi(); + auto const& protonProng = isPKPi ? prong0 : prong2; + auto const& pionProng = isPKPi ? prong2 : prong0; + float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); + float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); + + collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); + + int64_t const protonDauIndex = trackBuilder.template getDaughterIndex(protonProng, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + int64_t const kaonDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + int64_t const pionDauIndex = trackBuilder.template getDaughterIndex(pionProng, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + + float const signedPt = isParticle() ? candidate.pt() : -candidate.pt(); + this->fillLcTables(collisionProducts, charmHadronProducts, candidate, signedPt, mass, massCompeting, protonDauIndex, kaonDauIndex, pionDauIndex); + mcBuilder.template fillMcLcWithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); } - mcBuilder.template fillMcD0WithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); + + } } @@ -554,6 +678,9 @@ class CharmHadronBuilder bool mProduceD0s = false; bool mProduceD0Masks = false; bool mProduceD0Extras = false; + bool mProduceLcs = false; + bool mProduceLcMasks = false; + bool mProduceLcExtras = false; bool mFillAnyTable = false; }; } // namespace o2::analysis::femto::charmhadronbuilder diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index 488eeda4bb5..e92c9cc4a1d 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -63,6 +63,7 @@ struct McBuilderProducts : o2::framework::ProducesGroup { o2::framework::Produces producedLambdaLabels; o2::framework::Produces producedK0shortLabels; o2::framework::Produces producedD0Labels; + o2::framework::Produces producedLcLabels; o2::framework::Produces producedSigmaLabels; o2::framework::Produces producedSigmaPlusLabels; o2::framework::Produces producedXiLabels; @@ -82,6 +83,7 @@ struct ConfMcTables : o2::framework::ConfigurableGroup { o2::framework::Configurable producedLambdaLabels{"producedLambdaLabels", -1, "Produce lambda labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedK0shortLabels{"producedK0shortLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedD0Labels{"producedD0Labels", -1, "Produce D0 labels (-1: auto; 0 off; 1 on)"}; + o2::framework::Configurable producedLcLabels{"producedLcLabels", -1, "Produce Lc labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedSigmaLabels{"producedSigmaLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedSigmaPlusLabels{"producedSigmaPlusLabels", -1, "Produce k0short labels (-1: auto; 0 off; 1 on)"}; o2::framework::Configurable producedXiLabels{"producedXiLabels", -1, "Produce xi labels (-1: auto; 0 off; 1 on)"}; @@ -148,6 +150,7 @@ class McBuilder mProduceLambdaLabels = utils::enableTable("FLambdaLabels", table.producedLambdaLabels.value, initContext); mProduceK0shortLabels = utils::enableTable("FK0shortLabels", table.producedK0shortLabels.value, initContext); mProduceD0Labels = utils::enableTable("FD0Labels", table.producedD0Labels.value, initContext); + mProduceLcLabels = utils::enableTable("FLcLabels", table.producedLcLabels.value, initContext); mProduceSigmaLabels = utils::enableTable("FSigmaLabels", table.producedSigmaLabels.value, initContext); mProduceSigmaPlusLabels = utils::enableTable("FSigmaPlusLabels", table.producedSigmaPlusLabels.value, initContext); mProduceXiLabels = utils::enableTable("FXiLabels", table.producedXiLabels.value, initContext); @@ -160,7 +163,7 @@ class McBuilder mProduceLambdaLabels || mProduceK0shortLabels || mProduceSigmaLabels || mProduceSigmaPlusLabels || mProduceXiLabels || mProduceOmegaLabels || - mProduceD0Labels) { + mProduceD0Labels || mProduceLcLabels) { mFillAnyTable = true; } else { LOG(info) << "No tables configured..."; @@ -257,7 +260,8 @@ class McBuilder { // charm hadrons get a prompt/non-prompt origin, consistent with the reco-matched path; // all other particles use the generic getOrigin inside getOrCreateMcParticleRow - if (std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0) { + const int pdgAbs = std::abs(mcParticle.pdgCode()); + if (pdgAbs == o2::constants::physics::Pdg::kD0) { // truth-level acceptance for the efficiency denominator: keep only // generated D0 -> K pi decays inside the rapidity acceptance int8_t sign = 0; @@ -268,6 +272,15 @@ class McBuilder return; } } + if (pdgAbs == o2::constants::physics::Pdg::kLambdaCPlus) { + int8_t sign = 0; + if (!RecoDecay::isMatchedMCGen(mcParticles, mcParticle, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { + return; + } + if(std::abs(mcParticle.y()) > mCharmYGenMax) { + return; + } + } this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); } @@ -357,6 +370,35 @@ class McBuilder mcProducts.producedD0Labels(mcParticleRow); } + // Lc has no direct MC label. The three prongs are matched to a generated + // Lc -> p K pi decay;depthMax = 2 because the decay also proceeds through intermediate resonances. + template + void fillMcLcWithLabel(T1 const& lcCandidate, T2 const& /*tracks*/, T3 const& mcParticles, T4 const& /*mcCols*/, T5& mcProducts) + { + if (!mProduceLcLabels) { + mcProducts.producedLcLabels(-1); + return; + } + + auto prong0 = lcCandidate.template prong0_as(); + auto prong1 = lcCandidate.template prong1_as(); + auto prong2 = lcCandidate.template prong2_as(); + auto arrayDaughters = std::array{prong0, prong1, prong2}; + int8_t sign = 0; + const int indexMcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); + + if (indexMcRec < 0) { + mcProducts.producedLcLabels(-1); + return; + } + + auto mcParticle = mcParticles.rawIteratorAt(indexMcRec); + auto mcCol = mcParticle.template mcCollision_as(); + int64_t mcParticleRow = this->getOrCreateMcParticleRow(mcParticle, mcParticles, mcCol, mcProducts); + + mcProducts.producedLcLabels(mcParticleRow); + } + template void fillMcSigmaWithLabel(T1 const& sigmaDaughter, T2 const& mcParticles, T3 const& mcCols, T4& mcProducts) { @@ -467,7 +509,10 @@ class McBuilder template int64_t getOrCreateMcParticleRow(T1 const& mcParticle, T2 const& mcParticles, T3 const& mcCol, T4& mcProducts) { - auto origin = std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kD0 + const int pdgAbs = std::abs(mcParticle.pdgCode()); + const bool isCharmHadron = (pdgAbs == o2::constants::physics::Pdg::kD0 || + pdgAbs == o2::constants::physics::Pdg::kLambdaCPlus); + auto origin = isCharmHadron ? this->getHeavyFlavourOrigin(mcParticle, mcParticles) : this->getOrigin(mcParticle); return this->buildMcParticleRow(mcParticle, mcParticles, mcCol, origin, mcProducts); @@ -686,6 +731,7 @@ class McBuilder bool mProduceLambdaLabels = false; bool mProduceK0shortLabels = false; bool mProduceD0Labels = false; + bool mProduceLcLabels = false; bool mProduceSigmaLabels = false; bool mProduceSigmaPlusLabels = false; bool mProduceXiLabels = false; diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 841dfba7190..4b4f093060a 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -84,6 +84,9 @@ using Run3RecoVzeros = o2::soa::Join; using Run3D0s = soa::Join; using Run3RecoD0s = soa::Join; +using Run3Lcs = soa::Join; +using Run3RecoLcs = soa::Join; + using Run3Cascades = o2::soa::Join; using Run3RecoCascades = o2::soa::Join; @@ -101,6 +104,7 @@ struct FemtoProducer { o2::framework::Preslice perColRecoCascades = o2::aod::cascdata::collisionId; o2::framework::Preslice perColRecoKinks = o2::aod::kinkcand::collisionId; o2::framework::Preslice perColRecoD0s = o2::aod::hf_cand::collisionId; + o2::framework::Preslice perColRecoLcs = o2::aod::hf_cand::collisionId; // ccdb config collisionbuilder::ConfCcdb confCcdb; @@ -133,10 +137,13 @@ struct FemtoProducer { // charm hadron builder charmhadronbuilder::CharmHadronBuilderProducts charmHadronBuilderProducts; charmhadronbuilder::ConfCharmHadronFilters confCharmHadronFilters; - charmhadronbuilder::ConfD0Bits confD0Bits; charmhadronbuilder::ConfCharmHadronTables confCharmHadronTables; + charmhadronbuilder::ConfD0Bits confD0Bits; + charmhadronbuilder::ConfLcBits confLcBits; charmhadronbuilder::CharmHadronBuilder d0Builder; charmhadronbuilder::CharmHadronBuilder d0barBuilder; + charmhadronbuilder::CharmHadronBuilder lcBuilder; + charmhadronbuilder::CharmHadronBuilder lcBarBuilder; // cascade builder cascadebuilder::CascadeBuilderProducts cascadeBuilderProducts; @@ -194,6 +201,9 @@ struct FemtoProducer { d0Builder.init(&hRegistry, confD0Bits, confCharmHadronFilters, confCharmHadronTables, context); d0barBuilder.init(&hRegistry, confD0Bits, confCharmHadronFilters, confCharmHadronTables, context); + lcBuilder.init(&hRegistry, confLcBits, confCharmHadronFilters, confCharmHadronTables, context); + lcBarBuilder.init(&hRegistry, confLcBits, confCharmHadronFilters, confCharmHadronTables, context); + sigmaBuilder.init(&hRegistry, confSigmaBits, confKinkFilters, confKinkTables, context, trackBuilder); sigmaPlusBuilder.init(&hRegistry, confSigmaPlusBits, confKinkFilters, confKinkTables, context, trackBuilder); @@ -428,6 +438,20 @@ struct FemtoProducer { d0barBuilder.fillMcCharmHadrons(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); } + // processing Lcs + template + void processLcs(T1 const& col, T2 const& tracks, T3 const& candidates) + { + lcBuilder.fillCharmHadrons(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + lcBarBuilder.fillCharmHadrons(col, collisionBuilder, collisionBuilderProducts, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder); + } + template + void processMcLcs(T1 const& col, T2 const& mcCols, T3 const& tracks, T4 const& candidates, T5 const& mcParticles) + { + lcBuilder.fillMcCharmHadrons(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + lcBarBuilder.fillMcCharmHadrons(col, collisionBuilder, collisionBuilderProducts, mcCols, trackBuilderProducts, charmHadronBuilderProducts, candidates, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts); + } + // ========================================================================== // process functions - data // ========================================================================== @@ -901,6 +925,90 @@ struct FemtoProducer { } PROCESS_SWITCH(FemtoProducer, processTracksD0sRun3PbPbMc, "Provide reconstructed and generated tracks and D0s in PbPb collisions", false); + void processTracksLcsRun3pp(rawinputs::Run3PpCollisions::iterator const& col, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3Lcs const& candidates) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + 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, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3FullPidTracks const& tracks, + rawinputs::Run3Lcs const& candidates) + { + if (!processCollisions(col, bcs, tracks)) { + return; + } + 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); + + void processTracksLcsRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + rawinputs::Run3PpMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3RecoLcs const& lcs, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto lcsThisCol = lcs.sliceBy(perColRecoLcs, col.globalIndex()); + processMcLcs(col, mcCols, tracks, lcsThisCol, mcParticles); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksLcsRun3ppMc, "Provide reconstructed and generated tracks and Lcs", false); + + void processTracksLcsRun3PbPbMc(rawinputs::Run3PbPbMcGenCollisions const& mcCols, + rawinputs::Run3PbPbMcRecoCollisions const& cols, + o2::aod::BCsWithTimestamps const& bcs, + rawinputs::Run3McRecoTracks const& tracks, + rawinputs::Run3RecoLcs const& lcs, + rawinputs::Run3McGenParticles const& mcParticles) + { + if (mcBuilder.isPassThrough()) { + mcBuilder.reset(mcCols, mcParticles); + mcBuilder.fillMcPassThrough(mcCols, mcParticles, perMcCollision, mcProducts, pdgDb); + } + + for (const auto& col : cols) { + auto tracksThisCol = tracks.sliceBy(perColRecoTracks, col.globalIndex()); + if (!processMcCollisions(col, mcCols, bcs, tracksThisCol, mcParticles)) { + continue; + } + auto tracksWithItsPid = o2::soa::Attach(tracksThisCol); + processMcTracks(col, mcCols, tracksThisCol, tracksWithItsPid, mcParticles); + + auto lcsThisCol = lcs.sliceBy(perColRecoLcs, col.globalIndex()); + processMcLcs(col, mcCols, tracks, lcsThisCol, mcParticles); + } + } + PROCESS_SWITCH(FemtoProducer, processTracksLcsRun3PbPbMc, "Provide reconstructed and generated tracks and Lcs in PbPb collisions", false); + // ========================================================================== // process functions - generator level only (for MCGEN datasets) // ========================================================================== From bcab8a6f69f7a61d857c89fabf823b445716048a Mon Sep 17 00:00:00 2001 From: ptak Date: Tue, 11 Aug 2026 11:22:22 +0200 Subject: [PATCH 04/11] [PWGCF] Femto: add Lc QA and generalize the charm hadron QA task --- PWGCF/Femto/Core/charmHadronHistManager.h | 254 +++++++++++++++++----- PWGCF/Femto/Core/pairBuilder.h | 12 +- PWGCF/Femto/Core/trackHistManager.h | 19 ++ PWGCF/Femto/Tasks/CMakeLists.txt | 4 +- PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx | 252 +++++++++++++++++++++ PWGCF/Femto/Tasks/femtoD0Qa.cxx | 161 -------------- 6 files changed, 484 insertions(+), 218 deletions(-) create mode 100644 PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx delete mode 100644 PWGCF/Femto/Tasks/femtoD0Qa.cxx diff --git a/PWGCF/Femto/Core/charmHadronHistManager.h b/PWGCF/Femto/Core/charmHadronHistManager.h index 8405da1af43..aba6be98953 100644 --- a/PWGCF/Femto/Core/charmHadronHistManager.h +++ b/PWGCF/Femto/Core/charmHadronHistManager.h @@ -16,6 +16,7 @@ #ifndef PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ #define PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ +#include "PWGCF/Femto/Core/charmHadronBuilder.h" #include "PWGCF/Femto/Core/histManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/trackHistManager.h" @@ -49,18 +50,32 @@ enum CharmHadronHist { kPtVsEta, kPtVsPhi, kPhiVsEta, + + // mass under each hypothesis kMassD0, kMassD0bar, + kMassLcToPKPi, + kMassLcToPiKP, + + // ml scores kMlBkg, kMlPrompt, kMlNonPrompt, + + // topology, common kCpa, kCpaXY, kDecayLength, kDecayLengthXY, + + // topology, 2-prong only (D0) kImpactParameterProduct, kCosThetaStar, + // topology, 3-prong only (Lc) + kChi2Pca, + kImpactParameterProngSqSum, + // mc kOrigin, kPdg, @@ -91,6 +106,12 @@ struct ConfCharmHadronBinning : o2::framework::ConfigurableGroup { CHARMHADRON_DEFAULT_BINNING(1.7, 2.0) }; +template +struct ConfLcBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + CHARMHADRON_DEFAULT_BINNING(2.15, 2.42) +}; + #undef CHARMHADRON_DEFAULT_BINNING constexpr const char PrefixD0Binning1[] = "D0Binning1"; @@ -98,6 +119,9 @@ constexpr const char PrefixD0Binning2[] = "D0Binning2"; using ConfD0Binning1 = ConfCharmHadronBinning; using ConfD0Binning2 = ConfCharmHadronBinning; +constexpr const char PrefixLcBinning1[] = "LcBinning1"; +using ConfLcBinning1 = ConfLcBinning; + template struct ConfCharmHadronQaBinning : o2::framework::ConfigurableGroup { std::string prefix = Prefix; @@ -114,6 +138,22 @@ struct ConfCharmHadronQaBinning : o2::framework::ConfigurableGroup { constexpr const char PrefixD0QaBinning1[] = "D0QaBinning1"; using ConfD0QaBinning1 = ConfCharmHadronQaBinning; +template +struct ConfLcQaBinning : o2::framework::ConfigurableGroup { + std::string prefix = Prefix; + o2::framework::Configurable plotTopology{"plotTopology", true, "Generate topological QA plots (cpa, decayLength, chi2Pca, impactParameterProngSqSum)"}; + o2::framework::ConfigurableAxis massLcToPKPi{"massLcToPKPi", {{200, 2.15, 2.42}}, "Mass under the p K pi hypothesis"}; + o2::framework::ConfigurableAxis massLcToPiKP{"massLcToPiKP", {{200, 2.15, 2.42}}, "Mass under the pi K p hypothesis"}; + o2::framework::ConfigurableAxis mlScore{"mlScore", {{100, 0.f, 1.f}}, "BDT ML score (bkg/prompt/non-prompt)"}; + o2::framework::ConfigurableAxis cpa{"cpa", {{100, 0.9f, 1.f}}, "Cosine of pointing angle"}; + o2::framework::ConfigurableAxis decayLength{"decayLength", {{200, 0.f, 0.2f}}, "Decay length (cm)"}; + o2::framework::ConfigurableAxis chi2Pca{"chi2Pca", {{200, 0.f, 0.1f}}, "Sum of distances of the secondary vertex to its prongs (cm)"}; + o2::framework::ConfigurableAxis impactParameterProngSqSum{"impactParameterProngSqSum", {{200, 0.f, 0.01f}}, "Sum of squared prong impact parameters (cm^2)"}; +}; + +constexpr const char PrefixLcQaBinning1[] = "LcQaBinning1"; +using ConfLcQaBinning1 = ConfLcQaBinning; + // must be in sync with enum CharmHadronHist // the enum gives the correct index in the array constexpr std::array, kCharmHadronHistLast> HistTable = { @@ -128,6 +168,8 @@ constexpr std::array, kCharmHadronHistLas {kPhiVsEta, o2::framework::HistType::kTH2F, "hPhiVsEta", "#varphi vs #eta; #varphi; #eta"}, {kMassD0, o2::framework::HistType::kTH1F, "hMassD0", "Invariant mass of D^{0} candidates; m_{Inv} (GeV/#it{c}^{2}); Entries"}, {kMassD0bar, o2::framework::HistType::kTH1F, "hMassD0bar", "Invariant mass of #bar{D}^{0} candidates; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kMassLcToPKPi, o2::framework::HistType::kTH1F, "hMassLcToPKPi", "Invariant mass under the p K #pi hypothesis; m_{Inv} (GeV/#it{c}^{2}); Entries"}, + {kMassLcToPiKP, o2::framework::HistType::kTH1F, "hMassLcToPiKP", "Invariant mass under the #pi K p hypothesis; m_{Inv} (GeV/#it{c}^{2}); Entries"}, {kMlBkg, o2::framework::HistType::kTH1F, "hMlBkg", "BDT background score; ML score (bkg); Entries"}, {kMlPrompt, o2::framework::HistType::kTH1F, "hMlPrompt", "BDT prompt score; ML score (prompt); Entries"}, {kMlNonPrompt, o2::framework::HistType::kTH1F, "hMlNonPrompt", "BDT non-prompt score; ML score (non-prompt); Entries"}, @@ -137,6 +179,8 @@ constexpr std::array, kCharmHadronHistLas {kDecayLengthXY, o2::framework::HistType::kTH1F, "hDecayLengthXY", "Decay length (XY); L_{XY} (cm); Entries"}, {kImpactParameterProduct, o2::framework::HistType::kTH1F, "hImpactParameterProduct", "Product of daughter impact parameters; d_{0}^{K} #times d_{0}^{#pi} (cm^{2}); Entries"}, {kCosThetaStar, o2::framework::HistType::kTH1F, "hCosThetaStar", "Cosine of decay angle in D0 rest frame; cos(#theta*); Entries"}, + {kChi2Pca, o2::framework::HistType::kTH1F, "hChi2Pca", "Sum of distances of the secondary vertex to its prongs; #Sigma d (cm); Entries"}, + {kImpactParameterProngSqSum, o2::framework::HistType::kTH1F, "hImpactParameterProngSqSum", "Sum of squared prong impact parameters; #Sigma d_{0}^{2} (cm^{2}); Entries"}, {kOrigin, o2::framework::HistType::kTH1F, "hOrigin", "MC origin (prompt / non-prompt); origin; Entries"}, {kPdg, o2::framework::HistType::kTH1F, "hPdg", "PDG code of matched generated particle; PDG code; Entries"}, {kPdgMother, o2::framework::HistType::kTH1F, "hPdgMother", "PDG code of the mother; PDG code; Entries"}, @@ -212,14 +256,48 @@ auto makeD0McQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQ CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; } +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define LC_HIST_QA_MAP(conf) \ + {kMassLcToPKPi, {(conf).massLcToPKPi}}, \ + {kMassLcToPiKP, {(conf).massLcToPiKP}}, \ + {kMlBkg, {(conf).mlScore}}, \ + {kMlPrompt, {(conf).mlScore}}, \ + {kMlNonPrompt, {(conf).mlScore}}, \ + {kCpa, {(conf).cpa}}, \ + {kCpaXY, {(conf).cpa}}, \ + {kDecayLength, {(conf).decayLength}}, \ + {kDecayLengthXY, {(conf).decayLength}}, \ + {kChi2Pca, {(conf).chi2Pca}}, \ + {kImpactParameterProngSqSum, {(conf).impactParameterProngSqSum}}, + +template +auto makeLcQaHistSpecMap(const T& confBinningQa) +{ + return std::map>{ + LC_HIST_QA_MAP(confBinningQa)}; +} + +template +auto makeLcMcQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQa) +{ + return std::map>{ + CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis) + LC_HIST_QA_MAP(confBinningQa) + CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; +} + + #undef CHARMHADRON_HIST_ANALYSIS_MAP #undef CHARMHADRON_HIST_MC_MAP #undef CHARMHADRON_HIST_QA_MAP +#undef LC_HIST_QA_MAP // prefixes for the output directories in the histogram registry constexpr char PrefixD01[] = "D01/"; constexpr char PrefixD02[] = "D02/"; constexpr char PrefixD0Qa[] = "D0QA/"; +constexpr char PrefixLc1[] = "Lc1/"; +constexpr char PrefixLcQa[] = "LcQA/"; constexpr std::string_view AnalysisDir = "Analysis/"; constexpr std::string_view McDir = "MC/"; constexpr std::string_view QaDir = "QA/"; @@ -229,6 +307,7 @@ constexpr std::string_view QaDir = "QA/"; template class CharmHadronHistManager { @@ -242,15 +321,24 @@ class CharmHadronHistManager std::map> const& CharmHadronSpecs, T const& ConfCharmHadronSelection, std::map> const& Prong0Specs, - std::map> const& Prong1Specs) + std::map> const& Prong1Specs, + std::map> const& Prong2Specs) { mHistogramRegistry = registry; mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value); - auto [prong0PdgCodeAbs, prong1PdgCodeAbs] = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); + auto prongPdgCodes = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); - mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prong0PdgCodeAbs); - mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prong1PdgCodeAbs); + if constexpr (charmhadronbuilder::isThreeProng()) { + constexpr int protonSign = charmhadronbuilder::isParticle() ? SignPlus : SignMinus; + constexpr int kaonSign = -protonSign; + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, protonSign, prongPdgCodes[0]); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, kaonSign, prongPdgCodes[1]); + mProng2Manager.template init(registry, Prong2Specs, AbsCharge, protonSign, prongPdgCodes[2]); + } else { + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prongPdgCodes[0]); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prongPdgCodes[1]); + } if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->initAnalysis(CharmHadronSpecs); @@ -261,7 +349,7 @@ class CharmHadronHistManager } // init for analysis and qa - template + template void init(o2::framework::HistogramRegistry* registry, std::map> const& CharmHadronSpecs, std::map> const& CharmHadronQaSpecs, @@ -270,16 +358,26 @@ class CharmHadronHistManager std::map> const& Prong0Specs, T3 const& ConfProng0BinningQa, std::map> const& Prong1Specs, - T4 const& ConfProng1BinningQa) + T4 const& ConfProng1BinningQa, + std::map> const& Prong2Specs, + T5 const& ConfProng2BinningQa) { mHistogramRegistry = registry; mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value); this->enableOptionalHistograms(ConfCharmHadronQaBinning); - auto [prong0PdgCodeAbs, prong1PdgCodeAbs] = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); + auto prongPdgCodes = this->resolveProngPdgCodes(ConfCharmHadronSelection.sign.value); - mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prong0PdgCodeAbs, ConfProng0BinningQa); - mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prong1PdgCodeAbs, ConfProng1BinningQa); + if constexpr (charmhadronbuilder::isThreeProng()) { + constexpr int ProtonSign = charmhadronbuilder::isParticle() ? SignPlus : SignMinus; + constexpr int KaonSign = -ProtonSign; + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, ProtonSign, prongPdgCodes[0], ConfProng0BinningQa); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, KaonSign, prongPdgCodes[1], ConfProng1BinningQa); + mProng2Manager.template init(registry, Prong2Specs, AbsCharge, ProtonSign, prongPdgCodes[2], ConfProng2BinningQa); + } else { + mProng0Manager.template init(registry, Prong0Specs, AbsCharge, SignPlus, prongPdgCodes[0], ConfProng0BinningQa); + mProng1Manager.template init(registry, Prong1Specs, AbsCharge, SignMinus, prongPdgCodes[1], ConfProng1BinningQa); + } if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->initAnalysis(CharmHadronSpecs); @@ -295,10 +393,19 @@ class CharmHadronHistManager template void fill(T1 const& charmHadronCandidate, T2 const& tracks) { - auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); - mProng0Manager.template fill(prong0, tracks); - auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); - mProng1Manager.template fill(prong1, tracks); + if constexpr (charmhadronbuilder::isThreeProng()) { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.prong0DauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.prong1DauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks); + auto prong2 = tracks.rawIteratorAt(charmHadronCandidate.prong2DauId() - tracks.offset()); + mProng2Manager.template fill(prong2, tracks); + } else { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks); + } if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->fillAnalysis(charmHadronCandidate); @@ -311,10 +418,19 @@ class CharmHadronHistManager template void fill(T1 const& charmHadronCandidate, T2 const& tracks, T3 const& col, T4 const& mcParticles, T5 const& mcMothers, T6 const& mcPartonicMothers) { - auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); - mProng0Manager.template fill(prong0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); - auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); - mProng1Manager.template fill(prong1, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + if constexpr (charmhadronbuilder::isThreeProng()) { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.prong0DauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.prong1DauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + auto prong2 = tracks.rawIteratorAt(charmHadronCandidate.prong2DauId() - tracks.offset()); + mProng2Manager.template fill(prong2, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + } else { + auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset()); + mProng0Manager.template fill(prong0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset()); + mProng1Manager.template fill(prong1, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + } if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) { this->fillAnalysis(charmHadronCandidate); @@ -335,18 +451,29 @@ class CharmHadronHistManager // charge of the prongs is fixed by the PWGHF reconstruction: prong0 is the positive // daughter, prong1 the negative one. The D0/D0bar hypothesis only swaps which prong is // the pion and which is the kaon, not their charge. - std::pair resolveProngPdgCodes(int sign) + std::array resolveProngPdgCodes(int sign) { - if (mPdgCode != o2::constants::physics::Pdg::kD0) { - LOG(fatal) << "PDG code for charm hadron has to be D0"; - } - if (sign > 0) { - // D0 -> pi+ K- - return {std::abs(PDG_t::kPiPlus), std::abs(PDG_t::kKMinus)}; + if constexpr (charmhadronbuilder::isThreeProng()) { + if (mPdgCode != o2::constants::physics::Pdg::kLambdaCPlus) { + LOG(fatal) << "PDG code for a 3-prong charm hadron has to be Lc"; + } + if (sign < 0) { + mPdgCode = -1 * mPdgCode; // switch sign for Lcbar + } + // Lc -> p K pi, prongs stored remapped so that prong 0 is always the proton + return {std::abs(PDG_t::kProton), std::abs(PDG_t::kKPlus), std::abs(PDG_t::kPiPlus)}; + } else { + if (mPdgCode != o2::constants::physics::Pdg::kD0) { + LOG(fatal) << "PDG code for charm hadron has to be D0"; + } + if (sign > 0) { + // D0 -> pi+ K- + return {std::abs(PDG_t::kPiPlus), std::abs(PDG_t::kKMinus), 0}; + } + // D0bar -> K+ pi- + mPdgCode = -1 * mPdgCode; // switch sign for D0bar + return {std::abs(PDG_t::kKPlus), std::abs(PDG_t::kPiMinus), 0}; } - // D0bar -> K+ pi- - mPdgCode = -1 * mPdgCode; // switch sign for D0bar - return {std::abs(PDG_t::kKPlus), std::abs(PDG_t::kPiMinus)}; } template @@ -386,8 +513,13 @@ class CharmHadronHistManager void initQa(std::map> const& CharmHadronQaSpecs) { std::string qaDir = std::string(charmHadronPrefix) + std::string(QaDir); - mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0, HistTable), getHistDesc(kMassD0, HistTable), getHistType(kMassD0, HistTable), {CharmHadronQaSpecs.at(kMassD0)}); - mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0bar, HistTable), getHistDesc(kMassD0bar, HistTable), getHistType(kMassD0bar, HistTable), {CharmHadronQaSpecs.at(kMassD0bar)}); + if constexpr (charmhadronbuilder::isThreeProng()) { + mHistogramRegistry->add(qaDir + getHistNameV2(kMassLcToPKPi, HistTable), getHistDesc(kMassLcToPKPi, HistTable), getHistType(kMassLcToPKPi, HistTable), {CharmHadronQaSpecs.at(kMassLcToPKPi)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassLcToPiKP, HistTable), getHistDesc(kMassLcToPiKP, HistTable), getHistType(kMassLcToPiKP, HistTable), {CharmHadronQaSpecs.at(kMassLcToPiKP)}); + } else { + mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0, HistTable), getHistDesc(kMassD0, HistTable), getHistType(kMassD0, HistTable), {CharmHadronQaSpecs.at(kMassD0)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kMassD0bar, HistTable), getHistDesc(kMassD0bar, HistTable), getHistType(kMassD0bar, HistTable), {CharmHadronQaSpecs.at(kMassD0bar)}); + } mHistogramRegistry->add(qaDir + getHistNameV2(kMlBkg, HistTable), getHistDesc(kMlBkg, HistTable), getHistType(kMlBkg, HistTable), {CharmHadronQaSpecs.at(kMlBkg)}); mHistogramRegistry->add(qaDir + getHistNameV2(kMlPrompt, HistTable), getHistDesc(kMlPrompt, HistTable), getHistType(kMlPrompt, HistTable), {CharmHadronQaSpecs.at(kMlPrompt)}); mHistogramRegistry->add(qaDir + getHistNameV2(kMlNonPrompt, HistTable), getHistDesc(kMlNonPrompt, HistTable), getHistType(kMlNonPrompt, HistTable), {CharmHadronQaSpecs.at(kMlNonPrompt)}); @@ -397,11 +529,17 @@ class CharmHadronHistManager mHistogramRegistry->add(qaDir + getHistNameV2(kCpaXY, HistTable), getHistDesc(kCpaXY, HistTable), getHistType(kCpaXY, HistTable), {CharmHadronQaSpecs.at(kCpaXY)}); mHistogramRegistry->add(qaDir + getHistNameV2(kDecayLength, HistTable), getHistDesc(kDecayLength, HistTable), getHistType(kDecayLength, HistTable), {CharmHadronQaSpecs.at(kDecayLength)}); mHistogramRegistry->add(qaDir + getHistNameV2(kDecayLengthXY, HistTable), getHistDesc(kDecayLengthXY, HistTable), getHistType(kDecayLengthXY, HistTable), {CharmHadronQaSpecs.at(kDecayLengthXY)}); - mHistogramRegistry->add(qaDir + getHistNameV2(kImpactParameterProduct, HistTable), getHistDesc(kImpactParameterProduct, HistTable), getHistType(kImpactParameterProduct, HistTable), {CharmHadronQaSpecs.at(kImpactParameterProduct)}); - mHistogramRegistry->add(qaDir + getHistNameV2(kCosThetaStar, HistTable), getHistDesc(kCosThetaStar, HistTable), getHistType(kCosThetaStar, HistTable), {CharmHadronQaSpecs.at(kCosThetaStar)}); + if constexpr (charmhadronbuilder::isThreeProng()) { + mHistogramRegistry->add(qaDir + getHistNameV2(kChi2Pca, HistTable), getHistDesc(kChi2Pca, HistTable), getHistType(kChi2Pca, HistTable), {CharmHadronQaSpecs.at(kChi2Pca)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kImpactParameterProngSqSum, HistTable), getHistDesc(kImpactParameterProngSqSum, HistTable), getHistType(kImpactParameterProngSqSum, HistTable), {CharmHadronQaSpecs.at(kImpactParameterProngSqSum)}); + } else { + mHistogramRegistry->add(qaDir + getHistNameV2(kImpactParameterProduct, HistTable), getHistDesc(kImpactParameterProduct, HistTable), getHistType(kImpactParameterProduct, HistTable), {CharmHadronQaSpecs.at(kImpactParameterProduct)}); + mHistogramRegistry->add(qaDir + getHistNameV2(kCosThetaStar, HistTable), getHistDesc(kCosThetaStar, HistTable), getHistType(kCosThetaStar, HistTable), {CharmHadronQaSpecs.at(kCosThetaStar)}); + } } } + void initMc(std::map> const& CharmHadronSpecs) { std::string mcDir = std::string(charmHadronPrefix) + std::string(McDir); @@ -424,38 +562,55 @@ class CharmHadronHistManager template void fillQa(T const& charmHadronCandidate) { - // invariant mass split by hypothesis: D0 (sign > 0) or D0bar (sign < 0) - if (charmHadronCandidate.sign() > 0) { - mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0, HistTable)), charmHadronCandidate.mass()); - } else { - mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0bar, HistTable)), charmHadronCandidate.mass()); - } - - // BDT scores of the accepted hypothesis: D0 (sign > 0) or D0bar (sign < 0) float mlBkg = 0.f; float mlPrompt = 0.f; float mlNonPrompt = 0.f; - if (charmHadronCandidate.sign() > 0) { - mlBkg = charmHadronCandidate.mlProbD0Bkg(); - mlPrompt = charmHadronCandidate.mlProbD0Prompt(); - mlNonPrompt = charmHadronCandidate.mlProbD0NonPrompt(); + + if constexpr (charmhadronbuilder::isThreeProng()) { + // both hypotheses are histogrammed, so ambiguous candidates are visible + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassLcToPKPi, HistTable)), charmHadronCandidate.isSelLcToPKPi() ? charmHadronCandidate.mass() : charmHadronCandidate.massCompetingHypothesis()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassLcToPiKP, HistTable)), charmHadronCandidate.isSelLcToPKPi() ? charmHadronCandidate.massCompetingHypothesis() : charmHadronCandidate.mass()); + + if (charmHadronCandidate.isSelLcToPKPi()) { + mlBkg = charmHadronCandidate.mlProbLcToPKPiBkg(); + mlPrompt = charmHadronCandidate.mlProbLcToPKPiPrompt(); + mlNonPrompt = charmHadronCandidate.mlProbLcToPKPiNonPrompt(); + } else { + mlBkg = charmHadronCandidate.mlProbLcToPiKPBkg(); + mlPrompt = charmHadronCandidate.mlProbLcToPiKPPrompt(); + mlNonPrompt = charmHadronCandidate.mlProbLcToPiKPNonPrompt(); + } } else { - mlBkg = charmHadronCandidate.mlProbD0barBkg(); - mlPrompt = charmHadronCandidate.mlProbD0barPrompt(); - mlNonPrompt = charmHadronCandidate.mlProbD0barNonPrompt(); + // invariant mass split by hypothesis: D0 (sign > 0) or D0bar (sign < 0) + if (charmHadronCandidate.sign() > 0) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0, HistTable)), charmHadronCandidate.mass()); + mlBkg = charmHadronCandidate.mlProbD0Bkg(); + mlPrompt = charmHadronCandidate.mlProbD0Prompt(); + mlNonPrompt = charmHadronCandidate.mlProbD0NonPrompt(); + } else { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMassD0bar, HistTable)), charmHadronCandidate.mass()); + mlBkg = charmHadronCandidate.mlProbD0barBkg(); + mlPrompt = charmHadronCandidate.mlProbD0barPrompt(); + mlNonPrompt = charmHadronCandidate.mlProbD0barNonPrompt(); + } } + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlBkg, HistTable)), mlBkg); mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlPrompt, HistTable)), mlPrompt); mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kMlNonPrompt, HistTable)), mlNonPrompt); - // topological variables PWGHF selects on if (mPlotTopology) { mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCpa, HistTable)), charmHadronCandidate.cpa()); mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCpaXY, HistTable)), charmHadronCandidate.cpaXY()); mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kDecayLength, HistTable)), charmHadronCandidate.decayLength()); mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kDecayLengthXY, HistTable)), charmHadronCandidate.decayLengthXY()); - mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kImpactParameterProduct, HistTable)), charmHadronCandidate.impactParameterProduct()); - mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCosThetaStar, HistTable)), charmHadronCandidate.cosThetaStar()); + if constexpr (charmhadronbuilder::isThreeProng()) { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kChi2Pca, HistTable)), charmHadronCandidate.chi2PCA()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kImpactParameterProngSqSum, HistTable)), charmHadronCandidate.impactParameterProngSqSum()); + } else { + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kImpactParameterProduct, HistTable)), charmHadronCandidate.impactParameterProduct()); + mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(QaDir) + HIST(getHistName(kCosThetaStar, HistTable)), charmHadronCandidate.cosThetaStar()); + } } } @@ -496,6 +651,7 @@ class CharmHadronHistManager trackhistmanager::TrackHistManager mProng0Manager; trackhistmanager::TrackHistManager mProng1Manager; + trackhistmanager::TrackHistManager mProng2Manager; }; }; // namespace o2::analysis::femto::charmhadronhistmanager #endif // PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_ diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index 4d7cbed796a..dcf8bc5a794 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -653,7 +653,7 @@ class PairD0D0Builder mD0Cleaner1.init(confD0Cleaner1); mD0Cleaner2.init(confD0Cleaner2); - mD0HistManager1.template init(registry, D0HistSpec1, confD0Selection1, PosDauHistSpec1, NegDauHistSpec1); + mD0HistManager1.template init(registry, D0HistSpec1, confD0Selection1, PosDauHistSpec1, NegDauHistSpec1, NegDauHistSpec1); auto prongPdgCodes = [](int sign) -> std::pair { if (sign > 0) { @@ -672,7 +672,7 @@ class PairD0D0Builder mPairHistManagerMe.setCharge(1, 1); mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); } else { - mD0HistManager2.template init(registry, D0HistSpec2, confD0Selection2, PosDauHistSpec2, NegDauHistSpec2); + mD0HistManager2.template init(registry, D0HistSpec2, confD0Selection2, PosDauHistSpec2, NegDauHistSpec2, NegDauHistSpec2); auto [posDauPdg2, negDauPdg2] = prongPdgCodes(confD0Selection2.sign.value); mPairHistManagerSe.setMass(confD0Selection1.pdgCodeAbs.value, posDauPdg1, negDauPdg1, confD0Selection2.pdgCodeAbs.value, posDauPdg2, negDauPdg2); @@ -826,8 +826,8 @@ class PairD0D0Builder private: colhistmanager::CollisionHistManager mColHistManager; - charmhadronhistmanager::CharmHadronHistManager mD0HistManager1; - charmhadronhistmanager::CharmHadronHistManager mD0HistManager2; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager1; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager2; particlecleaner::ParticleCleaner mD0Cleaner1; particlecleaner::ParticleCleaner mD0Cleaner2; pairhistmanager::PairHistManager mPairHistManagerSe; @@ -898,7 +898,7 @@ class PairTrackD0Builder mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mTrackHistManager.template init(registry, trackHistSpec, confTrackSelection); - mD0HistManager.template init(registry, d0HistSpec, confD0Selection, posDauHistSpec, negDauHistSpec); + mD0HistManager.template init(registry, d0HistSpec, confD0Selection, posDauHistSpec, negDauHistSpec, negDauHistSpec); mTrackCleaner.init(confTrackCleaner); mD0Cleaner.init(confD0Cleaner); @@ -997,7 +997,7 @@ class PairTrackD0Builder private: colhistmanager::CollisionHistManager mColHistManager; trackhistmanager::TrackHistManager mTrackHistManager; - charmhadronhistmanager::CharmHadronHistManager mD0HistManager; + charmhadronhistmanager::CharmHadronHistManager mD0HistManager; particlecleaner::ParticleCleaner mTrackCleaner; particlecleaner::ParticleCleaner mD0Cleaner; pairhistmanager::PairHistManager mPairHistManagerSe; diff --git a/PWGCF/Femto/Core/trackHistManager.h b/PWGCF/Femto/Core/trackHistManager.h index 058f13af0cb..2c831f20962 100644 --- a/PWGCF/Femto/Core/trackHistManager.h +++ b/PWGCF/Femto/Core/trackHistManager.h @@ -162,6 +162,9 @@ constexpr const char PrefixD01PosDauBinning[] = "D01PosDauBinning"; constexpr const char PrefixD01NegDauBinning[] = "D01NegDauBinning"; constexpr const char PrefixD02PosDauBinning[] = "D02PosDauBinning"; constexpr const char PrefixD02NegDauBinning[] = "D02NegDauBinning"; +constexpr const char PrefixLc1ProtonDauBinning[] = "Lc1ProtonDauBinning"; +constexpr const char PrefixLc1KaonDauBinning[] = "Lc1KaonDauBinning"; +constexpr const char PrefixLc1PionDauBinning[] = "Lc1PionDauBinning"; constexpr const char PrefixCascadePosDauBinning[] = "CascadePosDauBinning"; constexpr const char PrefixCascadeNegDauBinning[] = "CascadeNegDauBinning"; constexpr const char PrefixCascadeBachelorBinning[] = "CascadeBachelorBinning"; @@ -184,6 +187,9 @@ using ConfD01PosDauBinning = ConfTrackBinning; using ConfD01NegDauBinning = ConfTrackBinning; using ConfD02PosDauBinning = ConfTrackBinning; using ConfD02NegDauBinning = ConfTrackBinning; +using ConfLc1ProtonDauBinning = ConfTrackBinning; +using ConfLc1KaonDauBinning = ConfTrackBinning; +using ConfLc1PionDauBinning = ConfTrackBinning; using ConfCascadePosDauBinning = ConfTrackBinning; using ConfCascadeNegDauBinning = ConfTrackBinning; using ConfCascadeBachelorBinning = ConfTrackBinning; @@ -273,6 +279,9 @@ constexpr const char PrefixV02PosDauQaBinning[] = "V02PosDauQaBinning"; constexpr const char PrefixV02NegDauQaBinning[] = "V02NegDauQaBinning"; constexpr const char PrefixD01PosDauQaBinning[] = "D01PosDauQaBinning"; constexpr const char PrefixD01NegDauQaBinning[] = "D01NegDauQaBinning"; +constexpr const char PrefixLc1ProtonDauQaBinning[] = "Lc1ProtonDauQaBinning"; +constexpr const char PrefixLc1KaonDauQaBinning[] = "Lc1KaonDauQaBinning"; +constexpr const char PrefixLc1PionDauQaBinning[] = "Lc1PionDauQaBinning"; constexpr const char PrefixCascadePosDauQaBinning[] = "CascadePosDauQaBinning"; constexpr const char PrefixCascadeNegDauQaBinning[] = "CascadeNegDauQaBinning"; constexpr const char PrefixCascadeBachelorQaBinning[] = "CascadeBachelorQaBinning"; @@ -288,6 +297,9 @@ using ConfV02PosDauQaBinning = ConfTrackQaBinning; using ConfV02NegDauQaBinning = ConfTrackQaBinning; using ConfD01PosDauQaBinning = ConfTrackQaBinning; using ConfD01NegDauQaBinning = ConfTrackQaBinning; +using ConfLc1ProtonDauQaBinning = ConfTrackQaBinning; +using ConfLc1KaonDauQaBinning = ConfTrackQaBinning; +using ConfLc1PionDauQaBinning = ConfTrackQaBinning; using ConfCascadePosDauQaBinning = ConfTrackQaBinning; using ConfCascadeNegDauQaBinning = ConfTrackQaBinning; using ConfCascadeBachelorQaBinning = ConfTrackQaBinning; @@ -536,6 +548,13 @@ constexpr char PrefixD02NegDaughter[] = "D02NegDau/"; constexpr char PrefixD01PosDaughterQa[] = "D01PosDauQa/"; constexpr char PrefixD01NegDaughterQa[] = "D01NegDauQa/"; +constexpr char PrefixLc1ProtonDaughter[] = "Lc1ProtonDau/"; +constexpr char PrefixLc1KaonDaughter[] = "Lc1KaonDau/"; +constexpr char PrefixLc1PionDaughter[] = "Lc1PionDau/"; +constexpr char PrefixLc1ProtonDaughterQa[] = "Lc1ProtonDauQa/"; +constexpr char PrefixLc1KaonDaughterQa[] = "Lc1KaonDauQa/"; +constexpr char PrefixLc1PionDaughterQa[] = "Lc1PionDauQa/"; + constexpr char PrefixV01PosDaughter[] = "V01PosDau/"; constexpr char PrefixV01NegDaughter[] = "V01NegDau/"; constexpr char PrefixV02PosDaughter[] = "V02PosDau/"; diff --git a/PWGCF/Femto/Tasks/CMakeLists.txt b/PWGCF/Femto/Tasks/CMakeLists.txt index 593e560699d..7a2a932c050 100644 --- a/PWGCF/Femto/Tasks/CMakeLists.txt +++ b/PWGCF/Femto/Tasks/CMakeLists.txt @@ -59,8 +59,8 @@ o2physics_add_dpl_workflow(femto-pair-d0-d0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(femto-d0-qa - SOURCES femtoD0Qa.cxx +o2physics_add_dpl_workflow(femto-charm-hadron-qa + SOURCES femtoCharmHadronQa.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx b/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx new file mode 100644 index 00000000000..8dd64bd6a61 --- /dev/null +++ b/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx @@ -0,0 +1,252 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file femtoCharmHadronQa.cxx +/// \brief QA task for charm hadrons +/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch + +#include "PWGCF/Femto/Core/charmHadronBuilder.h" +#include "PWGCF/Femto/Core/charmHadronHistManager.h" +#include "PWGCF/Femto/Core/collisionBuilder.h" +#include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/partitions.h" +#include "PWGCF/Femto/Core/trackHistManager.h" +#include "PWGCF/Femto/DataModel/FemtoTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2::analysis::femto; + +struct FemtoCharmHadronQa { + // setup collisions + using FemtoCollisions = o2::soa::Join; + using FilteredFemtoCollisions = o2::soa::Filtered; + using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + + // setup D0s, joined with the mask for the partition and the QA columns + using FemtoD0s = o2::soa::Join; + // setup Lcs, joined with the mask for the partition and the QA columns + using FemtoLcs = o2::soa::Join; + // setup tracks with full pid information for the daughter QA + using FemtoTracks = o2::soa::Join; + + // setup monte carlo, joining the labels that link reco to generated particles + using FemtoCollisionsWithLabel = o2::soa::Join; + using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; + using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + + using FemtoD0sWithLabel = o2::soa::Join; + using FemtoLcsWithLabel = o2::soa::Join; + using FemtoTracksWithLabel = o2::soa::Join; + using FemtoMcParticlesWithLabel = o2::soa::Join; + + o2::framework::SliceCache cache; + + // setup for collisions + collisionbuilder::ConfCollisionSelection collisionSelection; + o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); + colhistmanager::CollisionHistManager colHistManager; + colhistmanager::ConfCollisionBinning confCollisionBinning; + colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; + + // setup for D0s + charmhadronbuilder::ConfD0Selection1 confD0Selection; + + o2::framework::Partition d0Partition = MAKE_D0_PARTITION(confD0Selection); + o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; + o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(confD0Selection); + o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + + charmhadronhistmanager::ConfD0Binning1 confD0Binning; + charmhadronhistmanager::ConfD0QaBinning1 confD0QaBinning; + + // setup for Lcs + charmhadronbuilder::ConfLcSelection1 confLcSelection; + + o2::framework::Partition lcPartition = MAKE_CHARM3PRONG_PARTITION(confLcSelection); + o2::framework::Preslice perColLcs = o2::aod::femtobase::stored::fColId; + o2::framework::Partition lcWithLabelPartition = MAKE_CHARM3PRONG_PARTITION(confLcSelection); + o2::framework::Preslice perColLcsWithLabel = o2::aod::femtobase::stored::fColId; + + charmhadronhistmanager::ConfLcBinning1 confLcBinning; + charmhadronhistmanager::ConfLcQaBinning1 confLcQaBinning; + + // D0 + charmhadronhistmanager::CharmHadronHistManager< + charmhadronhistmanager::PrefixD0Qa, + trackhistmanager::PrefixD01PosDaughterQa, + trackhistmanager::PrefixD01NegDaughterQa, + trackhistmanager::PrefixD01NegDaughterQa, // unused for 2-prong candidates + modes::CharmHadron::kD0> + d0HistManager; + // Lc + charmhadronhistmanager::CharmHadronHistManager< + charmhadronhistmanager::PrefixLcQa, + trackhistmanager::PrefixLc1ProtonDaughterQa, + trackhistmanager::PrefixLc1KaonDaughterQa, + trackhistmanager::PrefixLc1PionDaughterQa, + modes::CharmHadron::kLc> + lcHistManager; + + + + // setup for daughters + trackhistmanager::ConfD01PosDauBinning confD01PosDaughterBinning; + trackhistmanager::ConfD01PosDauQaBinning confD01PosDaughterQaBinning; + + trackhistmanager::ConfD01NegDauBinning confD01NegDaughterBinning; + trackhistmanager::ConfD01NegDauQaBinning confD01NegDaughterQaBinning; + + trackhistmanager::ConfLc1ProtonDauBinning confLc1ProtonDaughterBinning; + trackhistmanager::ConfLc1ProtonDauQaBinning confLc1ProtonDaughterQaBinning; + + trackhistmanager::ConfLc1KaonDauBinning confLc1KaonDaughterBinning; + trackhistmanager::ConfLc1KaonDauQaBinning confLc1KaonDaughterQaBinning; + + trackhistmanager::ConfLc1PionDauBinning confLc1PionDaughterBinning; + trackhistmanager::ConfLc1PionDauQaBinning confLc1PionDaughterQaBinning; + + + o2::framework::HistogramRegistry hRegistry{"FemtoCharmHadronQa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext&) + { + if ((static_cast(doprocessD0) + static_cast(doprocessD0Mc) + static_cast(doprocessLc) + static_cast(doprocessLcMc)) != 1) { + LOG(fatal) << "Only one process can be activated"; + } + bool processData = doprocessD0 || doprocessLc; + + std::map> colHistSpec; + std::map> posDaughterHistSpec; + std::map> negDaughterHistSpec; + std::map> protonHistSpec; + std::map> kaonHistSpec; + std::map> pionHistSpec; + std::map> d0HistSpec; + std::map> d0QaHistSpec; + std::map> lcHistSpec; + std::map> lcQaHistSpec; + + if (processData) { + colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); + + if (doprocessD0) { + posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); + negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); + d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); + d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); + d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); + } + if (doprocessLc) { + protonHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confLc1ProtonDaughterBinning, confLc1ProtonDaughterQaBinning); + kaonHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confLc1KaonDaughterBinning, confLc1KaonDaughterQaBinning); + pionHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confLc1PionDaughterBinning, confLc1PionDaughterQaBinning); + lcHistSpec = charmhadronhistmanager::makeD0HistSpecMap(confLcBinning); + lcQaHistSpec = charmhadronhistmanager::makeLcQaHistSpecMap(confLcQaBinning); + lcHistManager.init(&hRegistry, lcHistSpec, lcQaHistSpec, confLcSelection, confLcQaBinning, protonHistSpec, confLc1ProtonDaughterQaBinning, kaonHistSpec, confLc1KaonDaughterQaBinning, pionHistSpec, confLc1PionDaughterQaBinning); + } + } else { + colHistSpec = colhistmanager::makeColMcQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); + colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); + + if (doprocessD0Mc) { + posDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); + negDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); + d0HistSpec = charmhadronhistmanager::makeD0McQaHistSpecMap(confD0Binning, confD0QaBinning); + d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); + d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); + } + if (doprocessLcMc) { + protonHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confLc1ProtonDaughterBinning, confLc1ProtonDaughterQaBinning); + kaonHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confLc1KaonDaughterBinning, confLc1KaonDaughterQaBinning); + pionHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confLc1PionDaughterBinning, confLc1PionDaughterQaBinning); + lcHistSpec = charmhadronhistmanager::makeLcMcQaHistSpecMap(confLcBinning, confLcQaBinning); + lcQaHistSpec = charmhadronhistmanager::makeLcQaHistSpecMap(confLcQaBinning); + lcHistManager.init(&hRegistry, lcHistSpec, lcQaHistSpec, confLcSelection, confLcQaBinning, protonHistSpec, confLc1ProtonDaughterQaBinning, kaonHistSpec, confLc1KaonDaughterQaBinning, pionHistSpec, confLc1PionDaughterQaBinning); + } + } + hRegistry.print(); + }; + + void processD0(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + { + auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice.size() == 0) { + return; + } + colHistManager.fill(col); + for (auto const& d0 : d0Slice) { + d0HistManager.fill(d0, tracks); + } + } + PROCESS_SWITCH(FemtoCharmHadronQa, processD0, "Process D0s", true); + + void processD0Mc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + auto d0Slice = d0WithLabelPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (d0Slice.size() == 0) { + return; + } + colHistManager.fill(col, mcCols); + for (auto const& d0 : d0Slice) { + d0HistManager.fill(d0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + } + } + PROCESS_SWITCH(FemtoCharmHadronQa, processD0Mc, "Process D0s with MC information", false); + + void processLc(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLcs const& /*lcs*/) + { + auto lcSlice = lcPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (lcSlice.size() == 0) { + return; + } + colHistManager.fill(col); + for (auto const& lc : lcSlice) { + lcHistManager.fill(lc, tracks); + } + } + PROCESS_SWITCH(FemtoCharmHadronQa, processLc, "Process Lcs", false); + + void processLcMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLcsWithLabel const& /*lcs*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + auto lcSlice = lcWithLabelPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (lcSlice.size() == 0) { + return; + } + colHistManager.fill(col, mcCols); + for (auto const& lc : lcSlice) { + lcHistManager.fill(lc, tracks, col, mcParticles, mcMothers, mcPartonicMothers); + } + } + PROCESS_SWITCH(FemtoCharmHadronQa, processLcMc, "Process Lcs with MC information", false); +}; + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + o2::framework::WorkflowSpec workflow{ + adaptAnalysisTask(context), + }; + return workflow; +} diff --git a/PWGCF/Femto/Tasks/femtoD0Qa.cxx b/PWGCF/Femto/Tasks/femtoD0Qa.cxx deleted file mode 100644 index 94ee74b0b4a..00000000000 --- a/PWGCF/Femto/Tasks/femtoD0Qa.cxx +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019-2026 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file femtoD0Qa.cxx -/// \brief QA task for D0 mesons -/// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch - -#include "PWGCF/Femto/Core/charmHadronBuilder.h" -#include "PWGCF/Femto/Core/charmHadronHistManager.h" -#include "PWGCF/Femto/Core/collisionBuilder.h" -#include "PWGCF/Femto/Core/collisionHistManager.h" -#include "PWGCF/Femto/Core/modes.h" -#include "PWGCF/Femto/Core/partitions.h" -#include "PWGCF/Femto/Core/trackHistManager.h" -#include "PWGCF/Femto/DataModel/FemtoTables.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace o2::analysis::femto; - -struct FemtoD0Qa { - - // setup collisions - using FemtoCollisions = o2::soa::Join; - using FilteredFemtoCollisions = o2::soa::Filtered; - using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; - - // setup D0s, joined with the mask for the partition and the QA columns - using FemtoD0s = o2::soa::Join; - // setup tracks with full pid information for the daughter QA - using FemtoTracks = o2::soa::Join; - - // setup monte carlo, joining the labels that link reco to generated particles - using FemtoCollisionsWithLabel = o2::soa::Join; - using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; - using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; - - using FemtoD0sWithLabel = o2::soa::Join; - using FemtoTracksWithLabel = o2::soa::Join; - using FemtoMcParticlesWithLabel = o2::soa::Join; - - o2::framework::SliceCache cache; - - // setup for collisions - collisionbuilder::ConfCollisionSelection collisionSelection; - o2::framework::expressions::Filter collisionFilter = MAKE_COLLISION_FILTER(collisionSelection); - colhistmanager::CollisionHistManager colHistManager; - colhistmanager::ConfCollisionBinning confCollisionBinning; - colhistmanager::ConfCollisionQaBinning confCollisionQaBinning; - - // setup for D0s - charmhadronbuilder::ConfD0Selection1 confD0Selection; - - o2::framework::Partition d0Partition = MAKE_D0_PARTITION(confD0Selection); - o2::framework::Preslice perColD0s = o2::aod::femtobase::stored::fColId; - o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(confD0Selection); - o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; - - charmhadronhistmanager::ConfD0Binning1 confD0Binning; - charmhadronhistmanager::ConfD0QaBinning1 confD0QaBinning; - charmhadronhistmanager::CharmHadronHistManager< - charmhadronhistmanager::PrefixD0Qa, - trackhistmanager::PrefixD01PosDaughterQa, - trackhistmanager::PrefixD01NegDaughterQa, - modes::CharmHadron::kD0> - d0HistManager; - - // setup for daughters - trackhistmanager::ConfD01PosDauBinning confD01PosDaughterBinning; - trackhistmanager::ConfD01PosDauQaBinning confD01PosDaughterQaBinning; - - trackhistmanager::ConfD01NegDauBinning confD01NegDaughterBinning; - trackhistmanager::ConfD01NegDauQaBinning confD01NegDaughterQaBinning; - - o2::framework::HistogramRegistry hRegistry{"FemtoD0Qa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; - - void init(o2::framework::InitContext&) - { - bool processData = doprocessD0; - - std::map> colHistSpec; - std::map> posDaughterHistSpec; - std::map> negDaughterHistSpec; - std::map> d0HistSpec; - std::map> d0QaHistSpec; - - if (processData) { - colHistSpec = colhistmanager::makeColQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); - colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); - posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); - negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); - d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); - d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); - d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); - } else { - colHistSpec = colhistmanager::makeColMcQaHistSpecMap(confCollisionBinning, confCollisionQaBinning); - colHistManager.init(&hRegistry, colHistSpec, confCollisionBinning, confCollisionQaBinning); - posDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); - negDaughterHistSpec = trackhistmanager::makeTrackMcQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); - d0HistSpec = charmhadronhistmanager::makeD0McQaHistSpecMap(confD0Binning, confD0QaBinning); - d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); - d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); - } - - hRegistry.print(); - }; - - void processD0(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) - { - auto d0Slice = d0Partition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - if (d0Slice.size() == 0) { - return; - } - colHistManager.fill(col); - for (auto const& d0 : d0Slice) { - d0HistManager.fill(d0, tracks); - } - } - PROCESS_SWITCH(FemtoD0Qa, processD0, "Process D0s", true); - - void processD0Mc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) - { - auto d0Slice = d0WithLabelPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); - if (d0Slice.size() == 0) { - return; - } - colHistManager.fill(col, mcCols); - for (auto const& d0 : d0Slice) { - d0HistManager.fill(d0, tracks, col, mcParticles, mcMothers, mcPartonicMothers); - } - } - PROCESS_SWITCH(FemtoD0Qa, processD0Mc, "Process D0s with MC information", false); -}; - -o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) -{ - o2::framework::WorkflowSpec workflow{ - adaptAnalysisTask(context), - }; - return workflow; -} From a37914ccd296ab200acd3381b96f34b7796a2dd4 Mon Sep 17 00:00:00 2001 From: ptak Date: Tue, 11 Aug 2026 13:43:44 +0200 Subject: [PATCH 05/11] [PWGCF] Femto: add track-Lc pair --- PWGCF/Femto/Core/closePairRejection.h | 64 ++++++++ PWGCF/Femto/Core/pairBuilder.h | 153 ++++++++++++++++++ PWGCF/Femto/Core/pairCleaner.h | 31 ++++ PWGCF/Femto/Tasks/CMakeLists.txt | 4 +- ...ckD0.cxx => femtoPairTrackCharmHadron.cxx} | 28 ++-- 5 files changed, 264 insertions(+), 16 deletions(-) rename PWGCF/Femto/Tasks/{femtoPairTrackD0.cxx => femtoPairTrackCharmHadron.cxx} (84%) diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h index 9460fad49dc..b56214fcc2d 100644 --- a/PWGCF/Femto/Core/closePairRejection.h +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -84,6 +84,9 @@ struct ConfCpr : o2::framework::ConfigurableGroup { constexpr const char PrefixCprTrackTrack[] = "CprTrackTrack"; constexpr const char PrefixCprTrackV0Daughter[] = "CprTrackV0Daughter"; constexpr const char PrefixCprTrackD0Daughter[] = "CprTrackD0Daughter"; +constexpr const char PrefixCprTrackLcProton[] = "CprTrackLcProton"; +constexpr const char PrefixCprTrackLcKaon[] = "CprTrackLcKaon"; +constexpr const char PrefixCprTrackLcPion[] = "CprTrackLcPion"; constexpr const char PrefixCprD0DaughterD0DaughterPos[] = "CprD0DaughterD0DaughterPos"; constexpr const char PrefixCprD0DaughterD0DaughterNeg[] = "CprD0DaughterD0DaughterNeg"; constexpr const char PrefixCprTrackResonanceDaughter[] = "CprTrackResonanceDaughter"; @@ -98,6 +101,9 @@ constexpr const char PrefixCprTrackCascadeBachelor[] = "CprTrackCascadeBachelor" using ConfCprTrackTrack = ConfCpr; using ConfCprTrackV0Daughter = ConfCpr; using ConfCprTrackD0Daughter = ConfCpr; +using ConfCprTrackLcProton = ConfCpr; +using ConfCprTrackLcKaon = ConfCpr; +using ConfCprTrackLcPion = ConfCpr; using ConfCprD0DaugherD0DaughterPos = ConfCpr; using ConfCprD0DaugherD0DaughterNeg = ConfCpr; using ConfCprTrackResonanceDaughter = ConfCpr; @@ -123,6 +129,12 @@ constexpr char PrefixD0D0PosSe[] = "CPR_D0D0_PosDau/SE/"; constexpr char PrefixD0D0NegSe[] = "CPR_D0D0_NegDau/SE/"; constexpr char PrefixD0D0PosMe[] = "CPR_D0D0_PosDau/ME/"; constexpr char PrefixD0D0NegMe[] = "CPR_D0D0_NegDau/ME/"; +constexpr char PrefixTrackLcProtonSe[] = "CPR_TrackLc_Proton/SE/"; +constexpr char PrefixTrackLcKaonSe[] = "CPR_TrackLc_Kaon/SE/"; +constexpr char PrefixTrackLcPionSe[] = "CPR_TrackLc_Pion/SE/"; +constexpr char PrefixTrackLcProtonMe[] = "CPR_TrackLc_Proton/ME/"; +constexpr char PrefixTrackLcKaonMe[] = "CPR_TrackLc_Kaon/ME/"; +constexpr char PrefixTrackLcPionMe[] = "CPR_TrackLc_Pion/ME/"; constexpr char PrefixV0V0PosSe[] = "CPR_V0V0_PosDau/SE/"; constexpr char PrefixV0V0NegSe[] = "CPR_V0V0_NegDau/SE/"; constexpr char PrefixV0V0PosMe[] = "CPR_V0V0_PosDau/ME/"; @@ -539,6 +551,58 @@ class ClosePairRejectionTrackV0 // can also be used for any particle type that h CloseTrackRejection mCtr; }; +template +class ClosePairRejectionTrackLc +{ + public: + template + void init(o2::framework::HistogramRegistry* registry, + std::map> const& specsProton, + std::map> const& specsKaon, + std::map> const& specsPion, + T1 const& confCprProton, + T2 const& confCprKaon, + T3 const& confCprPion, + int absChargeTrack) + { + mCtrProton.init(registry, specsProton, confCprProton, absChargeTrack, 1); + mCtrKaon.init(registry, specsKaon, confCprKaon, absChargeTrack, 1); + mCtrPion.init(registry, specsPion, confCprPion, absChargeTrack, 1); + } + + void setMagField(float magField) + { + mCtrProton.setMagField(magField); + mCtrKaon.setMagField(magField); + mCtrPion.setMagField(magField); + } + + template + void setPair(T1 const& track, T2 const& lc, T3 const& trackTable) + { + auto prong0 = trackTable.rawIteratorAt(lc.prong0DauId() - trackTable.offset()); + mCtrProton.compute(track, prong0); + auto prong1 = trackTable.rawIteratorAt(lc.prong1DauId() - trackTable.offset()); + mCtrKaon.compute(track, prong1); + auto prong2 = trackTable.rawIteratorAt(lc.prong2DauId() - trackTable.offset()); + mCtrPion.compute(track, prong2); + } + + [[nodiscard]] bool isClosePair() const { return mCtrProton.isClosePair() || mCtrKaon.isClosePair() || mCtrPion.isClosePair(); } + + void fill(float kstar) + { + mCtrProton.fill(kstar); + mCtrKaon.fill(kstar); + mCtrPion.fill(kstar); + } + + private: + CloseTrackRejection mCtrProton; + CloseTrackRejection mCtrKaon; + CloseTrackRejection mCtrPion; +}; + template class ClosePairRejectionTrackCascade { diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index dcf8bc5a794..fb4d2834986 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -1009,6 +1009,159 @@ class PairTrackD0Builder int mMixingDepth = 5; }; +template +class PairTrackLcBuilder +{ + public: + PairTrackLcBuilder() = default; + ~PairTrackLcBuilder() = default; + + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& confCollisionBinning, + T2 const& confTrackSelection, + T3 const& confTrackCleaner, + T4 const& confLcSelection, + T5 const& confLcCleaner, + T6 const& confCprProton, + T7 const& confCprKaon, + T8 const& confCprPion, + T9 const& confMixing, + T10 const& confPairBinning, + T11 const& confPairCuts, + std::map>& colHistSpec, + std::map>& trackHistSpec, + std::map>& lcHistSpec, + std::map>& protonDauHistSpec, + std::map>& kaonDauHistSpec, + std::map>& pionDauHistSpec, + std::map>& pairHistSpec, + std::map>& cprHistSpec) + { + mColHistManager.template init(registry, colHistSpec, confCollisionBinning); + + mTrackHistManager.template init(registry, trackHistSpec, confTrackSelection); + mLcHistManager.template init(registry, lcHistSpec, confLcSelection, protonDauHistSpec, kaonDauHistSpec, pionDauHistSpec); + + mTrackCleaner.init(confTrackCleaner); + mLcCleaner.init(confLcCleaner); + + // prongs are stored remapped onto the accepted hypothesis, so the roles are fixed: + // Lc -> p+ K- pi+ + // Lcbar -> p- K+ pi- + const int protonDauPdg = (confLcSelection.sign.value > 0) ? PDG_t::kProton : -PDG_t::kProton; + const int kaonDauPdg = (confLcSelection.sign.value > 0) ? PDG_t::kKMinus : PDG_t::kKPlus; + + mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerSe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confLcSelection.pdgCodeAbs.value, protonDauPdg, kaonDauPdg); + mPairHistManagerSe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprSe.init(registry, cprHistSpec, cprHistSpec, cprHistSpec, confCprProton, confCprKaon, confCprPion, confTrackSelection.chargeAbs.value); + + mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); + mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confLcSelection.pdgCodeAbs.value, protonDauPdg, kaonDauPdg); + mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); + mCprMe.init(registry, cprHistSpec, cprHistSpec, cprHistSpec, confCprProton, confCprKaon, confCprPion, confTrackSelection.chargeAbs.value); + mPc.template init(confPairCuts); + + // setup mixing + mMixingPolicy = static_cast(confMixing.policy.value); + mMixingDepth = confMixing.depth.value; + } + + template + void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*lcTable*/, T5& lcPartition, T6& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto lcSlice = lcPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() < nLimitPartitionParticles || lcSlice.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, lcSlice, trackTable, col, mTrackHistManager, mLcHistManager, mPairHistManagerSe, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& trackPartition, T4& lcPartition, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + template + void processSameEvent(T1 const& col, T2 const& mcCols, T3 const& trackTable, T4& trackPartition, T5 const& /*lcTable*/, T6& lcPartition, T7 const& mcParticles, T8 const& mcMothers, T9 const& mcPartonicMothers, T10& cache) + { + auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + auto lcSlice = lcPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + if (trackSlice.size() < nLimitPartitionParticles || lcSlice.size() < nLimitPartitionParticles) { + return; + } + mColHistManager.template fill(col, mcCols); + mCprSe.setMagField(col.magField()); + pairprocesshelpers::processSameEvent(trackSlice, lcSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mLcHistManager, mPairHistManagerSe, mTrackCleaner, mLcCleaner, mCprSe, mPc); + } + + template + void processMixedEvent(T1 const& cols, T2 const& mcCols, T3& trackTable, T4& trackPartition, T5& lcPartition, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& cache, T10& binsVtxMult, T11& binsVtxCent, T12& binsVtxMultCent) + { + switch (mMixingPolicy) { + case static_cast(pairhistmanager::kVtxMult): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPc); + break; + case static_cast(pairhistmanager::kVtxMultCent): + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPc); + break; + default: + LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; + } + } + + private: + colhistmanager::CollisionHistManager mColHistManager; + trackhistmanager::TrackHistManager mTrackHistManager; + charmhadronhistmanager::CharmHadronHistManager mLcHistManager; + particlecleaner::ParticleCleaner mTrackCleaner; + particlecleaner::ParticleCleaner mLcCleaner; + pairhistmanager::PairHistManager mPairHistManagerSe; + pairhistmanager::PairHistManager mPairHistManagerMe; + closepairrejection::ClosePairRejectionTrackLc mCprSe; + closepairrejection::ClosePairRejectionTrackLc mCprMe; + paircleaner::TrackLcPairCleaner mPc; + pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; + int mMixingDepth = 5; +}; + template + bool isCleanPair(T1 const& track, T2 const& lc, T3 const& trackTable) const + { + auto prong0 = trackTable.rawIteratorAt(lc.prong0DauId() - trackTable.offset()); + auto prong1 = trackTable.rawIteratorAt(lc.prong1DauId() - trackTable.offset()); + auto prong2 = trackTable.rawIteratorAt(lc.prong2DauId() - trackTable.offset()); + return (this->isCleanParticlePair(prong0, track) && this->isCleanParticlePair(prong1, track) && this->isCleanParticlePair(prong2, track)); + } + + template + bool isCleanPair(T1 const& track1, T2 const& lc, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + { + if (!this->isCleanPair(track1, lc, trackTable)) { + return false; + } + // pair is clean + // now check if we require common or non-common ancestry + if (mMixPairsWithCommonAncestor) { + return this->pairHasCommonAncestor(track1, lc, mcParticles, partonicMothers); + } + if (mMixPairsWithNonCommonAncestor) { + return this->pairHasNonCommonAncestor(track1, lc, mcParticles, partonicMothers); + } + return true; + } +}; + class McParticleMcParticlePairCleaner : public BasePairCleaner { public: diff --git a/PWGCF/Femto/Tasks/CMakeLists.txt b/PWGCF/Femto/Tasks/CMakeLists.txt index 7a2a932c050..e7c42416b04 100644 --- a/PWGCF/Femto/Tasks/CMakeLists.txt +++ b/PWGCF/Femto/Tasks/CMakeLists.txt @@ -49,8 +49,8 @@ o2physics_add_dpl_workflow(femto-pair-track-v0 PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(femto-pair-track-d0 - SOURCES femtoPairTrackD0.cxx +o2physics_add_dpl_workflow(femto-pair-track-charm-hadron + SOURCES femtoPairTrackCharmHadron.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx similarity index 84% rename from PWGCF/Femto/Tasks/femtoPairTrackD0.cxx rename to PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx index 61ab3340f73..4e97d9e664d 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackD0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file femtoPairTrackD0.cxx -/// \brief Tasks that computes correlation between tracks and D0 mesons +/// \file femtoPairTrackCharmHadron.cxx +/// \brief Tasks that computes correlation between tracks and charm hadrons /// \author Igor Ptak, WUT, igor.tomasz.ptak@cern.ch #include "PWGCF/Femto/Core/charmHadronBuilder.h" @@ -44,7 +44,7 @@ using namespace o2::analysis::femto; -struct FemtoPairTrackD0 { +struct FemtoPairTrackCharmHadron { // setup tables using FemtoCollisions = o2::soa::Join; @@ -127,8 +127,8 @@ struct FemtoPairTrackD0 { void init(o2::framework::InitContext&) { - bool processData = doprocessSameEvent || doprocessMixedEvent; - bool processMc = doprocessSameEventMc || doprocessMixedEventMc; + bool processData = doprocessD0SameEvent || doprocessD0MixedEvent; + bool processMc = doprocessD0SameEventMc || doprocessD0MixedEventMc; if (processData && processMc) { LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; @@ -169,35 +169,35 @@ struct FemtoPairTrackD0 { hRegistry.print(); }; - void processSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& d0s) + void processD0SameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& d0s) { pairTrackD0Builder.processSameEvent(col, tracks, trackPartition, d0s, d0Partition, cache); } - PROCESS_SWITCH(FemtoPairTrackD0, processSameEvent, "Enable processing same event processing for tracks and D0s", true); + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processD0SameEvent, "Enable processing same event processing for tracks and D0s", true); - void processMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) + void processD0MixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoD0s const& /*d0s*/) { pairTrackD0Builder.processMixedEvent(cols, tracks, trackPartition, d0Partition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } - PROCESS_SWITCH(FemtoPairTrackD0, processMixedEvent, "Enable processing mixed event processing for tracks and D0s", true); + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processD0MixedEvent, "Enable processing mixed event processing for tracks and D0s", true); - void processSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& d0s, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + void processD0SameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& d0s, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairTrackD0Builder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition, d0s, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); } - PROCESS_SWITCH(FemtoPairTrackD0, processSameEventMc, "Enable processing same event processing for tracks and D0s with MC information", false); + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processD0SameEventMc, "Enable processing same event processing for tracks and D0s with MC information", false); - void processMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + void processD0MixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoD0sWithLabel const& /*d0s*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairTrackD0Builder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } - PROCESS_SWITCH(FemtoPairTrackD0, processMixedEventMc, "Enable processing mixed event processing for tracks and D0s with MC information", false); + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processD0MixedEventMc, "Enable processing mixed event processing for tracks and D0s with MC information", false); }; o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) { o2::framework::WorkflowSpec workflow{ - adaptAnalysisTask(context), + adaptAnalysisTask(context), }; return workflow; } From 939807b95a69713f114c97a4834f7669da60be9c Mon Sep 17 00:00:00 2001 From: ptak Date: Tue, 11 Aug 2026 14:00:57 +0200 Subject: [PATCH 06/11] [PWGCF] Femto: wire the track-Lc pair task --- PWGCF/Femto/Core/charmHadronBuilder.h | 22 ++-- PWGCF/Femto/Core/charmHadronHistManager.h | 13 +- PWGCF/Femto/Core/mcBuilder.h | 4 +- PWGCF/Femto/Core/pairHistManager.h | 7 +- PWGCF/Femto/Core/particleCleaner.h | 3 + PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx | 4 +- PWGCF/Femto/Tasks/femtoPairD0D0.cxx | 8 +- .../Femto/Tasks/femtoPairTrackCharmHadron.cxx | 119 +++++++++++++++--- 8 files changed, 138 insertions(+), 42 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index 7ca7bbeec40..ac288023b64 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -561,12 +561,12 @@ class CharmHadronBuilder if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0) || modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); - + collisionBuilder.template fillCollision(collisionProducts, col); int64_t posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, collisionBuilder); int64_t negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); - + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0)) { this->fillD0Tables(collisionProducts, charmHadronProducts, candidate, candidate.pt(), mHfHelper.invMassD0ToPiK(candidate), posDauIndex, negDauIndex); } else { @@ -586,8 +586,8 @@ class CharmHadronBuilder // remap the prong onto the accepted hypothesis so that the proton is always first bool const isPKPi = candidate.isSelLcToPKPi(); - auto const& protonProng = isPKPi ? prong0 : prong2; - auto const& pionProng = isPKPi ? prong2 : prong0; + auto const& protonProng = isPKPi ? prong0 : prong2; + auto const& pionProng = isPKPi ? prong2 : prong0; float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); @@ -613,18 +613,18 @@ class CharmHadronBuilder if (!mCharmHadronSelection.checkFilters(candidate)) { continue; } - + mCharmHadronSelection.applySelections(candidate); if (!mCharmHadronSelection.passesAllRequiredSelections()) { continue; } - + if constexpr (modes::isEqual(hadronType, modes::CharmHadron::kD0) || modes::isEqual(hadronType, modes::CharmHadron::kD0Bar)) { auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); - + collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); - + int64_t posDauIndex = trackBuilder.template getDaughterIndex(prong0, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); int64_t negDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); @@ -648,8 +648,8 @@ class CharmHadronBuilder // remap the prongs onto the accepted hypothesis so that the proton is always first bool const isPKPi = candidate.isSelLcToPKPi(); - auto const& protonProng = isPKPi ? prong0 : prong2; - auto const& pionProng = isPKPi ? prong2 : prong0; + auto const& protonProng = isPKPi ? prong0 : prong2; + auto const& pionProng = isPKPi ? prong2 : prong0; float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); @@ -664,7 +664,7 @@ class CharmHadronBuilder mcBuilder.template fillMcLcWithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); } - + } } diff --git a/PWGCF/Femto/Core/charmHadronHistManager.h b/PWGCF/Femto/Core/charmHadronHistManager.h index aba6be98953..5ea73c65d67 100644 --- a/PWGCF/Femto/Core/charmHadronHistManager.h +++ b/PWGCF/Femto/Core/charmHadronHistManager.h @@ -35,7 +35,6 @@ #include #include #include -#include #include namespace o2::analysis::femto::charmhadronhistmanager @@ -50,7 +49,7 @@ enum CharmHadronHist { kPtVsEta, kPtVsPhi, kPhiVsEta, - + // mass under each hypothesis kMassD0, kMassD0bar, @@ -67,7 +66,7 @@ enum CharmHadronHist { kCpaXY, kDecayLength, kDecayLengthXY, - + // topology, 2-prong only (D0) kImpactParameterProduct, kCosThetaStar, @@ -119,7 +118,7 @@ constexpr const char PrefixD0Binning2[] = "D0Binning2"; using ConfD0Binning1 = ConfCharmHadronBinning; using ConfD0Binning2 = ConfCharmHadronBinning; -constexpr const char PrefixLcBinning1[] = "LcBinning1"; +constexpr const char PrefixLcBinning1[] = "LcBinning1"; using ConfLcBinning1 = ConfLcBinning; template @@ -203,7 +202,7 @@ constexpr std::array, kCharmHadronHistLas {kPhiVsEta, {(conf).phi2d, (conf).eta2d}}, template -auto makeD0HistSpecMap(const T& confBinningAnalysis) +auto makeCharmHadronHistSpecMap(const T& confBinningAnalysis) { return std::map>{ CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis)}; @@ -219,7 +218,7 @@ auto makeD0HistSpecMap(const T& confBinningAnalysis) {kPtVsOrigin, {(conf).pt2d}}, template -auto makeD0McHistSpecMap(const T& confBinningAnalysis) +auto makeCharmHadronMcHistSpecMap(const T& confBinningAnalysis) { return std::map>{ CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis) @@ -321,7 +320,7 @@ class CharmHadronHistManager std::map> const& CharmHadronSpecs, T const& ConfCharmHadronSelection, std::map> const& Prong0Specs, - std::map> const& Prong1Specs, + std::map> const& Prong1Specs, std::map> const& Prong2Specs) { mHistogramRegistry = registry; diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index e92c9cc4a1d..877248ccee1 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -273,7 +273,7 @@ class McBuilder } } if (pdgAbs == o2::constants::physics::Pdg::kLambdaCPlus) { - int8_t sign = 0; + int8_t sign = 0; if (!RecoDecay::isMatchedMCGen(mcParticles, mcParticle, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { return; } @@ -384,7 +384,7 @@ class McBuilder auto prong1 = lcCandidate.template prong1_as(); auto prong2 = lcCandidate.template prong2_as(); auto arrayDaughters = std::array{prong0, prong1, prong2}; - int8_t sign = 0; + int8_t sign = 0; const int indexMcRec = RecoDecay::getMatchedMCRec(mcParticles, arrayDaughters, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2); if (indexMcRec < 0) { diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 99d66198ad7..79acf0d7336 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -498,6 +498,8 @@ constexpr char PrefixTrackV0Me[] = "TrackV0/ME/"; constexpr char PrefixTrackD0Se[] = "TrackD0/SE/"; constexpr char PrefixTrackD0Me[] = "TrackD0/ME/"; +constexpr char PrefixTrackLcSe[] = "TrackLc/SE/"; +constexpr char PrefixTrackLcMe[] = "TrackLc/ME/"; constexpr char PrefixD0D0Se[] = "D0D0/SE/"; constexpr char PrefixD0D0Me[] = "D0D0/ME/"; @@ -710,8 +712,9 @@ class PairHistManager if (mPlotDalitz) { if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || - modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || - modes::isEqual(particleType2, modes::Particle::kCharmHadron))) { + modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || + modes::isEqual(particleType2, modes::Particle::kCharmHadron)) && + requires(T2 p) { p.posDauId(); p.negDauId(); }) { auto posDaughter = trackTable.rawIteratorAt(particle2.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(particle2.negDauId() - trackTable.offset()); ROOT::Math::PtEtaPhiMVector posDau4v = ROOT::Math::PtEtaPhiMVector(posDaughter.pt(), posDaughter.eta(), posDaughter.phi(), mPdgMassPosDau2); diff --git a/PWGCF/Femto/Core/particleCleaner.h b/PWGCF/Femto/Core/particleCleaner.h index ea4b65a91c7..57c61cd11ba 100644 --- a/PWGCF/Femto/Core/particleCleaner.h +++ b/PWGCF/Femto/Core/particleCleaner.h @@ -55,6 +55,9 @@ constexpr const char PrefixD0Cleaner2[] = "D0Cleaner2"; using ConfD0Cleaner1 = ConfParticleCleaner; using ConfD0Cleaner2 = ConfParticleCleaner; +constexpr const char PrefixLcCleaner1[] = "LcCleaner1"; +using ConfLcCleaner1 = ConfParticleCleaner; + constexpr const char PrefixK0shortCleaner1[] = "K0shortCleaner1"; constexpr const char PrefixK0shortCleaner2[] = "K0shortCleaner2"; using ConfK0shortCleaner1 = ConfParticleCleaner; diff --git a/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx b/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx index 8dd64bd6a61..adc25ce7f02 100644 --- a/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx +++ b/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx @@ -155,7 +155,7 @@ struct FemtoCharmHadronQa { if (doprocessD0) { posDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01PosDaughterBinning, confD01PosDaughterQaBinning); negDaughterHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confD01NegDaughterBinning, confD01NegDaughterQaBinning); - d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); + d0HistSpec = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning); d0QaHistSpec = charmhadronhistmanager::makeD0QaHistSpecMap(confD0QaBinning); d0HistManager.init(&hRegistry, d0HistSpec, d0QaHistSpec, confD0Selection, confD0QaBinning, posDaughterHistSpec, confD01PosDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning, negDaughterHistSpec, confD01NegDaughterQaBinning); } @@ -163,7 +163,7 @@ struct FemtoCharmHadronQa { protonHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confLc1ProtonDaughterBinning, confLc1ProtonDaughterQaBinning); kaonHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confLc1KaonDaughterBinning, confLc1KaonDaughterQaBinning); pionHistSpec = trackhistmanager::makeTrackQaHistSpecMap(confLc1PionDaughterBinning, confLc1PionDaughterQaBinning); - lcHistSpec = charmhadronhistmanager::makeD0HistSpecMap(confLcBinning); + lcHistSpec = charmhadronhistmanager::makeCharmHadronHistSpecMap(confLcBinning); lcQaHistSpec = charmhadronhistmanager::makeLcQaHistSpecMap(confLcQaBinning); lcHistManager.init(&hRegistry, lcHistSpec, lcQaHistSpec, confLcSelection, confLcQaBinning, protonHistSpec, confLc1ProtonDaughterQaBinning, kaonHistSpec, confLc1KaonDaughterQaBinning, pionHistSpec, confLc1PionDaughterQaBinning); } diff --git a/PWGCF/Femto/Tasks/femtoPairD0D0.cxx b/PWGCF/Femto/Tasks/femtoPairD0D0.cxx index 47a5959f2ca..4053c196774 100644 --- a/PWGCF/Femto/Tasks/femtoPairD0D0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairD0D0.cxx @@ -169,8 +169,8 @@ struct FemtoPairD0D0 { negDauSpec1 = trackhistmanager::makeTrackHistSpecMap(confD01NegDauBinning); posDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confD02PosDauBinning); negDauSpec2 = trackhistmanager::makeTrackHistSpecMap(confD02NegDauBinning); - d0HistSpec1 = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning1); - d0HistSpec2 = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning2); + d0HistSpec1 = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning1); + d0HistSpec2 = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning2); pairD0D0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg); } else { @@ -179,8 +179,8 @@ struct FemtoPairD0D0 { negDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confD01NegDauBinning); posDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confD02PosDauBinning); negDauSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confD02NegDauBinning); - d0HistSpec1 = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning1); - d0HistSpec2 = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning2); + d0HistSpec1 = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confD0Binning1); + d0HistSpec2 = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confD0Binning2); pairD0D0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg); } diff --git a/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx index 4e97d9e664d..2780d6f4503 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx @@ -53,6 +53,7 @@ struct FemtoPairTrackCharmHadron { using FemtoTracks = o2::soa::Join; using FemtoD0s = o2::soa::Join; + using FemtoLcs = o2::soa::Join; using FemtoCollisionsWithLabel = o2::soa::Join; using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; @@ -60,6 +61,7 @@ struct FemtoPairTrackCharmHadron { using FemtoTracksWithLabel = o2::soa::Join; using FemtoD0sWithLabel = o2::soa::Join; + using FemtoLcsWithLabel = o2::soa::Join; using FemtoMcParticlesWithLabel = o2::soa::Join; o2::framework::SliceCache cache; @@ -95,6 +97,22 @@ struct FemtoPairTrackCharmHadron { o2::framework::Partition d0WithLabelPartition = MAKE_D0_PARTITION(d0Selection); o2::framework::Preslice perColD0sWithLabel = o2::aod::femtobase::stored::fColId; + // setup for Lc daughters + trackhistmanager::ConfLc1ProtonDauBinning confProtonDauBinning; + trackhistmanager::ConfLc1KaonDauBinning confKaonDauBinning; + trackhistmanager::ConfLc1PionDauBinning confPionDauBinning; + + // setup Lcs + charmhadronbuilder::ConfLcSelection1 lcSelection; + charmhadronhistmanager::ConfLcBinning1 confLcBinning; + particlecleaner::ConfLcCleaner1 confLcCleaner; + + o2::framework::Partition lcPartition = MAKE_CHARM3PRONG_PARTITION(lcSelection); + o2::framework::Preslice perColLcs = o2::aod::femtobase::stored::fColId; + + o2::framework::Partition lcWithLabelPartition = MAKE_CHARM3PRONG_PARTITION(lcSelection); + o2::framework::Preslice perColLcsWithLabel = o2::aod::femtobase::stored::fColId; + // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; @@ -111,6 +129,23 @@ struct FemtoPairTrackCharmHadron { modes::CharmHadron::kD0> pairTrackD0Builder; + pairbuilder::PairTrackLcBuilder< + trackhistmanager::PrefixTrack1, + charmhadronhistmanager::PrefixLc1, + trackhistmanager::PrefixLc1ProtonDaughter, + trackhistmanager::PrefixLc1KaonDaughter, + trackhistmanager::PrefixLc1PionDaughter, + pairhistmanager::PrefixTrackLcSe, + pairhistmanager::PrefixTrackLcMe, + closepairrejection::PrefixTrackLcProtonSe, + closepairrejection::PrefixTrackLcKaonSe, + closepairrejection::PrefixTrackLcPionSe, + closepairrejection::PrefixTrackLcProtonMe, + closepairrejection::PrefixTrackLcKaonMe, + closepairrejection::PrefixTrackLcPionMe, + modes::CharmHadron::kLc> + pairTrackLcBuilder; + // setup mixing std::vector defaultVtxBins{10, -10, 10}; std::vector defaultMultBins{50, 0, 200}; @@ -124,16 +159,23 @@ struct FemtoPairTrackCharmHadron { // setup cpr closepairrejection::ConfCprTrackD0Daughter confCpr; + closepairrejection::ConfCprTrackLcProton confCprLcProton; + closepairrejection::ConfCprTrackLcKaon confCprLcKaon; + closepairrejection::ConfCprTrackLcPion confCprLcPion; void init(o2::framework::InitContext&) { - bool processData = doprocessD0SameEvent || doprocessD0MixedEvent; - bool processMc = doprocessD0SameEventMc || doprocessD0MixedEventMc; + bool processD0 = doprocessD0SameEvent || doprocessD0MixedEvent; + bool processD0Mc = doprocessD0SameEventMc || doprocessD0MixedEventMc; + bool processLc = doprocessLcSameEvent || doprocessLcMixedEvent; + bool processLcMc = doprocessLcSameEventMc || doprocessLcMixedEventMc; - if (processData && processMc) { - LOG(fatal) << "Both data and mc processing is enabled. Breaking..."; + if ((static_cast(processD0) + static_cast(processD0Mc) + static_cast(processLc) + static_cast(processLcMc)) > 1) { + LOG(fatal) << "Only one charm hadron species and data/mc mode can be processed at a time. Breaking..."; } + bool processData = processD0 || processLc; + // setup columnpolicy for binning // default values are used during instantiation, so we need to explicity update them here mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; @@ -144,26 +186,51 @@ struct FemtoPairTrackCharmHadron { std::map> trackHistSpec; std::map> posDauSpec; std::map> negDauSpec; + std::map> protonDauSpec; + std::map> kaonDauSpec; + std::map> pionDauSpec; std::map> d0HistSpec; + std::map> lcHistSpec; std::map> pairTrackD0HistSpec; + std::map> pairTrackLcHistSpec; std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); trackHistSpec = trackhistmanager::makeTrackHistSpecMap(confTrackBinning); - posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); - d0HistSpec = charmhadronhistmanager::makeD0HistSpecMap(confD0Binning); - pairTrackD0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + if (processD0) { + posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); + d0HistSpec = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning); + pairTrackD0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + } + if (processLc) { + protonDauSpec = trackhistmanager::makeTrackHistSpecMap(confProtonDauBinning); + kaonDauSpec = trackhistmanager::makeTrackHistSpecMap(confKaonDauBinning); + pionDauSpec = trackhistmanager::makeTrackHistSpecMap(confPionDauBinning); + lcHistSpec = charmhadronhistmanager::makeCharmHadronHistSpecMap(confLcBinning); + pairTrackLcHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + pairTrackLcBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lcSelection, confLcCleaner, confCprLcProton, confCprLcKaon, confCprLcPion, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lcHistSpec, protonDauSpec, kaonDauSpec, pionDauSpec, pairTrackLcHistSpec, cprHistSpec); + } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); trackHistSpec = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning); - posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); - negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); - d0HistSpec = charmhadronhistmanager::makeD0McHistSpecMap(confD0Binning); - pairTrackD0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + if (processD0Mc) { + posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); + negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); + d0HistSpec = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confD0Binning); + pairTrackD0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + } + if (processLcMc) { + protonDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confProtonDauBinning); + kaonDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confKaonDauBinning); + pionDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPionDauBinning); + lcHistSpec = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confLcBinning); + pairTrackLcHistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); + pairTrackLcBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lcSelection, confLcCleaner, confCprLcProton, confCprLcKaon, confCprLcPion, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lcHistSpec, protonDauSpec, kaonDauSpec, pionDauSpec, pairTrackLcHistSpec, cprHistSpec); + } } hRegistry.print(); @@ -192,6 +259,30 @@ struct FemtoPairTrackCharmHadron { pairTrackD0Builder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition, d0WithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairTrackCharmHadron, processD0MixedEventMc, "Enable processing mixed event processing for tracks and D0s with MC information", false); + + void processLcSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLcs const& lcs) + { + pairTrackLcBuilder.processSameEvent(col, tracks, trackPartition, lcs, lcPartition, cache); + } + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processLcSameEvent, "Enable processing same event processing for tracks and Lcs", false); + + void processLcMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoLcs const& /*lcs*/) + { + pairTrackLcBuilder.processMixedEvent(cols, tracks, trackPartition, lcPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processLcMixedEvent, "Enable processing mixed event processing for tracks and Lcs", false); + + void processLcSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLcsWithLabel const& lcs, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairTrackLcBuilder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition, lcs, lcWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache); + } + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processLcSameEventMc, "Enable processing same event processing for tracks and Lcs with MC information", false); + + void processLcMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoLcsWithLabel const& /*lcs*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + { + pairTrackLcBuilder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition, lcWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + } + PROCESS_SWITCH(FemtoPairTrackCharmHadron, processLcMixedEventMc, "Enable processing mixed event processing for tracks and Lcs with MC information", false); }; o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) From ddab34c7601437d324e3c8a6759942c51759eda7 Mon Sep 17 00:00:00 2001 From: ptak Date: Tue, 11 Aug 2026 14:34:01 +0200 Subject: [PATCH 07/11] [PWGCF] Femto: fill one row per Lc mass hypothesis --- PWGCF/Femto/Core/charmHadronBuilder.h | 103 ++++++++++++++++++-------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index ac288023b64..f200668b950 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -542,6 +542,73 @@ class CharmHadronBuilder } } + /// Write one row for the given mass hypothesis, if PWGHF accepted it. + /// A candidate passing both hypotheses is stored twice, once per hypothesis. + template + void fillLcHypothesis(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, + T5& charmHadronProducts, T6 const& candidate, T7& trackBuilder, + T8 const& prong0, T8 const& prong1, T8 const& prong2) + { + if constexpr (isPKPi) { + if (!candidate.isSelLcToPKPi()) { + return; + } + } else { + if (!candidate.isSelLcToPiKP()) { + return; + } + } + + // remap the prongs onto the accepted hypothesis so that the proton is always first + auto const& protonProng = isPKPi ? prong0 : prong2; + auto const& pionProng = isPKPi ? prong2 : prong0; + float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); + float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); + + collisionBuilder.template fillCollision(collisionProducts, col); + int64_t const protonDauIndex = trackBuilder.template getDaughterIndex(protonProng, trackProducts, collisionBuilder); + int64_t const kaonDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); + int64_t const pionDauIndex = trackBuilder.template getDaughterIndex(pionProng, trackProducts, collisionBuilder); + + float const signedPt = isParticle() ? candidate.pt() : -candidate.pt(); + this->fillLcTables(collisionProducts, charmHadronProducts, candidate, signedPt, mass, massCompeting, protonDauIndex, kaonDauIndex, pionDauIndex); + } + + /// Monte Carlo counterpart of fillLcHypothesis. The label is written inside this method, + /// so FLcs and FLcLabels stay in lockstep also for candidates passing both hypotheses. + template + void fillMcLcHypothesis(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& mcCols, T5& trackProducts, + T6& charmHadronProducts, T7 const& candidate, T8 const& tracks, T9& trackBuilder, + T10 const& mcParticles, T11& mcBuilder, T12& mcProducts, + T13 const& prong0, T13 const& prong1, T13 const& prong2) + { + if constexpr (isPKPi) { + if (!candidate.isSelLcToPKPi()) { + return; + } + } else { + if (!candidate.isSelLcToPiKP()) { + return; + } + } + + // remap the prongs onto the accepted hypothesis so that the proton is always first + auto const& protonProng = isPKPi ? prong0 : prong2; + auto const& pionProng = isPKPi ? prong2 : prong0; + float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); + float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); + + collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); + + int64_t const protonDauIndex = trackBuilder.template getDaughterIndex(protonProng, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + int64_t const kaonDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + int64_t const pionDauIndex = trackBuilder.template getDaughterIndex(pionProng, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); + + float const signedPt = isParticle() ? candidate.pt() : -candidate.pt(); + this->fillLcTables(collisionProducts, charmHadronProducts, candidate, signedPt, mass, massCompeting, protonDauIndex, kaonDauIndex, pionDauIndex); + mcBuilder.template fillMcLcWithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); + } + template void fillCharmHadrons(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& charmHadronProducts, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) @@ -584,20 +651,8 @@ class CharmHadronBuilder continue; } - // remap the prong onto the accepted hypothesis so that the proton is always first - bool const isPKPi = candidate.isSelLcToPKPi(); - auto const& protonProng = isPKPi ? prong0 : prong2; - auto const& pionProng = isPKPi ? prong2 : prong0; - float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); - float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); - - collisionBuilder.template fillCollision(collisionProducts, col); - int64_t const protonDauIndex = trackBuilder.template getDaughterIndex(protonProng, trackProducts, collisionBuilder); - int64_t const kaonDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, collisionBuilder); - int64_t const pionDauIndex = trackBuilder.template getDaughterIndex(pionProng, trackProducts, collisionBuilder); - - float const signedPt = isParticle() ? candidate.pt() : -candidate.pt(); - this->fillLcTables(collisionProducts, charmHadronProducts, candidate, signedPt, mass, massCompeting, protonDauIndex, kaonDauIndex, pionDauIndex); + this->fillLcHypothesis(col, collisionBuilder, collisionProducts, trackProducts, charmHadronProducts, candidate, trackBuilder, prong0, prong1, prong2); + this->fillLcHypothesis(col, collisionBuilder, collisionProducts, trackProducts, charmHadronProducts, candidate, trackBuilder, prong0, prong1, prong2); } } } @@ -646,25 +701,9 @@ class CharmHadronBuilder continue; } - // remap the prongs onto the accepted hypothesis so that the proton is always first - bool const isPKPi = candidate.isSelLcToPKPi(); - auto const& protonProng = isPKPi ? prong0 : prong2; - auto const& pionProng = isPKPi ? prong2 : prong0; - float const mass = isPKPi ? mHfHelper.invMassLcToPKPi(candidate) : mHfHelper.invMassLcToPiKP(candidate); - float const massCompeting = isPKPi ? mHfHelper.invMassLcToPiKP(candidate) : mHfHelper.invMassLcToPKPi(candidate); - - collisionBuilder.template fillMcCollision(collisionProducts, col, mcCols, mcProducts, mcBuilder); - - int64_t const protonDauIndex = trackBuilder.template getDaughterIndex(protonProng, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); - int64_t const kaonDauIndex = trackBuilder.template getDaughterIndex(prong1, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); - int64_t const pionDauIndex = trackBuilder.template getDaughterIndex(pionProng, trackProducts, mcCols, collisionBuilder, mcParticles, mcBuilder, mcProducts); - - float const signedPt = isParticle() ? candidate.pt() : -candidate.pt(); - this->fillLcTables(collisionProducts, charmHadronProducts, candidate, signedPt, mass, massCompeting, protonDauIndex, kaonDauIndex, pionDauIndex); - mcBuilder.template fillMcLcWithLabel(candidate, tracks, mcParticles, mcCols, mcProducts); + this->fillMcLcHypothesis(col, collisionBuilder, collisionProducts, mcCols, trackProducts, charmHadronProducts, candidate, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts, prong0, prong1, prong2); + this->fillMcLcHypothesis(col, collisionBuilder, collisionProducts, mcCols, trackProducts, charmHadronProducts, candidate, tracks, trackBuilder, mcParticles, mcBuilder, mcProducts, prong0, prong1, prong2); } - - } } From c36df4d09c151cfcdaa7a048e2fd837de0fcd723 Mon Sep 17 00:00:00 2001 From: ptak Date: Wed, 12 Aug 2026 09:38:16 +0200 Subject: [PATCH 08/11] [PWGCF] Femto: fix Lc process guard and pass-through mode --- PWGCF/Femto/Core/charmHadronBuilder.h | 33 ++++++++++----------- PWGCF/Femto/TableProducer/femtoProducer.cxx | 4 +++ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index f200668b950..fbf059754f8 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -542,21 +542,24 @@ class CharmHadronBuilder } } - /// Write one row for the given mass hypothesis, if PWGHF accepted it. - /// A candidate passing both hypotheses is stored twice, once per hypothesis. + /// pass-through accepts every candidate once, under the pKPi prong mapping + template + bool acceptsHypothesis(T const& candidate) const + { + if (mCharmHadronSelection.isPassThrough()) { + return isPKPi; + } + return isPKPi ? candidate.isSelLcToPKPi() : candidate.isSelLcToPiKP(); + } + + /// a candidate passing both hypotheses is stored twice, once per hypothesis template void fillLcHypothesis(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, T5& charmHadronProducts, T6 const& candidate, T7& trackBuilder, T8 const& prong0, T8 const& prong1, T8 const& prong2) { - if constexpr (isPKPi) { - if (!candidate.isSelLcToPKPi()) { - return; - } - } else { - if (!candidate.isSelLcToPiKP()) { - return; - } + if (!this->acceptsHypothesis(candidate)) { + return; } // remap the prongs onto the accepted hypothesis so that the proton is always first @@ -582,14 +585,8 @@ class CharmHadronBuilder T10 const& mcParticles, T11& mcBuilder, T12& mcProducts, T13 const& prong0, T13 const& prong1, T13 const& prong2) { - if constexpr (isPKPi) { - if (!candidate.isSelLcToPKPi()) { - return; - } - } else { - if (!candidate.isSelLcToPiKP()) { - return; - } + if (!this->acceptsHypothesis(candidate)) { + return; } // remap the prongs onto the accepted hypothesis so that the proton is always first diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 4b4f093060a..973ac91df12 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -313,6 +313,10 @@ struct FemtoProducer { static_cast(doprocessTracksV0sKinksRun3ppMc) + static_cast(doprocessTracksD0sRun3ppMc) + static_cast(doprocessTracksD0sRun3PbPbMc) + + static_cast(doprocessTracksLcsRun3pp) + + static_cast(doprocessTracksLcsRun3PbPb) + + static_cast(doprocessTracksLcsRun3ppMc) + + static_cast(doprocessTracksLcsRun3PbPbMc) + static_cast(doprocessMcOnly); if (nProcesses != 1) { From debfdb963708c00fb7595ae4da073ba0f45f29c1 Mon Sep 17 00:00:00 2001 From: ptak Date: Wed, 12 Aug 2026 10:53:58 +0200 Subject: [PATCH 09/11] [PWGCF] Femto: add Lc to the producer init guards --- PWGCF/Femto/TableProducer/femtoProducer.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 973ac91df12..9296f75c1cb 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -239,12 +239,18 @@ struct FemtoProducer { !doprocessTracksD0sRun3ppMc && !doprocessTracksD0sRun3PbPbMc)) { LOG(fatal) << "At least one d0 table is enabled, but wrong process function is enabled. Breaking..."; } + if ((lcBuilder.fillAnyTable() || lcBarBuilder.fillAnyTable()) && + (!doprocessTracksLcsRun3pp && !doprocessTracksLcsRun3PbPb && + !doprocessTracksLcsRun3ppMc && !doprocessTracksLcsRun3PbPbMc)) { + LOG(fatal) << "At least one lc table is enabled, but wrong process function is enabled. Breaking..."; + } if (mcBuilder.fillAnyTable() && (!doprocessTracksRun3ppMc && !doprocessTracksRun3PbPbMc && !doprocessTracksV0sRun3ppMc && !doprocessTracksV0sRun3PbPbMc && !doprocessTracksV0sCascadesRun3ppMc && !doprocessTracksV0sCascadesRun3PbPbMc && !doprocessTracksKinksRun3ppMc && !doprocessTracksV0sKinksRun3ppMc && !doprocessTracksD0sRun3ppMc && !doprocessTracksD0sRun3PbPbMc && + !doprocessTracksLcsRun3ppMc && !doprocessTracksLcsRun3PbPbMc && !doprocessMcOnly)) { LOG(fatal) << "At least one mc table is enabled, but wrong process function is enabled. Breaking..."; } @@ -265,6 +271,8 @@ struct FemtoProducer { add("antilambda", antilambdaBuilder.fillAnyTable(), antilambdaBuilder.isPassThrough()); add("d0", d0Builder.fillAnyTable(), d0Builder.isPassThrough()); add("d0bar", d0barBuilder.fillAnyTable(), d0barBuilder.isPassThrough()); + add("lc", lcBuilder.fillAnyTable(), lcBuilder.isPassThrough()); + add("lcbar", lcBarBuilder.fillAnyTable(), lcBarBuilder.isPassThrough()); add("sigma", sigmaBuilder.fillAnyTable(), sigmaBuilder.isPassThrough()); add("sigmaplus", sigmaPlusBuilder.fillAnyTable(), sigmaPlusBuilder.isPassThrough()); add("xi", xiBuilder.fillAnyTable(), xiBuilder.isPassThrough()); From 23f15fbfac1284943b51d7423ec5521b0e06be53 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Wed, 12 Aug 2026 08:58:00 +0000 Subject: [PATCH 10/11] Please consider the following formatting changes --- PWGCF/Femto/Core/charmHadronBuilder.h | 20 ++++++++--------- PWGCF/Femto/Core/charmHadronHistManager.h | 24 ++++++++++----------- PWGCF/Femto/Core/closePairRejection.h | 2 +- PWGCF/Femto/Core/mcBuilder.h | 2 +- PWGCF/Femto/Core/pairBuilder.h | 2 +- PWGCF/Femto/Core/pairHistManager.h | 4 +--- PWGCF/Femto/Core/partitions.h | 1 - PWGCF/Femto/TableProducer/femtoProducer.cxx | 2 +- PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx | 3 --- 9 files changed, 26 insertions(+), 34 deletions(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index fbf059754f8..6d3c0ffb137 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -139,8 +139,8 @@ using ConfLcSelection2 = ConfLcSelection; /// registered is decided per species in CharmHadronSelection::configure. enum CharmHadronSels { // topological selections - kCpaMin, ///< Min. CPA (cosine pointing angle) - kDecayLengthMin, ///< Min. decay length + kCpaMin, ///< Min. CPA (cosine pointing angle) + kDecayLengthMin, ///< Min. decay length // topological selections, 2-prong only (D0) kImpactParameterProductMax, ///< Max. product of prong impact parameters (d0*d0) @@ -472,12 +472,12 @@ class CharmHadronBuilder { if (mProduceD0s) { charmHadronProducts.producedD0s(collisionProducts.producedCollision.lastIndex(), - signedPt, - candidate.eta(), - candidate.phi(), - mass, - posDauIndex, - negDauIndex); + signedPt, + candidate.eta(), + candidate.phi(), + mass, + posDauIndex, + negDauIndex); } if (mProduceD0Masks) { charmHadronProducts.producedD0Masks(mCharmHadronSelection.getBitmask()); @@ -608,7 +608,7 @@ class CharmHadronBuilder template void fillCharmHadrons(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4& trackProducts, - T5& charmHadronProducts, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) + T5& charmHadronProducts, T6 const& candidates, T7 const& /*tracks*/, T8& trackBuilder) { if (!mFillAnyTable) { return; @@ -656,7 +656,7 @@ class CharmHadronBuilder template void fillMcCharmHadrons(T1 const& col, T2& collisionBuilder, T3& collisionProducts, T4 const& mcCols, T5& trackProducts, - T6& charmHadronProducts, T7 const& candidates, T8 const& tracks, T9& trackBuilder, T10 const& mcParticles, T11& mcBuilder, T12& mcProducts) + T6& charmHadronProducts, T7 const& candidates, T8 const& tracks, T9& trackBuilder, T10 const& mcParticles, T11& mcBuilder, T12& mcProducts) { if (!mFillAnyTable) { return; diff --git a/PWGCF/Femto/Core/charmHadronHistManager.h b/PWGCF/Femto/Core/charmHadronHistManager.h index 5ea73c65d67..6e783b11c6b 100644 --- a/PWGCF/Femto/Core/charmHadronHistManager.h +++ b/PWGCF/Femto/Core/charmHadronHistManager.h @@ -256,17 +256,17 @@ auto makeD0McQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQ } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define LC_HIST_QA_MAP(conf) \ - {kMassLcToPKPi, {(conf).massLcToPKPi}}, \ - {kMassLcToPiKP, {(conf).massLcToPiKP}}, \ - {kMlBkg, {(conf).mlScore}}, \ - {kMlPrompt, {(conf).mlScore}}, \ - {kMlNonPrompt, {(conf).mlScore}}, \ - {kCpa, {(conf).cpa}}, \ - {kCpaXY, {(conf).cpa}}, \ - {kDecayLength, {(conf).decayLength}}, \ - {kDecayLengthXY, {(conf).decayLength}}, \ - {kChi2Pca, {(conf).chi2Pca}}, \ +#define LC_HIST_QA_MAP(conf) \ + {kMassLcToPKPi, {(conf).massLcToPKPi}}, \ + {kMassLcToPiKP, {(conf).massLcToPiKP}}, \ + {kMlBkg, {(conf).mlScore}}, \ + {kMlPrompt, {(conf).mlScore}}, \ + {kMlNonPrompt, {(conf).mlScore}}, \ + {kCpa, {(conf).cpa}}, \ + {kCpaXY, {(conf).cpa}}, \ + {kDecayLength, {(conf).decayLength}}, \ + {kDecayLengthXY, {(conf).decayLength}}, \ + {kChi2Pca, {(conf).chi2Pca}}, \ {kImpactParameterProngSqSum, {(conf).impactParameterProngSqSum}}, template @@ -285,7 +285,6 @@ auto makeLcMcQaHistSpecMap(const T1& confBinningAnalysis, const T2& confBinningQ CHARMHADRON_HIST_MC_MAP(confBinningAnalysis)}; } - #undef CHARMHADRON_HIST_ANALYSIS_MAP #undef CHARMHADRON_HIST_MC_MAP #undef CHARMHADRON_HIST_QA_MAP @@ -538,7 +537,6 @@ class CharmHadronHistManager } } - void initMc(std::map> const& CharmHadronSpecs) { std::string mcDir = std::string(charmHadronPrefix) + std::string(McDir); diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h index b56214fcc2d..2dd8e07abf5 100644 --- a/PWGCF/Femto/Core/closePairRejection.h +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -588,7 +588,7 @@ class ClosePairRejectionTrackLc mCtrPion.compute(track, prong2); } - [[nodiscard]] bool isClosePair() const { return mCtrProton.isClosePair() || mCtrKaon.isClosePair() || mCtrPion.isClosePair(); } + [[nodiscard]] bool isClosePair() const { return mCtrProton.isClosePair() || mCtrKaon.isClosePair() || mCtrPion.isClosePair(); } void fill(float kstar) { diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index 877248ccee1..187fa5dce33 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -277,7 +277,7 @@ class McBuilder if (!RecoDecay::isMatchedMCGen(mcParticles, mcParticle, o2::constants::physics::Pdg::kLambdaCPlus, std::array{+kProton, -kKPlus, +kPiPlus}, true, &sign, 2)) { return; } - if(std::abs(mcParticle.y()) > mCharmYGenMax) { + if (std::abs(mcParticle.y()) > mCharmYGenMax) { return; } } diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index fb4d2834986..199f051a86f 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -1085,7 +1085,7 @@ class PairTrackLcBuilder mMixingDepth = confMixing.depth.value; } - template + template void processSameEvent(T1 const& col, T2& trackTable, T3& trackPartition, T4& /*lcTable*/, T5& lcPartition, T6& cache) { auto trackSlice = trackPartition->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 79acf0d7336..1dfed31ef7f 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -711,9 +711,7 @@ class PairHistManager } if (mPlotDalitz) { - if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || - modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || - modes::isEqual(particleType2, modes::Particle::kCharmHadron)) && + if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || modes::isEqual(particleType2, modes::Particle::kCharmHadron)) && requires(T2 p) { p.posDauId(); p.negDauId(); }) { auto posDaughter = trackTable.rawIteratorAt(particle2.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(particle2.negDauId() - trackTable.offset()); diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index 5706bb9e639..ed849b52048 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -195,7 +195,6 @@ (o2::aod::femtobase::stored::mass < (selection).massMax) && \ ncheckbit(o2::aod::femtocharmhadrons::mask, (selection).mask) - // macros for mc collisions (mc only) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define MAKE_MC_COLLISION_FILTER(selection) \ diff --git a/PWGCF/Femto/TableProducer/femtoProducer.cxx b/PWGCF/Femto/TableProducer/femtoProducer.cxx index 9296f75c1cb..6a4cd41d469 100644 --- a/PWGCF/Femto/TableProducer/femtoProducer.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducer.cxx @@ -967,7 +967,7 @@ struct FemtoProducer { } PROCESS_SWITCH(FemtoProducer, processTracksLcsRun3PbPb, "Provide tracks and Lcs in PbPb collisions", false); - void processTracksLcsRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, + void processTracksLcsRun3ppMc(rawinputs::Run3PpMcGenCollisions const& mcCols, rawinputs::Run3PpMcRecoCollisions const& cols, o2::aod::BCsWithTimestamps const& bcs, rawinputs::Run3McRecoTracks const& tracks, diff --git a/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx b/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx index adc25ce7f02..8a3ce875e97 100644 --- a/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx +++ b/PWGCF/Femto/Tasks/femtoCharmHadronQa.cxx @@ -109,8 +109,6 @@ struct FemtoCharmHadronQa { modes::CharmHadron::kLc> lcHistManager; - - // setup for daughters trackhistmanager::ConfD01PosDauBinning confD01PosDaughterBinning; trackhistmanager::ConfD01PosDauQaBinning confD01PosDaughterQaBinning; @@ -127,7 +125,6 @@ struct FemtoCharmHadronQa { trackhistmanager::ConfLc1PionDauBinning confLc1PionDaughterBinning; trackhistmanager::ConfLc1PionDauQaBinning confLc1PionDaughterQaBinning; - o2::framework::HistogramRegistry hRegistry{"FemtoCharmHadronQa", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) From 9d8281eec4f0752fe311a5b8e3118ef0dda4dbf7 Mon Sep 17 00:00:00 2001 From: ptak Date: Thu, 13 Aug 2026 10:41:29 +0200 Subject: [PATCH 11/11] [PWGCF] Femto: drop unused include in the charm hadron builder --- PWGCF/Femto/Core/charmHadronBuilder.h | 1 - 1 file changed, 1 deletion(-) diff --git a/PWGCF/Femto/Core/charmHadronBuilder.h b/PWGCF/Femto/Core/charmHadronBuilder.h index 6d3c0ffb137..62f235da485 100644 --- a/PWGCF/Femto/Core/charmHadronBuilder.h +++ b/PWGCF/Femto/Core/charmHadronBuilder.h @@ -23,7 +23,6 @@ #include "PWGCF/Femto/Core/selectionContainer.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" #include "PWGHF/Core/HfHelper.h" -#include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include