From 32e4f432b3b75cdb2b31b65d8f43341e822f5fb8 Mon Sep 17 00:00:00 2001 From: apalasciano Date: Tue, 13 Oct 2026 17:33:15 +0200 Subject: [PATCH 1/7] [PWGHF] D+-h corr, checks on MCClosure test --- PWGHF/HFC/DataModel/CorrelationTables.h | 15 +++++ .../TableProducer/correlatorDplusHadrons.cxx | 20 ++++++- .../HFC/Tasks/taskCorrelationDplusHadrons.cxx | 56 +++++++++++++++++-- 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/PWGHF/HFC/DataModel/CorrelationTables.h b/PWGHF/HFC/DataModel/CorrelationTables.h index de52b75420f..75543cd0d33 100644 --- a/PWGHF/HFC/DataModel/CorrelationTables.h +++ b/PWGHF/HFC/DataModel/CorrelationTables.h @@ -497,6 +497,21 @@ DECLARE_SOA_TABLE(TrkRecInfoDplus, "AOD", "TRKRECINFODPLUS", //! Tracks Reconstr aod::hf_correlation_dplus_hadron::TrackDcaZ, aod::hf_correlation_dplus_hadron::TrackTPCNClsCrossedRows); +// definition of columns and tables for the beauty-mother information of the charm-hadron trigger (MC only), usable by any D-hadron correlation analysis +namespace hf_correlation_b_mother +{ +DECLARE_SOA_COLUMN(PtB, ptB, float); //! Generated pT of the beauty mother of the charm hadron (-1 if not from beauty) +DECLARE_SOA_COLUMN(DeltaPhiBtoD, deltaPhiBtoD, float); //! phi(charm hadron) - phi(B mother, generated) in [-pihalf, 3.*pihalf) (-999 if not from beauty) +} // namespace hf_correlation_b_mother + +DECLARE_SOA_TABLE(BMotherPairInfo, "AOD", "BMOTHERPAIRINFO", //! Charm-hadron-hadron pairs beauty-mother information, joinable with the pair table + aod::hf_correlation_b_mother::PtB, + aod::hf_correlation_b_mother::DeltaPhiBtoD); + +DECLARE_SOA_TABLE(BMotherCandInfo, "AOD", "BMOTHERCANDINFO", //! Charm-hadron candidates beauty-mother information, joinable with the candidate table + aod::hf_correlation_b_mother::PtB, + aod::hf_correlation_b_mother::DeltaPhiBtoD); + // definition of columns and tables for Dstar-Hadron correlation pair namespace hf_correlation_dstar_hadron { diff --git a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx index ee3f8571f6f..493c232bdb8 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx @@ -22,6 +22,7 @@ #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h" +#include "PWGHF/HFC/Utils/utilsCorrelations.h" #include "PWGHF/Utils/utilsAnalysis.h" #include "Common/CCDB/EventSelectionParams.h" @@ -186,9 +187,12 @@ struct HfCorrelatorDplusHadrons { Produces candSelInfo; Produces assocTrackReduced; Produces assocTrackSelInfo; + Produces entryDplusHadronBMotherInfo; + Produces entryDplusCandBMotherInfo; static constexpr std::size_t NDaughters{3u}; - static constexpr float EtaDaughtersMax = 0.8f; // Eta cut on daughters of D+ meson as Run2 + static constexpr float EtaDaughtersMax = 0.8f; // Eta cut on daughters of D+ meson as Run2 + static constexpr int8_t DepthMaxDplusDaughters{2}; // max. depth of the D+ daughters in the decay chain (resonant channels) Configurable selectionFlagDplus{"selectionFlagDplus", 7, "Selection Flag for Dplus"}; // 7 corresponds to topo+PID cuts Configurable numberEventsMixed{"numberEventsMixed", 5, "Number of events mixed in ME process"}; @@ -401,6 +405,9 @@ struct HfCorrelatorDplusHadrons { // Count triggers registry.fill(HIST("hcountDplustriggersMCGen"), 0, particle.pt()); + // beauty-mother information + const auto [ptB, deltaPhiBtoD] = hf_correlations::getBMotherInfoMcGen(particle, particlesToLoop); + for (const auto& particleAssoc : groupedMcParticles) { if (std::abs(particleAssoc.eta()) > etaTrackMax || @@ -447,6 +454,7 @@ struct HfCorrelatorDplusHadrons { entryDplusHadronGenInfo(isDplusPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + entryDplusHadronBMotherInfo(ptB, deltaPhiBtoD); } } } @@ -552,7 +560,7 @@ struct HfCorrelatorDplusHadrons { int indexHfcReducedCollision = collReduced.lastIndex() + 1; - // Ds fill histograms and Dplus candidates information stored + // Dplus candidates information stored for (const auto& candidate : candsDplusThisColl) { std::vector outputMl = {-1., -1., -1.}; // candidate selected @@ -631,6 +639,8 @@ struct HfCorrelatorDplusHadrons { bool isDplusNonPrompt = candidate.originMcRec() == RecoDecay::OriginType::NonPrompt; std::vector outputMl = {-1., -1., -1.}; + // beauty-mother information (generated B, reconstructed D+) + const auto [ptB, deltaPhiBtoD] = hf_correlations::getBMotherInfoMcRec(candidate, mcParticles, Pdg::kDPlus, DepthMaxDplusDaughters); // fill invariant mass plots from Dplus signal and background candidates registry.fill(HIST("hMassDplusMcRec"), HfHelper::invMassDplusToPiKPi(candidate), efficiencyWeightD); @@ -663,6 +673,7 @@ struct HfCorrelatorDplusHadrons { registry.fill(HIST("hMassDplusMcRecSig"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), efficiencyWeightD); entryDplusCandRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]); entryDplusCandGenInfo(isDplusPrompt); + entryDplusCandBMotherInfo(ptB, deltaPhiBtoD); } else { registry.fill(HIST("hPtCandMcRecBkg"), candidate.pt()); registry.fill(HIST("hEtaMcRecBkg"), candidate.eta()); @@ -691,6 +702,7 @@ struct HfCorrelatorDplusHadrons { track.pt(), poolBin); entryDplusHadronRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), isDplusSignal); entryDplusHadronMlInfo(outputMl[0], outputMl[1], outputMl[2]); + entryDplusHadronBMotherInfo(ptB, deltaPhiBtoD); if (track.has_mcParticle()) { auto mcParticle = track.template mcParticle_as(); isPhysicalPrimary = mcParticle.isPhysicalPrimary(); @@ -866,6 +878,8 @@ struct HfCorrelatorDplusHadrons { poolBin); entryDplusHadronRecoInfo(HfHelper::invMassDplusToPiKPi(candidate), isDplusSignal); entryDplusHadronGenInfo(isDplusPrompt, isPhysicalPrimary, trackOrigin); + const auto [ptB, deltaPhiBtoD] = hf_correlations::getBMotherInfoMcRec(candidate, mcParticles, Pdg::kDPlus, DepthMaxDplusDaughters); + entryDplusHadronBMotherInfo(ptB, deltaPhiBtoD); for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; } @@ -910,6 +924,8 @@ struct HfCorrelatorDplusHadrons { poolBin); entryDplusHadronRecoInfo(MassDPlus, true); entryDplusHadronGenInfo(isDplusPrompt, particleAssoc.isPhysicalPrimary(), trackOrigin); + const auto [ptB, deltaPhiBtoD] = hf_correlations::getBMotherInfoMcGen(candidate, mcParticles); + entryDplusHadronBMotherInfo(ptB, deltaPhiBtoD); } } } diff --git a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx index dc49dd86dfe..9c13570974e 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx @@ -141,6 +141,8 @@ struct HfTaskCorrelationDplusHadrons { Configurable nTpcCrossedRaws{"nTpcCrossedRaws", 70, "Number of crossed TPC Rows"}; Configurable cutCollPosZMc{"cutCollPosZMc", 10., "max z-vertex position for collision acceptance"}; Configurable storeMassAxis{"storeMassAxis", false, "Store Mass axis in THnSparse"}; + Configurable storeBMotherInfo{"storeBMotherInfo", false, "Store generated pT(B mother) and phi(D+) - phi(B mother) of non-prompt D+ in MC Rec histograms"}; + Configurable> binsPtBMother{"binsPtBMother", std::vector{0., 2., 4., 6., 8., 12., 16., 24., 36., 50., 99.}, "pT bin limits for the B mother of non-prompt D+"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable associatedEffCcdbPath{"associatedEffCcdbPath", "", "CCDB path for associated efficiency"}; @@ -164,8 +166,9 @@ struct HfTaskCorrelationDplusHadrons { kCandidateStepMcRecoInAcceptance, kCandidateNSteps }; - using DplusHadronPair = soa::Join; + using DplusHadronPairWithBMother = soa::Join; using DplusHadronPairFullWithMl = soa::Join; + using DplusHadronPairFullWithMlAndBMother = soa::Join; using CandDplusMcReco = soa::Filtered>; using CandDplusMcGen = soa::Join; using TracksWithMc = soa::Filtered>; // trackFilter applied @@ -179,6 +182,7 @@ struct HfTaskCorrelationDplusHadrons { ConfigurableAxis binsPhi{"binsPhi", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}"}; ConfigurableAxis binsMultFT0M{"binsMultFT0M", {600, 0., 8000.}, "Multiplicity as FT0M signal amplitude"}; ConfigurableAxis binsPoolBin{"binsPoolBin", {9, 0., 9.}, "PoolBin"}; + ConfigurableAxis binsDeltaPhiBMother{"binsDeltaPhiBMother", {64, -PIHalf, 3. * PIHalf}, "#it{#varphi}^{D}-#it{#varphi}^{B}"}; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -195,6 +199,8 @@ struct HfTaskCorrelationDplusHadrons { AxisSpec axisPoolBin = {binsPoolBin, "poolBin"}; AxisSpec axisDplusPrompt = {2, -0.5, 1.5, "Prompt D+"}; AxisSpec const axisBdtScore = {binsBdtScore, "Bdt score"}; + AxisSpec axisPtBMother = {(std::vector)binsPtBMother, "#it{p}_{T}^{B} (GeV/#it{c})"}; + AxisSpec axisDeltaPhiBMother = {binsDeltaPhiBMother, "#it{#varphi}^{D}-#it{#varphi}^{B} (rad)"}; // Histograms for data analysis registry.add("hBdtScorePrompt", "D+ BDT prompt score", {HistType::kTH1F, {axisBdtScore}}); @@ -259,6 +265,17 @@ struct HfTaskCorrelationDplusHadrons { registry.get(HIST("hCorrel2DVsPtSidebandRightMcRec"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtSignalRegionMcRec"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtPhysicalPrimaryMcRec"))->Sumw2(); + + // beauty-mother information of non-prompt D+ (generated B, reconstructed D+) + if (storeBMotherInfo) { + registry.add("hMassNonPromptDplusVsPtVsPtBMother", "D+ non prompt candidates mass Vs Pt Vs Pt B mother", {HistType::kTH3F, {{axisMassD}, {axisPtD}, {axisPtBMother}}}); + registry.add("hDeltaPhiBMotherVsPtVsPtBMother", "D+ non prompt candidates #varphi^{D}-#varphi^{B} Vs Pt Vs Pt B mother", {HistType::kTH3F, {{axisDeltaPhiBMother}, {axisPtD}, {axisPtBMother}}}); + registry.add("hCorrel2DVsPtNonPromptDplusPhysicalPrimaryMcRecBMother", stringDHadron + "non-prompt D (only true primary particles)" + stringSignal, {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPtBMother}, {axisDeltaPhiBMother}}}); + registry.add("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRecBMother", stringDHadron + "signal region NonPromptD - NonPrompt Track MC reco", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPtBMother}, {axisDeltaPhiBMother}}}); + + registry.get(HIST("hCorrel2DVsPtNonPromptDplusPhysicalPrimaryMcRecBMother"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRecBMother"))->Sumw2(); + } } // Histograms for MC Gen analysis if (fillHistoMcGen) { @@ -274,6 +291,15 @@ struct HfTaskCorrelationDplusHadrons { registry.get(HIST("hCorrel2DVsPtMcGen"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtMcGenPrompt"))->Sumw2(); registry.get(HIST("hCorrel2DVsPtMcGenNonPrompt"))->Sumw2(); + + // beauty-mother information of non-prompt D+, same axes as the MC Rec counterparts to allow Rec/Gen ratios + if (storeBMotherInfo) { + registry.add("hCorrel2DVsPtMcGenNonPromptBMother", stringDHadron + " NonPrompt MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPtBMother}, {axisDeltaPhiBMother}}}); + registry.add("hCorrel2DVsPtMcGenNonPromptDNonPromptHadronBMother", stringDHadron + " non prompt D non prompt h MC Gen", {HistType::kTHnSparseD, {{axisDeltaPhi}, {axisDeltaEta}, {axisPtD}, {axisPtHadron}, {axisPtBMother}, {axisDeltaPhiBMother}}}); + + registry.get(HIST("hCorrel2DVsPtMcGenNonPromptBMother"))->Sumw2(); + registry.get(HIST("hCorrel2DVsPtMcGenNonPromptDNonPromptHadronBMother"))->Sumw2(); + } } // Histograms for efficiencies registry.add("Efficiency/hPtCandMcRecPrompt", stringMCRecoDPrompt + stringPtD, {HistType::kTH1F, {axisPtD}}); @@ -439,8 +465,8 @@ struct HfTaskCorrelationDplusHadrons { PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processData, "Process data", false); /// D-Hadron correlation pair filling task, from pair tables - for MC reco-level analysis (candidates matched to true signal only, but also bkg sources are studied) - void processMcRec(DplusHadronPairFullWithMl const& pairEntries, - soa::Join const& candidates) + void processMcRec(DplusHadronPairFullWithMlAndBMother const& pairEntries, + soa::Join const& candidates) { for (const auto& candidate : candidates) { float const massD = candidate.mD(); @@ -482,6 +508,10 @@ struct HfTaskCorrelationDplusHadrons { registry.fill(HIST("hMassNonPromptDplusVsPt"), massD, ptD, efficiencyWeightD); registry.fill(HIST("hBdtScorePrompt"), bdtScorePrompt); registry.fill(HIST("hBdtScoreBkg"), bdtScoreBkg); + if (storeBMotherInfo) { + registry.fill(HIST("hMassNonPromptDplusVsPtVsPtBMother"), massD, ptD, candidate.ptB(), efficiencyWeightD); + registry.fill(HIST("hDeltaPhiBMotherVsPtVsPtBMother"), candidate.deltaPhiBtoD(), ptD, candidate.ptB(), efficiencyWeightD); + } } } } @@ -556,6 +586,15 @@ struct HfTaskCorrelationDplusHadrons { } else if (!isDplusPrompt && originHadron == RecoDecay::OriginType::NonPrompt) { registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRec"), deltaPhi, deltaEta, ptD, ptHadron, poolBin, efficiencyWeight); } + // beauty-mother information, only for true non-prompt D+, to study the structures in the MC Closure test + if (storeBMotherInfo && pairEntry.signalStatus() && !isDplusPrompt) { + float const ptB = pairEntry.ptB(); + float const deltaPhiBtoD = pairEntry.deltaPhiBtoD(); + registry.fill(HIST("hCorrel2DVsPtNonPromptDplusPhysicalPrimaryMcRecBMother"), deltaPhi, deltaEta, ptD, ptHadron, ptB, deltaPhiBtoD, efficiencyWeight); + if (originHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtSignalRegionNonPromptDplusNonPromptHadronMcRecBMother"), deltaPhi, deltaEta, ptD, ptHadron, ptB, deltaPhiBtoD, efficiencyWeight); + } + } } } // in sideband left region @@ -583,7 +622,7 @@ struct HfTaskCorrelationDplusHadrons { PROCESS_SWITCH(HfTaskCorrelationDplusHadrons, processMcRec, "Process MC Reco mode", true); /// D-Hadron correlation pair filling task, from pair tables - for MC gen-level analysis (no filter/selection, only true signal) - void processMcGen(DplusHadronPair const& pairEntries) + void processMcGen(DplusHadronPairWithBMother const& pairEntries) { for (const auto& pairEntry : pairEntries) { // define variables for widely used quantities @@ -608,6 +647,15 @@ struct HfTaskCorrelationDplusHadrons { if (originHadron == RecoDecay::OriginType::NonPrompt) { registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDNonPromptHadron"), deltaPhi, deltaEta, ptD, ptHadron, poolBin); } + // beauty-mother information + if (storeBMotherInfo) { + float const ptB = pairEntry.ptB(); + float const deltaPhiBtoD = pairEntry.deltaPhiBtoD(); + registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptBMother"), deltaPhi, deltaEta, ptD, ptHadron, ptB, deltaPhiBtoD); + if (originHadron == RecoDecay::OriginType::NonPrompt) { + registry.fill(HIST("hCorrel2DVsPtMcGenNonPromptDNonPromptHadronBMother"), deltaPhi, deltaEta, ptD, ptHadron, ptB, deltaPhiBtoD); + } + } } } } From 18f95ec50d21c57ac80e9875bed533e688647f99 Mon Sep 17 00:00:00 2001 From: apalasciano Date: Wed, 14 Oct 2026 11:21:28 +0200 Subject: [PATCH 2/7] adding missing file to the previous commit --- PWGHF/HFC/DataModel/CorrelationTables.h | 12 ++--- PWGHF/HFC/Utils/utilsCorrelations.h | 61 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/PWGHF/HFC/DataModel/CorrelationTables.h b/PWGHF/HFC/DataModel/CorrelationTables.h index 75543cd0d33..fcea57be77c 100644 --- a/PWGHF/HFC/DataModel/CorrelationTables.h +++ b/PWGHF/HFC/DataModel/CorrelationTables.h @@ -498,19 +498,19 @@ DECLARE_SOA_TABLE(TrkRecInfoDplus, "AOD", "TRKRECINFODPLUS", //! Tracks Reconstr aod::hf_correlation_dplus_hadron::TrackTPCNClsCrossedRows); // definition of columns and tables for the beauty-mother information of the charm-hadron trigger (MC only), usable by any D-hadron correlation analysis -namespace hf_correlation_b_mother +namespace hf_correlation_info_b_mother { DECLARE_SOA_COLUMN(PtB, ptB, float); //! Generated pT of the beauty mother of the charm hadron (-1 if not from beauty) DECLARE_SOA_COLUMN(DeltaPhiBtoD, deltaPhiBtoD, float); //! phi(charm hadron) - phi(B mother, generated) in [-pihalf, 3.*pihalf) (-999 if not from beauty) -} // namespace hf_correlation_b_mother +} // namespace hf_correlation_info_b_mother DECLARE_SOA_TABLE(BMotherPairInfo, "AOD", "BMOTHERPAIRINFO", //! Charm-hadron-hadron pairs beauty-mother information, joinable with the pair table - aod::hf_correlation_b_mother::PtB, - aod::hf_correlation_b_mother::DeltaPhiBtoD); + aod::hf_correlation_info_b_mother::PtB, + aod::hf_correlation_info_b_mother::DeltaPhiBtoD); DECLARE_SOA_TABLE(BMotherCandInfo, "AOD", "BMOTHERCANDINFO", //! Charm-hadron candidates beauty-mother information, joinable with the candidate table - aod::hf_correlation_b_mother::PtB, - aod::hf_correlation_b_mother::DeltaPhiBtoD); + aod::hf_correlation_info_b_mother::PtB, + aod::hf_correlation_info_b_mother::DeltaPhiBtoD); // definition of columns and tables for Dstar-Hadron correlation pair namespace hf_correlation_dstar_hadron diff --git a/PWGHF/HFC/Utils/utilsCorrelations.h b/PWGHF/HFC/Utils/utilsCorrelations.h index 0f5fea00a9c..3259317c910 100644 --- a/PWGHF/HFC/Utils/utilsCorrelations.h +++ b/PWGHF/HFC/Utils/utilsCorrelations.h @@ -18,6 +18,7 @@ #include "PWGHF/Core/DecayChannels.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -29,6 +30,9 @@ #include #include +#include +#include +#include namespace o2::analysis::hf_correlations { @@ -227,5 +231,62 @@ int findLeadingParticleMcGen(TMcParticles const& mcParticles, T1 const etaTrackM } return leadingParticle.globalIndex(); } + +// ======= Beauty-mother information of non-prompt charm hadrons ============ +constexpr float PtBMotherDefault{-1.f}; // pT(B mother) returned when the charm hadron is not from beauty +constexpr float DeltaPhiBMotherDefault{-999.f}; // phi(charm hadron) - phi(B mother) returned when the charm hadron is not from beauty + +/// Gets the generated beauty mother of a reconstructed charm-hadron candidate matched to a non-prompt charm hadron +/// \tparam TTracks is the track table with MC labels, used to access the candidate prongs +/// \param candidate is the reconstructed candidate (with originMcRec column) +/// \param mcParticles is the table of MC particles +/// \param pdgCharmHadron is the PDG code of the charm hadron (e.g. Pdg::kDPlus), antiparticles are accepted +/// \param depthMaxDaughters is the max. depth of the candidate prong in the charm-hadron decay chain (> 1 for resonant channels) +/// \return pair (pT of the B mother, phi(candidate, reco) - phi(B mother, gen) in [-pi, pi)), default values if the candidate is not from beauty +template +std::pair getBMotherInfoMcRec(TCandidate const& candidate, TMcParticles const& mcParticles, int pdgCharmHadron, int8_t depthMaxDaughters = 2) +{ + std::pair bMotherInfo{PtBMotherDefault, DeltaPhiBMotherDefault}; + if (candidate.originMcRec() != RecoDecay::OriginType::NonPrompt) { + return bMotherInfo; + } + // retrieve the generated charm hadron from the MC particle of one of its daughters + auto prong0 = candidate.template prong0_as(); + if (!prong0.has_mcParticle()) { + return bMotherInfo; + } + auto prong0McPart = prong0.template mcParticle_as(); + int const indexCharmHadronGen = RecoDecay::getMother(mcParticles, prong0McPart, pdgCharmHadron, true, nullptr, depthMaxDaughters); + if (indexCharmHadronGen < 0) { + return bMotherInfo; + } + // same procedure used in the candidate creators to fill PtBhadMotherPart + auto charmHadronGen = mcParticles.rawIteratorAt(indexCharmHadronGen - mcParticles.offset()); + std::vector idxBhadMothers{}; + if (RecoDecay::getCharmHadronOrigin(mcParticles, charmHadronGen, false, &idxBhadMothers) != RecoDecay::OriginType::NonPrompt || idxBhadMothers.empty()) { + return bMotherInfo; + } + auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0] - mcParticles.offset()); + bMotherInfo.first = bHadMother.pt(); + bMotherInfo.second = RecoDecay::constrainAngle(candidate.phi() - bHadMother.phi(), -o2::constants::math::PI); + return bMotherInfo; +} + +/// Gets the beauty mother of a generated charm hadron +/// \param particle is the generated charm hadron (with originMcGen and idxBhadMotherPart columns) +/// \param mcParticles is the table of MC particles containing the B mother +/// \return pair (pT of the B mother, phi(charm hadron) - phi(B mother) in [-pi, pi)), default values if the charm hadron is not from beauty +template +std::pair getBMotherInfoMcGen(TParticle const& particle, TMcParticles const& mcParticles) +{ + std::pair bMotherInfo{PtBMotherDefault, DeltaPhiBMotherDefault}; + if (particle.originMcGen() != RecoDecay::OriginType::NonPrompt || particle.idxBhadMotherPart() < 0) { + return bMotherInfo; + } + auto bHadMother = mcParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcParticles.offset()); + bMotherInfo.first = bHadMother.pt(); + bMotherInfo.second = RecoDecay::constrainAngle(particle.phi() - bHadMother.phi(), -o2::constants::math::PI); + return bMotherInfo; +} } // namespace o2::analysis::hf_correlations #endif // PWGHF_HFC_UTILS_UTILSCORRELATIONS_H_ From e86d2f87019703781452c27ec1fe6eb6406eef1e Mon Sep 17 00:00:00 2001 From: apalasciano Date: Wed, 14 Oct 2026 14:49:40 +0200 Subject: [PATCH 3/7] minor fix --- PWGHF/HFC/Utils/utilsCorrelations.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/HFC/Utils/utilsCorrelations.h b/PWGHF/HFC/Utils/utilsCorrelations.h index 3259317c910..da79061d4b5 100644 --- a/PWGHF/HFC/Utils/utilsCorrelations.h +++ b/PWGHF/HFC/Utils/utilsCorrelations.h @@ -268,7 +268,7 @@ std::pair getBMotherInfoMcRec(TCandidate const& candidate, TMcPart } auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0] - mcParticles.offset()); bMotherInfo.first = bHadMother.pt(); - bMotherInfo.second = RecoDecay::constrainAngle(candidate.phi() - bHadMother.phi(), -o2::constants::math::PI); + bMotherInfo.second = RecoDecay::constrainAngle(candidate.phi() - bHadMother.phi(), -o2::constants::math::PIhalf); return bMotherInfo; } @@ -285,7 +285,7 @@ std::pair getBMotherInfoMcGen(TParticle const& particle, TMcPartic } auto bHadMother = mcParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcParticles.offset()); bMotherInfo.first = bHadMother.pt(); - bMotherInfo.second = RecoDecay::constrainAngle(particle.phi() - bHadMother.phi(), -o2::constants::math::PI); + bMotherInfo.second = RecoDecay::constrainAngle(particle.phi() - bHadMother.phi(), -o2::constants::math::PIhalf); return bMotherInfo; } } // namespace o2::analysis::hf_correlations From 1e1aa41d65a9f473133b79e5cf7c4212ca852896 Mon Sep 17 00:00:00 2001 From: apalasciano Date: Wed, 14 Oct 2026 14:54:07 +0200 Subject: [PATCH 4/7] minor fix --- PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx index 9c13570974e..5ac86bf95f9 100644 --- a/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx +++ b/PWGHF/HFC/Tasks/taskCorrelationDplusHadrons.cxx @@ -338,7 +338,7 @@ struct HfTaskCorrelationDplusHadrons { } LOGF(info, "Loaded associated efficiency histogram from %s", associatedEffCcdbPath.value.c_str()); } - auto effD = isPromptAnalysis ? mEfficiencyPrompt : mEfficiencyFD; + effD = isPromptAnalysis ? mEfficiencyPrompt : mEfficiencyFD; idxBdtScore = isPromptAnalysis ? 1 : 2; if (activateQA) { From 1b7d0e907ab5c7c36cdb675359f5e27eb7e25bda Mon Sep 17 00:00:00 2001 From: apalasciano Date: Wed, 14 Oct 2026 17:57:43 +0200 Subject: [PATCH 5/7] improve clarity in reduced tables for correlations --- .../DataModel/DerivedDataCorrelationTables.h | 24 ++++++++++--------- .../TableProducer/correlatorDplusHadrons.cxx | 3 ++- .../HFC/TableProducer/correlatorDsHadrons.cxx | 5 ++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h b/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h index e7c69695f32..6a807a0db0c 100644 --- a/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h +++ b/PWGHF/HFC/DataModel/DerivedDataCorrelationTables.h @@ -47,16 +47,17 @@ using HfcRedCollision = HfcRedCollisions::iterator; namespace hf_candidate_reduced { -DECLARE_SOA_INDEX_COLUMN(HfcRedCollision, hfcRedCollision); //! ReducedCollision index -DECLARE_SOA_COLUMN(Prong0Id, prong0Id, int); //! Prong 0 index -DECLARE_SOA_COLUMN(Prong1Id, prong1Id, int); //! Prong 1 index -DECLARE_SOA_COLUMN(Prong2Id, prong2Id, int); //! Prong2 index -DECLARE_SOA_COLUMN(PhiCand, phiCand, float); //! Phi of the candidate -DECLARE_SOA_COLUMN(EtaCand, etaCand, float); //! Eta of the candidate -DECLARE_SOA_COLUMN(PtCand, ptCand, float); //! Pt of the candidate -DECLARE_SOA_COLUMN(InvMass, invMass, float); //! Invariant mass of charm candidate -DECLARE_SOA_COLUMN(BdtScorePrompt, bdtScorePrompt, float); //! BDT output score for prompt hypothesis -DECLARE_SOA_COLUMN(BdtScoreBkg, bdtScoreBkg, float); //! BDT output score for background hypothesis +DECLARE_SOA_INDEX_COLUMN(HfcRedCollision, hfcRedCollision); //! ReducedCollision index +DECLARE_SOA_COLUMN(Prong0Id, prong0Id, int); //! Prong 0 index +DECLARE_SOA_COLUMN(Prong1Id, prong1Id, int); //! Prong 1 index +DECLARE_SOA_COLUMN(Prong2Id, prong2Id, int); //! Prong2 index +DECLARE_SOA_COLUMN(PhiCand, phiCand, float); //! Phi of the candidate +DECLARE_SOA_COLUMN(EtaCand, etaCand, float); //! Eta of the candidate +DECLARE_SOA_COLUMN(PtCand, ptCand, float); //! Pt of the candidate +DECLARE_SOA_COLUMN(InvMass, invMass, float); //! Invariant mass of charm candidate +DECLARE_SOA_COLUMN(BdtScorePrompt, bdtScorePrompt, float); //! BDT output score for prompt hypothesis +DECLARE_SOA_COLUMN(BdtScoreNonPrompt, bdtScoreNonPrompt, float); //! BDT output score for non-prompt hypothesis +DECLARE_SOA_COLUMN(BdtScoreBkg, bdtScoreBkg, float); //! BDT output score for background hypothesis } // namespace hf_candidate_reduced DECLARE_SOA_TABLE(HcCandReduceds, "AOD", "HCCANDREDUCED", //! Table with charm hadron candidate info soa::Index<>, @@ -72,8 +73,9 @@ DECLARE_SOA_TABLE(HcCandReduceds, "AOD", "HCCANDREDUCED", //! Table with charm h DECLARE_SOA_TABLE(HcCandSelInfos, "AOD", "HCCANDSELINFO", //! Table with charm hadron candidate selection info soa::Index<>, aod::hf_candidate_reduced::HfcRedCollisionId, + aod::hf_candidate_reduced::BdtScoreBkg, aod::hf_candidate_reduced::BdtScorePrompt, - aod::hf_candidate_reduced::BdtScoreBkg); + aod::hf_candidate_reduced::BdtScoreNonPrompt); namespace hf_assoc_track_reduced { diff --git a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx index 493c232bdb8..a4d52996823 100644 --- a/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDplusHadrons.cxx @@ -569,7 +569,8 @@ struct HfCorrelatorDplusHadrons { outputMl[iclass] = candidate.mlProbDplusToPiKPi()[classMl->at(iclass)]; } candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt(), HfHelper::invMassDplusToPiKPi(candidate), candidate.prong0Id(), candidate.prong1Id(), candidate.prong2Id()); - candSelInfo(indexHfcReducedCollision, outputMl[0], outputMl[2]); + // Check compatibility with the candidate selector options: BdtScoreBkg, BdtScorePrompt, BdtScoreNonPrompt + candSelInfo(indexHfcReducedCollision, outputMl[0], outputMl[1], outputMl[2]); } } diff --git a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx index f0d4194148b..58fe4c1bb7d 100644 --- a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx @@ -859,13 +859,14 @@ struct HfCorrelatorDsHadrons { outputMl[iclass] = candidate.mlProbDsToKKPi()[classMl->at(iclass)]; } candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt() * chargeDs, HfHelper::invMassDsToKKPi(candidate), candidate.prong0Id(), candidate.prong1Id(), candidate.prong2Id()); - candSelInfo(indexHfcReducedCollision, outputMl[0], outputMl[2]); + // Check compatibility with the candidate selector options; candSelInfo considers BdtScoreBkg, BdtScorePrompt, BdtScoreNonPrompt + candSelInfo(indexHfcReducedCollision, outputMl[2], outputMl[0], outputMl[1]); // bkg, prompt, non-prompt (Ds convention: outputMl[0] = prompt, outputMl[2] = bkg) } else if (candidate.isSelDsToPiKK() >= selectionFlagDs) { for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMl[iclass] = candidate.mlProbDsToPiKK()[classMl->at(iclass)]; } candReduced(indexHfcReducedCollision, candidate.phi(), candidate.eta(), candidate.pt() * chargeDs, HfHelper::invMassDsToPiKK(candidate), candidate.prong0Id(), candidate.prong1Id(), candidate.prong2Id()); - candSelInfo(indexHfcReducedCollision, outputMl[0], outputMl[2]); + candSelInfo(indexHfcReducedCollision, outputMl[2], outputMl[0], outputMl[1]); // bkg, prompt, non-prompt (Ds convention: outputMl[0] = prompt, outputMl[2] = bkg) } } From 62ee0f07402a91304c57f571d7bace24157a6246 Mon Sep 17 00:00:00 2001 From: apalasciano Date: Wed, 14 Oct 2026 18:07:21 +0200 Subject: [PATCH 6/7] megalinter --- PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx index 58fe4c1bb7d..17add0a004d 100644 --- a/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDsHadrons.cxx @@ -673,7 +673,6 @@ struct HfCorrelatorDsHadrons { entryTrackRecoInfo(track.dcaXY(), track.dcaZ(), track.tpcNClsCrossedRows()); } else if (isCorrectInvMassHypo && candidate.isSelDsToPiKK() >= selectionFlagDs) { // if (track.has_mcParticle()) { - auto mcParticle = track.template mcParticle_as(); entryDsHadronPair(getDeltaPhi(track.phi(), candidate.phi()), track.eta() - candidate.eta(), candidate.pt() * chargeDs, From 074baba91ad1166c6fe4c80f867dec43df892f66 Mon Sep 17 00:00:00 2001 From: apalasciano Date: Fri, 16 Oct 2026 11:47:27 +0200 Subject: [PATCH 7/7] typo --- PWGHF/HFC/Utils/utilsCorrelations.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PWGHF/HFC/Utils/utilsCorrelations.h b/PWGHF/HFC/Utils/utilsCorrelations.h index da79061d4b5..884be2d1704 100644 --- a/PWGHF/HFC/Utils/utilsCorrelations.h +++ b/PWGHF/HFC/Utils/utilsCorrelations.h @@ -268,7 +268,7 @@ std::pair getBMotherInfoMcRec(TCandidate const& candidate, TMcPart } auto bHadMother = mcParticles.rawIteratorAt(idxBhadMothers[0] - mcParticles.offset()); bMotherInfo.first = bHadMother.pt(); - bMotherInfo.second = RecoDecay::constrainAngle(candidate.phi() - bHadMother.phi(), -o2::constants::math::PIhalf); + bMotherInfo.second = RecoDecay::constrainAngle(candidate.phi() - bHadMother.phi(), -o2::constants::math::PIHalf); return bMotherInfo; } @@ -285,7 +285,7 @@ std::pair getBMotherInfoMcGen(TParticle const& particle, TMcPartic } auto bHadMother = mcParticles.rawIteratorAt(particle.idxBhadMotherPart() - mcParticles.offset()); bMotherInfo.first = bHadMother.pt(); - bMotherInfo.second = RecoDecay::constrainAngle(particle.phi() - bHadMother.phi(), -o2::constants::math::PIhalf); + bMotherInfo.second = RecoDecay::constrainAngle(particle.phi() - bHadMother.phi(), -o2::constants::math::PIHalf); return bMotherInfo; } } // namespace o2::analysis::hf_correlations