diff --git a/Common/Core/TrackSelectorPID.h b/Common/Core/TrackSelectorPID.h index f0a0e0619e2..da5ed2f6732 100644 --- a/Common/Core/TrackSelectorPID.h +++ b/Common/Core/TrackSelectorPID.h @@ -17,6 +17,7 @@ #ifndef COMMON_CORE_TRACKSELECTORPID_H_ #define COMMON_CORE_TRACKSELECTORPID_H_ +#include #include #include @@ -43,6 +44,9 @@ class TrackSelectorPidBase /// Default constructor TrackSelectorPidBase() = default; + static constexpr float NSigmaMinDefault{-999.f}; + static constexpr float NSigmaMaxDefault{999.f}; + /// Conversion operator template operator TrackSelectorPidBase() const @@ -108,10 +112,10 @@ class TrackSelectorPidBase /// \param tpcNSigmaCustom custom TPC nσ value to be used for the selection, in case the desired value cannot be taken from the track table /// \return true if track satisfies TPC PID hypothesis for given TPC nσ range template - bool isSelectedByTpc(const T& track, bool& conditionalTof, float tpcNSigmaCustom = -999.f) + bool isSelectedByTpc(const T& track, bool& conditionalTof, float tpcNSigmaCustom = NSigmaMinDefault) { // Accept if selection is disabled via large values. - if (mNSigmaTpcMin < -999. && mNSigmaTpcMax > 999.) { + if (mNSigmaTpcMin < NSigmaMinDefault && mNSigmaTpcMax > NSigmaMaxDefault) { return true; } @@ -127,16 +131,18 @@ class TrackSelectorPidBase nSigma = track.tpcNSigmaKa(); } else if constexpr (pdg == kProton) { nSigma = track.tpcNSigmaPr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + nSigma = track.tpcNSigmaDe(); } else { errorPdg(); } /// use custom TPC nσ, if a valid value is provided - if (tpcNSigmaCustom > -999.f) { + if (tpcNSigmaCustom > NSigmaMinDefault) { nSigma = tpcNSigmaCustom; } - if (mNSigmaTpcMinCondTof < -999. && mNSigmaTpcMaxCondTof > 999.) { + if (mNSigmaTpcMinCondTof < NSigmaMinDefault && mNSigmaTpcMaxCondTof > NSigmaMaxDefault) { conditionalTof = true; } else { conditionalTof = mNSigmaTpcMinCondTof <= nSigma && nSigma <= mNSigmaTpcMaxCondTof; @@ -148,7 +154,7 @@ class TrackSelectorPidBase /// \param track track /// \return TPC selection status (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTpc(const T& track, float tpcNSigmaCustom = -999.f) + TrackSelectorPID::Status statusTpc(const T& track, float tpcNSigmaCustom = NSigmaMinDefault) { if (!isValidForTpc(track)) { return TrackSelectorPID::NotApplicable; @@ -202,10 +208,10 @@ class TrackSelectorPidBase /// \param tofNSigmaCustom custom TOF nσ value to be used for the selection, in case the desired value cannot be taken from the track table /// \return true if track satisfies TOF PID hypothesis for given TOF nσ range template - bool isSelectedByTof(const T& track, bool& conditionalTpc, float tofNSigmaCustom = -999.f) + bool isSelectedByTof(const T& track, bool& conditionalTpc, float tofNSigmaCustom = NSigmaMinDefault) { // Accept if selection is disabled via large values. - if (mNSigmaTofMin < -999. && mNSigmaTofMax > 999.) { + if (mNSigmaTofMin < NSigmaMinDefault && mNSigmaTofMax > NSigmaMaxDefault) { return true; } @@ -221,16 +227,18 @@ class TrackSelectorPidBase nSigma = track.tofNSigmaKa(); } else if constexpr (pdg == kProton) { nSigma = track.tofNSigmaPr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + nSigma = track.tofNSigmaDe(); } else { errorPdg(); } /// use custom TOF nσ, if a valid value is provided - if (tofNSigmaCustom > -999.f) { + if (tofNSigmaCustom > NSigmaMinDefault) { nSigma = tofNSigmaCustom; } - if (mNSigmaTofMinCondTpc < -999. && mNSigmaTofMaxCondTpc > 999.) { + if (mNSigmaTofMinCondTpc < NSigmaMinDefault && mNSigmaTofMaxCondTpc > NSigmaMaxDefault) { conditionalTpc = true; } else { conditionalTpc = mNSigmaTofMinCondTpc <= nSigma && nSigma <= mNSigmaTofMaxCondTpc; @@ -242,7 +250,7 @@ class TrackSelectorPidBase /// \param track track /// \return TOF selection status (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTof(const T& track, float tofNSigmaCustom = -999.f) + TrackSelectorPID::Status statusTof(const T& track, float tofNSigmaCustom = NSigmaMinDefault) { if (!isValidForTof(track)) { return TrackSelectorPID::NotApplicable; @@ -301,7 +309,7 @@ class TrackSelectorPidBase bool isSelectedByRich(const T& track, bool& conditionalTof) { // Accept if selection is disabled via large values. - if (mNSigmaRichMin < -999. && mNSigmaRichMax > 999.) { + if (mNSigmaRichMin < NSigmaMinDefault && mNSigmaRichMax > NSigmaMaxDefault) { return true; } @@ -321,7 +329,7 @@ class TrackSelectorPidBase errorPdg(); } - if (mNSigmaRichMinCondTof < -999. && mNSigmaRichMaxCondTof > 999.) { + if (mNSigmaRichMinCondTof < NSigmaMinDefault && mNSigmaRichMaxCondTof > NSigmaMaxDefault) { conditionalTof = true; } else { conditionalTof = mNSigmaRichMinCondTof <= nSigma && nSigma <= mNSigmaRichMaxCondTof; @@ -405,7 +413,7 @@ class TrackSelectorPidBase /// \param track track /// \return status of combined PID (TPC or TOF) (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTpcOrTof(const T& track, float tpcNSigmaCustom = -999.f, float tofNSigmaCustom = -999.f) + TrackSelectorPID::Status statusTpcOrTof(const T& track, float tpcNSigmaCustom = NSigmaMinDefault, float tofNSigmaCustom = NSigmaMinDefault) { int pidTpc = statusTpc(track, tpcNSigmaCustom); int pidTof = statusTof(track, tofNSigmaCustom); @@ -426,7 +434,7 @@ class TrackSelectorPidBase /// \param track track /// \return status of combined PID (TPC and TOF) (see TrackSelectorPID::Status) template - TrackSelectorPID::Status statusTpcAndTof(const T& track, float tpcNSigmaCustom = -999.f, float tofNSigmaCustom = -999.f) + TrackSelectorPID::Status statusTpcAndTof(const T& track, float tpcNSigmaCustom = NSigmaMinDefault, float tofNSigmaCustom = NSigmaMinDefault) { int pidTpc = TrackSelectorPID::NotApplicable; if (track.hasTPC()) { @@ -464,23 +472,29 @@ class TrackSelectorPidBase template bool isElectronAndNotPion(const T& track, bool useTof = true, bool useRich = true) { + constexpr float NSigmaInvalid{-1000.f}; + constexpr float PTofRichTElectronMin{0.4f}; + constexpr float PTofRichTElectronMax{0.6f}; + constexpr float PRichPionBandMin{1.0f}; + constexpr float PRichPionBandMax{2.0f}; + bool isSelTof = false; bool isSelRich = false; bool hasRich = track.richId() > -1; bool hasTof = isValidForTof(track); auto nSigmaTofEl = track.tofNSigmaEl(); auto nSigmaTofPi = track.tofNSigmaPi(); - auto nSigmaRichEl = hasRich ? track.rich().richNsigmaEl() : -1000.; - auto nSigmaRichPi = hasRich ? track.rich().richNsigmaPi() : -1000.; + auto nSigmaRichEl = hasRich ? track.rich().richNsigmaEl() : NSigmaInvalid; + auto nSigmaRichPi = hasRich ? track.rich().richNsigmaPi() : NSigmaInvalid; auto p = track.p(); // TOF - if (useTof && hasTof && (p < 0.6)) { - if (p > 0.4 && hasRich) { + if (useTof && hasTof && (p < PTofRichTElectronMax)) { + if (p > PTofRichTElectronMin && hasRich) { if ((std::abs(nSigmaTofEl) < mNSigmaTofMax) && (std::abs(nSigmaRichEl) < mNSigmaRichMax)) { isSelTof = true; // is selected as electron by TOF and RICH } - } else if (p <= 0.4) { + } else if (p <= PTofRichTElectronMin) { if (std::abs(nSigmaTofEl) < mNSigmaTofMax) { isSelTof = true; // is selected as electron by TOF } @@ -499,7 +513,7 @@ class TrackSelectorPidBase if (std::abs(nSigmaRichEl) < mNSigmaRichMax) { isSelRich = true; // is selected as electron by RICH } - if ((std::abs(nSigmaRichPi) < mNSigmaRichMax) && (p > 1.0) && (p < 2.0)) { + if ((std::abs(nSigmaRichPi) < mNSigmaRichMax) && (p > PRichPionBandMin) && (p < PRichPionBandMax)) { isSelRich = false; // is selected as pion by RICH } } else { @@ -551,6 +565,8 @@ class TrackSelectorPidBase return track.bayesID() == o2::track::PID::Kaon; } else if constexpr (pdg == kProton) { return track.bayesID() == o2::track::PID::Proton; + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + return track.bayesID() == o2::track::PID::Deuteron; } else { errorPdg(); return false; @@ -579,6 +595,8 @@ class TrackSelectorPidBase prob = track.bayesKa(); } else if constexpr (pdg == kProton) { prob = track.bayesPr(); + } else if constexpr (pdg == o2::constants::physics::Pdg::kDeuteron) { + prob = track.bayesDe(); } else { errorPdg(); } @@ -656,10 +674,11 @@ class TrackSelectorPidBase }; // Predefined types -using TrackSelectorEl = TrackSelectorPidBase; // El -using TrackSelectorMu = TrackSelectorPidBase; // Mu -using TrackSelectorPi = TrackSelectorPidBase; // Pi -using TrackSelectorKa = TrackSelectorPidBase; // Ka -using TrackSelectorPr = TrackSelectorPidBase; // Pr +using TrackSelectorEl = TrackSelectorPidBase; // El +using TrackSelectorMu = TrackSelectorPidBase; // Mu +using TrackSelectorPi = TrackSelectorPidBase; // Pi +using TrackSelectorKa = TrackSelectorPidBase; // Ka +using TrackSelectorPr = TrackSelectorPidBase; // Pr +using TrackSelectorDe = TrackSelectorPidBase; // De #endif // COMMON_CORE_TRACKSELECTORPID_H_ diff --git a/PWGHF/Core/HfHelper.h b/PWGHF/Core/HfHelper.h index 85190c4e245..9bbae7b2617 100644 --- a/PWGHF/Core/HfHelper.h +++ b/PWGHF/Core/HfHelper.h @@ -410,6 +410,20 @@ class HfHelper return RecoDecay::m(std::array{candidate.pVectorProng2(), candidate.pVectorProng0()}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassPiPlus}); } + // Cd± → De± K∓ π± + + template + auto invMassCdToDeKPi(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassDeuteron, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiPlus}); + } + + template + auto invMassCdToPiKDe(const T& candidate) + { + return candidate.m(std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus, o2::constants::physics::MassDeuteron}); + } + // Ξc± → p± K∓ π± template diff --git a/PWGHF/Core/SelectorCuts.h b/PWGHF/Core/SelectorCuts.h index 2feeb313af6..2a0917cdf97 100644 --- a/PWGHF/Core/SelectorCuts.h +++ b/PWGHF/Core/SelectorCuts.h @@ -68,12 +68,13 @@ 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[4][6] = {{0.f, 1000.f, 5.f, 0.f, 1000.f, 5.f}, +constexpr float CutsPid[5][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}}; static const std::vector labelsCutsPid = {"minPtTpc", "maxPtTpc", "nSigmaMaxTpc", "minPtTof", "maxPtTof", "nSigmaMaxTof"}; -static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs"}; +static const std::vector labelsRowsPid = {"ProtonInLcToPKPi", "ProtonInXicToPKPi", "ProtonInLcToPK0S", "KaonIn3Prongs", "DeuteronInCdToDeKPi"}; } // namespace hf_presel_pid namespace hf_cuts_bdt_multiclass @@ -1516,6 +1517,43 @@ static const std::vector labelsPt = { static const std::vector labelsCutVar = {"max pKpi mass Lc", "max piKp mass Lc"}; } // namespace hf_cuts_sigmac_to_p_k_pi +namespace hf_cuts_cd_to_de_k_pi +{ +static constexpr int NBinsPt = 6; +static constexpr int NCutVars = 10; +// default values for the pT bin edges (can be used to configure histogram axis) +// offset by 1 from the bin numbers in cuts array +constexpr double BinsPt[NBinsPt + 1] = { + 0., + 2., + 4., + 6., + 8., + 12., + 24.}; +const auto vecBinsPt = std::vector{BinsPt, BinsPt + NBinsPt + 1}; + +// default values for the cuts m, ptP, ptK, ptPi, chi2PCA, dL, cosp, dLXY, NdLXY, ImpParXY, mass(Kpi) +constexpr double Cuts[NBinsPt][NCutVars] = {{0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 0 < pT < 2 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 2 < pT < 4 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 4 < pT < 6 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 6 < pT < 8 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}, /* 8 < pT < 12 */ + {0.4, 0.4, 0.4, 0.4, 0., 0.005, 0., 0., 0., 1e+10}}; /* 12 < pT < 24 */ + +// row labels +static const std::vector labelsPt = { + "pT bin 0", + "pT bin 1", + "pT bin 2", + "pT bin 3", + "pT bin 4", + "pT bin 5"}; + +// column labels +static const std::vector labelsCutVar = {"m", "pT De", "pT K", "pT Pi", "Chi2PCA", "decay length", "cos pointing angle", "decLengthXY", "normDecLXY", "impParXY"}; +} // namespace hf_cuts_cd_to_de_k_pi + } // namespace o2::analysis #endif // PWGHF_CORE_SELECTORCUTS_H_ diff --git a/PWGHF/D2H/Tasks/CMakeLists.txt b/PWGHF/D2H/Tasks/CMakeLists.txt index 3fb53720168..83119df1245 100644 --- a/PWGHF/D2H/Tasks/CMakeLists.txt +++ b/PWGHF/D2H/Tasks/CMakeLists.txt @@ -49,6 +49,11 @@ o2physics_add_dpl_workflow(task-bs PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-cd + SOURCES taskCd.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(task-charm-polarisation SOURCES taskCharmPolarisation.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore diff --git a/PWGHF/D2H/Tasks/taskCd.cxx b/PWGHF/D2H/Tasks/taskCd.cxx new file mode 100644 index 00000000000..5bcd8a328a8 --- /dev/null +++ b/PWGHF/D2H/Tasks/taskCd.cxx @@ -0,0 +1,277 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file taskCd.cxx +/// \brief Cd± → d± K∓ π± analysis task +/// \author Biao Zhang , Heidelberg Universiity + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/DecayChannels.h" +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include // std::vector + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::hf_centrality; +using namespace o2::hf_occupancy; +using namespace o2::hf_evsel; + +struct HfTaskCd { + Configurable selectionFlagCd{"selectionFlagCd", 1, "Selection Flag for Cd"}; + Configurable> binsPt{"binsPt", std::vector{hf_cuts_cd_to_de_k_pi::vecBinsPt}, "pT bin limits"}; + Configurable fillTHn{"fillTHn", false, "fill THn"}; + + HfHelper hfHelper; + SliceCache cache; + + using CollisionsWEvSel = soa::Join; + using CollisionsWithEvSelFT0C = soa::Join; + using CollisionsWithEvSelFT0M = soa::Join; + + using CdCandidates = soa::Filtered>; + + Filter filterSelectCandidates = aod::hf_sel_candidate_cd::isSelCdToDeKPi >= selectionFlagCd; + Preslice candCdPerCollision = aod::hf_cand::collisionId; + + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {72, 0, 36}, ""}; + ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {400, 2.4, 4.4}, ""}; + ConfigurableAxis thnConfigAxisPtProng{"thnConfigAxisPtProng", {100, 0, 20}, ""}; + ConfigurableAxis thnConfigAxisChi2PCA{"thnConfigAxisChi2PCA", {100, 0, 20}, ""}; + ConfigurableAxis thnConfigAxisDecLength{"thnConfigAxisDecLength", {10, 0, 0.05}, ""}; + ConfigurableAxis thnConfigAxisCPA{"thnConfigAxisCPA", {20, 0.8, 1}, ""}; + ConfigurableAxis thnConfigAxisCentrality{"thnConfigAxisCentrality", {100, 0, 100}, ""}; + + HistogramRegistry registry{ + "registry", + {/// mass candidate + {"Data/hMass", "3-prong candidates;inv. mass (de K #pi) (GeV/#it{c}^{2})", {HistType::kTH1F, {{400, 2.4, 4.4}}}}, + /// pT + {"Data/hPt", "3-prong candidates;candidate #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + {"Data/hPtProng0", "3-prong candidates;prong 0 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + {"Data/hPtProng1", "3-prong candidates;prong 1 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + {"Data/hPtProng2", "3-prong candidates;prong 2 #it{p}_{T} (GeV/#it{c});entries", {HistType::kTH1F, {{360, 0., 36.}}}}, + /// DCAxy to prim. vertex prongs + {"Data/hd0Prong0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, + {"Data/hd0Prong1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, + {"Data/hd0Prong2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH1F, {{600, -0.4, 0.4}}}}, + /// decay length candidate + {"Data/hDecLength", "3-prong candidates;decay length (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, + /// decay length xy candidate + {"Data/hDecLengthxy", "3-prong candidates;decay length xy (cm);entries", {HistType::kTH1F, {{400, 0., 1.}}}}, + /// cosine of pointing angle + {"Data/hCPA", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, + /// cosine of pointing angle xy + {"Data/hCPAxy", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}}, + /// Chi 2 PCA to sec. vertex + {"Data/hDca2", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH1F, {{400, 0., 20.}}}}, + /// eta + {"Data/hEta", "3-prong candidates;#it{#eta};entries", {HistType::kTH1F, {{100, -2., 2.}}}}, + /// phi + {"Data/hPhi", "3-prong candidates;#it{#Phi};entries", {HistType::kTH1F, {{100, 0., 6.3}}}}}}; + + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext&) + { + std::array doprocess{doprocessDataStd, doprocessDataStdWithFT0C, doprocessDataStdWithFT0M}; + if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { + LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); + } + /// mass candidate + registry.add("Data/hMassVsPtVsNPvContributors", "3-prong candidates;inv. mass (de K #pi) (GeV/#it{c}^{2}); p_{T}; Number of PV contributors", {HistType::kTH3F, {{400, 2.4, 4.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}, {500, 0., 5000.}}}); + registry.add("Data/hMassVsPt", "3-prong candidates;inv. mass (de K #pi) (GeV/#it{c}^{2}); p_{T}", {HistType::kTH2F, {{400, 2.4, 4.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// DCAxy to prim. vertex prongs + registry.add("Data/hd0VsPtProng0", "3-prong candidates;prong 0 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hd0VsPtProng1", "3-prong candidates;prong 1 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hd0VsPtProng2", "3-prong candidates;prong 2 DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {{600, -0.4, 0.4}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// decay length candidate + registry.add("Data/hDecLengthVsPt", "3-prong candidates;decay length (cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// decay length xy candidate + registry.add("Data/hDecLengthxyVsPt", "3-prong candidates;decay length xy(cm);entries", {HistType::kTH2F, {{400, 0., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// cosine of pointing angle + registry.add("Data/hCPAVsPt", "3-prong candidates;cosine of pointing angle;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// cosine of pointing angle xy + registry.add("Data/hCPAxyVsPt", "3-prong candidates;cosine of pointing angle xy;entries", {HistType::kTH2F, {{110, -1.1, 1.1}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// Chi 2 PCA to sec. vertex + registry.add("Data/hDca2VsPt", "3-prong candidates;prong Chi2PCA to sec. vertex (cm);entries", {HistType::kTH2F, {{400, 0., 20.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// eta + registry.add("Data/hEtaVsPt", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// phi + registry.add("Data/hPhiVsPt", "3-prong candidates;candidate #it{#Phi};entries", {HistType::kTH2F, {{100, 0., 6.3}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// selection status + registry.add("hSelectionStatus", "3-prong candidates;selection status;entries", {HistType::kTH2F, {{5, -0.5, 4.5}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + /// impact parameter error + registry.add("Data/hImpParErrProng0", "3-prong candidates;prong 0 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hImpParErrProng1", "3-prong candidates;prong 1 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + registry.add("Data/hImpParErrProng2", "3-prong candidates;prong 2 impact parameter error (cm);entries", {HistType::kTH2F, {{100, -1., 1.}, {binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + + if (fillTHn) { + const AxisSpec thnAxisMass{thnConfigAxisMass, "inv. mass (de K #pi) (GeV/#it{c}^{2})"}; + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T}(C_{d}^{+}) (GeV/#it{c})"}; + const AxisSpec thnAxisPtProng0{thnConfigAxisPtProng, "#it{p}_{T}(prong0) (GeV/#it{c})"}; + const AxisSpec thnAxisPtProng1{thnConfigAxisPtProng, "#it{p}_{T}(prong1) (GeV/#it{c})"}; + const AxisSpec thnAxisPtProng2{thnConfigAxisPtProng, "#it{p}_{T}(prong2) (GeV/#it{c})"}; + const AxisSpec thnAxisChi2PCA{thnConfigAxisChi2PCA, "Chi2PCA to sec. vertex (cm)"}; + const AxisSpec thnAxisDecLength{thnConfigAxisDecLength, "decay length (cm)"}; + const AxisSpec thnAxisCPA{thnConfigAxisCPA, "cosine of pointing angle"}; + const AxisSpec thnAxisCentrality{thnConfigAxisCentrality, "centrality (FT0C)"}; + + std::vector axesStd{thnAxisMass, thnAxisPt, thnAxisPtProng0, thnAxisPtProng1, thnAxisPtProng2, thnAxisChi2PCA, thnAxisDecLength, thnAxisCPA, thnAxisCentrality}; + registry.add("hnCdVars", "THn for Reconstructed Cd candidates for data", HistType::kTHnSparseF, axesStd); + } + } + + /// Fill histograms for real data + template + void fillHistosData(CollType const& collision, CandType const& candidates) + { + auto thisCollId = collision.globalIndex(); + auto groupedCdCandidates = candidates.sliceBy(candCdPerCollision, thisCollId); + auto numPvContributors = collision.numContrib(); + + for (const auto& candidate : groupedCdCandidates) { + if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::CdToDeKPi)) { + continue; + } + + const auto pt = candidate.pt(); + const auto ptProng0 = candidate.ptProng0(); + const auto ptProng1 = candidate.ptProng1(); + const auto ptProng2 = candidate.ptProng2(); + const auto decayLength = candidate.decayLength(); + const auto decayLengthXY = candidate.decayLengthXY(); + const auto chi2PCA = candidate.chi2PCA(); + const auto cpa = candidate.cpa(); + const auto cpaXY = candidate.cpaXY(); + + if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { + registry.fill(HIST("Data/hMass"), hfHelper.invMassCdToDeKPi(candidate)); + registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), hfHelper.invMassCdToDeKPi(candidate), pt, numPvContributors); + registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassCdToDeKPi(candidate), pt); + } + if (candidate.isSelCdToPiKDe() >= selectionFlagCd) { + registry.fill(HIST("Data/hMass"), hfHelper.invMassCdToPiKDe(candidate)); + registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), hfHelper.invMassCdToPiKDe(candidate), pt, numPvContributors); + registry.fill(HIST("Data/hMassVsPt"), hfHelper.invMassCdToPiKDe(candidate), pt); + } + registry.fill(HIST("Data/hPt"), pt); + registry.fill(HIST("Data/hPtProng0"), ptProng0); + registry.fill(HIST("Data/hPtProng1"), ptProng1); + registry.fill(HIST("Data/hPtProng2"), ptProng2); + registry.fill(HIST("Data/hd0Prong0"), candidate.impactParameter0()); + registry.fill(HIST("Data/hd0Prong1"), candidate.impactParameter1()); + registry.fill(HIST("Data/hd0Prong2"), candidate.impactParameter2()); + registry.fill(HIST("Data/hd0VsPtProng0"), candidate.impactParameter0(), pt); + registry.fill(HIST("Data/hd0VsPtProng1"), candidate.impactParameter1(), pt); + registry.fill(HIST("Data/hd0VsPtProng2"), candidate.impactParameter2(), pt); + registry.fill(HIST("Data/hDecLength"), decayLength); + registry.fill(HIST("Data/hDecLengthVsPt"), decayLength, pt); + registry.fill(HIST("Data/hDecLengthxy"), decayLengthXY); + registry.fill(HIST("Data/hDecLengthxyVsPt"), decayLengthXY, pt); + registry.fill(HIST("Data/hCPA"), cpa); + registry.fill(HIST("Data/hCPAVsPt"), cpa, pt); + registry.fill(HIST("Data/hCPAxy"), cpaXY); + registry.fill(HIST("Data/hCPAxyVsPt"), cpaXY, pt); + registry.fill(HIST("Data/hDca2"), chi2PCA); + registry.fill(HIST("Data/hDca2VsPt"), chi2PCA, pt); + registry.fill(HIST("Data/hEta"), candidate.eta()); + registry.fill(HIST("Data/hEtaVsPt"), candidate.eta(), pt); + registry.fill(HIST("Data/hPhi"), candidate.phi()); + registry.fill(HIST("Data/hPhiVsPt"), candidate.phi(), pt); + registry.fill(HIST("hSelectionStatus"), candidate.isSelCdToDeKPi(), pt); + registry.fill(HIST("hSelectionStatus"), candidate.isSelCdToPiKDe(), pt); + registry.fill(HIST("Data/hImpParErrProng0"), candidate.errorImpactParameter0(), pt); + registry.fill(HIST("Data/hImpParErrProng1"), candidate.errorImpactParameter1(), pt); + registry.fill(HIST("Data/hImpParErrProng2"), candidate.errorImpactParameter2(), pt); + + if (fillTHn) { + float const cent = o2::hf_centrality::getCentralityColl(collision); + double massCd(-1); + if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { + massCd = hfHelper.invMassCdToDeKPi(candidate); + std::vector valuesToFill{massCd, pt, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, cent}; + registry.get(HIST("hnCdVars"))->Fill(valuesToFill.data()); + } + if (candidate.isSelCdToPiKDe() >= selectionFlagCd) { + massCd = hfHelper.invMassCdToPiKDe(candidate); + std::vector valuesToFill{massCd, pt, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, cent}; + registry.get(HIST("hnCdVars"))->Fill(valuesToFill.data()); + } + } + } + } + /// Run the analysis on real data + template + void runAnalysisPerCollisionData(CollType const& collisions, + CandType const& candidates) + { + + for (const auto& collision : collisions) { + fillHistosData(collision, candidates); + } + } + + void processDataStd(CollisionsWEvSel const& collisions, + CdCandidates const& selectedCdCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedCdCandidates); + } + PROCESS_SWITCH(HfTaskCd, processDataStd, "Process Data with the standard method", true); + + void processDataStdWithFT0C(CollisionsWithEvSelFT0C const& collisions, + CdCandidates const& selectedCdCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedCdCandidates); + } + PROCESS_SWITCH(HfTaskCd, processDataStdWithFT0C, "Process real data with the standard method and with FT0C centrality", false); + + void processDataStdWithFT0M(CollisionsWithEvSelFT0M const& collisions, + CdCandidates const& selectedCdCandidates, + aod::Tracks const&) + { + runAnalysisPerCollisionData(collisions, selectedCdCandidates); + } + PROCESS_SWITCH(HfTaskCd, processDataStdWithFT0M, "Process real data with the standard method and with FT0M centrality", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/DataModel/CandidateReconstructionTables.h b/PWGHF/DataModel/CandidateReconstructionTables.h index 37c96d5627a..5c24594a2ba 100644 --- a/PWGHF/DataModel/CandidateReconstructionTables.h +++ b/PWGHF/DataModel/CandidateReconstructionTables.h @@ -58,12 +58,14 @@ using TracksPidMu = soa::Join; using TracksPidPi = soa::Join; using TracksPidKa = soa::Join; using TracksPidPr = soa::Join; +using TracksPidDe = soa::Join; using TracksPidTinyEl = soa::Join; using TracksPidTinyMu = soa::Join; using TracksPidTinyPi = soa::Join; using TracksPidTinyKa = soa::Join; using TracksPidTinyPr = soa::Join; +using TracksPidTinyDe = soa::Join; // namespace pid_tpc_tof_utils // { @@ -156,6 +158,7 @@ DECLARE_SOA_COLUMN(TpcTofNSigmaMu, tpcTofNSigmaMu, float); //! Combined NSigma s DECLARE_SOA_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, float); //! Combined NSigma separation with the TPC & TOF detectors for pion 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 } // namespace pid_tpc_tof_static_full namespace pid_tpc_tof_static_tiny @@ -166,6 +169,7 @@ DECLARE_SOA_COLUMN(TpcTofNSigmaMu, tpcTofNSigmaMu, float); //! Combined NSigma s DECLARE_SOA_COLUMN(TpcTofNSigmaPi, tpcTofNSigmaPi, float); //! Combined NSigma separation with the TPC & TOF detectors for pion 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 } // namespace pid_tpc_tof_static_tiny // Extension of per particle tables @@ -179,6 +183,8 @@ DECLARE_SOA_TABLE(PidTpcTofFullKa, "AOD", "PIDTPCTOFFULLKA", //! Table of the TP pid_tpc_tof_static_full::TpcTofNSigmaKa); DECLARE_SOA_TABLE(PidTpcTofFullPr, "AOD", "PIDTPCTOFFULLPR", //! Table of the TPC & TOF Combined NSigma for proton 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); // Extension of per particle tables DECLARE_SOA_TABLE(PidTpcTofTinyEl, "AOD", "PIDTPCTOFTINYEL", //! Table of the TPC & TOF Combined NSigma for electron @@ -191,6 +197,8 @@ DECLARE_SOA_TABLE(PidTpcTofTinyKa, "AOD", "PIDTPCTOFTINYKA", //! Table of the TP pid_tpc_tof_static_tiny::TpcTofNSigmaKa); DECLARE_SOA_TABLE(PidTpcTofTinyPr, "AOD", "PIDTPCTOFTINYPR", //! Table of the TPC & TOF Combined NSigma for proton 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); namespace hf_sel_collision { @@ -517,6 +525,9 @@ DECLARE_SOA_COLUMN(NSigTpcKa2, nSigTpcKa2, float); //! TPC nSigma for DECLARE_SOA_COLUMN(NSigTpcPr0, nSigTpcPr0, float); //! TPC nSigma for proton hypothesis - prong 0 DECLARE_SOA_COLUMN(NSigTpcPr1, nSigTpcPr1, float); //! TPC nSigma for proton hypothesis - prong 1 DECLARE_SOA_COLUMN(NSigTpcPr2, nSigTpcPr2, float); //! TPC nSigma for proton hypothesis - prong 2 +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(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 @@ -526,6 +537,9 @@ DECLARE_SOA_COLUMN(NSigTofKa2, nSigTofKa2, float); //! TOF nSigma for DECLARE_SOA_COLUMN(NSigTofPr0, nSigTofPr0, float); //! TOF nSigma for proton hypothesis - prong 0 DECLARE_SOA_COLUMN(NSigTofPr1, nSigTofPr1, float); //! TOF nSigma for proton hypothesis - prong 1 DECLARE_SOA_COLUMN(NSigTofPr2, nSigTofPr2, float); //! TOF nSigma for proton hypothesis - prong 2 +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_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 @@ -544,6 +558,13 @@ DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPr1, tpcTofNSigmaPr1, //! Combined NSigma [](float tpcNSigmaPr1, float tofNSigmaPr1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr1, tofNSigmaPr1); }); DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaPr2, tpcTofNSigmaPr2, //! Combined NSigma separation with the TPC & TOF detectors for proton - prong 2 [](float tpcNSigmaPr2, float tofNSigmaPr2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPr2, tofNSigmaPr2); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe0, tpcTofNSigmaDe0, //! Combined NSigma separation with the TPC & TOF detectors for deuteron - prong 0 + [](float tpcNSigmaDe0, float tofNSigmaDe0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaDe0, tofNSigmaDe0); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcTofNSigmaDe1, tpcTofNSigmaDe1, //! Combined NSigma separation with the TPC & TOF detectors for deuteron - prong 1 + [](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); }); + // 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); }); @@ -980,6 +1001,7 @@ enum DecayType { DplusToPiKPi = 0, LcToPKPi, DsToKKPi, XicToPKPi, + CdToDeKPi, N3ProngDecays }; // always keep N3ProngDecays at the end // Ds± → K± K∓ π± or D± → K± K∓ π± @@ -1099,10 +1121,20 @@ DECLARE_SOA_TABLE(HfCand3Prong1PidPr, "AOD", "HFCAND3P1PIDPR", //! DECLARE_SOA_TABLE(HfCand3Prong2PidPr, "AOD", "HFCAND3P2PIDPR", //! hf_cand::NSigTpcPr2, hf_cand::NSigTofPr2, hf_cand::TpcTofNSigmaPr2); +DECLARE_SOA_TABLE(HfCand3Prong0PidDe, "AOD", "HFCAND3P0PIDDE", //! + hf_cand::NSigTpcDe0, hf_cand::NSigTofDe0, + hf_cand::TpcTofNSigmaDe0); +DECLARE_SOA_TABLE(HfCand3Prong1PidDe, "AOD", "HFCAND3P1PIDDE", //! + hf_cand::NSigTpcDe1, hf_cand::NSigTofDe1, + hf_cand::TpcTofNSigmaDe1); +DECLARE_SOA_TABLE(HfCand3Prong2PidDe, "AOD", "HFCAND3P2PIDDE", //! + hf_cand::NSigTpcDe2, hf_cand::NSigTofDe2, + hf_cand::TpcTofNSigmaDe2); using HfCand3Prong = HfCand3ProngExt; using HfCand3ProngWPidPiKaPr = soa::Join; using HfCand3ProngWPidPiKa = soa::Join; +using HfCand3ProngWPidPiKaDe = 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 125b0fb7286..90ffd6ada32 100644 --- a/PWGHF/DataModel/CandidateSelectionTables.h +++ b/PWGHF/DataModel/CandidateSelectionTables.h @@ -164,6 +164,14 @@ DECLARE_SOA_TABLE(HfSelLc, "AOD", "HFSELLC", //! DECLARE_SOA_TABLE(HfMlLcToPKPi, "AOD", "HFMLLc", //! hf_sel_candidate_lc::MlProbLcToPKPi, hf_sel_candidate_lc::MlProbLcToPiKP); +namespace hf_sel_candidate_cd +{ +DECLARE_SOA_COLUMN(IsSelCdToDeKPi, isSelCdToDeKPi, int); //! +DECLARE_SOA_COLUMN(IsSelCdToPiKDe, isSelCdToPiKDe, int); //! +} // namespace hf_sel_candidate_cd +DECLARE_SOA_TABLE(HfSelCd, "AOD", "HFSELCD", //! + hf_sel_candidate_cd::IsSelCdToDeKPi, hf_sel_candidate_cd::IsSelCdToPiKDe); + namespace hf_sel_candidate_lc_alice3 { DECLARE_SOA_COLUMN(IsSelLcToPKPiNoPid, isSelLcToPKPiNoPid, int); //! diff --git a/PWGHF/TableProducer/CMakeLists.txt b/PWGHF/TableProducer/CMakeLists.txt index 9b28ce9e88d..e84c579187c 100644 --- a/PWGHF/TableProducer/CMakeLists.txt +++ b/PWGHF/TableProducer/CMakeLists.txt @@ -202,6 +202,11 @@ o2physics_add_dpl_workflow(candidate-selector-xicc-to-p-k-pi-pi PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(candidate-selector-cd + SOURCES candidateSelectorCd.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + # Tree creators o2physics_add_dpl_workflow(tree-creator-b0-to-d-pi diff --git a/PWGHF/TableProducer/candidateCreator3Prong.cxx b/PWGHF/TableProducer/candidateCreator3Prong.cxx index 0bf6c47fc91..ca1363ba0c8 100644 --- a/PWGHF/TableProducer/candidateCreator3Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator3Prong.cxx @@ -94,12 +94,15 @@ struct HfCandidateCreator3Prong { Produces rowProng0PidPi; Produces rowProng0PidKa; Produces rowProng0PidPr; + Produces rowProng0PidDe; Produces rowProng1PidPi; Produces rowProng1PidKa; Produces rowProng1PidPr; + Produces rowProng1PidDe; Produces rowProng2PidPi; Produces rowProng2PidKa; Produces rowProng2PidPr; + Produces rowProng2PidDe; // vertexing Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; @@ -120,6 +123,7 @@ struct HfCandidateCreator3Prong { Configurable createDs{"createDs", false, "enable Ds+/- candidate creation"}; Configurable createLc{"createLc", false, "enable Lc+/- candidate creation"}; Configurable createXic{"createXic", false, "enable Xic+/- candidate creation"}; + Configurable createCd{"createCd", false, "enable Cd candidate creation"}; // KF Configurable applyTopoConstraint{"applyTopoConstraint", false, "apply origin from PV hypothesis for created candidate, works only in KF mode"}; Configurable applyInvMassConstraint{"applyInvMassConstraint", false, "apply particle type hypothesis to recalculate created candidate's momentum, works only in KF mode"}; @@ -136,10 +140,10 @@ struct HfCandidateCreator3Prong { using FilteredHf3Prongs = soa::Filtered; using FilteredPvRefitHf3Prongs = soa::Filtered>; - using TracksWCovExtraPidPiKaPr = soa::Join; + using TracksWCovExtraPidPiKaPrDe = soa::Join; // filter candidates - Filter filterSelected3Prongs = (createDplus && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::DplusToPiKPi))) != static_cast(0)) || (createDs && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::DsToKKPi))) != static_cast(0)) || (createLc && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::LcToPKPi))) != static_cast(0)) || (createXic && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::XicToPKPi))) != static_cast(0)); + Filter filterSelected3Prongs = (createDplus && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::DplusToPiKPi))) != static_cast(0)) || (createDs && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::DsToKKPi))) != static_cast(0)) || (createLc && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::LcToPKPi))) != static_cast(0)) || (createXic && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::XicToPKPi))) != static_cast(0)) || (createCd && (o2::aod::hf_track_index::hfflag & static_cast(BIT(DecayType::CdToDeKPi))) != static_cast(0)); std::shared_ptr hCandidates; HistogramRegistry registry{"registry"}; @@ -181,13 +185,13 @@ struct HfCandidateCreator3Prong { if (nProcessesUpc > 0 && isRun2) { LOGP(fatal, "Process function for UPC is only available in Run 3!"); } - std::array creationFlags = {createDplus, createDs, createLc, createXic}; + std::array creationFlags = {createDplus, createDs, createLc, createXic, createCd}; if (std::accumulate(creationFlags.begin(), creationFlags.end(), 0) == 0) { LOGP(fatal, "At least one particle specie should be enabled for the creation."); } if (createLc && createXic && applyInvMassConstraint) { - LOGP(fatal, "Unable to apply invariant mass constraint due to ambiguity of mass hypothesis: only one of Lc and Xic can be reconstructed."); + LOGP(fatal, "Unable to apply invariant mass constraint due to ambiguity of mass hypothesis: only one of Lc and Xic and Cd can be reconstructed."); } // histograms @@ -196,6 +200,8 @@ struct HfCandidateCreator3Prong { registry.add("hMass3PiKPi", "3-prong candidates;inv. mass (#pi K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{600, 1.6, 2.2}}}); registry.add("hMass3KKPi", "3-prong candidates;inv. mass (KK #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{600, 1.7, 2.3}}}); registry.add("hMass3PiKK", "3-prong candidates;inv. mass (#pi KK) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{600, 1.7, 2.3}}}); + registry.add("hMass3DeKPi", "3-prong candidates;inv. mass (deK#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{2000, 2.5, 4.5}}}); + registry.add("hMass3PiKDe", "3-prong candidates;inv. mass (#pi Kde) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{2000, 2.5, 4.5}}}); registry.add("hMass2KPi", "2-prong pairs;inv. mass (K#pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{1200, 0.8, 2.0}}}); registry.add("hMass2PiK", "2-prong pairs;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{1200, 0.8, 2.0}}}); registry.add("hCovPVXX", "3-prong candidates;XX element of cov. matrix of prim. vtx. position (cm^{2});entries", {HistType::kTH1F, {{100, 0., 1.e-4}}}); @@ -248,12 +254,17 @@ struct HfCandidateCreator3Prong { fillProngPid(track1, rowProng1PidPr); fillProngPid(track2, rowProng2PidPr); } + if (createCd) { + fillProngPid(track0, rowProng0PidDe); + fillProngPid(track1, rowProng1PidDe); + fillProngPid(track2, rowProng2PidDe); + } } template void runCreator3ProngWithDCAFitterN(Coll const&, Cand const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const&, + TracksWCovExtraPidPiKaPrDe const&, BCsType const& bcs) { // loop over triplets of track indices @@ -273,9 +284,9 @@ struct HfCandidateCreator3Prong { continue; } - auto track0 = rowTrackIndexProng3.template prong0_as(); - auto track1 = rowTrackIndexProng3.template prong1_as(); - auto track2 = rowTrackIndexProng3.template prong2_as(); + auto track0 = rowTrackIndexProng3.template prong0_as(); + auto track1 = rowTrackIndexProng3.template prong1_as(); + auto track2 = rowTrackIndexProng3.template prong2_as(); auto trackParVar0 = getTrackParCov(track0); auto trackParVar1 = getTrackParCov(track1); auto trackParVar2 = getTrackParCov(track2); @@ -410,6 +421,8 @@ struct HfCandidateCreator3Prong { const auto massPiKPi = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassPiPlus}); const auto massKKPi = RecoDecay::m(arrayMomenta, std::array{MassKPlus, MassKPlus, MassPiPlus}); const auto massPiKK = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassKPlus}); + const auto massDeKPi = RecoDecay::m(arrayMomenta, std::array{MassDeuteron, MassKPlus, MassPiPlus}); + const auto massPiKDe = RecoDecay::m(arrayMomenta, std::array{MassPiPlus, MassKPlus, MassDeuteron}); const auto massKPi = RecoDecay::m(std::array{arrayMomenta.at(1), arrayMomenta.at(2)}, std::array{MassKPlus, MassPiPlus}); const auto massPiK = RecoDecay::m(std::array{arrayMomenta.at(0), arrayMomenta.at(1)}, std::array{MassPiPlus, MassKPlus}); registry.fill(HIST("hMass3PiKPi"), massPiKPi); @@ -417,6 +430,8 @@ struct HfCandidateCreator3Prong { registry.fill(HIST("hMass3PiKP"), massPiKP); registry.fill(HIST("hMass3KKPi"), massKKPi); registry.fill(HIST("hMass3PiKK"), massPiKK); + registry.fill(HIST("hMass3DeKPi"), massDeKPi); + registry.fill(HIST("hMass3PiKDe"), massPiKDe); registry.fill(HIST("hMass2KPi"), massKPi); registry.fill(HIST("hMass2PiK"), massPiK); } @@ -426,7 +441,7 @@ struct HfCandidateCreator3Prong { template void runCreator3ProngWithKFParticle(Coll const&, Cand const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const&, + TracksWCovExtraPidPiKaPrDe const&, BCsType const& bcs) { for (const auto& rowTrackIndexProng3 : rowsTrackIndexProng3) { @@ -444,9 +459,9 @@ struct HfCandidateCreator3Prong { continue; } - auto track0 = rowTrackIndexProng3.template prong0_as(); - auto track1 = rowTrackIndexProng3.template prong1_as(); - auto track2 = rowTrackIndexProng3.template prong2_as(); + auto track0 = rowTrackIndexProng3.template prong0_as(); + auto track1 = rowTrackIndexProng3.template prong1_as(); + auto track2 = rowTrackIndexProng3.template prong2_as(); /// Set the magnetic field from ccdb. /// The static instance of the propagator was already modified in the HFTrackIndexSkimCreator, @@ -675,7 +690,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/ PV refit and w/o centrality selections void processPvRefitWithDCAFitterN(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -685,7 +700,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/o PV refit and w/o centrality selections void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -695,7 +710,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/ PV refit and w/o centrality selections void processPvRefitWithKFParticle(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -705,7 +720,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections void processNoPvRefitWithKFParticle(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -721,7 +736,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0C void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -731,7 +746,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on FT0C void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -741,7 +756,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0C void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -751,7 +766,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on FT0C void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -767,7 +782,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0M void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -777,7 +792,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on FT0M void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithDCAFitterN(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -787,7 +802,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0M void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -797,7 +812,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on FT0M void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) { runCreator3ProngWithKFParticle(collisions, rowsTrackIndexProng3, tracks, bcWithTimeStamps); @@ -813,7 +828,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on UPC void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BcFullInfos const& bcWithTimeStamps, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, @@ -827,7 +842,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on UPC void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BcFullInfos const& bcWithTimeStamps, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, @@ -841,7 +856,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on UPC void processPvRefitWithKFParticleUpc(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BcFullInfos const& bcWithTimeStamps, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, @@ -855,7 +870,7 @@ struct HfCandidateCreator3Prong { /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on UPC void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, - TracksWCovExtraPidPiKaPr const& tracks, + TracksWCovExtraPidPiKaPrDe const& tracks, aod::BcFullInfos const& bcWithTimeStamps, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, diff --git a/PWGHF/TableProducer/candidateSelectorCd.cxx b/PWGHF/TableProducer/candidateSelectorCd.cxx new file mode 100644 index 00000000000..4eb1c0e2e95 --- /dev/null +++ b/PWGHF/TableProducer/candidateSelectorCd.cxx @@ -0,0 +1,384 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file candidateSelectorCd.cxx +/// \brief Cd± → d± K∓ π± selection task +/// +/// \author Biao Zhang , Heidelberg Universiity + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +#include "Common/Core/TrackSelectorPID.h" +#include "Common/DataModel/PIDResponseCombined.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::framework; + +/// Struct for applying Cd selection cuts +struct HfCandidateSelectorCd { + Produces hfSelCdCandidate; + + Configurable ptCandMin{"ptCandMin", 0., "Lower bound of candidate pT"}; + Configurable ptCandMax{"ptCandMax", 36., "Upper bound of candidate pT"}; + Configurable usePid{"usePid", true, "Bool to use or not the PID based on nSigma cut at filtering level"}; + // TPC PID + Configurable ptPidTpcMin{"ptPidTpcMin", 0.1, "Lower bound of track pT for TPC PID"}; + Configurable ptPidTpcMax{"ptPidTpcMax", 1., "Upper bound of track pT for TPC PID"}; + Configurable nSigmaTpcMax{"nSigmaTpcMax", 3., "Nsigma cut on TPC only"}; + Configurable nSigmaTpcCombinedMax{"nSigmaTpcCombinedMax", 5., "Nsigma cut on TPC combined with TOF"}; + // TOF PID + Configurable ptPidTofMin{"ptPidTofMin", 0.5, "Lower bound of track pT for TOF PID"}; + Configurable ptPidTofMax{"ptPidTofMax", 2.5, "Upper bound of track pT for TOF PID"}; + Configurable nSigmaTofMax{"nSigmaTofMax", 3., "Nsigma cut on TOF only"}; + Configurable nSigmaTofCombinedMax{"nSigmaTofCombinedMax", 5., "Nsigma cut on TOF combined with TPC"}; + // Combined PID options + Configurable usePidTpcAndTof{"usePidTpcAndTof", false, "Bool to decide how to combine TPC and TOF PID: true = both (if present, only one otherwise); false = one is enough"}; + // TPC quality track cuts + Configurable tpcNClustersFoundMin{"tpcNClustersFoundMin", 0, "min number of found TPC clusters"}; + Configurable tpcNCrossedRowsMin{"tpcNCrossedRowsMin", 0, "min number of crossed rows in TPC"}; + Configurable tpcNCrossedRowsOverFindableClustersMin{"tpcNCrossedRowsOverFindableClustersMin", 0., "min ratio crossed rows / findable clusters"}; + Configurable tpcChi2PerClusterMax{"tpcChi2PerClusterMax", 1e10f, "max tpc fit chi2 per TPC cluster"}; + // ITS quality track cuts + Configurable itsNClustersFoundMin{"itsNClustersFoundMin", 0, "min. number of found ITS clusters"}; + Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 1e10f, "max its fit chi2 per ITS cluster"}; + // DCA track cuts + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA XY/Z pT-dependent cut"}; + Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; + // topological cuts + Configurable> binsPt{"binsPt", std::vector{hf_cuts_cd_to_de_k_pi::vecBinsPt}, "pT bin limits"}; + Configurable> cuts{"cuts", {hf_cuts_cd_to_de_k_pi::Cuts[0], hf_cuts_cd_to_de_k_pi::NBinsPt, hf_cuts_cd_to_de_k_pi::NCutVars, hf_cuts_cd_to_de_k_pi::labelsPt, hf_cuts_cd_to_de_k_pi::labelsCutVar}, "Cd candidate selection per pT bin"}; + // QA switch + Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; + + HfHelper hfHelper; + + TrackSelectorPi selectorPion; + TrackSelectorKa selectorKaon; + TrackSelectorDe selectorDeuteron; + + const float massCharmDeuteron = 3.23; // possible mass + + using TracksSel = soa::Join; + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + + selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); + selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); + selectorPion.setRangeNSigmaTpcCondTof(-nSigmaTpcCombinedMax, nSigmaTpcCombinedMax); + selectorPion.setRangePtTof(ptPidTofMin, ptPidTofMax); + selectorPion.setRangeNSigmaTof(-nSigmaTofMax, nSigmaTofMax); + selectorPion.setRangeNSigmaTofCondTpc(-nSigmaTofCombinedMax, nSigmaTofCombinedMax); + selectorKaon = selectorPion; + selectorDeuteron = selectorPion; + + if (activateQA) { + constexpr int kNBinsSelections = aod::SelectionStep::NSelectionSteps; + std::string labels[kNBinsSelections]; + labels[0] = "No selection"; + labels[1 + aod::SelectionStep::RecoSkims] = "Skims selection"; + labels[1 + aod::SelectionStep::RecoTopol] = "Skims & Topological selections"; + labels[1 + aod::SelectionStep::RecoPID] = "Skims & Topological & PID selections"; + static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; + registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); + for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { + registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); + } + } + } + + /// Single track quality cuts + /// \param track is track + /// \return true if track passes all cuts + template + bool isSelectedCandidateProngQuality(const T& trackPos1, const T& trackNeg, const T& trackPos2) + { + if (!isSelectedTrackTpcQuality(trackPos1, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value) || + !isSelectedTrackTpcQuality(trackNeg, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value) || + !isSelectedTrackTpcQuality(trackPos2, tpcNClustersFoundMin.value, tpcNCrossedRowsMin.value, tpcNCrossedRowsOverFindableClustersMin.value, tpcChi2PerClusterMax.value)) { + return false; + } + if (!isSelectedTrackItsQuality(trackPos1, itsNClustersFoundMin.value, itsChi2PerClusterMax.value) || + !isSelectedTrackItsQuality(trackNeg, itsNClustersFoundMin.value, itsChi2PerClusterMax.value) || + !isSelectedTrackItsQuality(trackPos2, itsNClustersFoundMin.value, itsChi2PerClusterMax.value)) { + return false; + } + return true; + } + + /// Conjugate-independent topological cuts + /// \param candidate is candidate + /// \return true if candidate passes all cuts + template + bool selectionTopol(const T& candidate) + { + auto ptCand = candidate.pt(); + + int const binPt = findBin(binsPt, ptCand); + if (binPt == -1) { + return false; + } + + // check that the candidate pT is within the analysis range + if (ptCand < ptCandMin || ptCand >= ptCandMax) { + return false; + } + + // cosine of pointing angle + if (candidate.cpa() <= cuts->get(binPt, "cos pointing angle")) { + return false; + } + + // candidate chi2PCA + if (candidate.chi2PCA() > cuts->get(binPt, "Chi2PCA")) { + return false; + } + + if (candidate.decayLength() <= cuts->get(binPt, "decay length")) { + return false; + } + + // candidate decay length XY + if (candidate.decayLengthXY() <= cuts->get(binPt, "decLengthXY")) { + return false; + } + + // candidate normalized decay length XY + if (candidate.decayLengthXYNormalised() < cuts->get(binPt, "normDecLXY")) { + return false; + } + + // candidate impact parameter XY + if (std::abs(candidate.impactParameterXY()) > cuts->get(binPt, "impParXY")) { + return false; + } + + if (!isSelectedCandidateProngDca(candidate)) { + return false; + } + + return true; + } + + /// Conjugate-dependent topological cuts + /// \param candidate is candidate + /// \param trackDeuteron is the track with the deuteron hypothesis + /// \param trackPion is the track with the pion hypothesis + /// \param trackKaon is the track with the kaon hypothesis + /// \return true if candidate passes all cuts for the given Conjugate + template + bool selectionTopolConjugate(const T1& candidate, const T2& trackDeuteron, const T2& trackKaon, const T2& trackPion) + { + + auto ptCand = candidate.pt(); + int const binPt = findBin(binsPt, ptCand); + if (binPt == -1) { + return false; + } + + // cut on daughter pT + if (trackDeuteron.pt() < cuts->get(binPt, "pT De") || trackKaon.pt() < cuts->get(binPt, "pT K") || trackPion.pt() < cuts->get(binPt, "pT Pi")) { + return false; + } + + float massCd{0.f}; + if (trackDeuteron.globalIndex() == candidate.prong0Id()) { + massCd = hfHelper.invMassCdToDeKPi(candidate); + } else { + massCd = hfHelper.invMassCdToPiKDe(candidate); + } + + // cut on Cd->deKpi, piKde mass values + if (std::abs(massCd - massCharmDeuteron) > cuts->get(binPt, "m")) { + return false; + } + + return true; + } + + /// Single-track dca_xy and dca_z cuts + /// \param candidate is the Cd candidate + /// \return true if all the prongs pass the selections + template + bool isSelectedCandidateProngDca(const T1& candidate) + { + return (isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0(), candidate.impactParameterZ0()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1(), candidate.impactParameterZ1()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng2(), candidate.impactParameter2(), candidate.impactParameterZ2())); + } + + /// Apply PID selection + /// \param pidTrackDeuteron is the PID status of deuteron candidate track + /// \param pidTrackKaon is the PID status of kaon candidate track + /// \param pidTrackPion is the PID status of pion candidate track + /// \return true if prongs pass all selections + bool isSelectedPID(const TrackSelectorPID::Status pidTrackDeuteron, const TrackSelectorPID::Status pidTrackKaon, const TrackSelectorPID::Status pidTrackPion) + { + return pidTrackDeuteron != TrackSelectorPID::Rejected && + pidTrackKaon != TrackSelectorPID::Rejected && + pidTrackPion != TrackSelectorPID::Rejected; + } + + /// \brief function to apply Cd selections + /// \param reconstructionType is the reconstruction type (DCAFitterN ) + /// \param candidates Cd candidate table + /// \param tracks track table + template + void runSelectCd(CandType const& candidates, TTracks const&) + { + // looping over 3-prong candidates + for (const auto& candidate : candidates) { + + // final selection flag + auto statusCdToDeKPi = 0; + auto statusCdToPiKDe = 0; + + auto ptCand = candidate.pt(); + + if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::CdToDeKPi)) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + if (activateQA) { + registry.fill(HIST("hSelections"), 1, ptCand); + } + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoSkims, ptCand); + } + + auto trackPos1 = candidate.template prong0_as(); // positive daughter (negative for the antiparticles) + auto trackNeg = candidate.template prong1_as(); // negative daughter (positive for the antiparticles) + auto trackPos2 = candidate.template prong2_as(); // positive daughter (negative for the antiparticles) + + // implement filter bit 4 cut - should be done before this task at the track selection level + + // track quality selection + bool const trackQualitySel = isSelectedCandidateProngQuality(trackPos1, trackNeg, trackPos2); + if (!trackQualitySel) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + // conjugate-independent topological selection + if (!selectionTopol(candidate)) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + // conjugate-dependent topological selection for Cd + bool const topolCdToDeKPi = selectionTopolConjugate(candidate, trackPos1, trackNeg, trackPos2); + bool const topolCdToPiKDe = selectionTopolConjugate(candidate, trackPos2, trackNeg, trackPos1); + + if (!topolCdToDeKPi && !topolCdToPiKDe) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoTopol, candidate.pt()); + } + + // PID not applied, accepted by default + auto pidCdToDeKPi = 1; + auto pidCdToPiKDe = 1; + + if (usePid) { + // track-level PID selection + TrackSelectorPID::Status pidTrackPos1Deuteron; + TrackSelectorPID::Status pidTrackPos2Deuteron; + TrackSelectorPID::Status pidTrackPos1Pion; + TrackSelectorPID::Status pidTrackPos2Pion; + TrackSelectorPID::Status pidTrackNegKaon; + if (usePidTpcAndTof) { + pidTrackPos1Deuteron = selectorDeuteron.statusTpcAndTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); + pidTrackPos2Deuteron = selectorDeuteron.statusTpcAndTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); + pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + } else { + pidTrackPos1Deuteron = selectorDeuteron.statusTpcOrTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); + pidTrackPos2Deuteron = selectorDeuteron.statusTpcOrTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); + pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); + } + + if (!isSelectedPID(pidTrackPos1Deuteron, pidTrackNegKaon, pidTrackPos2Pion)) { + pidCdToDeKPi = 0; // reject CdToDeKPi + } + if (!isSelectedPID(pidTrackPos2Deuteron, pidTrackNegKaon, pidTrackPos1Pion)) { + pidCdToPiKDe = 0; // accept CdToPiKDe + } + } + + if (pidCdToDeKPi == 0 && pidCdToPiKDe == 0) { + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + continue; + } + + if (activateQA) { + registry.fill(HIST("hSelections"), 2 + aod::SelectionStep::RecoPID, candidate.pt()); + } + + if (pidCdToDeKPi == 1 && topolCdToDeKPi && trackQualitySel) { + statusCdToDeKPi = 1; // identified as CdToDeKPi + } + if (pidCdToPiKDe == 1 && topolCdToPiKDe && trackQualitySel) { + statusCdToPiKDe = 1; // identified as CdToPiKDe + } + + hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); + } + } + + /// \brief process function with DCAFitterN + /// \param candidates Cd candidate table + /// \param tracks track table + void processCdWithDCAFitterN(aod::HfCand3ProngWPidPiKaDe const& candidates, + TracksSel const& tracks) + { + runSelectCd(candidates, tracks); + } + PROCESS_SWITCH(HfCandidateSelectorCd, processCdWithDCAFitterN, "Process Cd selection with DCAFitterN", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGHF/TableProducer/pidCreator.cxx b/PWGHF/TableProducer/pidCreator.cxx index e011b18cf9b..e914c4f1c38 100644 --- a/PWGHF/TableProducer/pidCreator.cxx +++ b/PWGHF/TableProducer/pidCreator.cxx @@ -44,6 +44,8 @@ struct HfPidCreator { Produces trackPidTinyKa; Produces trackPidFullPr; Produces trackPidTinyPr; + Produces trackPidFullDe; + Produces trackPidTinyDe; static constexpr float NSigmaToleranceDefault = .1f; static constexpr float NSigmaDefault = -999.f + NSigmaToleranceDefault; // -999.f is the default value set in TPCPIDResponse.h and PIDTOF.h @@ -79,6 +81,8 @@ struct HfPidCreator { checkTableSwitch(initContext, "PidTpcTofTinyKa", doprocessTinyKa); checkTableSwitch(initContext, "PidTpcTofFullPr", doprocessFullPr); checkTableSwitch(initContext, "PidTpcTofTinyPr", doprocessTinyPr); + checkTableSwitch(initContext, "PidTpcTofFullDe", doprocessFullDe); + checkTableSwitch(initContext, "PidTpcTofTinyDe", doprocessTinyDe); } /// Function to combine TPC and TOF NSigma @@ -132,6 +136,7 @@ struct HfPidCreator { PROCESS_PID(Pi) PROCESS_PID(Ka) PROCESS_PID(Pr) + PROCESS_PID(De) #undef PROCESS_PID }; diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index f95eb86a58a..f556be3170e 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -120,6 +120,7 @@ enum ChannelsProtonPid { }; // kaon PID (opposite-sign track in 3-prong decays) constexpr int ChannelKaonPid = ChannelsProtonPid::NChannelsProtonPid; +constexpr int ChannelsDeuteronPid = ChannelsProtonPid::NChannelsProtonPid + 1; /// Event selection struct HfTrackIndexSkimCreatorTagSelCollisions { @@ -307,7 +308,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], 4, 6, hf_presel_pid::labelsRowsPid, hf_presel_pid::labelsCutsPid}, "PID selections for proton / kaon applied if proper 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"}; // CCDB Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; @@ -324,9 +325,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; @@ -338,6 +339,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { // proton PID, if enabled std::array selectorProton{}; TrackSelectorKa selectorKaon; + TrackSelectorDe selectorDeuteron; 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)); @@ -460,6 +462,11 @@ struct HfTrackIndexSkimCreatorTagSelTracks { selectorKaon.setRangePtTof(config.selectionsPid->get(ChannelKaonPid, 3u), config.selectionsPid->get(ChannelKaonPid, 4u)); // 3u == "minPtTof, 4u == "maxPtTof" selectorKaon.setRangeNSigmaTpc(-config.selectionsPid->get(ChannelKaonPid, 2u), config.selectionsPid->get(ChannelKaonPid, 2u)); // 2u == "nSigmaMaxTpc" selectorKaon.setRangeNSigmaTof(-config.selectionsPid->get(ChannelKaonPid, 5u), config.selectionsPid->get(ChannelKaonPid, 5u)); // 5u == "nSigmaMaxTof" + + selectorDeuteron.setRangePtTpc(config.selectionsPid->get(ChannelsDeuteronPid, 0u), config.selectionsPid->get(ChannelsDeuteronPid, 1u)); // 0u == "minPtTpc", 1u == "maxPtTpc" + 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" } /// PID track cuts (for proton only) @@ -468,13 +475,14 @@ struct HfTrackIndexSkimCreatorTagSelTracks { template uint8_t isSelectedPid(const T& hfTrack) { - std::array statusPid{TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted, TrackSelectorPID::Accepted}; + std::array statusPid{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) { statusPid[iChannel] = selectorProton[iChannel].statusTof(hfTrack); } statusPid[ChannelKaonPid] = selectorKaon.statusTof(hfTrack); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTof(hfTrack); } } if constexpr (PidStrategy == ProtonPidStrategy::PidTpcOnly) { @@ -483,6 +491,7 @@ struct HfTrackIndexSkimCreatorTagSelTracks { statusPid[iChannel] = selectorProton[iChannel].statusTpc(hfTrack); } statusPid[ChannelKaonPid] = selectorKaon.statusTpc(hfTrack); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpc(hfTrack); } } if constexpr (PidStrategy == ProtonPidStrategy::PidTpcOrTof) { @@ -490,16 +499,18 @@ struct HfTrackIndexSkimCreatorTagSelTracks { statusPid[iChannel] = selectorProton[iChannel].statusTpcOrTof(hfTrack); } statusPid[ChannelKaonPid] = selectorKaon.statusTpcOrTof(hfTrack); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpcOrTof(hfTrack); } if constexpr (PidStrategy == ProtonPidStrategy::PidTpcAndTof) { for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid; ++iChannel) { statusPid[iChannel] = selectorProton[iChannel].statusTpcAndTof(hfTrack); } statusPid[ChannelKaonPid] = selectorKaon.statusTpcAndTof(hfTrack); + statusPid[ChannelsDeuteronPid] = selectorDeuteron.statusTpcAndTof(hfTrack); } - int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 1) - 1; // all bits on (including the kaon one) - for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 1; ++iChannel) { + int8_t flag = BIT(ChannelsProtonPid::NChannelsProtonPid + 2) - 1; // all bits on (including the kaon one) + for (auto iChannel{0u}; iChannel < ChannelsProtonPid::NChannelsProtonPid + 2; ++iChannel) { if (statusPid[iChannel] == TrackSelectorPID::Rejected) { CLRBIT(flag, iChannel); } @@ -1232,6 +1243,10 @@ struct HfTrackIndexSkimCreator { // Xic+ cuts Configurable> binsPtXicToPKPi{"binsPtXicToPKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for Xic->pKpi pT-dependent cuts"}; Configurable> cutsXicToPKPi{"cutsXicToPKPi", {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}, "Xic->pKpi selections per pT bin"}; + // 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"}; + // 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"}; @@ -1240,7 +1255,7 @@ struct HfTrackIndexSkimCreator { 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"}; // 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"}; @@ -1267,11 +1282,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}; // 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 + 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 std::array, 2>, kN2ProngDecays> arrMass2Prong{}; std::array, 2>, kN3ProngDecays> arrMass3Prong{}; // arrays of 2-prong and 3-prong cuts @@ -1339,12 +1354,15 @@ struct HfTrackIndexSkimCreator { arrMass3Prong[hf_cand_3prong::DecayType::XicToPKPi] = std::array{std::array{MassProton, MassKPlus, MassPiPlus}, std::array{MassPiPlus, MassKPlus, MassProton}}; + arrMass3Prong[hf_cand_3prong::DecayType::CdToDeKPi] = std::array{std::array{MassDeuteron, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassDeuteron}}; + // 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}; - binsPt3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi}; + cut3Prong = {config.cutsDplusToPiKPi, config.cutsLcToPKPi, config.cutsDsToKKPi, config.cutsXicToPKPi, config.cutsCdToDeKPi}; + binsPt3Prong = {config.binsPtDplusToPiKPi, config.binsPtLcToPKPi, config.binsPtDsToKKPi, config.binsPtXicToPKPi, config.binsPtCdToDeKPi}; df2.setPropagateToPCA(config.propagateToPCA); df2.setMaxR(config.maxR); @@ -1392,6 +1410,7 @@ struct HfTrackIndexSkimCreator { registry.add("hMassDsToKKPi", "D_{s}^{#plus} candidates;inv. mass (K K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); 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.}}}); // needed for PV refitting if (doprocess2And3ProngsWithPvRefit || doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt) { @@ -1617,11 +1636,13 @@ struct HfTrackIndexSkimCreator { // 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)) { - if ((iDecay3P == hf_cand_3prong::DecayType::LcToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::LcToPKPi)) || (iDecay3P == hf_cand_3prong::DecayType::XicToPKPi && !TESTBIT(isIdentifiedPidTrack0, ChannelsProtonPid::XicToPKPi))) { + + 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 ((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))) { 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))) { + 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))) { CLRBIT(whichHypo[iDecay3P], 1); } if (whichHypo[iDecay3P] == 0) { @@ -1632,7 +1653,6 @@ struct HfTrackIndexSkimCreator { continue; // no need to check further for this particle hypothesis } } - // pT const auto binPt = findBin(&binsPt3Prong[iDecay3P], pt); // return immediately if it is outside the defined pT bins @@ -1806,14 +1826,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>& outputScores, auto& isSelected) + void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecays - 1>& 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; ++iDecay3P) { + for (int iDecay3P{0}; iDecay3P < kN3ProngDecays - 1; ++iDecay3P) { if (TESTBIT(isSelected, iDecay3P) && hasMlModel3Prong[iDecay3P]) { bool isMlSel = false; if constexpr (UsePidForHfFiltersBdt) { @@ -2542,7 +2562,7 @@ struct HfTrackIndexSkimCreator { // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Pos, secondaryVertex3, pvRefitCoord3Prong2Pos1Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays> mlScores3Prongs; + std::array, kN3ProngDecays - 1> 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{}; @@ -2607,6 +2627,9 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } if (TESTBIT(whichHypo3Prong[iDecay3P], 1)) { @@ -2621,6 +2644,9 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } } @@ -2793,7 +2819,7 @@ struct HfTrackIndexSkimCreator { // 3-prong selections after secondary vertex applySelection3Prong(pVecCandProng3Neg, secondaryVertex3, pvRefitCoord3Prong1Pos2Neg, cutStatus3Prong, isSelected3ProngCand); - std::array, kN3ProngDecays> mlScores3Prongs{}; + std::array, kN3ProngDecays - 1> 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{}; @@ -2858,6 +2884,9 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } if (TESTBIT(whichHypo3Prong[iDecay3P], 1)) { @@ -2872,6 +2901,9 @@ struct HfTrackIndexSkimCreator { case hf_cand_3prong::DecayType::XicToPKPi: registry.fill(HIST("hMassXicToPKPi"), mass3Prong); break; + case hf_cand_3prong::DecayType::CdToDeKPi: + registry.fill(HIST("hMassCdToDeKPi"), mass3Prong); + break; } } } diff --git a/PWGHF/Utils/utilsPid.h b/PWGHF/Utils/utilsPid.h index 83307bc43d8..629db2a0325 100644 --- a/PWGHF/Utils/utilsPid.h +++ b/PWGHF/Utils/utilsPid.h @@ -31,6 +31,7 @@ enum HfProngSpecies : uint8_t { Pion = 0, Kaon, Proton, + Deuteron, NHfProngSpecies }; @@ -108,8 +109,16 @@ void fillProngPid(TTrack const& track, TCursor& rowPid) if (track.hasTOF()) { nSigTof = track.tofNSigmaPr(); } + } else if constexpr (SpecPid == HfProngSpecies::Deuteron) { + // deuteron PID + if (track.hasTPC()) { + nSigTpc = track.tpcNSigmaDe(); + } + if (track.hasTOF()) { + nSigTof = track.tofNSigmaDe(); + } } else { - LOG(fatal) << "Unsupported PID. Supported species in HF framework: HfProngSpecies::Pion, HfProngSpecies::Kaon, HfProngSpecies::Proton"; + LOG(fatal) << "Unsupported PID. Supported species in HF framework: HfProngSpecies::Pion, HfProngSpecies::Kaon, HfProngSpecies::Proton, HfProngSpecies::Deuteron"; } // fill candidate prong PID rows