Skip to content

Commit 7dcbd92

Browse files
committed
[PWGCF] Femto: Add D0 data model, builder and histogram manager
1 parent e041e77 commit 7dcbd92

7 files changed

Lines changed: 785 additions & 1 deletion

File tree

PWGCF/Femto/Core/charmHadronBuilder.h

Lines changed: 430 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// Copyright 2019-2025 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file charmHadronHistManager.h
13+
/// \brief histogram manager for charm hadron histograms
14+
/// \author Igor Ptak, WUT, igor.ptak.stud@pw.edu.pl
15+
16+
#ifndef PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_
17+
#define PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_
18+
19+
#include "PWGCF/Femto/Core/histManager.h"
20+
#include "PWGCF/Femto/Core/modes.h"
21+
#include "PWGCF/Femto/Core/trackHistManager.h"
22+
23+
#include <CommonConstants/MathConstants.h>
24+
#include <Framework/Configurable.h>
25+
#include <Framework/HistogramRegistry.h>
26+
#include <Framework/HistogramSpec.h>
27+
#include <Framework/Logger.h>
28+
29+
#include <TPDGCode.h>
30+
31+
#include <array>
32+
#include <cstddef>
33+
#include <map>
34+
#include <string>
35+
#include <string_view>
36+
#include <vector>
37+
38+
namespace o2::analysis::femto::charmhadronhistmanager
39+
{
40+
enum CharmHadronHist {
41+
kPt,
42+
kEta,
43+
kPhi,
44+
kMass,
45+
kSign,
46+
kPtVsMass,
47+
48+
kCharmHadronHistLast
49+
};
50+
51+
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
52+
#define CHARMHADRON_DEFAULT_BINNING(defaultMassMin, defaultMassMax) \
53+
o2::framework::ConfigurableAxis pt{"pt", {{600, 0, 6}}, "Pt"}; \
54+
o2::framework::ConfigurableAxis eta{"eta", {{300, -1.5, 1.5}}, "Eta"}; \
55+
o2::framework::ConfigurableAxis phi{"phi", {{720, 0, 1.f * o2::constants::math::TwoPI}}, "Phi"}; \
56+
o2::framework::ConfigurableAxis mass{"mass", {{200, (defaultMassMin), (defaultMassMax)}}, "Mass"}; \
57+
o2::framework::ConfigurableAxis sign{"sign", {{3, -1.5, 1.5}}, "Sign"}; \
58+
o2::framework::ConfigurableAxis charmHadrons{"charmHadrons", {{8001, -4000.5, 4000.5}}, "MC ONLY: CharmHadrons codes of reconstructed D0s"};
59+
60+
template <auto& Prefix>
61+
struct ConfD0Binning : o2::framework::ConfigurableGroup {
62+
std::string prefix = Prefix;
63+
CHARMHADRON_DEFAULT_BINNING(1.7, 2.0)
64+
};
65+
66+
#undef CHARMHADRON_DEFAULT_BINNING
67+
68+
constexpr const char PrefixD0Binning1[] = "D0Binning1";
69+
using ConfD0Binning1 = ConfD0Binning<PrefixD0Binning1>;
70+
71+
72+
// must be in sync with enum CharmHadronHist
73+
// the enum gives the correct index in the array
74+
constexpr std::array<histmanager::HistInfo<CharmHadronHist>, kCharmHadronHistLast> HistTable = {
75+
{{kPt, o2::framework::HistType::kTH1F, "hPt", "Transverse Momentum; p_{T} (GeV/#it{c}); Entries"},
76+
{kEta, o2::framework::HistType::kTH1F, "hEta", "Pseudorapdity; #eta; Entries"},
77+
{kPhi, o2::framework::HistType::kTH1F, "hPhi", "Azimuthal angle; #varphi; Entries"},
78+
{kMass, o2::framework::HistType::kTH1F, "hMass", "Invariant Mass; m_{Inv} (GeV/#it{c}^{2}); Entries"},
79+
{kSign, o2::framework::HistType::kTH1F, "hSign", "Sign (-1 -> D0bar, +1 -> D0); sign; Entries"},
80+
{kPtVsMass, o2::framework::HistType::kTH2F, "hPtVsMass", "Transverse momentum vs invariant mass; p_{T} (GeV/#it{c}); m_{Inv} (GeV/#it{c}^{2})"}},
81+
};
82+
83+
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
84+
#define CHARMHADRON_HIST_ANALYSIS_MAP(conf) \
85+
{kPt, {(conf).pt}}, \
86+
{kEta, {(conf).eta}}, \
87+
{kPhi, {(conf).phi}}, \
88+
{kMass, {(conf).mass}}, \
89+
{kSign, {(conf).sign}}, \
90+
{kPtVsMass, {(conf).pt, (conf).mass}},
91+
92+
template <typename T>
93+
auto makeD0HistSpecMap(const T& confBinningAnalysis)
94+
{
95+
return std::map<CharmHadronHist, std::vector<o2::framework::AxisSpec>>{
96+
CHARMHADRON_HIST_ANALYSIS_MAP(confBinningAnalysis)};
97+
}
98+
99+
#undef CHARMHADRON_HIST_ANALYSIS_MAP
100+
101+
// prefixes for the output directories in the histogram registry
102+
constexpr char PrefixD01[] = "D01/";
103+
constexpr char PrefixD02[] = "D02/";
104+
105+
constexpr std::string_view AnalysisDir = "Analysis/";
106+
107+
/// \class CharmHadronHistManager
108+
/// \brief Class for histogramming charm hadron properties
109+
template <auto& charmHadronPrefix,
110+
auto& prong0Prefix,
111+
auto& prong1Prefix,
112+
modes::CharmHadron charmHadron>
113+
class CharmHadronHistManager
114+
{
115+
public:
116+
CharmHadronHistManager() = default;
117+
~CharmHadronHistManager() = default;
118+
119+
// init for analysis
120+
template <modes::Mode mode, typename T>
121+
void init(o2::framework::HistogramRegistry* registry,
122+
std::map<CharmHadronHist, std::vector<o2::framework::AxisSpec>> const& CharmHadronSpecs,
123+
T const& ConfCharmHadronSelection,
124+
std::map<trackhistmanager::TrackHist, std::vector<o2::framework::AxisSpec>> const& Prong0Specs,
125+
std::map<trackhistmanager::TrackHist, std::vector<o2::framework::AxisSpec>> const& Prong1Specs)
126+
{
127+
mHistogramRegistry = registry;
128+
mPdgCode = std::abs(ConfCharmHadronSelection.pdgCodeAbs.value);
129+
130+
// in PWGHF the prong charge is fixed by the reconstruction: prong0 is always the positive
131+
// daughter, prong1 the negative one. The D0/D0bar hypothesis only swaps which prong is the
132+
// pion and which is the kaon, not their charge.
133+
int prong0PdgCodeAbs = 0;
134+
int prong1PdgCodeAbs = 0;
135+
const int absCharge = 1;
136+
const int signPlus = 1;
137+
const int signMinus = -1;
138+
139+
constexpr int PdgD0 = 421; // not defined in ROOT's TPDGCode.h
140+
if (mPdgCode == PdgD0) {
141+
if (ConfCharmHadronSelection.sign.value > 0) {
142+
// D0 -> pi+ K-
143+
prong0PdgCodeAbs = std::abs(PDG_t::kPiPlus);
144+
prong1PdgCodeAbs = std::abs(PDG_t::kKMinus);
145+
} else {
146+
// D0bar -> K+ pi-
147+
mPdgCode = -1 * mPdgCode; // switch sign for D0bar
148+
prong0PdgCodeAbs = std::abs(PDG_t::kKPlus);
149+
prong1PdgCodeAbs = std::abs(PDG_t::kPiMinus);
150+
}
151+
} else {
152+
LOG(fatal) << "PDG code for charm hadron has to be D0 (421)";
153+
}
154+
155+
mProng0Manager.template init<mode>(registry, Prong0Specs, absCharge, signPlus, prong0PdgCodeAbs);
156+
mProng1Manager.template init<mode>(registry, Prong1Specs, absCharge, signMinus, prong1PdgCodeAbs);
157+
158+
if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) {
159+
this->initAnalysis(CharmHadronSpecs);
160+
}
161+
}
162+
163+
template <modes::Mode mode, typename T1, typename T2>
164+
void fill(T1 const& charmHadronCandidate, T2 const& tracks)
165+
{
166+
auto prong0 = tracks.rawIteratorAt(charmHadronCandidate.posDauId() - tracks.offset());
167+
mProng0Manager.template fill<mode>(prong0, tracks);
168+
auto prong1 = tracks.rawIteratorAt(charmHadronCandidate.negDauId() - tracks.offset());
169+
mProng1Manager.template fill<mode>(prong1, tracks);
170+
171+
if constexpr (modes::isFlagSet(mode, modes::Mode::kReco)) {
172+
this->fillAnalysis(charmHadronCandidate);
173+
}
174+
}
175+
176+
private:
177+
void initAnalysis(std::map<CharmHadronHist, std::vector<o2::framework::AxisSpec>> const& CharmHadronSpecs)
178+
{
179+
std::string analysisDir = std::string(charmHadronPrefix) + std::string(AnalysisDir);
180+
mHistogramRegistry->add(analysisDir + getHistNameV2(kPt, HistTable), getHistDesc(kPt, HistTable), getHistType(kPt, HistTable), {CharmHadronSpecs.at(kPt)});
181+
mHistogramRegistry->add(analysisDir + getHistNameV2(kEta, HistTable), getHistDesc(kEta, HistTable), getHistType(kEta, HistTable), {CharmHadronSpecs.at(kEta)});
182+
mHistogramRegistry->add(analysisDir + getHistNameV2(kPhi, HistTable), getHistDesc(kPhi, HistTable), getHistType(kPhi, HistTable), {CharmHadronSpecs.at(kPhi)});
183+
mHistogramRegistry->add(analysisDir + getHistNameV2(kMass, HistTable), getHistDesc(kMass, HistTable), getHistType(kMass, HistTable), {CharmHadronSpecs.at(kMass)});
184+
mHistogramRegistry->add(analysisDir + getHistNameV2(kSign, HistTable), getHistDesc(kSign, HistTable), getHistType(kSign, HistTable), {CharmHadronSpecs.at(kSign)});
185+
mHistogramRegistry->add(analysisDir + getHistNameV2(kPtVsMass, HistTable), getHistDesc(kPtVsMass, HistTable), getHistType(kPtVsMass, HistTable), {CharmHadronSpecs.at(kPtVsMass)});
186+
}
187+
188+
template <typename T>
189+
void fillAnalysis(T const& charmHadronCandidate)
190+
{
191+
mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPt, HistTable)), charmHadronCandidate.pt());
192+
mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kEta, HistTable)), charmHadronCandidate.eta());
193+
mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPhi, HistTable)), charmHadronCandidate.phi());
194+
mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kMass, HistTable)), charmHadronCandidate.mass());
195+
mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kSign, HistTable)), charmHadronCandidate.sign());
196+
mHistogramRegistry->fill(HIST(charmHadronPrefix) + HIST(AnalysisDir) + HIST(getHistName(kPtVsMass, HistTable)), charmHadronCandidate.pt(), charmHadronCandidate.mass());
197+
}
198+
199+
o2::framework::HistogramRegistry* mHistogramRegistry = nullptr;
200+
int mPdgCode = 0;
201+
202+
trackhistmanager::TrackHistManager<prong0Prefix> mProng0Manager;
203+
trackhistmanager::TrackHistManager<prong1Prefix> mProng1Manager;
204+
};
205+
}; // namespace o2::analysis::femto::charmhadronhistmanager
206+
#endif // PWGCF_FEMTO_CORE_CHARMHADRONHISTMANAGER_H_

PWGCF/Femto/Core/dataTypes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ using ParticleType = uint16_t;
5757
using MomentumType = uint16_t;
5858
using TransverseMassType = uint16_t;
5959

60+
// datatype for charm hadrons
61+
using CharmHadronMaskType = uint32_t;
62+
using CharmHadronType = uint16_t;
63+
6064
} // namespace o2::analysis::femto::datatypes
6165

6266
#endif // PWGCF_FEMTO_CORE_DATATYPES_H_

PWGCF/Femto/Core/modes.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ enum class Track : o2::analysis::femto::datatypes::TrackType {
136136
kV0Daughter,
137137
kCascadeBachelor,
138138
kResonanceDaughter,
139-
kKinkDaughter
139+
kKinkDaughter,
140+
kCharmDaughter
140141
};
141142

142143
enum class V0 : o2::analysis::femto::datatypes::V0Type {
@@ -163,5 +164,12 @@ enum class TwoTrackResonance : o2::analysis::femto::datatypes::TwoTrackResonance
163164
kKstar0Bar
164165
};
165166

167+
enum class CharmHadron : o2::analysis::femto::datatypes::CharmHadronType {
168+
kD0,
169+
kD0Bar,
170+
kDplus,
171+
kLc
172+
};
173+
166174
}; // namespace o2::analysis::femto::modes
167175
#endif // PWGCF_FEMTO_CORE_MODES_H_

PWGCF/Femto/Core/partitions.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,22 @@
163163
(o2::aod::femtobase::stored::mass < (selection).massMax) && \
164164
ncheckbit(o2::aod::femtokinks::mask, (selection).mask)
165165

166+
// partition for D0
167+
// sign of signedPt encodes the hypothesis: D0 (+) / D0bar (-)
168+
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
169+
#define MAKE_D0_PARTITION(selection) \
170+
ifnode((selection).sign.node() != 0, \
171+
ifnode((selection).sign.node() > 0, o2::aod::femtobase::stored::signedPt > 0.f, o2::aod::femtobase::stored::signedPt < 0.f), true) && \
172+
(nabs(o2::aod::femtobase::stored::signedPt) > (selection).ptMin) && \
173+
(nabs(o2::aod::femtobase::stored::signedPt) < (selection).ptMax) && \
174+
(o2::aod::femtobase::stored::eta > (selection).etaMin) && \
175+
(o2::aod::femtobase::stored::eta < (selection).etaMax) && \
176+
(o2::aod::femtobase::stored::phi > (selection).phiMin) && \
177+
(o2::aod::femtobase::stored::phi < (selection).phiMax) && \
178+
(o2::aod::femtobase::stored::mass > (selection).massMin) && \
179+
(o2::aod::femtobase::stored::mass < (selection).massMax) && \
180+
ncheckbit(o2::aod::femtocharmhadrons::mask, (selection).mask)
181+
166182
// macros for mc collisions (mc only)
167183
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
168184
#define MAKE_MC_COLLISION_FILTER(selection) \

PWGCF/Femto/DataModel/FemtoTables.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,5 +1160,76 @@ DECLARE_SOA_TABLE(FMcMotherLabels, "AOD", "FMCMOTHERLABEL",
11601160
femtolabels::FMcMotherId,
11611161
femtolabels::FMcPartMothId);
11621162

1163+
namespace femtocharmhadrons
1164+
{
1165+
// bitmask column
1166+
DECLARE_SOA_COLUMN(Mask, mask, o2::analysis::femto::datatypes::CharmHadronMaskType); //! selection bitmask
1167+
1168+
// daughter links - row indices into the femto TRACK table
1169+
DECLARE_SOA_INDEX_COLUMN_FULL(PosDau, posDau, int32_t, FTracks, "_PosDau"); //! + prong (pion in D0)
1170+
DECLARE_SOA_INDEX_COLUMN_FULL(NegDau, negDau, int32_t, FTracks, "_NegDau"); //! - prong (kaon in D0)
1171+
1172+
// QA/debug columns
1173+
DECLARE_SOA_COLUMN(MassD0, massD0, float); //! Kpi-hypothesis mass
1174+
DECLARE_SOA_COLUMN(MassD0bar, massD0bar, float); //! piK-hypothesis mass
1175+
DECLARE_SOA_COLUMN(Cpa, cpa, float);
1176+
DECLARE_SOA_COLUMN(CpaXY, cpaXY, float);
1177+
DECLARE_SOA_COLUMN(DecayLength, decayLength, float);
1178+
DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float);
1179+
DECLARE_SOA_COLUMN(ImpactParameterProduct, impactParameterProduct, float); //! d0*d0 of the two prongs
1180+
DECLARE_SOA_COLUMN(CosThetaStar, cosThetaStar, float);
1181+
// ML BDT scores: [0] background, [1] prompt (D0 from c), [2] non-prompt (D0 from b decay)
1182+
DECLARE_SOA_COLUMN(MlProbD0Bkg, mlProbD0Bkg, float); //! D0 hypothesis: background score
1183+
DECLARE_SOA_COLUMN(MlProbD0Prompt, mlProbD0Prompt, float); //! D0 hypothesis: prompt score
1184+
DECLARE_SOA_COLUMN(MlProbD0NonPrompt, mlProbD0NonPrompt, float); //! D0 hypothesis: non-prompt score
1185+
DECLARE_SOA_COLUMN(MlProbD0barBkg, mlProbD0barBkg, float); //! D0bar hypothesis: background
1186+
DECLARE_SOA_COLUMN(MlProbD0barPrompt, mlProbD0barPrompt, float); //! D0bar hypothesis: prompt
1187+
DECLARE_SOA_COLUMN(MlProbD0barNonPrompt, mlProbD0barNonPrompt, float); //! D0bar hypothesis: non-prompt
1188+
DECLARE_SOA_COLUMN(IsSelD0, isSelD0, int8_t); //! PWGHF verdict (cross-check)
1189+
DECLARE_SOA_COLUMN(IsSelD0bar, isSelD0bar, int8_t); //! PWGHF verdict (cross-check)
1190+
} // namespace femtocharmhadrons
1191+
1192+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0s_001, "FD0", 1, //! femto D0/D0bar (kinematics only)
1193+
o2::soa::Index<>,
1194+
femtobase::stored::FColId,
1195+
femtobase::stored::SignedPt, //! sign encodes D0(+)/D0bar(-)
1196+
femtobase::stored::Eta,
1197+
femtobase::stored::Phi,
1198+
femtobase::stored::Mass, //! mass of the accepted hypothesis
1199+
femtocharmhadrons::PosDauId,
1200+
femtocharmhadrons::NegDauId,
1201+
femtobase::dynamic::Sign<femtobase::stored::SignedPt>,
1202+
femtobase::dynamic::Pt<femtobase::stored::SignedPt>,
1203+
femtobase::dynamic::P<femtobase::stored::SignedPt, femtobase::stored::Eta>,
1204+
femtobase::dynamic::Px<femtobase::stored::SignedPt, femtobase::stored::Phi>,
1205+
femtobase::dynamic::Py<femtobase::stored::SignedPt, femtobase::stored::Phi>,
1206+
femtobase::dynamic::Pz<femtobase::stored::SignedPt, femtobase::stored::Eta>,
1207+
femtobase::dynamic::Theta<femtobase::stored::Eta>);
1208+
using FD0s = FD0s_001;
1209+
using StoredFD0s = StoredFD0s_001;
1210+
1211+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Masks_001, "FD0MASK", 1, //! femto D0 selection bitmask
1212+
femtocharmhadrons::Mask);
1213+
using FD0Masks = FD0Masks_001;
1214+
using StoredFD0Masks = StoredFD0Masks_001;
1215+
1216+
DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Extras_001, "FD0EXTRA", 1, //! femto D0 QA / debug
1217+
femtocharmhadrons::MassD0, // BOTH hypotheses, always
1218+
femtocharmhadrons::MassD0bar, // (main table only has the accepted one)
1219+
femtocharmhadrons::Cpa,
1220+
femtocharmhadrons::CpaXY,
1221+
femtocharmhadrons::DecayLength,
1222+
femtocharmhadrons::DecayLengthXY,
1223+
femtocharmhadrons::ImpactParameterProduct,
1224+
femtocharmhadrons::CosThetaStar,
1225+
femtocharmhadrons::MlProbD0Bkg,
1226+
femtocharmhadrons::MlProbD0Prompt,
1227+
femtocharmhadrons::MlProbD0NonPrompt,
1228+
femtocharmhadrons::MlProbD0barBkg,
1229+
femtocharmhadrons::MlProbD0barPrompt,
1230+
femtocharmhadrons::MlProbD0barNonPrompt,
1231+
femtocharmhadrons::IsSelD0, // raw PWGHF verdicts
1232+
femtocharmhadrons::IsSelD0bar);
1233+
using FD0Extras = FD0Extras_001;
11631234
} // namespace o2::aod
11641235
#endif // PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_

0 commit comments

Comments
 (0)