From 8152d1c95159e17a7767dc20c2ab9a488065589e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BiaoZhang=20=28=E5=BC=A0=E5=BD=AA=29?= <52267892+zhangbiao-phy@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:48:57 +0200 Subject: [PATCH 1/3] Add PID support for charm nuclei candidates based on cascades channel Added support for additional PID configurations for deuterons, tritons, helium-3, and alpha particles in charm nuclei analysis. Updated histogram registrations and invariant mass calculations accordingly. --- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 16ca600001b..55b844d5c01 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -502,7 +502,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { selectorKaon.setRangeNSigmaTof(-config.selectionsPid->get(ChannelKaonPid, 5u), config.selectionsPid->get(ChannelKaonPid, 5u)); // 5u == "nSigmaMaxTof" } - /// Apply track-quality (ITS/TPC) + optional ITS-PID preselection for light-nucleus daughters used in charm-nuclei 3-prong channels (Cd/Ct/Ch). + /// Apply track-quality (ITS/TPC) + optional ITS-PID preselection for light-nucleus daughters used in charm-nuclei 3-prong channels (Cd/Ct/Ch/Ca). /// \tparam TrackType Track providing ITS/TPC quality accessors. /// \param track Daughter track to be tested (either prong0 or prong2). /// \param lightnuclei Species selector: 0=Deuteron, 1=Triton, 2=Helium3. @@ -3348,9 +3348,15 @@ struct HfTrackIndexSkimCreatorCascades { // cascade cuts Configurable ptCascCandMin{"ptCascCandMin", -1., "min. pT of the cascade candidate"}; // PbPb 2018: use 1 Configurable cutInvMassCascLc{"cutInvMassCascLc", 1., "Lc candidate invariant mass difference wrt PDG"}; // for PbPb 2018: use 0.2 + Configurable cutInvMassCascCharmNuclei{"cutInvMassCascCharmNuclei", 1., "charm nuclei candidate invariant mass difference wrt mass threshold"}; + // Configurable cutCascDCADaughters{"cutCascDCADaughters", .1, "DCA between V0 and bachelor in cascade"}; // proton PID Configurable applyProtonPid{"applyProtonPid", false, "Apply proton PID for Lc->pK0S"}; + Configurable applyDeuteronPid{"applyDeuteronPid", false, "Apply Deuteron PID for Cd->dK0S"}; + Configurable applyTritonPid{"applyTritonPid", false, "Apply Triton PID for Ct->trK0S"}; + Configurable applyHelium3Pid{"applyHelium3Pid", false, "Apply Helium3 PID for Ch->HeK0S"}; + Configurable applyAlphaPid{"applyAlphaPid", false, "Apply Alpha PID for Ca->AlK0S"}; // CCDB Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -3371,7 +3377,16 @@ struct HfTrackIndexSkimCreatorCascades { using FilteredTrackAssocSel = soa::Filtered>; Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); - Filter filterSelectTrackIds = (aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandV0bachelor))) != 0u && (!config.applyProtonPid || (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsProtonPid::LcToPK0S))) != 0u); + + Filter filterSelectTrackIds = + ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::CandV0bachelor))) != 0u) && + + ((config.applyProtonPid && (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsProtonPid::LcToPK0S))) != 0u) || + (config.applyDeuteronPid && (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsDeuteronPid))) != 0u) || + (config.applyTritonPid && (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsTritonPid))) != 0u) || + (config.applyHelium3Pid && (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsHeliumPid))) != 0u) || + (config.applyAlphaPid && (aod::hf_sel_track::isIdentifiedPid & static_cast(BIT(ChannelsAlphaPid))) != 0u) || + (!config.applyProtonPid && !config.applyDeuteronPid && !config.applyTritonPid && !config.applyHelium3Pid && !config.applyAlphaPid)); Preslice trackIndicesPerCollision = aod::track_association::collisionId; Preslice v0sPerCollision = aod::v0data::collisionId; @@ -3408,7 +3423,11 @@ struct HfTrackIndexSkimCreatorCascades { registry.add("hVtx2ProngX", "2-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); registry.add("hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); registry.add("hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); - registry.add("hMassLcToPK0S", "#Lambda_{c}^ candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassLcToPK0S", " #Lambda_{c}^ candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassCdToDeK0S", "Cd candidates;inv. mass (d K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassCtToTrK0S", "Ct candidates;inv. mass (tr K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassChToHeK0S", "Ch candidates;inv. mass (he3 K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassCaToAlK0S", "Ca candidates;inv. mass (alpha K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 7.}}}); } } @@ -3492,7 +3511,29 @@ struct HfTrackIndexSkimCreatorCascades { // invariant-mass cut: we do it here, before updating the momenta of bach and V0 during the fitting to save CPU // TODO: but one should better check that the value here and after the fitter do not change significantly!!! double mass2K0sP = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassProton, MassK0Short}); - if ((config.cutInvMassCascLc >= 0.) && (std::abs(mass2K0sP - MassLambdaCPlus) > config.cutInvMassCascLc)) { + double mass2K0sDe = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassDeuteron, MassK0Short}); + double mass2K0sTr = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassTriton, MassK0Short}); + double mass2K0sHe = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassHelium3, MassK0Short}); + double mass2K0sAl = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassAlpha, MassK0Short}); + + const bool applyAnyBachelorPid = config.applyProtonPid || config.applyDeuteronPid || config.applyTritonPid || config.applyHelium3Pid || config.applyAlphaPid; + bool keepMassHypothesis = false; + if (!applyAnyBachelorPid || config.applyProtonPid) { + keepMassHypothesis |= (config.cutInvMassCascLc < 0.) || (std::abs(mass2K0sP - MassLambdaCPlus) <= config.cutInvMassCascLc); + } + if (config.applyDeuteronPid) { + keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sDe - MassDeuteron - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); + } + if (config.applyTritonPid) { + keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sTr - MassTriton - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); + } + if (config.applyHelium3Pid) { + keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sHe - MassHelium3 - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); + } + if (config.applyAlphaPid) { + keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sAl - MassAlpha - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); + } + if (!keepMassHypothesis) { continue; } @@ -3535,6 +3576,11 @@ struct HfTrackIndexSkimCreatorCascades { // invariant mass // re-calculate invariant masses with updated momenta, to fill the histogram mass2K0sP = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassProton, MassK0Short}); + mass2K0sDe = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassDeuteron, MassK0Short}); + mass2K0sTr = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassTriton, MassK0Short}); + mass2K0sHe = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassHelium3, MassK0Short}); + mass2K0sAl = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassAlpha, MassK0Short}); + std::array posCasc{0., 0., 0.}; if (config.useDCAFitter) { const auto& cascVtx = df2.getPCACandidate(); @@ -3551,6 +3597,10 @@ struct HfTrackIndexSkimCreatorCascades { registry.fill(HIST("hVtx2ProngY"), posCasc[1]); registry.fill(HIST("hVtx2ProngZ"), posCasc[2]); registry.fill(HIST("hMassLcToPK0S"), mass2K0sP); + registry.fill(HIST("hMassCdToDeK0S"), mass2K0sDe); + registry.fill(HIST("hMassCtToTrK0S"), mass2K0sTr); + registry.fill(HIST("hMassChToHeK0S"), mass2K0sHe); + registry.fill(HIST("hMassCaToAlK0S"), mass2K0sAl); } } // loop over V0s } // loop over tracks From 6fd5de22dcbba039100823d1ab616044cdc61f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BiaoZhang=20=28=E5=BC=A0=E5=BD=AA=29?= <52267892+zhangbiao-phy@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:56:15 +0200 Subject: [PATCH 2/3] Update mass range for various candidate histograms --- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 55b844d5c01..c9f22a52367 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -3424,9 +3424,9 @@ struct HfTrackIndexSkimCreatorCascades { registry.add("hVtx2ProngY", "2-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); registry.add("hVtx2ProngZ", "2-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); registry.add("hMassLcToPK0S", " #Lambda_{c}^ candidates;inv. mass (p K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); - registry.add("hMassCdToDeK0S", "Cd candidates;inv. mass (d K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); - registry.add("hMassCtToTrK0S", "Ct candidates;inv. mass (tr K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); - registry.add("hMassChToHeK0S", "Ch candidates;inv. mass (he3 K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassCdToDeK0S", "Cd candidates;inv. mass (d K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 7.}}}); + registry.add("hMassCtToTrK0S", "Ct candidates;inv. mass (tr K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 7.}}}); + registry.add("hMassChToHeK0S", "Ch candidates;inv. mass (he3 K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 7.}}}); registry.add("hMassCaToAlK0S", "Ca candidates;inv. mass (alpha K_{S}^{0}) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 2., 7.}}}); } } From dfa2ec5d3fc05a6d3b45ba2947f4e317faff2ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BiaoZhang=20=28=E5=BC=A0=E5=BD=AA=29?= <52267892+zhangbiao-phy@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:14:05 +0200 Subject: [PATCH 3/3] Refactor mass hypothesis checks and selections --- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index c9f22a52367..f0bed523d9c 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -3516,24 +3516,20 @@ struct HfTrackIndexSkimCreatorCascades { double mass2K0sHe = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassHelium3, MassK0Short}); double mass2K0sAl = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassAlpha, MassK0Short}); + const auto isIdentifiedPid = bachIdx.isIdentifiedPid(); const bool applyAnyBachelorPid = config.applyProtonPid || config.applyDeuteronPid || config.applyTritonPid || config.applyHelium3Pid || config.applyAlphaPid; - bool keepMassHypothesis = false; - if (!applyAnyBachelorPid || config.applyProtonPid) { - keepMassHypothesis |= (config.cutInvMassCascLc < 0.) || (std::abs(mass2K0sP - MassLambdaCPlus) <= config.cutInvMassCascLc); - } - if (config.applyDeuteronPid) { - keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sDe - MassDeuteron - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); - } - if (config.applyTritonPid) { - keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sTr - MassTriton - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); - } - if (config.applyHelium3Pid) { - keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sHe - MassHelium3 - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); - } - if (config.applyAlphaPid) { - keepMassHypothesis |= (config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sAl - MassAlpha - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei); - } - if (!keepMassHypothesis) { + const bool isChannelLc = !applyAnyBachelorPid || (config.applyProtonPid && TESTBIT(isIdentifiedPid, ChannelsProtonPid::LcToPK0S)); + const bool isChannelCd = config.applyDeuteronPid && TESTBIT(isIdentifiedPid, ChannelsDeuteronPid); + const bool isChannelCt = config.applyTritonPid && TESTBIT(isIdentifiedPid, ChannelsTritonPid); + const bool isChannelCh = config.applyHelium3Pid && TESTBIT(isIdentifiedPid, ChannelsHeliumPid); + const bool isChannelCa = config.applyAlphaPid && TESTBIT(isIdentifiedPid, ChannelsAlphaPid); + + bool isSelectedLc = isChannelLc && ((config.cutInvMassCascLc < 0.) || (std::abs(mass2K0sP - MassLambdaCPlus) <= config.cutInvMassCascLc)); + bool isSelectedCd = isChannelCd && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sDe - MassDeuteron - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + bool isSelectedCt = isChannelCt && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sTr - MassTriton - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + bool isSelectedCh = isChannelCh && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sHe - MassHelium3 - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + bool isSelectedCa = isChannelCa && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sAl - MassAlpha - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + if (!isSelectedLc && !isSelectedCd && !isSelectedCt && !isSelectedCh && !isSelectedCa) { continue; } @@ -3581,6 +3577,12 @@ struct HfTrackIndexSkimCreatorCascades { mass2K0sHe = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassHelium3, MassK0Short}); mass2K0sAl = RecoDecay::m(std::array{pVecBach, pVecV0}, std::array{MassAlpha, MassK0Short}); + isSelectedLc = isChannelLc && ((config.cutInvMassCascLc < 0.) || (std::abs(mass2K0sP - MassLambdaCPlus) <= config.cutInvMassCascLc)); + isSelectedCd = isChannelCd && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sDe - MassDeuteron - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + isSelectedCt = isChannelCt && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sTr - MassTriton - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + isSelectedCh = isChannelCh && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sHe - MassHelium3 - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + isSelectedCa = isChannelCa && ((config.cutInvMassCascCharmNuclei < 0.) || (mass2K0sAl - MassAlpha - MassLambdaCPlus <= config.cutInvMassCascCharmNuclei)); + std::array posCasc{0., 0., 0.}; if (config.useDCAFitter) { const auto& cascVtx = df2.getPCACandidate(); @@ -3596,11 +3598,21 @@ struct HfTrackIndexSkimCreatorCascades { registry.fill(HIST("hVtx2ProngX"), posCasc[0]); registry.fill(HIST("hVtx2ProngY"), posCasc[1]); registry.fill(HIST("hVtx2ProngZ"), posCasc[2]); - registry.fill(HIST("hMassLcToPK0S"), mass2K0sP); - registry.fill(HIST("hMassCdToDeK0S"), mass2K0sDe); - registry.fill(HIST("hMassCtToTrK0S"), mass2K0sTr); - registry.fill(HIST("hMassChToHeK0S"), mass2K0sHe); - registry.fill(HIST("hMassCaToAlK0S"), mass2K0sAl); + if (isSelectedLc) { + registry.fill(HIST("hMassLcToPK0S"), mass2K0sP); + } + if (isSelectedCd) { + registry.fill(HIST("hMassCdToDeK0S"), mass2K0sDe); + } + if (isSelectedCt) { + registry.fill(HIST("hMassCtToTrK0S"), mass2K0sTr); + } + if (isSelectedCh) { + registry.fill(HIST("hMassChToHeK0S"), mass2K0sHe); + } + if (isSelectedCa) { + registry.fill(HIST("hMassCaToAlK0S"), mass2K0sAl); + } } } // loop over V0s } // loop over tracks