Skip to content

Commit ba6bf39

Browse files
fchinuMarcellocostialibuild
authored
[PWGHF] Add task for studies on PID variables (#8617)
Co-authored-by: marcellocosti <marcellodicostanzo00@gmail.com> Co-authored-by: ALICE Action Bot <alibuild@cern.ch> Co-authored-by: Marcellocosti <96481191+Marcellocosti@users.noreply.github.com>
1 parent fbbd171 commit ba6bf39

File tree

2 files changed

+299
-0
lines changed

2 files changed

+299
-0
lines changed

PWGHF/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,8 @@ o2physics_add_dpl_workflow(task-mc-validation
4343
# SOURCES taskSelOptimisation.cxx
4444
# PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
4545
# COMPONENT_NAME Analysis)
46+
47+
o2physics_add_dpl_workflow(pid-studies
48+
SOURCES pidStudies.cxx
49+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore
50+
COMPONENT_NAME Analysis)

PWGHF/Tasks/pidStudies.cxx

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
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 pidStudies.cxx
13+
/// \brief task for studies of PID performance
14+
///
15+
/// \author Fabrizio Chinu <fabrizio.chinu@cern.ch>, Università and INFN Torino
16+
/// \author Stefano Politanò <stefano.politano@cern.ch>, INFN Torino
17+
/// \author Marcello Di Costanzo <marcello.di.costanzo@cern.ch>, Politecnico and INFN Torino
18+
/// \author Luca Aglietta <luca.aglietta@unito.it>, Università and INFN Torino
19+
20+
#include "TPDGCode.h"
21+
22+
#include "Framework/AnalysisTask.h"
23+
#include "Framework/runDataProcessing.h"
24+
25+
#include "Common/DataModel/PIDResponse.h"
26+
#include "Common/DataModel/Centrality.h"
27+
#include "Common/DataModel/Multiplicity.h"
28+
#include "Common/DataModel/EventSelection.h"
29+
#include "Common/DataModel/TrackSelectionTables.h"
30+
#include "PWGLF/DataModel/LFStrangenessTables.h"
31+
#include "PWGLF/DataModel/LFStrangenessPIDTables.h"
32+
33+
using namespace o2;
34+
using namespace o2::framework;
35+
using namespace o2::framework::expressions;
36+
37+
namespace o2::aod
38+
{
39+
namespace pid_studies
40+
{
41+
enum Particle { NotMatched = 0,
42+
K0s,
43+
Lambda,
44+
Omega };
45+
// V0s
46+
DECLARE_SOA_COLUMN(MassK0, massK0, float); //! Candidate mass
47+
DECLARE_SOA_COLUMN(MassLambda, massLambda, float); //! Candidate mass
48+
DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); //! Candidate mass
49+
DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of the candidate (GeV/c)
50+
DECLARE_SOA_COLUMN(PtPos, ptPos, float); //! Transverse momentum of positive track (GeV/c)
51+
DECLARE_SOA_COLUMN(PtNeg, ptNeg, float); //! Transverse momentum of negative track (GeV/c)
52+
DECLARE_SOA_COLUMN(Radius, radius, float); //! Radius
53+
DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine of pointing angle
54+
DECLARE_SOA_COLUMN(NSigmaTpcPosPi, nSigmaTpcPosPi, float); //! nSigmaTPC of positive track with pion hypothesis
55+
DECLARE_SOA_COLUMN(NSigmaTpcNegPi, nSigmaTpcNegPi, float); //! nSigmaTPC of negative track with pion hypothesis
56+
DECLARE_SOA_COLUMN(NSigmaTpcPosPr, nSigmaTpcPosPr, float); //! nSigmaTPC of positive track with proton hypothesis
57+
DECLARE_SOA_COLUMN(NSigmaTpcNegPr, nSigmaTpcNegPr, float); //! nSigmaTPC of negative track with proton hypothesis
58+
DECLARE_SOA_COLUMN(NSigmaTofPosPi, nSigmaTofPosPi, float); //! nSigmaTOF of positive track with pion hypothesis
59+
DECLARE_SOA_COLUMN(NSigmaTofNegPi, nSigmaTofNegPi, float); //! nSigmaTOF of negative track with pion hypothesis
60+
DECLARE_SOA_COLUMN(NSigmaTofPosPr, nSigmaTofPosPr, float); //! nSigmaTOF of positive track with proton hypothesis
61+
DECLARE_SOA_COLUMN(NSigmaTofNegPr, nSigmaTofNegPr, float); //! nSigmaTOF of negative track with proton hypothesis
62+
DECLARE_SOA_COLUMN(AlphaArm, alphaArm, float); //! Armenteros alpha
63+
DECLARE_SOA_COLUMN(QtArm, qtArm, float); //! Armenteros Qt
64+
65+
// Cascades
66+
DECLARE_SOA_COLUMN(MassOmega, massOmega, float); //! Candidate mass
67+
DECLARE_SOA_COLUMN(MassXi, massXi, float); //! Candidate mass
68+
DECLARE_SOA_COLUMN(BachPt, bachPt, float); //! Transverse momentum of the bachelor (GeV/c)
69+
DECLARE_SOA_COLUMN(V0cosPA, v0cosPA, float); //! V0 CPA
70+
DECLARE_SOA_COLUMN(CascCosPA, casccosPA, float); //! Cascade CPA
71+
DECLARE_SOA_COLUMN(DCAV0daughters, dcaV0daughters, float); //! DCA of V0 daughters
72+
DECLARE_SOA_COLUMN(DCAv0topv, dcav0topv, float); //! V0 DCA to PV
73+
DECLARE_SOA_COLUMN(NSigmaTpcBachKa, nSigmaTpcBachKa, float); //! nSigmaTPC of bachelor with kaon hypothesis
74+
DECLARE_SOA_COLUMN(NSigmaTofBachKa, nSigmaTofBachKa, float); //! nSigmaTOF of bachelor with kaon hypothesis
75+
76+
// Common columns
77+
DECLARE_SOA_COLUMN(OccupancyFt0c, occupancyFt0c, float); //! Occupancy from FT0C
78+
DECLARE_SOA_COLUMN(OccupancyIts, occupancyIts, float); //! Occupancy from ITS
79+
DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); //! Centrality from FT0C
80+
DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); //! Centrality from FT0M
81+
DECLARE_SOA_COLUMN(CandFlag, candFlag, int); //! Flag for MC matching
82+
} // namespace pid_studies
83+
84+
DECLARE_SOA_TABLE(PidV0s, "AOD", "PIDV0S", //! Table with PID information
85+
pid_studies::MassK0,
86+
pid_studies::MassLambda,
87+
pid_studies::MassAntiLambda,
88+
pid_studies::Pt,
89+
pid_studies::PtPos,
90+
pid_studies::PtNeg,
91+
pid_studies::Radius,
92+
pid_studies::Cpa,
93+
pid_studies::NSigmaTpcPosPi,
94+
pid_studies::NSigmaTpcNegPi,
95+
pid_studies::NSigmaTpcPosPr,
96+
pid_studies::NSigmaTpcNegPr,
97+
pid_studies::NSigmaTofPosPi,
98+
pid_studies::NSigmaTofNegPi,
99+
pid_studies::NSigmaTofPosPr,
100+
pid_studies::NSigmaTofNegPr,
101+
pid_studies::AlphaArm,
102+
pid_studies::QtArm,
103+
pid_studies::OccupancyFt0c,
104+
pid_studies::OccupancyIts,
105+
pid_studies::CentralityFT0C,
106+
pid_studies::CentralityFT0M,
107+
pid_studies::CandFlag);
108+
109+
DECLARE_SOA_TABLE(PidCascades, "AOD", "PIDCASCADES", //! Table with PID information
110+
pid_studies::MassOmega,
111+
pid_studies::Pt,
112+
pid_studies::BachPt,
113+
pid_studies::V0cosPA,
114+
pid_studies::MassXi,
115+
pid_studies::CascCosPA,
116+
pid_studies::DCAV0daughters,
117+
pid_studies::DCAv0topv,
118+
pid_studies::NSigmaTpcBachKa,
119+
pid_studies::NSigmaTofBachKa,
120+
pid_studies::OccupancyFt0c,
121+
pid_studies::OccupancyIts,
122+
pid_studies::CentralityFT0C,
123+
pid_studies::CentralityFT0M,
124+
pid_studies::CandFlag);
125+
} // namespace o2::aod
126+
127+
struct HfPidStudies {
128+
Produces<o2::aod::PidV0s> pidV0;
129+
Produces<o2::aod::PidCascades> pidCascade;
130+
131+
Configurable<float> massK0Min{"massK0Min", 0.4, "Minimum mass for K0"};
132+
Configurable<float> massK0Max{"massK0Max", 0.6, "Maximum mass for K0"};
133+
Configurable<float> massLambdaMin{"massLambdaMin", 1.0, "Minimum mass for lambda"};
134+
Configurable<float> massLambdaMax{"massLambdaMax", 1.3, "Maximum mass for lambda"};
135+
Configurable<float> massOmegaMin{"massOmegaMin", 1.5, "Minimum mass for omega"};
136+
Configurable<float> massOmegaMax{"massOmegaMax", 1.8, "Maximum mass for omega"};
137+
Configurable<float> downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of candidates to keep"};
138+
Configurable<float> ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"};
139+
140+
using PidTracks = soa::Join<aod::Tracks, aod::TracksExtra,
141+
aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr,
142+
aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>;
143+
using CollSels = soa::Join<aod::Collisions, aod::EvSels, aod::CentFT0Cs, aod::CentFT0Ms>;
144+
using V0sMcRec = soa::Join<aod::V0Datas, aod::V0CoreMCLabels>;
145+
using CascsMcRec = soa::Join<aod::CascDatas, aod::CascCoreMCLabels>;
146+
147+
template <bool isV0, typename Cand>
148+
void fillTree(Cand const& candidate, const int flag)
149+
{
150+
float pseudoRndm = candidate.pt() * 1000. - static_cast<int64_t>(candidate.pt() * 1000);
151+
if (candidate.pt() < ptMaxForDownSample && pseudoRndm > downSampleBkgFactor) {
152+
return;
153+
}
154+
155+
const auto& coll = candidate.template collision_as<CollSels>();
156+
if constexpr (isV0) {
157+
const auto& posTrack = candidate.template posTrack_as<PidTracks>();
158+
const auto& negTrack = candidate.template negTrack_as<PidTracks>();
159+
pidV0(
160+
candidate.mK0Short(),
161+
candidate.mLambda(),
162+
candidate.mAntiLambda(),
163+
candidate.pt(),
164+
posTrack.pt(),
165+
negTrack.pt(),
166+
candidate.v0radius(),
167+
candidate.v0cosPA(),
168+
posTrack.tofNSigmaPi(),
169+
negTrack.tofNSigmaPi(),
170+
posTrack.tofNSigmaPr(),
171+
negTrack.tofNSigmaPr(),
172+
posTrack.tpcNSigmaPi(),
173+
negTrack.tpcNSigmaPi(),
174+
posTrack.tpcNSigmaPr(),
175+
negTrack.tpcNSigmaPr(),
176+
candidate.alpha(),
177+
candidate.qtarm(),
178+
coll.ft0cOccupancyInTimeRange(),
179+
coll.trackOccupancyInTimeRange(),
180+
coll.centFT0C(),
181+
coll.centFT0M(),
182+
flag);
183+
} else {
184+
const auto& bachTrack = candidate.template bachelor_as<PidTracks>();
185+
pidCascade(
186+
candidate.mOmega(),
187+
candidate.pt(),
188+
candidate.bachelorpt(),
189+
candidate.v0cosPA(coll.posX(), coll.posY(), coll.posZ()),
190+
candidate.mXi(),
191+
candidate.casccosPA(coll.posX(), coll.posY(), coll.posZ()),
192+
candidate.dcaV0daughters(),
193+
candidate.dcav0topv(coll.posX(), coll.posY(), coll.posZ()),
194+
bachTrack.tpcNSigmaKa(),
195+
bachTrack.tofNSigmaKa(),
196+
coll.ft0cOccupancyInTimeRange(),
197+
coll.trackOccupancyInTimeRange(),
198+
coll.centFT0C(),
199+
coll.centFT0M(),
200+
flag);
201+
}
202+
}
203+
204+
template <typename T1>
205+
int isMatched(const T1& cand)
206+
{
207+
if constexpr (std::is_same<T1, V0sMcRec::iterator>::value) {
208+
if (!cand.has_v0MCCore()) {
209+
return aod::pid_studies::Particle::NotMatched;
210+
}
211+
auto v0MC = cand.template v0MCCore_as<aod::V0MCCores>();
212+
if (v0MC.pdgCode() == kK0Short && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kPiPlus) {
213+
return aod::pid_studies::Particle::K0s;
214+
}
215+
if (v0MC.pdgCode() == kLambda0 && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kProton) {
216+
return aod::pid_studies::Particle::Lambda;
217+
}
218+
if (v0MC.pdgCode() == -kLambda0 && v0MC.pdgCodeNegative() == -kProton && v0MC.pdgCodePositive() == kPiPlus) {
219+
return -aod::pid_studies::Particle::Lambda;
220+
}
221+
}
222+
if constexpr (std::is_same<T1, CascsMcRec::iterator>::value) {
223+
if (!cand.has_cascMCCore()) {
224+
return aod::pid_studies::Particle::NotMatched;
225+
}
226+
auto cascMC = cand.template cascMCCore_as<aod::CascMCCores>();
227+
if (cascMC.pdgCode() == kOmegaMinus &&
228+
cascMC.pdgCodeBachelor() == -kKPlus &&
229+
cascMC.pdgCodeV0() == kLambda0 &&
230+
cascMC.pdgCodePositive() == kProton &&
231+
cascMC.pdgCodeNegative() == -kPiPlus) {
232+
return aod::pid_studies::Particle::Omega;
233+
}
234+
if (cascMC.pdgCode() == -kOmegaMinus &&
235+
cascMC.pdgCodeBachelor() == kKPlus &&
236+
cascMC.pdgCodeV0() == -kLambda0 &&
237+
cascMC.pdgCodePositive() == kPiPlus &&
238+
cascMC.pdgCodeNegative() == -kProton) {
239+
return -aod::pid_studies::Particle::Omega;
240+
}
241+
}
242+
return aod::pid_studies::Particle::NotMatched;
243+
}
244+
245+
void processMc(V0sMcRec const& V0s,
246+
aod::V0MCCores const&,
247+
CascsMcRec const& cascades,
248+
aod::CascMCCores const&,
249+
CollSels const&,
250+
PidTracks const&)
251+
{
252+
for (const auto& v0 : V0s) {
253+
if ((v0.mK0Short() > massK0Min && v0.mK0Short() < massK0Max) ||
254+
(v0.mLambda() > massLambdaMin && v0.mLambda() < massLambdaMax) ||
255+
(v0.mAntiLambda() > massLambdaMin && v0.mAntiLambda() < massLambdaMax)) {
256+
int matched = isMatched(v0);
257+
if (matched != aod::pid_studies::Particle::NotMatched) {
258+
fillTree<true>(v0, matched);
259+
}
260+
}
261+
}
262+
for (const auto& casc : cascades) {
263+
if (casc.mOmega() > massOmegaMin && casc.mOmega() < massOmegaMax && casc.mLambda() > massLambdaMin && casc.mLambda() < massLambdaMax) {
264+
int matched = isMatched(casc);
265+
if (matched != aod::pid_studies::Particle::NotMatched) {
266+
fillTree<false>(casc, matched);
267+
}
268+
}
269+
}
270+
}
271+
PROCESS_SWITCH(HfPidStudies, processMc, "Process MC", true);
272+
273+
void processData(aod::V0Datas const& V0s, aod::CascDatas const& cascades, CollSels const&, PidTracks const&)
274+
{
275+
for (const auto& v0 : V0s) {
276+
if ((v0.mK0Short() > massK0Min && v0.mK0Short() < massK0Max) ||
277+
(v0.mLambda() > massLambdaMin && v0.mLambda() < massLambdaMax) ||
278+
(v0.mAntiLambda() > massLambdaMin && v0.mAntiLambda() < massLambdaMax)) {
279+
fillTree<true>(v0, aod::pid_studies::Particle::NotMatched);
280+
}
281+
}
282+
for (const auto& casc : cascades) {
283+
if (casc.mOmega() > massOmegaMin && casc.mOmega() < massOmegaMax && casc.mLambda() > massLambdaMin && casc.mLambda() < massLambdaMax) {
284+
fillTree<false>(casc, aod::pid_studies::Particle::NotMatched);
285+
}
286+
}
287+
}
288+
PROCESS_SWITCH(HfPidStudies, processData, "Process data", false);
289+
};
290+
291+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
292+
{
293+
return WorkflowSpec{adaptAnalysisTask<HfPidStudies>(cfgc)};
294+
}

0 commit comments

Comments
 (0)