Skip to content

Commit 89250d6

Browse files
authored
[DPG] Add qa with ITS PID (#9399)
1 parent e0f417b commit 89250d6

File tree

3 files changed

+335
-0
lines changed

3 files changed

+335
-0
lines changed

DPG/Tasks/AOTTrack/PID/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
add_subdirectory(Combined)
1313
add_subdirectory(TOF)
1414
add_subdirectory(TPC)
15+
add_subdirectory(ITS)
1516
add_subdirectory(HMPID)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
# ITS
13+
o2physics_add_dpl_workflow(pid-its-qa
14+
SOURCES qaPIDITS.cxx
15+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
16+
COMPONENT_NAME Analysis)
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
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+
///
13+
/// \file qaPIDITS.cxx
14+
/// \author Nicolò Jacazio nicolo.jacazio@cern.ch
15+
/// \brief Implementation for QA tasks of the ITS PID quantities
16+
///
17+
18+
#include "Framework/AnalysisTask.h"
19+
#include "Framework/runDataProcessing.h"
20+
#include "Framework/HistogramRegistry.h"
21+
#include "Framework/StaticFor.h"
22+
#include "Common/DataModel/TrackSelectionTables.h"
23+
#include "Common/DataModel/EventSelection.h"
24+
#include "Common/DataModel/PIDResponse.h"
25+
#include "Common/DataModel/PIDResponseITS.h"
26+
27+
using namespace o2;
28+
using namespace o2::framework;
29+
using namespace o2::framework::expressions;
30+
using namespace o2::track;
31+
32+
static constexpr int nParameters = 1;
33+
static const std::vector<std::string> tableNames{"Electron", // 0
34+
"Muon", // 1
35+
"Pion", // 2
36+
"Kaon", // 3
37+
"Proton", // 4
38+
"Deuteron", // 5
39+
"Triton", // 6
40+
"Helium", // 7
41+
"Alpha"}; // 8
42+
static const std::vector<std::string> parameterNames{"enable"};
43+
static const int defaultParameters[9][nParameters]{{0}, {0}, {1}, {1}, {1}, {0}, {0}, {0}, {0}};
44+
static const float defaultPIDSelection[9][nParameters]{{-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}, {-1.f}};
45+
static constexpr int Np = 9;
46+
std::array<std::shared_ptr<TH2>, Np> hNsigmaPos;
47+
std::array<std::shared_ptr<TH2>, Np> hNsigmaNeg;
48+
49+
template <typename TrackType>
50+
float nsigmaITS(const TrackType& track, const o2::track::PID::ID id)
51+
{
52+
switch (id) {
53+
case o2::track::PID::Electron:
54+
return track.itsNSigmaEl();
55+
case o2::track::PID::Muon:
56+
return track.itsNSigmaMu();
57+
case o2::track::PID::Pion:
58+
return track.itsNSigmaPi();
59+
case o2::track::PID::Kaon:
60+
return track.itsNSigmaKa();
61+
case o2::track::PID::Proton:
62+
return track.itsNSigmaPr();
63+
case o2::track::PID::Deuteron:
64+
return track.itsNSigmaDe();
65+
case o2::track::PID::Triton:
66+
return track.itsNSigmaTr();
67+
case o2::track::PID::Helium3:
68+
return track.itsNSigmaHe();
69+
case o2::track::PID::Alpha:
70+
return track.itsNSigmaAl();
71+
default:
72+
LOG(fatal) << "PID not implemented";
73+
return 0.f;
74+
}
75+
}
76+
template <typename TrackType>
77+
float nsigmaTOF(const TrackType& track, const o2::track::PID::ID id)
78+
{
79+
switch (id) {
80+
case o2::track::PID::Electron:
81+
return track.tofNSigmaEl();
82+
case o2::track::PID::Muon:
83+
return track.tofNSigmaMu();
84+
case o2::track::PID::Pion:
85+
return track.tofNSigmaPi();
86+
case o2::track::PID::Kaon:
87+
return track.tofNSigmaKa();
88+
case o2::track::PID::Proton:
89+
return track.tofNSigmaPr();
90+
case o2::track::PID::Deuteron:
91+
return track.tofNSigmaDe();
92+
case o2::track::PID::Triton:
93+
return track.tofNSigmaTr();
94+
case o2::track::PID::Helium3:
95+
return track.tofNSigmaHe();
96+
case o2::track::PID::Alpha:
97+
return track.tofNSigmaAl();
98+
default:
99+
LOG(fatal) << "PID not implemented";
100+
return 0.f;
101+
}
102+
}
103+
template <typename TrackType>
104+
float nsigmaTPC(const TrackType& track, const o2::track::PID::ID id)
105+
{
106+
switch (id) {
107+
case o2::track::PID::Electron:
108+
return track.tpcNSigmaEl();
109+
case o2::track::PID::Muon:
110+
return track.tpcNSigmaMu();
111+
case o2::track::PID::Pion:
112+
return track.tpcNSigmaPi();
113+
case o2::track::PID::Kaon:
114+
return track.tpcNSigmaKa();
115+
case o2::track::PID::Proton:
116+
return track.tpcNSigmaPr();
117+
case o2::track::PID::Deuteron:
118+
return track.tpcNSigmaDe();
119+
case o2::track::PID::Triton:
120+
return track.tpcNSigmaTr();
121+
case o2::track::PID::Helium3:
122+
return track.tpcNSigmaHe();
123+
case o2::track::PID::Alpha:
124+
return track.tpcNSigmaAl();
125+
default:
126+
LOG(fatal) << "PID not implemented";
127+
return 0.f;
128+
}
129+
}
130+
131+
float tpcSelValues[9];
132+
float tofSelValues[9];
133+
134+
/// Task to produce the ITS QA plots
135+
struct itsPidQa {
136+
static constexpr const char* pT[Np] = {"e", "#mu", "#pi", "K", "p", "d", "t", "^{3}He", "#alpha"};
137+
static constexpr const char* pN[Np] = {"El", "Mu", "Pi", "Ka", "Pr", "De", "Tr", "He", "Al"};
138+
139+
HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject};
140+
Configurable<LabeledArray<int>> enabledTables{"enabledTables",
141+
{defaultParameters[0], 9, nParameters, tableNames, parameterNames},
142+
"Produce QA for this species: 0 - no, 1 - yes"};
143+
Configurable<LabeledArray<float>> tofSelection{"tofSelection",
144+
{defaultPIDSelection[0], 9, nParameters, tableNames, parameterNames},
145+
"Selection on the TOF nsigma"};
146+
Configurable<LabeledArray<float>> tpcSelection{"tpcSelection",
147+
{defaultPIDSelection[0], 9, nParameters, tableNames, parameterNames},
148+
"Selection on the TPC nsigma"};
149+
150+
Configurable<int> logAxis{"logAxis", 1, "Flag to use a log momentum axis"};
151+
Configurable<int> nBinsP{"nBinsP", 3000, "Number of bins for the momentum"};
152+
Configurable<float> minP{"minP", 0.01, "Minimum momentum in range"};
153+
Configurable<float> maxP{"maxP", 20, "Maximum momentum in range"};
154+
ConfigurableAxis etaBins{"etaBins", {100, -1.f, 1.f}, "Binning in eta"};
155+
ConfigurableAxis phiBins{"phiBins", {100, 0, TMath::TwoPi()}, "Binning in phi"};
156+
ConfigurableAxis trackLengthBins{"trackLengthBins", {100, 0, 1000.f}, "Binning in track length plot"};
157+
ConfigurableAxis deltaBins{"deltaBins", {200, -1000.f, 1000.f}, "Binning in Delta (dEdx - expected dEdx)"};
158+
ConfigurableAxis expSigmaBins{"expSigmaBins", {200, 0.f, 200.f}, "Binning in expected Sigma"};
159+
ConfigurableAxis nSigmaBins{"nSigmaBins", {401, -10.025f, 10.025f}, "Binning in NSigma"};
160+
ConfigurableAxis dEdxBins{"dEdxBins", {5000, 0.f, 5000.f}, "Binning in dE/dx"};
161+
Configurable<int> trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"};
162+
Configurable<bool> applyRapidityCut{"applyRapidityCut", false, "Flag to apply rapidity cut"};
163+
Configurable<bool> enableDeDxPlot{"enableDeDxPlot", true, "Enables the dEdx plot (reduces memory footprint if off)"};
164+
Configurable<int16_t> minTPCNcls{"minTPCNcls", 0, "Minimum number or TPC Clusters for tracks"};
165+
ConfigurableAxis tpcNclsBins{"tpcNclsBins", {16, 0, 160}, "Binning in number of clusters in TPC"};
166+
Configurable<bool> fillTHnSparses{"fillTHnSparses", false, "Flag to fill multidimensional histograms for nsigma vs pt, eta, Ncls"};
167+
168+
void init(o2::framework::InitContext&)
169+
{
170+
const AxisSpec vtxZAxis{100, -20, 20, "Vtx_{z} (cm)"};
171+
const AxisSpec etaAxis{etaBins, "#it{#eta}"};
172+
const AxisSpec phiAxis{phiBins, "#it{#phi}"};
173+
const AxisSpec lAxis{trackLengthBins, "Track length (cm)"};
174+
AxisSpec ptAxis{nBinsP, minP, maxP, "#it{p}_{T}/|Z| (GeV/#it{c})"};
175+
AxisSpec pAxis{nBinsP, minP, maxP, "#it{p}/|Z| (GeV/#it{c})"};
176+
if (logAxis) {
177+
ptAxis.makeLogarithmic();
178+
pAxis.makeLogarithmic();
179+
}
180+
const AxisSpec dedxAxis{dEdxBins, "d#it{E}/d#it{x} Arb. units"};
181+
const AxisSpec chargeAxis{2, -2.f, 2.f, "Charge"};
182+
183+
// Event properties
184+
auto h = histos.add<TH1>("event/evsel", "", kTH1D, {{10, 0.5, 10.5, "Ev. Sel."}});
185+
h->GetXaxis()->SetBinLabel(1, "Events read");
186+
h->GetXaxis()->SetBinLabel(2, "Passed ev. sel.");
187+
h->GetXaxis()->SetBinLabel(3, "Passed vtx Z");
188+
189+
h = histos.add<TH1>("event/trackselection", "", kTH1D, {{10, 0.5, 10.5, "Selection passed"}});
190+
h->GetXaxis()->SetBinLabel(1, "Tracks read");
191+
h->GetXaxis()->SetBinLabel(2, "isGlobalTrack");
192+
h->GetXaxis()->SetBinLabel(3, "hasITS");
193+
h->GetXaxis()->SetBinLabel(4, "hasTPC");
194+
h->GetXaxis()->SetBinLabel(5, Form("tpcNClsFound > %i", minTPCNcls.value));
195+
196+
histos.add("event/vertexz", "", kTH1D, {vtxZAxis});
197+
h = histos.add<TH1>("event/particlehypo", "", kTH1D, {{10, 0, 10, "PID in tracking"}});
198+
for (int id = 0; id < 9; id++) {
199+
h->GetXaxis()->SetBinLabel(id + 1, PID::getName(id));
200+
tpcSelValues[id] = tpcSelection->get(tableNames[id].c_str(), "enable");
201+
if (tpcSelValues[id] <= 0.f) {
202+
tpcSelValues[id] = 999.f;
203+
}
204+
tofSelValues[id] = tofSelection->get(tableNames[id].c_str(), "enable");
205+
if (tofSelValues[id] <= 0.f) {
206+
tofSelValues[id] = 999.f;
207+
}
208+
}
209+
histos.add("event/eta", "", kTH1D, {etaAxis});
210+
histos.add("event/phi", "", kTH1D, {phiAxis});
211+
histos.add("event/etaphi", "", kTH2F, {etaAxis, phiAxis});
212+
histos.add("event/length", "", kTH1D, {lAxis});
213+
histos.add("event/pt", "", kTH1D, {ptAxis});
214+
histos.add("event/p", "", kTH1D, {pAxis});
215+
216+
for (int id = 0; id < 9; id++) {
217+
const int f = enabledTables->get(tableNames[id].c_str(), "enable");
218+
if (f != 1) {
219+
continue;
220+
}
221+
// NSigma
222+
const char* axisTitle = Form("N_{#sigma}^{ITS}(%s)", pT[id]);
223+
const AxisSpec nSigmaAxis{nSigmaBins, axisTitle};
224+
hNsigmaPos[id] = histos.add<TH2>(Form("nsigmaPos/%s", pN[id]), axisTitle, kTH2F, {pAxis, nSigmaAxis});
225+
hNsigmaNeg[id] = histos.add<TH2>(Form("nsigmaNeg/%s", pN[id]), axisTitle, kTH2F, {pAxis, nSigmaAxis});
226+
}
227+
LOG(info) << "QA PID ITS histograms:";
228+
histos.print();
229+
}
230+
231+
Filter eventFilter = (o2::aod::evsel::sel8 == true);
232+
Filter trackFilter = (requireGlobalTrackInFilter());
233+
using CollisionCandidate = soa::Filtered<soa::Join<aod::Collisions, aod::EvSels>>::iterator;
234+
using TrackCandidates = soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection,
235+
aod::pidTPCEl, aod::pidTPCMu, aod::pidTPCPi,
236+
aod::pidTPCKa, aod::pidTPCPr, aod::pidTPCDe,
237+
aod::pidTPCTr, aod::pidTPCHe, aod::pidTPCAl,
238+
aod::pidTOFEl, aod::pidTOFMu, aod::pidTOFPi,
239+
aod::pidTOFKa, aod::pidTOFPr, aod::pidTOFDe,
240+
aod::pidTOFTr, aod::pidTOFHe, aod::pidTOFAl>;
241+
void process(CollisionCandidate const& collision,
242+
soa::Filtered<TrackCandidates> const& tracks)
243+
{
244+
auto tracksWithPid = soa::Attach<TrackCandidates,
245+
aod::pidits::ITSNSigmaEl, aod::pidits::ITSNSigmaMu, aod::pidits::ITSNSigmaPi,
246+
aod::pidits::ITSNSigmaKa, aod::pidits::ITSNSigmaPr, aod::pidits::ITSNSigmaDe,
247+
aod::pidits::ITSNSigmaTr, aod::pidits::ITSNSigmaHe, aod::pidits::ITSNSigmaAl>(tracks);
248+
249+
histos.fill(HIST("event/evsel"), 1);
250+
if (!collision.sel8()) {
251+
return;
252+
}
253+
254+
histos.fill(HIST("event/evsel"), 2);
255+
256+
if (std::abs(collision.posZ()) > 10.f) {
257+
return;
258+
}
259+
histos.fill(HIST("event/evsel"), 3);
260+
histos.fill(HIST("event/vertexz"), collision.posZ());
261+
262+
for (const auto& track : tracksWithPid) {
263+
histos.fill(HIST("event/trackselection"), 1.f);
264+
if (!track.isGlobalTrack()) { // Skipping non global tracks
265+
continue;
266+
}
267+
histos.fill(HIST("event/trackselection"), 2.f);
268+
if (!track.hasITS()) { // Skipping tracks without ITS
269+
continue;
270+
}
271+
histos.fill(HIST("event/trackselection"), 3.f);
272+
if (!track.hasTPC()) { // Skipping tracks without TPC
273+
continue;
274+
}
275+
histos.fill(HIST("event/trackselection"), 4.f);
276+
if (track.tpcNClsFound() < minTPCNcls) { // Skipping tracks without enough TPC clusters
277+
continue;
278+
}
279+
280+
histos.fill(HIST("event/trackselection"), 5.f);
281+
histos.fill(HIST("event/particlehypo"), track.pidForTracking());
282+
histos.fill(HIST("event/eta"), track.eta());
283+
histos.fill(HIST("event/phi"), track.phi());
284+
histos.fill(HIST("event/etaphi"), track.eta(), track.phi());
285+
histos.fill(HIST("event/length"), track.length());
286+
histos.fill(HIST("event/pt"), track.pt());
287+
histos.fill(HIST("event/p"), track.p());
288+
289+
bool discard = false;
290+
for (int id = 0; id < 9; id++) {
291+
if (std::abs(nsigmaTPC(track, id)) > tpcSelValues[id]) {
292+
discard = true;
293+
}
294+
if (std::abs(nsigmaTOF(track, id)) > tofSelValues[id]) {
295+
discard = true;
296+
}
297+
}
298+
if (discard) {
299+
continue;
300+
}
301+
for (o2::track::PID::ID id = 0; id <= o2::track::PID::Last; id++) {
302+
if (applyRapidityCut) {
303+
if (std::abs(track.rapidity(PID::getMass(id))) > 0.5) {
304+
continue;
305+
}
306+
}
307+
const float nsigma = nsigmaITS(track, id);
308+
if (track.sign() > 0) {
309+
hNsigmaPos[id]->Fill(track.p(), nsigma);
310+
} else {
311+
hNsigmaNeg[id]->Fill(track.p(), nsigma);
312+
}
313+
}
314+
}
315+
}
316+
};
317+
318+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask<itsPidQa>(cfgc)}; }

0 commit comments

Comments
 (0)