Skip to content

Commit f0c0841

Browse files
authored
PWGHF: Implement tree creator for B0 (#2800)
1 parent b6605f6 commit f0c0841

2 files changed

Lines changed: 386 additions & 0 deletions

File tree

PWGHF/TableProducer/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ o2physics_add_dpl_workflow(candidate-selector-xicc-to-p-k-pi-pi
137137

138138
# Tree creators
139139

140+
o2physics_add_dpl_workflow(tree-creator-b0-to-d-pi
141+
SOURCES treeCreatorB0ToDPi.cxx
142+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
143+
COMPONENT_NAME Analysis)
144+
140145
o2physics_add_dpl_workflow(tree-creator-bplus-to-d0-pi
141146
SOURCES treeCreatorBplusToD0Pi.cxx
142147
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore
Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
// Copyright 2019-2020 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 treeCreatorB0ToDPi.cxx
13+
/// \brief Writer of B0 → D- π+ candidates in the form of flat tables to be stored in TTrees.
14+
/// Intended for debug, local optimization of analysis on small samples or ML training.
15+
/// In this file are defined and filled the output tables
16+
///
17+
/// \author Alexandre Bigot <alexandre.bigot@cern.ch>, IPHC Strasbourg
18+
19+
#include "Framework/AnalysisTask.h"
20+
#include "Framework/runDataProcessing.h"
21+
22+
#include "PWGHF/DataModel/CandidateReconstructionTables.h"
23+
#include "PWGHF/DataModel/CandidateSelectionTables.h"
24+
25+
using namespace o2;
26+
using namespace o2::framework;
27+
using namespace o2::framework::expressions;
28+
using namespace o2::aod::hf_cand_b0;
29+
using namespace o2::aod::hf_sel_candidate_b0;
30+
31+
namespace o2::aod
32+
{
33+
namespace full
34+
{
35+
DECLARE_SOA_COLUMN(RSecondaryVertex, rSecondaryVertex, float); //! Radius of secondary vertex (cm)
36+
DECLARE_SOA_COLUMN(PtProng0, ptProng0, float); //! Transverse momentum of prong0 (GeV/c)
37+
DECLARE_SOA_COLUMN(PProng0, pProng0, float); //! Momentum of prong0 (GeV/c)
38+
DECLARE_SOA_COLUMN(ImpactParameterNormalised0, impactParameterNormalised0, float); //! Normalised impact parameter of prong0
39+
DECLARE_SOA_COLUMN(PtProng1, ptProng1, float); //! Transverse momentum of prong1 (GeV/c)
40+
DECLARE_SOA_COLUMN(PProng1, pProng1, float); //! Momentum of prong1 (in GeV/c)
41+
DECLARE_SOA_COLUMN(ImpactParameterNormalised1, impactParameterNormalised1, float); //! Normalised impact parameter of prong1
42+
DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int); //! Selection flag of candidate (output of candidateSelector)
43+
DECLARE_SOA_COLUMN(M, m, float); //! Invariant mass of candidate (GeV/c2)
44+
DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c)
45+
DECLARE_SOA_COLUMN(P, p, float); //! Momentum of candidate (GeV/c)
46+
DECLARE_SOA_COLUMN(Y, y, float); //! Rapidity of candidate
47+
DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity of candidate
48+
DECLARE_SOA_COLUMN(Phi, phi, float); //! Azimuth angle of candidate
49+
DECLARE_SOA_COLUMN(E, e, float); //! Energy of candidate (GeV)
50+
DECLARE_SOA_COLUMN(NSigTpcPi1, nSigTpcPi1, float); //! TPC Nsigma separation for prong1 with pion mass hypothesis
51+
DECLARE_SOA_COLUMN(NSigTofPi1, nSigTofPi1, float); //! TOF Nsigma separation for prong1 with pion mass hypothesis
52+
DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! Decay length of candidate (cm)
53+
DECLARE_SOA_COLUMN(DecayLengthXY, decayLengthXY, float); //! Transverse decay length of candidate (cm)
54+
DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! Normalised decay length of candidate
55+
DECLARE_SOA_COLUMN(DecayLengthXYNormalised, decayLengthXYNormalised, float); //! Normalised transverse decay length of candidate
56+
DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine pointing angle of candidate
57+
DECLARE_SOA_COLUMN(CpaXY, cpaXY, float); //! Cosine pointing angle of candidate in transverse plane
58+
DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs
59+
DECLARE_SOA_COLUMN(Ct, ct, float); //! Proper lifetime times c of candidate (cm)
60+
// Events
61+
DECLARE_SOA_COLUMN(IsEventReject, isEventReject, int); //! Event rejection flag
62+
DECLARE_SOA_COLUMN(RunNumber, runNumber, int); //! Run number
63+
} // namespace full
64+
65+
DECLARE_SOA_TABLE(HfCandB0Lite, "AOD", "HFCANDB0Lite",
66+
hf_cand::Chi2PCA,
67+
full::DecayLength,
68+
full::DecayLengthXY,
69+
full::DecayLengthNormalised,
70+
full::DecayLengthXYNormalised,
71+
full::PtProng0,
72+
full::PtProng1,
73+
hf_cand::ImpactParameter0,
74+
hf_cand::ImpactParameter1,
75+
full::NSigTpcPi1,
76+
full::NSigTofPi1,
77+
full::CandidateSelFlag,
78+
full::M,
79+
full::Pt,
80+
full::Cpa,
81+
full::CpaXY,
82+
full::MaxNormalisedDeltaIP,
83+
full::Eta,
84+
full::Phi,
85+
full::Y,
86+
hf_cand_3prong::FlagMcMatchRec,
87+
hf_cand_3prong::OriginMcRec);
88+
89+
DECLARE_SOA_TABLE(HfCandB0Full, "AOD", "HFCANDB0Full",
90+
collision::BCId,
91+
collision::NumContrib,
92+
collision::PosX,
93+
collision::PosY,
94+
collision::PosZ,
95+
hf_cand::XSecondaryVertex,
96+
hf_cand::YSecondaryVertex,
97+
hf_cand::ZSecondaryVertex,
98+
hf_cand::ErrorDecayLength,
99+
hf_cand::ErrorDecayLengthXY,
100+
hf_cand::Chi2PCA,
101+
full::RSecondaryVertex,
102+
full::DecayLength,
103+
full::DecayLengthXY,
104+
full::DecayLengthNormalised,
105+
full::DecayLengthXYNormalised,
106+
full::ImpactParameterNormalised0,
107+
full::PtProng0,
108+
full::PProng0,
109+
full::ImpactParameterNormalised1,
110+
full::PtProng1,
111+
full::PProng1,
112+
hf_cand::PxProng0,
113+
hf_cand::PyProng0,
114+
hf_cand::PzProng0,
115+
hf_cand::PxProng1,
116+
hf_cand::PyProng1,
117+
hf_cand::PzProng1,
118+
hf_cand::ImpactParameter0,
119+
hf_cand::ImpactParameter1,
120+
hf_cand::ErrorImpactParameter0,
121+
hf_cand::ErrorImpactParameter1,
122+
full::NSigTpcPi1,
123+
full::NSigTofPi1,
124+
full::CandidateSelFlag,
125+
full::M,
126+
full::Pt,
127+
full::P,
128+
full::Cpa,
129+
full::CpaXY,
130+
full::MaxNormalisedDeltaIP,
131+
full::Ct,
132+
full::Eta,
133+
full::Phi,
134+
full::Y,
135+
full::E,
136+
hf_cand_3prong::FlagMcMatchRec,
137+
hf_cand_3prong::OriginMcRec);
138+
139+
DECLARE_SOA_TABLE(HfCandB0FullEvents, "AOD", "HFCANDB0FullE",
140+
collision::BCId,
141+
collision::NumContrib,
142+
collision::PosX,
143+
collision::PosY,
144+
collision::PosZ,
145+
full::IsEventReject,
146+
full::RunNumber);
147+
148+
DECLARE_SOA_TABLE(HfCandB0FullParticles, "AOD", "HFCANDB0FullP",
149+
collision::BCId,
150+
full::Pt,
151+
full::Eta,
152+
full::Phi,
153+
full::Y,
154+
hf_cand_3prong::FlagMcMatchRec,
155+
hf_cand_3prong::OriginMcGen);
156+
} // namespace o2::aod
157+
158+
/// Writes the full information in an output TTree
159+
struct HfTreeCreatorB0ToDPi {
160+
Produces<o2::aod::HfCandB0Full> rowCandidateFull;
161+
Produces<o2::aod::HfCandB0FullEvents> rowCandidateFullEvents;
162+
Produces<o2::aod::HfCandB0FullParticles> rowCandidateFullParticles;
163+
Produces<o2::aod::HfCandB0Lite> rowCandidateLite;
164+
165+
Configurable<int> selectionFlagB0{"selectionB0", 1, "Selection Flag for B0"};
166+
Configurable<bool> fillCandidateLiteTable{"fillCandidateLiteTable", false, "Switch to fill lite table with candidate properties"};
167+
168+
// parameters for production of training samples
169+
Configurable<bool> fillOnlySignal{"fillOnlySignal", false, "Flag to fill derived tables with signal for ML trainings"};
170+
Configurable<bool> fillOnlyBackground{"fillOnlyBackground", false, "Flag to fill derived tables with background for ML trainings"};
171+
Configurable<float> downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"};
172+
Configurable<float> ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"};
173+
174+
using SelectedCandidatesMc = soa::Filtered<soa::Join<aod::HfCandB0, aod::HfCandB0McRec, aod::HfSelB0ToDPi>>;
175+
176+
Filter filterSelectCandidates = aod::hf_sel_candidate_b0::isSelB0ToDPi >= selectionFlagB0;
177+
178+
Partition<SelectedCandidatesMc> recSig = nabs(aod::hf_cand_b0::flagMcMatchRec) == (int8_t)BIT(aod::hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi);
179+
Partition<SelectedCandidatesMc> recBg = nabs(aod::hf_cand_b0::flagMcMatchRec) != (int8_t)BIT(aod::hf_cand_b0::DecayTypeMc::B0ToDplusPiToPiKPiPi);
180+
181+
void init(InitContext const&)
182+
{
183+
}
184+
185+
template <typename T>
186+
void fillEvent(const T& collision, int isEventReject, int runNumber)
187+
{
188+
rowCandidateFullEvents(
189+
collision.bcId(),
190+
collision.numContrib(),
191+
collision.posX(),
192+
collision.posY(),
193+
collision.posZ(),
194+
isEventReject,
195+
runNumber);
196+
}
197+
198+
template <bool doMc = false, typename T, typename U>
199+
void fillCandidateTable(const T& candidate, const U& prong1)
200+
{
201+
int8_t flagMc = 0;
202+
int8_t originMc = 0;
203+
if constexpr (doMc) {
204+
flagMc = candidate.flagMcMatchRec();
205+
originMc = candidate.originMcRec();
206+
}
207+
if (fillCandidateLiteTable) {
208+
rowCandidateLite(
209+
candidate.chi2PCA(),
210+
candidate.decayLength(),
211+
candidate.decayLengthXY(),
212+
candidate.decayLengthNormalised(),
213+
candidate.decayLengthXYNormalised(),
214+
candidate.ptProng0(),
215+
candidate.ptProng1(),
216+
candidate.impactParameter0(),
217+
candidate.impactParameter1(),
218+
prong1.tpcNSigmaPi(),
219+
prong1.tofNSigmaPi(),
220+
candidate.isSelB0ToDPi(),
221+
invMassB0ToDPi(candidate),
222+
candidate.pt(),
223+
candidate.cpa(),
224+
candidate.cpaXY(),
225+
candidate.maxNormalisedDeltaIP(),
226+
candidate.eta(),
227+
candidate.phi(),
228+
yB0(candidate),
229+
flagMc,
230+
originMc);
231+
} else {
232+
rowCandidateFull(
233+
prong1.collision().bcId(),
234+
prong1.collision().numContrib(),
235+
candidate.posX(),
236+
candidate.posY(),
237+
candidate.posZ(),
238+
candidate.xSecondaryVertex(),
239+
candidate.ySecondaryVertex(),
240+
candidate.zSecondaryVertex(),
241+
candidate.errorDecayLength(),
242+
candidate.errorDecayLengthXY(),
243+
candidate.chi2PCA(),
244+
candidate.rSecondaryVertex(),
245+
candidate.decayLength(),
246+
candidate.decayLengthXY(),
247+
candidate.decayLengthNormalised(),
248+
candidate.decayLengthXYNormalised(),
249+
candidate.impactParameterNormalised0(),
250+
candidate.ptProng0(),
251+
RecoDecay::p(candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0()),
252+
candidate.impactParameterNormalised1(),
253+
candidate.ptProng1(),
254+
RecoDecay::p(candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1()),
255+
candidate.pxProng0(),
256+
candidate.pyProng0(),
257+
candidate.pzProng0(),
258+
candidate.pxProng1(),
259+
candidate.pyProng1(),
260+
candidate.pzProng1(),
261+
candidate.impactParameter0(),
262+
candidate.impactParameter1(),
263+
candidate.errorImpactParameter0(),
264+
candidate.errorImpactParameter1(),
265+
prong1.tpcNSigmaPi(),
266+
prong1.tofNSigmaPi(),
267+
candidate.isSelB0ToDPi(),
268+
invMassB0ToDPi(candidate),
269+
candidate.pt(),
270+
candidate.p(),
271+
candidate.cpa(),
272+
candidate.cpaXY(),
273+
candidate.maxNormalisedDeltaIP(),
274+
ctB0(candidate),
275+
candidate.eta(),
276+
candidate.phi(),
277+
yB0(candidate),
278+
eB0(candidate),
279+
flagMc,
280+
originMc);
281+
}
282+
}
283+
284+
void processData(aod::Collisions const& collisions,
285+
soa::Filtered<soa::Join<aod::HfCandB0, aod::HfSelB0ToDPi>> const& candidates,
286+
aod::BigTracksPID const&)
287+
{
288+
// Filling event properties
289+
rowCandidateFullEvents.reserve(collisions.size());
290+
for (auto const& collision : collisions) {
291+
fillEvent(collision, 0, 1);
292+
}
293+
294+
// Filling candidate properties
295+
rowCandidateFull.reserve(candidates.size());
296+
if (fillCandidateLiteTable) {
297+
rowCandidateLite.reserve(candidates.size());
298+
}
299+
for (auto const& candidate : candidates) {
300+
if (fillOnlyBackground) {
301+
float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000);
302+
if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) {
303+
continue;
304+
}
305+
}
306+
auto prong1 = candidate.prong1_as<aod::BigTracksPID>();
307+
fillCandidateTable(candidate, prong1);
308+
}
309+
}
310+
311+
PROCESS_SWITCH(HfTreeCreatorB0ToDPi, processData, "Process data", true);
312+
313+
void processMc(aod::Collisions const& collisions,
314+
aod::McCollisions const&,
315+
SelectedCandidatesMc const& candidates,
316+
soa::Join<aod::McParticles, aod::HfCandB0McGen> const& particles,
317+
aod::BigTracksPID const&)
318+
{
319+
// Filling event properties
320+
rowCandidateFullEvents.reserve(collisions.size());
321+
for (auto const& collision : collisions) {
322+
fillEvent(collision, 0, 1);
323+
}
324+
325+
// Filling candidate properties
326+
if (fillOnlySignal) {
327+
rowCandidateFull.reserve(recSig.size());
328+
if (fillCandidateLiteTable) {
329+
rowCandidateLite.reserve(recSig.size());
330+
}
331+
for (const auto& candidate : recSig) {
332+
auto prong1 = candidate.prong1_as<aod::BigTracksPID>();
333+
fillCandidateTable<true>(candidate, prong1);
334+
}
335+
} else if (fillOnlyBackground) {
336+
rowCandidateFull.reserve(recBg.size());
337+
if (fillCandidateLiteTable) {
338+
rowCandidateLite.reserve(recBg.size());
339+
}
340+
for (const auto& candidate : recBg) {
341+
float pseudoRndm = candidate.ptProng1() * 1000. - (int64_t)(candidate.ptProng1() * 1000);
342+
if (candidate.pt() < ptMaxForDownSample && pseudoRndm >= downSampleBkgFactor) {
343+
continue;
344+
}
345+
auto prong1 = candidate.prong1_as<aod::BigTracksPID>();
346+
fillCandidateTable<true>(candidate, prong1);
347+
}
348+
} else {
349+
rowCandidateFull.reserve(candidates.size());
350+
if (fillCandidateLiteTable) {
351+
rowCandidateLite.reserve(candidates.size());
352+
}
353+
for (const auto& candidate : candidates) {
354+
auto prong1 = candidate.prong1_as<aod::BigTracksPID>();
355+
fillCandidateTable<true>(candidate, prong1);
356+
}
357+
}
358+
359+
// Filling particle properties
360+
rowCandidateFullParticles.reserve(particles.size());
361+
for (auto const& particle : particles) {
362+
if (TESTBIT(std::abs(particle.flagMcMatchGen()), DecayTypeMc::B0ToDplusPiToPiKPiPi)) {
363+
rowCandidateFullParticles(
364+
particle.mcCollision().bcId(),
365+
particle.pt(),
366+
particle.eta(),
367+
particle.phi(),
368+
RecoDecay::y(array{particle.px(), particle.py(), particle.pz()}, RecoDecay::getMassPDG(particle.pdgCode())),
369+
particle.flagMcMatchGen(),
370+
particle.originMcGen());
371+
}
372+
}
373+
}
374+
375+
PROCESS_SWITCH(HfTreeCreatorB0ToDPi, processMc, "Process MC", false);
376+
};
377+
378+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
379+
{
380+
return WorkflowSpec{adaptAnalysisTask<HfTreeCreatorB0ToDPi>(cfgc)};
381+
}

0 commit comments

Comments
 (0)