From b08f91b87b0201b5ac1986fa1857fda5ec0d568c Mon Sep 17 00:00:00 2001 From: BiaoZhang Date: Mon, 5 Jan 2026 11:25:14 +0100 Subject: [PATCH 1/6] Complete the charmed-hyper nuclei search and add the track quality QA of light nuclei in the skimming task --- Common/Core/TrackSelectorPID.h | 26 ++ PWGHF/Core/SelectorCuts.h | 18 +- PWGHF/DataModel/AliasTables.h | 4 + .../DataModel/CandidateReconstructionTables.h | 59 ++++- PWGHF/DataModel/CandidateSelectionTables.h | 16 ++ PWGHF/DataModel/TrackIndexSkimmingTables.h | 2 + PWGHF/TableProducer/pidCreator.cxx | 10 + PWGHF/TableProducer/trackIndexSkimCreator.cxx | 236 +++++++++++++++--- PWGHF/Utils/utilsPid.h | 20 +- 9 files changed, 352 insertions(+), 39 deletions(-) diff --git a/Common/Core/TrackSelectorPID.h b/Common/Core/TrackSelectorPID.h index e8ceaa4fa07..cbced7e8f6b 100644 --- a/Common/Core/TrackSelectorPID.h +++ b/Common/Core/TrackSelectorPID.h @@ -133,6 +133,10 @@ class TrackSelectorPidBase nSigma = track.tpcNSigmaPr(); } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { nSigma = track.tpcNSigmaDe(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kTriton) { + nSigma = track.tpcNSigmaTr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kHelium3) { + nSigma = track.tpcNSigmaHe(); } else { errorPdg(); } @@ -229,6 +233,10 @@ class TrackSelectorPidBase nSigma = track.tofNSigmaPr(); } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { nSigma = track.tofNSigmaDe(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kTriton) { + nSigma = track.tofNSigmaTr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kHelium3) { + nSigma = track.tofNSigmaHe(); } else { errorPdg(); } @@ -567,6 +575,10 @@ class TrackSelectorPidBase return track.bayesID() == o2::track::PID::Proton; } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { return track.bayesID() == o2::track::PID::Deuteron; + } else if constexpr (pdg == o2::constants::physics::Pdg::kTriton) { + return track.bayesID() == o2::track::PID::Triton; + } else if constexpr (pdg == o2::constants::physics::Pdg::kHelium3) { + return track.bayesID() == o2::track::PID::Helium3; } else { errorPdg(); return false; @@ -597,6 +609,10 @@ class TrackSelectorPidBase prob = track.bayesPr(); } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { prob = track.bayesDe(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kTriton) { + prob = track.bayesTr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kHelium3) { + prob = track.bayesHe(); } else { errorPdg(); } @@ -637,6 +653,14 @@ class TrackSelectorPidBase } private: + // ITS + float mPtItsMin = 0.; ///< minimum pT for TPC PID [GeV/c] + float mPtItsMax = 100.; ///< maximum pT for TPC PID [GeV/c] + float mNSigmaItsMin = -3.; ///< minimum number of TPC σ + float mNSigmaItsMax = 3.; ///< maximum number of TPC σ + float mNSigmaItsMinCondTpc = 0.; ///< minimum number of TPC σ if combined with TOF + float mNSigmaItsMaxCondTpc = 0.; ///< maximum number of TPC σ if combined with TOF + // TPC float mPtTpcMin = 0.; ///< minimum pT for TPC PID [GeV/c] float mPtTpcMax = 100.; ///< maximum pT for TPC PID [GeV/c] @@ -680,5 +704,7 @@ using TrackSelectorPi = TrackSelectorPidBase; using TrackSelectorKa = TrackSelectorPidBase; // Ka using TrackSelectorPr = TrackSelectorPidBase; // Pr using TrackSelectorDe = TrackSelectorPidBase; // De +using TrackSelectorTr = TrackSelectorPidBase; // Tr +using TrackSelectorHe = TrackSelectorPidBase; // He #endif // COMMON_CORE_TRACKSELECTORPID_H_ diff --git a/PWGHF/Core/SelectorCuts.h b/PWGHF/Core/SelectorCuts.h index 2a0917cdf97..48caed87dec 100644 --- a/PWGHF/Core/SelectorCuts.h +++ b/PWGHF/Core/SelectorCuts.h @@ -68,15 +68,29 @@ static const std::vector labelsCutVarTrack = {"min_dcaxytoprimary", namespace hf_presel_pid { // default values for the PID cuts for protons in the track-index-skim-creator -constexpr float CutsPid[5][6] = {{0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, +constexpr float CutsPid[7][6] = {{0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, + {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, + {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, {0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}}; static const std::vector labelsCutsPid = {"minPtTpc", "maxPtTpc", "nSigmaMaxTpc", "minPtTof", "maxPtTof", "nSigmaMaxTof"}; -static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs", "DeuteronInCdToDeKPi"}; +static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs", "DeuteronInCdToDeKPi", "TritonInCtToTrKPi", "HeliumInChToHeKPi"}; } // namespace hf_presel_pid +namespace hf_presel_charmnuclei +{ + +// default values for the track cuts for lightnuclei in the track-index-skim-creator +constexpr float CutsTrackQuality[3][9] = {{-4, 3, 5., 0., 100, 100, 0.83, 160., 1.}, + {-4, 3, 5., 0., 100, 100, 0.83, 160., 1.}, + {-4, 3, 5., 0., 100, 100, 0.83, 160., 1.}}; +static const std::vector labelsCutsTrack = {"nSigmaMinIts", "minItsClusterSizes", "minItsCluster", "minItsIbCluster", "minTpcCluster", "minTpcRow", "minTpcCrossedOverFound", "maxTpcShared", "maxTpcFracShared"}; +static const std::vector labelsRowsNucleiType = {"Deutron", "Triton", "Helium3"}; + +} // namespace hf_presel_charmnuclei + namespace hf_cuts_bdt_multiclass { static constexpr int NBinsPt = 1; diff --git a/PWGHF/DataModel/AliasTables.h b/PWGHF/DataModel/AliasTables.h index 37e396770db..98594b546db 100644 --- a/PWGHF/DataModel/AliasTables.h +++ b/PWGHF/DataModel/AliasTables.h @@ -45,6 +45,8 @@ using TracksPidPi = soa::Join; using TracksPidKa = soa::Join; using TracksPidPr = soa::Join; using TracksPidDe = soa::Join; +using TracksPidTr = soa::Join; +using TracksPidHe = soa::Join; using TracksPidTinyEl = soa::Join; using TracksPidTinyMu = soa::Join; @@ -52,6 +54,8 @@ using TracksPidTinyPi = soa::Join; using TracksPidTinyKa = soa::Join; using TracksPidTinyPr = soa::Join; using TracksPidTinyDe = soa::Join; +using TracksPidTinyTr = soa::Join; +using TracksPidTinyHe = soa::Join; } // namespace o2::aod #endif // PWGHF_DATAMODEL_ALIASTABLES_H_ diff --git a/PWGHF/DataModel/CandidateReconstructionTables.h b/PWGHF/DataModel/CandidateReconstructionTables.h index 5bc4cc45c1c..3af629eb0e4 100644 --- a/PWGHF/DataModel/CandidateReconstructionTables.h +++ b/PWGHF/DataModel/CandidateReconstructionTables.h @@ -44,6 +44,8 @@ DECLARE_SOA_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, float); //! Combined NSigma s DECLARE_SOA_COLUMN(TpcTofNSigmaKa, tpcTofNSigmaKa, float); //! Combined NSigma separation with the TPC & TOF detectors for kaon DECLARE_SOA_COLUMN(TpcTofNSigmaPr, tpcTofNSigmaPr, float); //! Combined NSigma separation with the TPC & TOF detectors for proton DECLARE_SOA_COLUMN(TpcTofNSigmaDe, tpcTofNSigmaDe, float); //! Combined NSigma separation with the TPC & TOF detectors for deuteron +DECLARE_SOA_COLUMN(TpcTofNSigmaTr, tpcTofNSigmaTr, float); //! Combined NSigma separation with the TPC & TOF detectors for triton +DECLARE_SOA_COLUMN(TpcTofNSigmaHe, tpcTofNSigmaHe, float); //! Combined NSigma separation with the TPC & TOF detectors for helium } // namespace pid_tpc_tof_static_full namespace pid_tpc_tof_static_tiny @@ -55,6 +57,8 @@ DECLARE_SOA_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, float); //! Combined NSigma s DECLARE_SOA_COLUMN(TpcTofNSigmaKa, tpcTofNSigmaKa, float); //! Combined NSigma separation with the TPC & TOF detectors for kaon DECLARE_SOA_COLUMN(TpcTofNSigmaPr, tpcTofNSigmaPr, float); //! Combined NSigma separation with the TPC & TOF detectors for proton DECLARE_SOA_COLUMN(TpcTofNSigmaDe, tpcTofNSigmaDe, float); //! Combined NSigma separation with the TPC & TOF detectors for deuteron +DECLARE_SOA_COLUMN(TpcTofNSigmaTr, tpcTofNSigmaTr, float); //! Combined NSigma separation with the TPC & TOF detectors for triton +DECLARE_SOA_COLUMN(TpcTofNSigmaHe, tpcTofNSigmaHe, float); //! Combined NSigma separation with the TPC & TOF detectors for helium } // namespace pid_tpc_tof_static_tiny // Extension of per particle tables @@ -70,7 +74,10 @@ DECLARE_SOA_TABLE(PidTpcTofFullPr, "AOD", "PIDTPCTOFFULLPR", //! Table of the TP pid_tpc_tof_static_full::TpcTofNSigmaPr); DECLARE_SOA_TABLE(PidTpcTofFullDe, "AOD", "PIDTPCTOFFULLDe", //! Table of the TPC & TOF Combined NSigma for deuteron pid_tpc_tof_static_full::TpcTofNSigmaDe); - +DECLARE_SOA_TABLE(PidTpcTofFullTr, "AOD", "PIDTPCTOFFULLTr", //! Table of the TPC & TOF Combined NSigma for triton + pid_tpc_tof_static_full::TpcTofNSigmaTr); +DECLARE_SOA_TABLE(PidTpcTofFullHe, "AOD", "PIDTPCTOFFULLHe", //! Table of the TPC & TOF Combined NSigma for helium + pid_tpc_tof_static_full::TpcTofNSigmaHe); // Extension of per particle tables DECLARE_SOA_TABLE(PidTpcTofTinyEl, "AOD", "PIDTPCTOFTINYEL", //! Table of the TPC & TOF Combined NSigma for electron pid_tpc_tof_static_tiny::TpcTofNSigmaEl); @@ -84,7 +91,10 @@ DECLARE_SOA_TABLE(PidTpcTofTinyPr, "AOD", "PIDTPCTOFTINYPR", //! Table of the TP pid_tpc_tof_static_tiny::TpcTofNSigmaPr); DECLARE_SOA_TABLE(PidTpcTofTinyDe, "AOD", "PIDTPCTOFTINYDE", //! Table of the TPC & TOF Combined NSigma for deuteron pid_tpc_tof_static_tiny::TpcTofNSigmaDe); - +DECLARE_SOA_TABLE(PidTpcTofTinyTr, "AOD", "PIDTPCTOFTINYTr", //! Table of the TPC & TOF Combined NSigma for triton + pid_tpc_tof_static_tiny::TpcTofNSigmaTr); +DECLARE_SOA_TABLE(PidTpcTofTinyHe, "AOD", "PIDTPCTOFTINYHe", //! Table of the TPC & TOF Combined NSigma for helium + pid_tpc_tof_static_tiny::TpcTofNSigmaHe); // general decay properties namespace hf_cand { @@ -181,6 +191,12 @@ DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); //! TPC nSigma for DECLARE_SOA_COLUMN(NSigTpcDe0, nSigTpcDe0, float); //! TPC nSigma for deuteron hypothesis - prong 0 DECLARE_SOA_COLUMN(NSigTpcDe1, nSigTpcDe1, float); //! TPC nSigma for deuteron hypothesis - prong 1 DECLARE_SOA_COLUMN(NSigTpcDe2, nSigTpcDe2, float); //! TPC nSigma for deuteron hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTpcTr0, nSigTpcTr0, float); //! TPC nSigma for triton hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTpcTr1, nSigTpcTr1, float); //! TPC nSigma for triton hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTpcTr2, nSigTpcTr2, float); //! TPC nSigma for triton hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTpcHe0, nSigTpcHe0, float); //! TPC nSigma for helium hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTpcHe1, nSigTpcHe1, float); //! TPC nSigma for helium hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTpcHe2, nSigTpcHe2, float); //! TPC nSigma for helium hypothesis - prong 2 DECLARE_SOA_COLUMN(NSigTofPi0, nSigTofPi0, float); //! TOF nSigma for pion hypothesis - prong 0 DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF nSigma for pion hypothesis - prong 1 DECLARE_SOA_COLUMN(NSigTofPi2, nSigTofPi2, float); //! TOF nSigma for pion hypothesis - prong 2 @@ -193,6 +209,12 @@ DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); //! TOF nSigma for DECLARE_SOA_COLUMN(NSigTofDe0, nSigTofDe0, float); //! TOF nSigma for deuteron hypothesis - prong 0 DECLARE_SOA_COLUMN(NSigTofDe1, nSigTofDe1, float); //! TOF nSigma for deuteron hypothesis - prong 1 DECLARE_SOA_COLUMN(NSigTofDe2, nSigTofDe2, float); //! TOF nSigma for deuteron hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTofTr0, nSigTofTr0, float); //! TOF nSigma for triton hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTofTr1, nSigTofTr1, float); //! TOF nSigma for triton hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTofTr2, nSigTofTr2, float); //! TOF nSigma for triton hypothesis - prong 2 +DECLARE_SOA_COLUMN(NSigTofHe0, nSigTofHe0, float); //! TOF nSigma for helium hypothesis - prong 0 +DECLARE_SOA_COLUMN(NSigTofHe1, nSigTofHe1, float); //! TOF nSigma for helium hypothesis - prong 1 +DECLARE_SOA_COLUMN(NSigTofHe2, nSigTofHe2, float); //! TOF nSigma for helium hypothesis - prong 2 DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPi0, tpcTofNSigmaPi0, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 0 [](float tpcNSigmaPi0, float tofNSigmaPi0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi0, tofNSigmaPi0); }); DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPi1, tpcTofNSigmaPi1, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 1 @@ -217,7 +239,18 @@ DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe1, tpcTofNSigmaDe1, //! Combined NSigma [](float tpcNSigmaDe1, float tofNSigmaDe1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaDe1, tofNSigmaDe1); }); DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe2, tpcTofNSigmaDe2, //! Combined NSigma separation with the TPC & TOF detectors for deuteron - prong 2 [](float tpcNSigmaDe2, float tofNSigmaDe2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaDe2, tofNSigmaDe2); }); - +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTr0, tpcTofNSigmaTr0, //! Combined NSigma separation with the TPC & TOF detectors for triton - prong 0 + [](float tpcNSigmaTr0, float tofNSigmaTr0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaTr0, tofNSigmaTr0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTr1, tpcTofNSigmaTr1, //! Combined NSigma separation with the TPC & TOF detectors for triton - prong 1 + [](float tpcNSigmaTr1, float tofNSigmaTr1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaTr1, tofNSigmaTr1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTr2, tpcTofNSigmaTr2, //! Combined NSigma separation with the TPC & TOF detectors for triton - prong 2 + [](float tpcNSigmaTr2, float tofNSigmaTr2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaTr2, tofNSigmaTr2); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaHe0, tpcTofNSigmaHe0, //! Combined NSigma separation with the TPC & TOF detectors for helium - prong 0 + [](float tpcNSigmaHe0, float tofNSigmaHe0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaHe0, tofNSigmaHe0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaHe1, tpcTofNSigmaHe1, //! Combined NSigma separation with the TPC & TOF detectors for helium - prong 1 + [](float tpcNSigmaHe1, float tofNSigmaHe1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaHe1, tofNSigmaHe1); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaHe2, tpcTofNSigmaHe2, //! Combined NSigma separation with the TPC & TOF detectors for helium - prong 2 + [](float tpcNSigmaHe2, float tofNSigmaHe2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaHe2, tofNSigmaHe2); }); // tiny (binned) option DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaTinyPi0, tpcTofNSigmaTinyPi0, //! Combined NSigma separation with the TPC & TOF detectors for pion - prong 0 [](float tpcNSigmaPi0, float tofNSigmaPi0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi0, tofNSigmaPi0); }); @@ -767,11 +800,31 @@ DECLARE_SOA_TABLE(HfCand3Prong1PidDe, "AOD", "HFCAND3P1PIDDE", //! DECLARE_SOA_TABLE(HfCand3Prong2PidDe, "AOD", "HFCAND3P2PIDDE", //! hf_cand::NSigTpcDe2, hf_cand::NSigTofDe2, hf_cand::TpcTofNSigmaDe2); +DECLARE_SOA_TABLE(HfCand3Prong0PidTr, "AOD", "HFCAND3P0PIDTR", //! + hf_cand::NSigTpcTr0, hf_cand::NSigTofTr0, + hf_cand::TpcTofNSigmaTr0); +DECLARE_SOA_TABLE(HfCand3Prong1PidTr, "AOD", "HFCAND3P1PIDTR", //! + hf_cand::NSigTpcTr1, hf_cand::NSigTofTr1, + hf_cand::TpcTofNSigmaTr1); +DECLARE_SOA_TABLE(HfCand3Prong2PidTr, "AOD", "HFCAND3P2PIDTR", //! + hf_cand::NSigTpcTr2, hf_cand::NSigTofTr2, + hf_cand::TpcTofNSigmaTr2); +DECLARE_SOA_TABLE(HfCand3Prong0PidHe, "AOD", "HFCAND3P0PIDHe", //! + hf_cand::NSigTpcHe0, hf_cand::NSigTofHe0, + hf_cand::TpcTofNSigmaTr0); +DECLARE_SOA_TABLE(HfCand3Prong1PidHe, "AOD", "HFCAND3P1PIDHe", //! + hf_cand::NSigTpcHe1, hf_cand::NSigTofHe1, + hf_cand::TpcTofNSigmaHe1); +DECLARE_SOA_TABLE(HfCand3Prong2PidHe, "AOD", "HFCAND3P2PIDHe", //! + hf_cand::NSigTpcHe2, hf_cand::NSigTofHe2, + hf_cand::TpcTofNSigmaHe2); using HfCand3Prong = HfCand3ProngExt; using HfCand3ProngWPidPiKaPr = soa::Join; using HfCand3ProngWPidPiKa = soa::Join; using HfCand3ProngWPidPiKaDe = soa::Join; +using HfCand3ProngWPidPiKaTr = soa::Join; +using HfCand3ProngWPidPiKaHe = soa::Join; DECLARE_SOA_TABLE(HfCand3ProngKF, "AOD", "HFCAND3PKF", hf_cand_3prong::KfXError, hf_cand_3prong::KfYError, hf_cand_3prong::KfZError, diff --git a/PWGHF/DataModel/CandidateSelectionTables.h b/PWGHF/DataModel/CandidateSelectionTables.h index 839c289d6f5..a359794da92 100644 --- a/PWGHF/DataModel/CandidateSelectionTables.h +++ b/PWGHF/DataModel/CandidateSelectionTables.h @@ -172,6 +172,22 @@ DECLARE_SOA_COLUMN(IsSelCdToPiKDe, isSelCdToPiKDe, int); //! DECLARE_SOA_TABLE(HfSelCd, "AOD", "HFSELCD", //! hf_sel_candidate_cd::IsSelCdToDeKPi, hf_sel_candidate_cd::IsSelCdToPiKDe); +namespace hf_sel_candidate_ct +{ +DECLARE_SOA_COLUMN(IsSelCtToTrKPi, isSelCtToTrKPi, int); //! +DECLARE_SOA_COLUMN(IsSelCtToPiKTr, isSelCtToPiKTr, int); //! +} // namespace hf_sel_candidate_ct +DECLARE_SOA_TABLE(HfSelCt, "AOD", "HFSELCT", //! + hf_sel_candidate_ct::IsSelCtToTrKPi, hf_sel_candidate_ct::IsSelCtToPiKTr); + +namespace hf_sel_candidate_ch +{ +DECLARE_SOA_COLUMN(IsSelChToHeKPi, isSelChToHeKPi, int); //! +DECLARE_SOA_COLUMN(IsSelChToPiKHe, isSelChToPiKHe, int); //! +} // namespace hf_sel_candidate_ch +DECLARE_SOA_TABLE(HfSelCh, "AOD", "HFSELCH", //! + hf_sel_candidate_ch::IsSelChToHeKPi, hf_sel_candidate_ch::IsSelChToPiKHe); + namespace hf_sel_candidate_lc_alice3 { DECLARE_SOA_COLUMN(IsSelLcToPKPiNoPid, isSelLcToPKPiNoPid, int); //! diff --git a/PWGHF/DataModel/TrackIndexSkimmingTables.h b/PWGHF/DataModel/TrackIndexSkimmingTables.h index 6408c636f8e..90183815170 100644 --- a/PWGHF/DataModel/TrackIndexSkimmingTables.h +++ b/PWGHF/DataModel/TrackIndexSkimmingTables.h @@ -299,6 +299,8 @@ enum DecayType { DsToKKPi, XicToPKPi, CdToDeKPi, + CtToTrKPi, + ChToHeKPi, N3ProngDecays }; } // namespace hf_cand_3prong diff --git a/PWGHF/TableProducer/pidCreator.cxx b/PWGHF/TableProducer/pidCreator.cxx index a563e8f5d43..1b5d7ca73f9 100644 --- a/PWGHF/TableProducer/pidCreator.cxx +++ b/PWGHF/TableProducer/pidCreator.cxx @@ -47,6 +47,10 @@ struct HfPidCreator { Produces trackPidTinyPr; Produces trackPidFullDe; Produces trackPidTinyDe; + Produces trackPidFullTr; + Produces trackPidTinyTr; + Produces trackPidFullHe; + Produces trackPidTinyHe; /// Function to check whether the process function flag matches the need for filling the table /// \param initContext workflow context (argument of the init function) @@ -81,6 +85,10 @@ struct HfPidCreator { checkTableSwitch(initContext, "PidTpcTofTinyPr", doprocessTinyPr); checkTableSwitch(initContext, "PidTpcTofFullDe", doprocessFullDe); checkTableSwitch(initContext, "PidTpcTofTinyDe", doprocessTinyDe); + checkTableSwitch(initContext, "PidTpcTofFullTr", doprocessFullTr); + checkTableSwitch(initContext, "PidTpcTofTinyTr", doprocessTinyTr); + checkTableSwitch(initContext, "PidTpcTofFullHe", doprocessFullHe); + checkTableSwitch(initContext, "PidTpcTofTinyHe", doprocessTinyHe); } void processDummy(aod::Collisions const&) {} @@ -111,6 +119,8 @@ struct HfPidCreator { PROCESS_PID(Ka) PROCESS_PID(Pr) PROCESS_PID(De) + PROCESS_PID(Tr) + PROCESS_PID(He) #undef PROCESS_PID }; diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 83e558c0dca..0cd95e6d95d 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -20,6 +20,7 @@ /// \author Fabrizio Grosa , CERN /// \author Federica Zanone , Heidelberg University /// \author Ruiqi Yin , Fudan University +/// \author Biao Zhang , Heidelberg University #include "PWGHF/Core/CentralityEstimation.h" #include "PWGHF/Core/SelectorCuts.h" @@ -37,6 +38,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -122,7 +124,14 @@ enum ChannelsProtonPid { // kaon PID (opposite-sign track in 3-prong decays) constexpr int ChannelKaonPid = ChannelsProtonPid::NChannelsProtonPid; constexpr int ChannelsDeuteronPid = ChannelsProtonPid::NChannelsProtonPid + 1; +constexpr int ChannelsTritonPid = ChannelsProtonPid::NChannelsProtonPid + 2; +constexpr int ChannelsHeliumPid = ChannelsProtonPid::NChannelsProtonPid + 3; +enum class ChannelsNucleiQA : int { + Deuteron = 0, + Triton = 1, + Helium3 = 2 +}; /// Event selection struct HfTrackIndexSkimCreatorTagSelCollisions { Produces rowSelectedCollision; @@ -309,7 +318,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { Configurable useIsGlobalTrackWoDCAForSoftPion{"useIsGlobalTrackWoDCAForSoftPion", false, "check isGlobalTrackWoDCA status for soft pion tracks"}; Configurable useIsQualityTrackITSForSoftPion{"useIsQualityTrackITSForSoftPion", true, "check qualityTracksITS status for soft pion tracks"}; // proton PID, applied only if corresponding process function enabled - Configurable> selectionsPid{"selectionsPid", {hf_presel_pid::CutsPid[0], 5, 6, hf_presel_pid::labelsRowsPid, hf_presel_pid::labelsCutsPid}, "PID selections for proton / kaon / deuteron applied if proper process function enabled"}; + Configurable> selectionsPid{"selectionsPid", {hf_presel_pid::CutsPid[0], 7, 6, hf_presel_pid::labelsRowsPid, hf_presel_pid::labelsCutsPid}, "PID selections for proton / kaon / deuteron / triton /helium applied if proper process function enabled"}; // CCDB Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; @@ -326,9 +335,9 @@ struct HfTrackIndexSkimCreatorTagSelTracks { int runNumber{}; using TracksWithSelAndDca = soa::Join; - using TracksWithSelAndDcaAndPidTpc = soa::Join; - using TracksWithSelAndDcaAndPidTof = soa::Join; - using TracksWithSelAndDcaAndPidTpcTof = soa::Join; + using TracksWithSelAndDcaAndPidTpc = soa::Join; + using TracksWithSelAndDcaAndPidTof = soa::Join; + using TracksWithSelAndDcaAndPidTpcTof = soa::Join; Preslice perCol = aod::track::collisionId; Preslice trackIndicesPerCollision = aod::track_association::collisionId; @@ -341,6 +350,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { std::array selectorProton{}; TrackSelectorKa selectorKaon; TrackSelectorDe selectorDeuteron; + TrackSelectorTr selectorTriton; + TrackSelectorHe selectorHelium; Partition pvContributors = ((aod::track::flags & static_cast(aod::track::PVContributor)) == static_cast(aod::track::PVContributor)); Partition pvContributorsWithPidTpc = ((aod::track::flags & static_cast(aod::track::PVContributor)) == static_cast(aod::track::PVContributor)); @@ -468,6 +479,16 @@ struct HfTrackIndexSkimCreatorTagSelTracks { selectorDeuteron.setRangePtTof(config.selectionsPid->get(ChannelsDeuteronPid, 3u), config.selectionsPid->get(ChannelsDeuteronPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" selectorDeuteron.setRangeNSigmaTpc(-config.selectionsPid->get(ChannelsDeuteronPid, 2u), config.selectionsPid->get(ChannelsDeuteronPid, 2u)); // 2u == "nSigmaMaxTpc" selectorDeuteron.setRangeNSigmaTof(-config.selectionsPid->get(ChannelsDeuteronPid, 5u), config.selectionsPid->get(ChannelsDeuteronPid, 5u)); // 5u == "nSigmaMaxTof" + + selectorTriton.setRangePtTpc(config.selectionsPid->get(ChannelsTritonPid, 0u), config.selectionsPid->get(ChannelsTritonPid, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" + selectorTriton.setRangePtTof(config.selectionsPid->get(ChannelsTritonPid, 3u), config.selectionsPid->get(ChannelsTritonPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" + selectorTriton.setRangeNSigmaTpc(-config.selectionsPid->get(ChannelsTritonPid, 2u), config.selectionsPid->get(ChannelsTritonPid, 2u)); // 2u == "nSigmaMaxTpc" + selectorTriton.setRangeNSigmaTof(-config.selectionsPid->get(ChannelsTritonPid, 5u), config.selectionsPid->get(ChannelsTritonPid, 5u)); // 5u == "nSigmaMaxTof" + + selectorHelium.setRangePtTpc(config.selectionsPid->get(ChannelsHeliumPid, 0u), config.selectionsPid->get(ChannelsHeliumPid, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" + selectorHelium.setRangePtTof(config.selectionsPid->get(ChannelsHeliumPid, 3u), config.selectionsPid->get(ChannelsHeliumPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" + selectorHelium.setRangeNSigmaTpc(-config.selectionsPid->get(ChannelsHeliumPid, 2u), config.selectionsPid->get(ChannelsHeliumPid, 2u)); // 2u == "nSigmaMaxTpc" + selectorHelium.setRangeNSigmaTof(-config.selectionsPid->get(ChannelsHeliumPid, 5u), config.selectionsPid->get(ChannelsHeliumPid, 5u)); // 5u == "nSigmaMaxTof" } /// PID track cuts (for proton only) @@ -476,7 +497,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { template uint8_t isSelectedPid(const T& hfTrack) { - std::array statusPid{TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted}; + std::array statusPid{TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted}; if constexpr (PidStrategy == ProtonPidStrategy::PidTofOnly) { if (hfTrack.hasTOF()) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { @@ -484,6 +505,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } statusPid[ChannelKaonPid] = selectorKaon.statusTof(hfTrack); statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTof(hfTrack); + statusPid[ChannelsTritonPid] = selectorTriton.statusTof(hfTrack); + statusPid[ChannelsHeliumPid] = selectorHelium.statusTof(hfTrack); } } if constexpr (PidStrategy == ProtonPidStrategy::PidTpcOnly) { @@ -493,6 +516,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } statusPid[ChannelKaonPid] = selectorKaon.statusTpc(hfTrack); statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpc(hfTrack); + statusPid[ChannelsTritonPid] = selectorTriton.statusTpc(hfTrack); + statusPid[ChannelsHeliumPid] = selectorHelium.statusTpc(hfTrack); } } if constexpr (PidStrategy == ProtonPidStrategy::PidTpcOrTof) { @@ -501,6 +526,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } statusPid[ChannelKaonPid] = selectorKaon.statusTpcOrTof(hfTrack); statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpcOrTof(hfTrack); + statusPid[ChannelsTritonPid] = selectorTriton.statusTpcOrTof(hfTrack); + statusPid[ChannelsHeliumPid] = selectorHelium.statusTpcOrTof(hfTrack); } if constexpr (PidStrategy == ProtonPidStrategy::PidTpcAndTof) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { @@ -508,10 +535,12 @@ struct HfTrackIndexSkimCreatorTagSelTracks { } statusPid[ChannelKaonPid] = selectorKaon.statusTpcAndTof(hfTrack); statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpcAndTof(hfTrack); + statusPid[ChannelsTritonPid] = selectorTriton.statusTpcAndTof(hfTrack); + statusPid[ChannelsHeliumPid] = selectorHelium.statusTpcAndTof(hfTrack); } - int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 2) - 1; // all bits on (including the kaon one) - for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 2; ++iChannel) { + int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 4) - 1; // all bits on (including the kaon one) + for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 4; ++iChannel) { if (statusPid[iChannel] == TrackSelectorPID::Rejected) { CLRBIT(flag, iChannel); } @@ -1247,16 +1276,28 @@ struct HfTrackIndexSkimCreator { // Cd cuts Configurable> binsPtCdToDeKPi{"binsPtCdToDeKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Cd->DeKpi pT-dependent cuts"}; Configurable> cutsCdToDeKPi{"cutsCdToDeKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Cd->deKpi selections per pT bin"}; - + // Ct cuts + Configurable> binsPtCtToTrKPi{"binsPtCtToTrKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Ct->tKpi pT-dependent cuts"}; + Configurable> cutsCtToTrKPi{"cutsCdToTrKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Ct->tKpi selections per pT bin"}; + // Ch cuts + Configurable> binsPtChToHeKPi{"binsPtChToHeKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Ch->heKpi pT-dependent cuts"}; + Configurable> cutsChToHeKPi{"cutsChToHeKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "Ch->heKpi selections per pT bin"}; // D*+ cuts Configurable> binsPtDstarToD0Pi{"binsPtDstarToD0Pi", std::vector{hf_cuts_presel_dstar::vecBinsPt}, "pT bin limits for D*+->D0pi pT-dependent cuts"}; Configurable> cutsDstarToD0Pi{"cutsDstarToD0Pi", {hf_cuts_presel_dstar::Cuts[0], hf_cuts_presel_dstar::NBinsPt, hf_cuts_presel_dstar::NCutVars, hf_cuts_presel_dstar::labelsPt, hf_cuts_presel_dstar::labelsCutVar}, "D*+->D0pi selections per pT bin"}; + // CharmNuclei track selection + Configurable> selectionsLightNuclei{"selectionsLightNuclei", {hf_presel_charmnuclei::CutsTrackQuality[0], 3, 9, hf_presel_charmnuclei::labelsRowsNucleiType, hf_presel_charmnuclei::labelsCutsTrack}, "nuclei track selections for deuteron / triton / helium applied if proper process function enabled"}; + // proton PID selections for Lc and Xic Configurable applyProtonPidForLcToPKPi{"applyProtonPidForLcToPKPi", false, "Apply proton PID for Lc->pKpi"}; Configurable applyProtonPidForXicToPKPi{"applyProtonPidForXicToPKPi", false, "Apply proton PID for Xic->pKpi"}; Configurable applyKaonPidIn3Prongs{"applyKaonPidIn3Prongs", false, "Apply kaon PID for opposite-sign track in 3-prong and D* decays"}; Configurable applyDeuteronPidForCdToDeKPi{"applyDeuteronPidForCdToDeKPi", false, "Require deuteron PID for Cd->deKpi"}; + Configurable applyTritonPidForCtToTrKPi{"applyTritonPidForCtToTrKPi", false, "Require triton PID for Ct->tKpi"}; + Configurable applyHeliumPidForChToHeKPi{"applyHeliumPidForChToHeKPi", false, "Require helium3 PID for Ch->heKpi"}; + // lightnuclei track selection for charmnuclei + Configurable applyNucleiSelcForCharmNuclei{"applyNucleiSelcForCharmNuclei", false, "Require track selection for charm nuclei"}; // ML models for triggers Configurable applyMlForHfFilters{"applyMlForHfFilters", false, "Flag to enable ML application for HF Filters"}; Configurable mlModelPathCCDB{"mlModelPathCCDB", "EventFiltering/PWGHF/BDTSmeared", "Path on CCDB of ML models for HF Filters"}; @@ -1283,11 +1324,11 @@ struct HfTrackIndexSkimCreator { // int nColls{0}; //can be added to run over limited collisions per file - for tesing purposes - static constexpr int kN2ProngDecays = hf_cand_2prong::DecayType::N2ProngDecays; // number of 2-prong hadron types - static constexpr int kN3ProngDecays = hf_cand_3prong::DecayType::N3ProngDecays; // number of 3-prong hadron types - static constexpr int kNCuts2Prong[kN2ProngDecays] = {hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars}; // how many different selections are made on 2-prongs - static constexpr int kNCuts3Prong[kN3ProngDecays] = {hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_ds::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_3prong::NCutVars + 1}; // how many different selections are made on 3-prongs (Lc and Xic have also PID potentially) - static constexpr int kNCutsDstar = 3; // how many different selections are made on Dstars + static constexpr int kN2ProngDecays = hf_cand_2prong::DecayType::N2ProngDecays; // number of 2-prong hadron types + static constexpr int kN3ProngDecays = hf_cand_3prong::DecayType::N3ProngDecays; // number of 3-prong hadron types + static constexpr int kNCuts2Prong[kN2ProngDecays] = {hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars}; // how many different selections are made on 2-prongs + static constexpr int kNCuts3Prong[kN3ProngDecays] = {hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_ds::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_3prong::NCutVars + 2, hf_cuts_presel_3prong::NCutVars + 2, hf_cuts_presel_3prong::NCutVars + 2}; // how many different selections are made on 3-prongs (Lc, Xic and CharmNuclei have also PID potentially, charmnuclei has also daughter track quality cut potentially) + static constexpr int kNCutsDstar = 3; // how many different selections are made on Dstars std::array, 2>, kN2ProngDecays> arrMass2Prong{}; std::array, 2>, kN3ProngDecays> arrMass3Prong{}; // arrays of 2-prong and 3-prong cuts @@ -1303,7 +1344,7 @@ struct HfTrackIndexSkimCreator { o2::ccdb::CcdbApi ccdbApi; using SelectedCollisions = soa::Filtered>; - using TracksWithPVRefitAndDCA = soa::Join; + using TracksWithPVRefitAndDCA = soa::Join; using FilteredTrackAssocSel = soa::Filtered>; // filter collisions @@ -1358,12 +1399,18 @@ struct HfTrackIndexSkimCreator { arrMass3Prong[hf_cand_3prong::DecayType::CdToDeKPi] = std::array{std::array{MassDeuteron, MassKPlus, MassPiPlus}, std::array{MassPiPlus, MassKPlus, MassDeuteron}}; + arrMass3Prong[hf_cand_3prong::DecayType::CtToTrKPi] = std::array{std::array{MassTriton, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassTriton}}; + + arrMass3Prong[hf_cand_3prong::DecayType::ChToHeKPi] = std::array{std::array{MassHelium3, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassHelium3}}; + // cuts for 2-prong decays retrieved by json. the order must be then one in hf_cand_2prong::DecayType cut2Prong = {config.cutsD0ToPiK, config.cutsJpsiToEE, config.cutsJpsiToMuMu}; binsPt2Prong = {config.binsPtD0ToPiK, config.binsPtJpsiToEE, config.binsPtJpsiToMuMu}; // cuts for 3-prong decays retrieved by json. the order must be then one in hf_cand_3prong::DecayType - cut3Prong = {config.cutsDplusToPiKPi, config.cutsLcToPKPi, config.cutsDsToKKPi, config.cutsXicToPKPi, config.cutsCdToDeKPi}; - binsPt3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi, config.binsPtCdToDeKPi}; + cut3Prong = {config.cutsDplusToPiKPi, config.cutsLcToPKPi, config.cutsDsToKKPi, config.cutsXicToPKPi, config.cutsCdToDeKPi, config.cutsCtToTrKPi, config.cutsChToHeKPi}; + binsPt3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi, config.binsPtCdToDeKPi, config.binsPtCtToTrKPi, config.binsPtChToHeKPi}; df2.setPropagateToPCA(config.propagateToPCA); df2.setMaxR(config.maxR); @@ -1412,6 +1459,8 @@ struct HfTrackIndexSkimCreator { registry.add("hMassXicToPKPi", "#Xi_{c}^{#plus} candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); registry.add("hMassDstarToD0Pi", "D^{*#plus} candidates;inv. mass (K #pi #pi) - mass (K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0.135, 0.185}}}); registry.add("hMassCdToDeKPi", "C Deuteron candidates;inv. mass (De K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassCtToTrKPi", "C Triton candidates;inv. mass (Tr K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassChToHeKPi", "C Helium3 candidates;inv. mass (He3 K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); // needed for PV refitting if (doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) { @@ -1465,13 +1514,13 @@ struct HfTrackIndexSkimCreator { if (config.applyMlForHfFilters) { const std::vector onnxFileNames2Prongs{config.onnxFileNames->get(0u, 0u)}; - // Exclude Cd from the 3-prong list, as it is not included in the pp trigger program - const std::array, kN3ProngDecays - 1> onnxFileNames3Prongs{std::vector{config.onnxFileNames->get(1u, 0u)}, std::vector{config.onnxFileNames->get(2u, 0u)}, std::vector{config.onnxFileNames->get(3u, 0u)}, std::vector{config.onnxFileNames->get(4u, 0u)}}; + // Exclude Cd, Ct, Ch from the 3-prong list, as it is not included in the pp trigger program + const std::array, kN3ProngDecays - 3> onnxFileNames3Prongs{std::vector{config.onnxFileNames->get(1u, 0u)}, std::vector{config.onnxFileNames->get(2u, 0u)}, std::vector{config.onnxFileNames->get(3u, 0u)}, std::vector{config.onnxFileNames->get(4u, 0u)}}; const std::vector mlModelPathCcdb2Prongs{config.mlModelPathCCDB.value + "D0"}; - const std::array, kN3ProngDecays - 1> mlModelPathCcdb3Prongs{std::vector{config.mlModelPathCCDB.value + "Dplus"}, std::vector{config.mlModelPathCCDB.value + "Lc"}, std::vector{config.mlModelPathCCDB.value + "Ds"}, std::vector{config.mlModelPathCCDB.value + "Xic"}}; + const std::array, kN3ProngDecays - 3> mlModelPathCcdb3Prongs{std::vector{config.mlModelPathCCDB.value + "Dplus"}, std::vector{config.mlModelPathCCDB.value + "Lc"}, std::vector{config.mlModelPathCCDB.value + "Ds"}, std::vector{config.mlModelPathCCDB.value + "Xic"}}; const std::vector ptBinsMl{0., 1.e10}; const std::vector cutDirMl{o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller}; - const std::array, kN3ProngDecays - 1> thresholdMlScore3Prongs{config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; + const std::array, kN3ProngDecays - 3> thresholdMlScore3Prongs{config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; // initialise 2-prong ML response hfMlResponse2Prongs.configure(ptBinsMl, config.thresholdMlScoreD0ToKPi, cutDirMl, 3); @@ -1484,7 +1533,7 @@ struct HfTrackIndexSkimCreator { hfMlResponse2Prongs.init(); // initialise 3-prong ML responses - for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 1; ++iDecay3P) { + for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 3; ++iDecay3P) { if (onnxFileNames3Prongs[iDecay3P][0].empty()) { // 3-prong species to be skipped continue; } @@ -1588,6 +1637,60 @@ struct HfTrackIndexSkimCreator { } } + /// Apply track-quality (ITS/TPC) + optional ITS-PID preselection for light-nucleus daughters used in charm-nuclei 3-prong channels (Cd/Ct/Ch). + /// \tparam TrackType Track/ASoA row type 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. + /// \param nSigmaItsPid ITS nσ value for the selected light nucleus hypothesis + template + bool applyTrackSelectionForCharmNuclei(const TrackType& track, + ChannelsNucleiQA lightnuclei, + float nSigmaItsPid) + { + // Row index in the selection table: 0 (De), 1 (Tr), 2 (He3) + const int row = static_cast(lightnuclei); + const float nSigmaItsNuclei = nSigmaItsPid; + // Load cuts for the selected species. + const float minItsNSigmaPid = config.selectionsLightNuclei->get(row, 0u); + const int minItsClusterSizes = config.selectionsLightNuclei->get(row, 1u); + const int minItsCluster = config.selectionsLightNuclei->get(row, 2u); + const int minItsIbCluster = config.selectionsLightNuclei->get(row, 3u); + const int minTpcCluster = config.selectionsLightNuclei->get(row, 4u); + const int minTpcRow = config.selectionsLightNuclei->get(row, 5u); + const float minTpcCrossedOverFound = config.selectionsLightNuclei->get(row, 6u); + const int maxTpcShared = config.selectionsLightNuclei->get(row, 7u); + const float maxTpcFracShared = config.selectionsLightNuclei->get(row, 8u); + + if (nSigmaItsNuclei < minItsNSigmaPid) { + return false; + } + if (track.itsClusterSizes() < static_cast(minItsClusterSizes)) { + return false; + } + if (track.itsNCls() < minItsCluster) { + return false; + } + if (track.itsNClsInnerBarrel() < minItsIbCluster) { + return false; + } + if (track.tpcNClsFound() < minTpcCluster) { + return false; + } + if (track.tpcNClsCrossedRows() < minTpcRow) { + return false; + } + if (track.tpcCrossedRowsOverFindableCls() < minTpcCrossedOverFound) { + return false; + } + if (maxTpcShared >= 0 && track.tpcNClsShared() > maxTpcShared) { + return false; + } + if (track.tpcFractionSharedCls() > maxTpcFracShared) { + return false; + } + return true; + } + /// Method to perform selections on difference from nominal mass for phi decay /// \param binPt pt bin for the cuts /// \param pVecTrack0 is the momentum array of the first daughter track @@ -1629,22 +1732,59 @@ struct HfTrackIndexSkimCreator { /// \param cutStatus is a 2D array with outcome of each selection (filled only in debug mode) /// \param whichHypo information of the mass hypoteses that were selected /// \param isSelected is a bitmap with selection outcome - template - void applyPreselection3Prong(T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, const auto isIdentifiedPidTrack0, const auto isIdentifiedPidTrack2, T2& cutStatus, T3& whichHypo, auto& isSelected) + template + void applyPreselection3Prong(T1 const& track0, T1 const& track2, T2 const& pVecTrack0, T2 const& pVecTrack1, T2 const& pVecTrack2, const auto isIdentifiedPidTrack0, const auto isIdentifiedPidTrack2, T3& cutStatus, T4& whichHypo, auto& isSelected) { const auto pt = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { - // check proton PID for Lc and Xic whichHypo[iDecay3P] = 3; // 2 bits on - if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && config.applyProtonPidForLcToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && config.applyProtonPidForXicToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && config.applyDeuteronPidForCdToDeKPi)) { + if (config.applyNucleiSelcForCharmNuclei && + (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi || + iDecay3P == hf_cand_3prong::DecayType::CtToTrKPi || + iDecay3P == hf_cand_3prong::DecayType::ChToHeKPi)) { + + ChannelsNucleiQA nucleiType = ChannelsNucleiQA::Deuteron; + float nSigmaItsNuclei0 = track0.itsNSigmaDe(); + float nSigmaItsNuclei2 = track2.itsNSigmaDe(); + + if (iDecay3P == hf_cand_3prong::DecayType::CtToTrKPi) { + nucleiType = ChannelsNucleiQA::Triton; + nSigmaItsNuclei0 = track0.itsNSigmaTr(); + nSigmaItsNuclei2 = track2.itsNSigmaTr(); + } else if (iDecay3P == hf_cand_3prong::DecayType::ChToHeKPi) { + nucleiType = ChannelsNucleiQA::Helium3; + nSigmaItsNuclei0 = track0.itsNSigmaHe(); + nSigmaItsNuclei2 = track2.itsNSigmaHe(); + } - if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::XicToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsDeuteronPid))) { + // hypo0: nucleus on track0 + if (!applyTrackSelectionForCharmNuclei(track0, nucleiType, nSigmaItsNuclei0)) { CLRBIT(whichHypo[iDecay3P], 0); } - if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::XicToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsDeuteronPid))) { + // hypo1: nucleus on track2 + if (!applyTrackSelectionForCharmNuclei(track2, nucleiType, nSigmaItsNuclei2)) { + CLRBIT(whichHypo[iDecay3P], 1); + } + + if (whichHypo[iDecay3P] == 0) { + CLRBIT(isSelected, iDecay3P); + if (config.debug) { + cutStatus[iDecay3P][hf_cuts_presel_3prong::NCutVars + 1] = false; // nuclei track QA slot + } + continue; + } + } + + // check proton PID for 3prongs + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && config.applyProtonPidForLcToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && config.applyProtonPidForXicToPKPi) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && config.applyDeuteronPidForCdToDeKPi) || (iDecay3P == hf_cand_3prong::DecayType::CtToTrKPi && config.applyTritonPidForCtToTrKPi) || (iDecay3P == hf_cand_3prong::DecayType::ChToHeKPi && config.applyHeliumPidForChToHeKPi)) { + + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::XicToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsDeuteronPid)) || (iDecay3P == hf_cand_3prong::DecayType::CtToTrKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsTritonPid)) || (iDecay3P == hf_cand_3prong::DecayType::ChToHeKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsHeliumPid))) { + CLRBIT(whichHypo[iDecay3P], 0); + } + if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsProtonPid::XicToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::CdToDeKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsDeuteronPid)) || (iDecay3P == hf_cand_3prong::DecayType::CtToTrKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsTritonPid)) || (iDecay3P == hf_cand_3prong::DecayType::ChToHeKPi && !TESTBIT(isIdentifiedPidTrack2, ChannelsHeliumPid))) { CLRBIT(whichHypo[iDecay3P], 1); } if (whichHypo[iDecay3P] == 0) { @@ -1828,14 +1968,14 @@ struct HfTrackIndexSkimCreator { /// \param outputScores is the array of vectors with the output scores to be filled /// \param isSelected ia s bitmap with selection outcome template - void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecays - 1>& outputScores, auto& isSelected) + void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecays - 3>& outputScores, auto& isSelected) { if (isSelected == 0) { return; } const float ptDummy = 1.f; // dummy pT value (only one pT bin) - for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 1; ++iDecay3P) { + for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 3; ++iDecay3P) { if (TESTBIT(isSelected, iDecay3P) && hasMlModel3Prong[iDecay3P]) { bool isMlSel = false; if constexpr (UsePidForHfFiltersBdt) { @@ -2156,12 +2296,14 @@ struct HfTrackIndexSkimCreator { //} const auto thisCollId = collision.globalIndex(); + auto tracksWithItsPid = soa::Attach(tracks); // first loop over positive tracks const auto groupedTrackIndicesPos1 = positiveFor2And3Prongs->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); int lastFilledD0 = -1; // index to be filled in table for D* mesons for (auto trackIndexPos1 = groupedTrackIndicesPos1.begin(); trackIndexPos1 != groupedTrackIndicesPos1.end(); ++trackIndexPos1) { const auto trackPos1 = trackIndexPos1.template track_as(); + const auto trackPosWithItsPid1 = tracksWithItsPid.rawIteratorAt(trackIndexPos1.trackId()); // retrieve the selection flag that corresponds to this collision const auto isSelProngPos1 = trackIndexPos1.isSelProng(); @@ -2180,6 +2322,7 @@ struct HfTrackIndexSkimCreator { const auto groupedTrackIndicesNeg1 = negativeFor2And3Prongs->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); for (auto trackIndexNeg1 = groupedTrackIndicesNeg1.begin(); trackIndexNeg1 != groupedTrackIndicesNeg1.end(); ++trackIndexNeg1) { const auto trackNeg1 = trackIndexNeg1.template track_as(); + const auto trackNegWithItsPid1 = tracksWithItsPid.rawIteratorAt(trackIndexNeg1.trackId()); // retrieve the selection flag that corresponds to this collision const auto isSelProngNeg1 = trackIndexNeg1.isSelProng(); @@ -2419,6 +2562,8 @@ struct HfTrackIndexSkimCreator { } const auto trackPos2 = trackIndexPos2.template track_as(); + const auto trackPosWithItsPid2 = tracksWithItsPid.rawIteratorAt(trackIndexPos2.trackId()); + auto trackParVarPos2 = getTrackParCov(trackPos2); std::array dcaInfoPos2{trackPos2.dcaXY(), trackPos2.dcaZ()}; @@ -2441,7 +2586,7 @@ struct HfTrackIndexSkimCreator { // 3-prong preselections const auto isIdentifiedPidTrackPos1 = trackIndexPos1.isIdentifiedPid(); const auto isIdentifiedPidTrackPos2 = trackIndexPos2.isIdentifiedPid(); - applyPreselection3Prong(pVecTrackPos1, pVecTrackNeg1, pVecTrackPos2, isIdentifiedPidTrackPos1, isIdentifiedPidTrackPos2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); + applyPreselection3Prong(trackPosWithItsPid1, trackPosWithItsPid2, pVecTrackPos1, pVecTrackNeg1, pVecTrackPos2, isIdentifiedPidTrackPos1, isIdentifiedPidTrackPos2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); if (!config.debug && isSelected3ProngCand == 0) { continue; } @@ -2564,7 +2709,7 @@ struct HfTrackIndexSkimCreator { // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Pos, secondaryVertex3, pvRefitCoord3Prong2Pos1Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays - 1> mlScores3Prongs; + std::array, kN3ProngDecays - 3> mlScores3Prongs; if (config.applyMlForHfFilters) { const std::vector inputFeatures{trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos2.getPt(), dcaInfoPos2[0], dcaInfoPos2[1]}; std::vector inputFeaturesLcPid{}; @@ -2632,6 +2777,12 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::CdToDeKPi: registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CtToTrKPi: + registry.fill(HIST("hMassCtToTrKPi"), mass3Prong); + break; + case hf_cand_3prong::DecayType::ChToHeKPi: + registry.fill(HIST("hMassChToHeKPi"), mass3Prong); + break; } } if (TESTBIT(whichHypo3Prong[iDecay3P], 1)) { @@ -2649,6 +2800,12 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::CdToDeKPi: registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CtToTrKPi: + registry.fill(HIST("hMassCtToTrKPi"), mass3Prong); + break; + case hf_cand_3prong::DecayType::ChToHeKPi: + registry.fill(HIST("hMassChToHeKPi"), mass3Prong); + break; } } } @@ -2675,6 +2832,7 @@ struct HfTrackIndexSkimCreator { } auto trackNeg2 = trackIndexNeg2.template track_as(); + const auto trackNegWithItsPid2 = tracksWithItsPid.rawIteratorAt(trackIndexNeg2.trackId()); auto trackParVarNeg2 = getTrackParCov(trackNeg2); std::array dcaInfoNeg2{trackNeg2.dcaXY(), trackNeg2.dcaZ()}; @@ -2697,7 +2855,7 @@ struct HfTrackIndexSkimCreator { // 3-prong preselections int8_t const isIdentifiedPidTrackNeg1 = trackIndexNeg1.isIdentifiedPid(); int8_t const isIdentifiedPidTrackNeg2 = trackIndexNeg2.isIdentifiedPid(); - applyPreselection3Prong(pVecTrackNeg1, pVecTrackPos1, pVecTrackNeg2, isIdentifiedPidTrackNeg1, isIdentifiedPidTrackNeg2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); + applyPreselection3Prong(trackNegWithItsPid1, trackNegWithItsPid2, pVecTrackNeg1, pVecTrackPos1, pVecTrackNeg2, isIdentifiedPidTrackNeg1, isIdentifiedPidTrackNeg2, cutStatus3Prong, whichHypo3Prong, isSelected3ProngCand); if (!config.debug && isSelected3ProngCand == 0) { continue; } @@ -2821,7 +2979,7 @@ struct HfTrackIndexSkimCreator { // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Neg, secondaryVertex3, pvRefitCoord3Prong1Pos2Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays - 1> mlScores3Prongs{}; + std::array, kN3ProngDecays - 3> mlScores3Prongs{}; if (config.applyMlForHfFilters) { const std::vector inputFeatures{trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg2.getPt(), dcaInfoNeg2[0], dcaInfoNeg2[1]}; std::vector inputFeaturesLcPid{}; @@ -2889,6 +3047,12 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::CdToDeKPi: registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CtToTrKPi: + registry.fill(HIST("hMassCtToTrKPi"), mass3Prong); + break; + case hf_cand_3prong::DecayType::ChToHeKPi: + registry.fill(HIST("hMassChToHeKPi"), mass3Prong); + break; } } if (TESTBIT(whichHypo3Prong[iDecay3P], 1)) { @@ -2906,6 +3070,12 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::CdToDeKPi: registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CtToTrKPi: + registry.fill(HIST("hMassCtToTrKPi"), mass3Prong); + break; + case hf_cand_3prong::DecayType::ChToHeKPi: + registry.fill(HIST("hMassChToHeKPi"), mass3Prong); + break; } } } diff --git a/PWGHF/Utils/utilsPid.h b/PWGHF/Utils/utilsPid.h index fc1d0d18940..8be0035453d 100644 --- a/PWGHF/Utils/utilsPid.h +++ b/PWGHF/Utils/utilsPid.h @@ -32,6 +32,8 @@ enum HfProngSpecies : uint8_t { Kaon, Proton, Deuteron, + Triton, + Helium, NHfProngSpecies }; @@ -117,8 +119,24 @@ void fillProngPid(TTrack const& track, TCursor& rowPid) if (track.hasTOF()) { nSigTof = track.tofNSigmaDe(); } + } else if constexpr (SpecPid == HfProngSpecies::Triton) { + // triton PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaTr(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaTr(); + } + } else if constexpr (SpecPid == HfProngSpecies::Helium) { + // triton PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaHe(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaHe(); + } } else { - LOG(fatal) << "Unsupported PID. Supported species in HF framework: HfProngSpecies::Pion, HfProngSpecies::Kaon, HfProngSpecies::Proton, HfProngSpecies::Deuteron"; + LOG(fatal) << "Unsupported PID. Supported species in HF framework: HfProngSpecies::Pion, HfProngSpecies::Kaon, HfProngSpecies::Proton, HfProngSpecies::Deuteron, HfProngSpecies::Triton, HfProngSpecies::Helium"; } // fill candidate prong PID rows From e693b41c9bdd40a8c1a35350a7f44a3d0d0d87f0 Mon Sep 17 00:00:00 2001 From: BiaoZhang Date: Mon, 5 Jan 2026 11:33:33 +0100 Subject: [PATCH 2/6] change the namespace for lightnuclei --- PWGHF/Core/SelectorCuts.h | 4 ++-- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PWGHF/Core/SelectorCuts.h b/PWGHF/Core/SelectorCuts.h index 48caed87dec..ede42118c4b 100644 --- a/PWGHF/Core/SelectorCuts.h +++ b/PWGHF/Core/SelectorCuts.h @@ -79,7 +79,7 @@ static const std::vector labelsCutsPid = {"minPtTpc", "maxPtTpc", " static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs", "DeuteronInCdToDeKPi", "TritonInCtToTrKPi", "HeliumInChToHeKPi"}; } // namespace hf_presel_pid -namespace hf_presel_charmnuclei +namespace hf_presel_lightnuclei { // default values for the track cuts for lightnuclei in the track-index-skim-creator @@ -89,7 +89,7 @@ constexpr float CutsTrackQuality[3][9] = {{-4, 3, 5., 0., 100, 100, 0.83, 160., static const std::vector labelsCutsTrack = {"nSigmaMinIts", "minItsClusterSizes", "minItsCluster", "minItsIbCluster", "minTpcCluster", "minTpcRow", "minTpcCrossedOverFound", "maxTpcShared", "maxTpcFracShared"}; static const std::vector labelsRowsNucleiType = {"Deutron", "Triton", "Helium3"}; -} // namespace hf_presel_charmnuclei +} // namespace hf_presel_lightnuclei namespace hf_cuts_bdt_multiclass { diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 0cd95e6d95d..7e5dda11127 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -1287,7 +1287,7 @@ struct HfTrackIndexSkimCreator { Configurable> cutsDstarToD0Pi{"cutsDstarToD0Pi", {hf_cuts_presel_dstar::Cuts[0], hf_cuts_presel_dstar::NBinsPt, hf_cuts_presel_dstar::NCutVars, hf_cuts_presel_dstar::labelsPt, hf_cuts_presel_dstar::labelsCutVar}, "D*+->D0pi selections per pT bin"}; // CharmNuclei track selection - Configurable> selectionsLightNuclei{"selectionsLightNuclei", {hf_presel_charmnuclei::CutsTrackQuality[0], 3, 9, hf_presel_charmnuclei::labelsRowsNucleiType, hf_presel_charmnuclei::labelsCutsTrack}, "nuclei track selections for deuteron / triton / helium applied if proper process function enabled"}; + Configurable> selectionsLightNuclei{"selectionsLightNuclei", {hf_presel_lightnuclei::CutsTrackQuality[0], 3, 9, hf_presel_lightnuclei::labelsRowsNucleiType, hf_presel_lightnuclei::labelsCutsTrack}, "nuclei track selections for deuteron / triton / helium applied if proper process function enabled"}; // proton PID selections for Lc and Xic Configurable applyProtonPidForLcToPKPi{"applyProtonPidForLcToPKPi", false, "Apply proton PID for Lc->pKpi"}; From ada6fc3519cb50b416e4af3f9d52c5a58ce98b6a Mon Sep 17 00:00:00 2001 From: BiaoZhang Date: Tue, 6 Jan 2026 16:22:50 +0100 Subject: [PATCH 3/6] Add tr and helium3 into the mcPidTof task --- PWGHF/TableProducer/mcPidTof.cxx | 84 +++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/PWGHF/TableProducer/mcPidTof.cxx b/PWGHF/TableProducer/mcPidTof.cxx index d89a7c7144e..6689d061ef5 100644 --- a/PWGHF/TableProducer/mcPidTof.cxx +++ b/PWGHF/TableProducer/mcPidTof.cxx @@ -12,7 +12,7 @@ /// /// \file mcPidTof.cxx /// \author Fabrizio Grosa fabrizio.grosa@cern.ch -/// \brief Task to produce PID tables for TOF split for pi, K, p, de, copied from https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/PID/pidTofMerge.cxx +/// \brief Task to produce PID tables for TOF split for pi, K, p, de, tr, he3 copied from https://github.com/AliceO2Group/O2Physics/blob/master/Common/TableProducer/PID/pidTofMerge.cxx /// It works only for MC and adds the possibility to apply postcalibrations for MC. /// @@ -720,6 +720,8 @@ static constexpr int IdxPi = 2; static constexpr int IdxKa = 3; static constexpr int IdxPr = 4; static constexpr int IdxDe = 5; +static constexpr int IdxTr = 6; +static constexpr int IdxHe = 7; /// Task to produce the response table struct McPidTof { @@ -728,12 +730,16 @@ struct McPidTof { Produces tablePIDKa; Produces tablePIDPr; Produces tablePIDDe; + Produces tablePIDTr; + Produces tablePIDHe; // Tables to produce (full) Produces tablePIDFullPi; Produces tablePIDFullKa; Produces tablePIDFullPr; Produces tablePIDFullDe; + Produces tablePIDFullTr; + Produces tablePIDFullHe; // Detector response parameters o2::pid::tof::TOFResoParamsV3 mRespParamsV3; @@ -768,7 +774,7 @@ struct McPidTof { { mTOFCalibConfig.inheritFromBaseTask(initContext); // Checking the tables are requested in the workflow and enabling them (only pi, K, p) - std::array supportedSpecies = {IdxPi, IdxKa, IdxPr, IdxDe}; + std::array supportedSpecies = {IdxPi, IdxKa, IdxPr, IdxDe, IdxTr, IdxHe}; for (auto iSpecie{0u}; iSpecie < supportedSpecies.size(); ++iSpecie) { // First checking tiny int flag = -1; @@ -855,6 +861,22 @@ struct McPidTof { } break; } + case IdxTr: { + if (fullTable) { + tablePIDFullTr.reserve(size); + } else { + tablePIDTr.reserve(size); + } + break; + } + case IdxHe: { + if (fullTable) { + tablePIDFullHe.reserve(size); + } else { + tablePIDHe.reserve(size); + } + break; + } default: LOG(fatal) << "Wrong particle ID in reserveTable() for " << (fullTable ? "full" : "tiny") << " tables"; break; @@ -893,6 +915,20 @@ struct McPidTof { aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDDe); } break; + case IdxTr: + if (fullTable) { + tablePIDFullTr(-999.f, -999.f); + } else { + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDTr); + } + break; + case IdxHe: + if (fullTable) { + tablePIDFullHe(-999.f, -999.f); + } else { + aod::pidtof_tiny::binning::packInTable(-999.f, tablePIDHe); + } + break; default: LOG(fatal) << "Wrong particle ID in makeTableEmpty() for " << (fullTable ? "full" : "tiny") << " tables"; break; @@ -974,6 +1010,8 @@ struct McPidTof { constexpr auto ResponseKa = ResponseImplementation(); constexpr auto ResponsePr = ResponseImplementation(); constexpr auto ResponseDe = ResponseImplementation(); + constexpr auto ResponseTr = ResponseImplementation(); + constexpr auto ResponseHe = ResponseImplementation(); mTOFCalibConfig.processSetup(mRespParamsV3, ccdb, bcs.iteratorAt(0)); // Update the calibration parameters @@ -1050,6 +1088,26 @@ struct McPidTof { aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDDe); break; } + case IdxTr: { + nSigma = ResponseTr.GetSeparation(mRespParamsV3, trk); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == o2::constants::physics::kTriton) { // we rescale only true signal + nSigma = applyMcRecalib(IdxPr, trk.pt(), nSigma); // FIXME: currently postcalibrations for protons applied to deuterons, to be checked + } + } + aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDTr); + break; + } + case IdxHe: { + nSigma = ResponseHe.GetSeparation(mRespParamsV3, trk); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == o2::constants::physics::kHelium3) { // we rescale only true signal + nSigma = applyMcRecalib(IdxPr, trk.pt(), nSigma); // FIXME: currently postcalibrations for protons applied to deuterons, to be checked + } + } + aod::pidtof_tiny::binning::packInTable(nSigma, tablePIDHe); + break; + } default: LOG(fatal) << "Wrong particle ID for standard tables"; break; @@ -1105,6 +1163,28 @@ struct McPidTof { tablePIDFullDe(resolution, nSigma); break; } + case IdxTr: { + resolution = ResponseTr.GetExpectedSigma(mRespParamsV3, trk); + nSigma = ResponseTr.GetSeparation(mRespParamsV3, trk, resolution); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == o2::constants::physics::kTriton) { // we rescale only true signal + nSigma = applyMcRecalib(IdxPr, trk.pt(), nSigma); // FIXME: currently postcalibrations for protons applied to deuterons, to be checked + } + } + tablePIDFullTr(resolution, nSigma); + break; + } + case IdxHe: { + resolution = ResponseHe.GetExpectedSigma(mRespParamsV3, trk); + nSigma = ResponseHe.GetSeparation(mRespParamsV3, trk, resolution); + if (enableMcRecalib && trk.has_mcParticle()) { + if (std::abs(trk.mcParticle().pdgCode()) == o2::constants::physics::kHelium3) { // we rescale only true signal + nSigma = applyMcRecalib(IdxPr, trk.pt(), nSigma); // FIXME: currently postcalibrations for protons applied to deuterons, to be checked + } + } + tablePIDFullHe(resolution, nSigma); + break; + } default: LOG(fatal) << "Wrong particle ID for full tables"; break; From dc42992def905debae244e0f265be5b8477fa2f2 Mon Sep 17 00:00:00 2001 From: BiaoZhang Date: Thu, 8 Jan 2026 11:55:02 +0100 Subject: [PATCH 4/6] Fixed the comment from vit --- Common/Core/TrackSelectorPID.h | 8 -------- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Common/Core/TrackSelectorPID.h b/Common/Core/TrackSelectorPID.h index cbced7e8f6b..c9daf4057fd 100644 --- a/Common/Core/TrackSelectorPID.h +++ b/Common/Core/TrackSelectorPID.h @@ -653,14 +653,6 @@ class TrackSelectorPidBase } private: - // ITS - float mPtItsMin = 0.; ///< minimum pT for TPC PID [GeV/c] - float mPtItsMax = 100.; ///< maximum pT for TPC PID [GeV/c] - float mNSigmaItsMin = -3.; ///< minimum number of TPC σ - float mNSigmaItsMax = 3.; ///< maximum number of TPC σ - float mNSigmaItsMinCondTpc = 0.; ///< minimum number of TPC σ if combined with TOF - float mNSigmaItsMaxCondTpc = 0.; ///< maximum number of TPC σ if combined with TOF - // TPC float mPtTpcMin = 0.; ///< minimum pT for TPC PID [GeV/c] float mPtTpcMax = 100.; ///< maximum pT for TPC PID [GeV/c] diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 7e5dda11127..16bac54b187 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -1344,7 +1344,7 @@ struct HfTrackIndexSkimCreator { o2::ccdb::CcdbApi ccdbApi; using SelectedCollisions = soa::Filtered>; - using TracksWithPVRefitAndDCA = soa::Join; + using TracksWithPVRefitAndDCA = soa::Join; using FilteredTrackAssocSel = soa::Filtered>; // filter collisions From f84a3135ea7a00dd6f192f59aad7087832aba1c2 Mon Sep 17 00:00:00 2001 From: BiaoZhang Date: Thu, 8 Jan 2026 17:07:35 +0100 Subject: [PATCH 5/6] Fixed the comment from vit --- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 16bac54b187..7bfba1590c1 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -121,11 +121,26 @@ enum ChannelsProtonPid { LcToPK0S, NChannelsProtonPid }; + +enum ChannelsKaonPid { + Charm3ProngToKaon = 0, + NChannelsKaonPid +}; + +enum ChannelsLightNucleiPid { + CdToDeKPi = 0, + CtToTrKPi, + ChToHeKPi, + NChannelsLightNucleiPid +}; + + // kaon PID (opposite-sign track in 3-prong decays) constexpr int ChannelKaonPid = ChannelsProtonPid::NChannelsProtonPid; constexpr int ChannelsDeuteronPid = ChannelsProtonPid::NChannelsProtonPid + 1; constexpr int ChannelsTritonPid = ChannelsProtonPid::NChannelsProtonPid + 2; constexpr int ChannelsHeliumPid = ChannelsProtonPid::NChannelsProtonPid + 3; +constexpr int NChannelsPidFor3Prong = ChannelsProtonPid::NChannelsProtonPid + ChannelsKaonPid::NChannelsKaonPid + ChannelsLightNucleiPid::NChannelsLightNucleiPid; enum class ChannelsNucleiQA : int { Deuteron = 0, @@ -539,8 +554,8 @@ struct HfTrackIndexSkimCreatorTagSelTracks { statusPid[ChannelsHeliumPid] = selectorHelium.statusTpcAndTof(hfTrack); } - int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 4) - 1; // all bits on (including the kaon one) - for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 4; ++iChannel) { + int8_t flag = BIT(NChannelsPidFor3Prong) - 1; // all bits on (including the kaon one) + for (auto iChannel{0u}; iChannel < NChannelsPidFor3Prong; ++iChannel) { if (statusPid[iChannel] == TrackSelectorPID::Rejected) { CLRBIT(flag, iChannel); } From 798fbae9381aad0049137a6e7d740a6948bb523f Mon Sep 17 00:00:00 2001 From: BiaoZhang Date: Thu, 8 Jan 2026 17:36:45 +0100 Subject: [PATCH 6/6] Fixed the comment from vit --- PWGHF/TableProducer/trackIndexSkimCreator.cxx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 7bfba1590c1..24f8025da39 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -134,14 +134,12 @@ enum ChannelsLightNucleiPid { NChannelsLightNucleiPid }; - // kaon PID (opposite-sign track in 3-prong decays) constexpr int ChannelKaonPid = ChannelsProtonPid::NChannelsProtonPid; constexpr int ChannelsDeuteronPid = ChannelsProtonPid::NChannelsProtonPid + 1; constexpr int ChannelsTritonPid = ChannelsProtonPid::NChannelsProtonPid + 2; constexpr int ChannelsHeliumPid = ChannelsProtonPid::NChannelsProtonPid + 3; -constexpr int NChannelsPidFor3Prong = ChannelsProtonPid::NChannelsProtonPid + ChannelsKaonPid::NChannelsKaonPid + ChannelsLightNucleiPid::NChannelsLightNucleiPid; - +constexpr int NChannelsPidFor3Prong = static_cast(ChannelsProtonPid::NChannelsProtonPid) + static_cast(ChannelsKaonPid::NChannelsKaonPid) + static_cast(ChannelsLightNucleiPid::NChannelsLightNucleiPid); enum class ChannelsNucleiQA : int { Deuteron = 0, Triton = 1, @@ -1344,6 +1342,7 @@ struct HfTrackIndexSkimCreator { static constexpr int kNCuts2Prong[kN2ProngDecays] = {hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars, hf_cuts_presel_2prong::NCutVars}; // how many different selections are made on 2-prongs static constexpr int kNCuts3Prong[kN3ProngDecays] = {hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_ds::NCutVars, hf_cuts_presel_3prong::NCutVars + 1, hf_cuts_presel_3prong::NCutVars + 2, hf_cuts_presel_3prong::NCutVars + 2, hf_cuts_presel_3prong::NCutVars + 2}; // how many different selections are made on 3-prongs (Lc, Xic and CharmNuclei have also PID potentially, charmnuclei has also daughter track quality cut potentially) static constexpr int kNCutsDstar = 3; // how many different selections are made on Dstars + static constexpr int kN3ProngDecaysUsedMlForHfFilters = kN3ProngDecays - NChannelsLightNucleiPid; // number of 3-prong HF decays using ML filters std::array, 2>, kN2ProngDecays> arrMass2Prong{}; std::array, 2>, kN3ProngDecays> arrMass3Prong{}; // arrays of 2-prong and 3-prong cuts @@ -1530,12 +1529,12 @@ struct HfTrackIndexSkimCreator { if (config.applyMlForHfFilters) { const std::vector onnxFileNames2Prongs{config.onnxFileNames->get(0u, 0u)}; // Exclude Cd, Ct, Ch from the 3-prong list, as it is not included in the pp trigger program - const std::array, kN3ProngDecays - 3> onnxFileNames3Prongs{std::vector{config.onnxFileNames->get(1u, 0u)}, std::vector{config.onnxFileNames->get(2u, 0u)}, std::vector{config.onnxFileNames->get(3u, 0u)}, std::vector{config.onnxFileNames->get(4u, 0u)}}; + const std::array, kN3ProngDecaysUsedMlForHfFilters> onnxFileNames3Prongs{std::vector{config.onnxFileNames->get(1u, 0u)}, std::vector{config.onnxFileNames->get(2u, 0u)}, std::vector{config.onnxFileNames->get(3u, 0u)}, std::vector{config.onnxFileNames->get(4u, 0u)}}; const std::vector mlModelPathCcdb2Prongs{config.mlModelPathCCDB.value + "D0"}; - const std::array, kN3ProngDecays - 3> mlModelPathCcdb3Prongs{std::vector{config.mlModelPathCCDB.value + "Dplus"}, std::vector{config.mlModelPathCCDB.value + "Lc"}, std::vector{config.mlModelPathCCDB.value + "Ds"}, std::vector{config.mlModelPathCCDB.value + "Xic"}}; + const std::array, kN3ProngDecaysUsedMlForHfFilters> mlModelPathCcdb3Prongs{std::vector{config.mlModelPathCCDB.value + "Dplus"}, std::vector{config.mlModelPathCCDB.value + "Lc"}, std::vector{config.mlModelPathCCDB.value + "Ds"}, std::vector{config.mlModelPathCCDB.value + "Xic"}}; const std::vector ptBinsMl{0., 1.e10}; const std::vector cutDirMl{o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller}; - const std::array, kN3ProngDecays - 3> thresholdMlScore3Prongs{config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; + const std::array, kN3ProngDecaysUsedMlForHfFilters> thresholdMlScore3Prongs{config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; // initialise 2-prong ML response hfMlResponse2Prongs.configure(ptBinsMl, config.thresholdMlScoreD0ToKPi, cutDirMl, 3); @@ -1548,7 +1547,7 @@ struct HfTrackIndexSkimCreator { hfMlResponse2Prongs.init(); // initialise 3-prong ML responses - for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 3; ++iDecay3P) { + for (int iDecay3P{0}; iDecay3P < kN3ProngDecaysUsedMlForHfFilters; ++iDecay3P) { if (onnxFileNames3Prongs[iDecay3P][0].empty()) { // 3-prong species to be skipped continue; } @@ -1983,14 +1982,14 @@ struct HfTrackIndexSkimCreator { /// \param outputScores is the array of vectors with the output scores to be filled /// \param isSelected ia s bitmap with selection outcome template - void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecays - 3>& outputScores, auto& isSelected) + void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecaysUsedMlForHfFilters>& outputScores, auto& isSelected) { if (isSelected == 0) { return; } const float ptDummy = 1.f; // dummy pT value (only one pT bin) - for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 3; ++iDecay3P) { + for (int iDecay3P{0}; iDecay3P < kN3ProngDecaysUsedMlForHfFilters; ++iDecay3P) { if (TESTBIT(isSelected, iDecay3P) && hasMlModel3Prong[iDecay3P]) { bool isMlSel = false; if constexpr (UsePidForHfFiltersBdt) { @@ -2724,7 +2723,7 @@ struct HfTrackIndexSkimCreator { // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Pos, secondaryVertex3, pvRefitCoord3Prong2Pos1Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays - 3> mlScores3Prongs; + std::array, kN3ProngDecaysUsedMlForHfFilters> mlScores3Prongs; if (config.applyMlForHfFilters) { const std::vector inputFeatures{trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos2.getPt(), dcaInfoPos2[0], dcaInfoPos2[1]}; std::vector inputFeaturesLcPid{}; @@ -2994,7 +2993,7 @@ struct HfTrackIndexSkimCreator { // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Neg, secondaryVertex3, pvRefitCoord3Prong1Pos2Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays - 3> mlScores3Prongs{}; + std::array, kN3ProngDecaysUsedMlForHfFilters> mlScores3Prongs{}; if (config.applyMlForHfFilters) { const std::vector inputFeatures{trackParVarPcaNeg1.getPt(), dcaInfoNeg1[0], dcaInfoNeg1[1], trackParVarPcaPos1.getPt(), dcaInfoPos1[0], dcaInfoPos1[1], trackParVarPcaNeg2.getPt(), dcaInfoNeg2[0], dcaInfoNeg2[1]}; std::vector inputFeaturesLcPid{};