Skip to content

Commit 873dd2c

Browse files
authored
[PWGLF] QA of ITS-TPC matching efficiency for V0 daughters (#9813)
1 parent 6cb56b5 commit 873dd2c

File tree

2 files changed

+337
-0
lines changed

2 files changed

+337
-0
lines changed

PWGLF/Tasks/QC/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,8 @@ o2physics_add_dpl_workflow(str-derived-genqa
129129
SOURCES strderivedGenQA.cxx
130130
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
131131
COMPONENT_NAME Analysis)
132+
133+
o2physics_add_dpl_workflow(its-tpc-matching-vzeros
134+
SOURCES lfITSTPCMatchingSecondaryTracksQA.cxx
135+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
136+
COMPONENT_NAME Analysis)
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
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 lfITSTPCMatchingSecondaryTracksQA.cxx
13+
///
14+
/// \brief task for QA of ITS-TPC matching efficiency of secondary tracks from V0s
15+
/// \author Alberto Caliva (alberto.caliva@cern.ch), Francesca Ercolessi (francesca.ercolessi@cern.ch), Nicolò Jacazio (nicolo.jacazio@cern.ch)
16+
/// \since May 22, 2024
17+
18+
#include <TLorentzVector.h>
19+
#include <TMath.h>
20+
#include <TObjArray.h>
21+
#include <TPDGCode.h>
22+
#include <TVector2.h>
23+
#include <TVector3.h>
24+
#include <cmath>
25+
#include <vector>
26+
#include <string>
27+
#include "Common/Core/RecoDecay.h"
28+
#include "Common/Core/trackUtilities.h"
29+
#include "Common/DataModel/EventSelection.h"
30+
#include "Common/DataModel/Multiplicity.h"
31+
#include "Common/DataModel/PIDResponse.h"
32+
#include "Common/DataModel/TrackSelectionTables.h"
33+
#include "Framework/ASoAHelpers.h"
34+
#include "Framework/AnalysisDataModel.h"
35+
#include "Framework/AnalysisTask.h"
36+
#include "Framework/runDataProcessing.h"
37+
#include "PWGLF/DataModel/LFStrangenessTables.h"
38+
#include "ReconstructionDataFormats/Track.h"
39+
40+
using namespace std;
41+
using namespace o2;
42+
using namespace o2::soa;
43+
using namespace o2::aod;
44+
using namespace o2::framework;
45+
using namespace o2::framework::expressions;
46+
using namespace o2::constants::physics;
47+
using namespace o2::constants::math;
48+
using std::array;
49+
50+
using SelCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::CentFT0Ms>;
51+
using SimCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::CentFT0Ms, aod::McCollisionLabels>;
52+
using StrHadronDaughterTracks = soa::Join<aod::Tracks, aod::TracksIU, aod::TracksExtra, aod::TracksCovIU, aod::TracksDCA, aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>;
53+
using MCTracks = soa::Join<StrHadronDaughterTracks, aod::McTrackLabels>;
54+
55+
struct LfITSTPCMatchingSecondaryTracksQA {
56+
57+
HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true};
58+
HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true};
59+
60+
// Global Parameters
61+
Configurable<double> zVtx{"zVtx", 10.0, "Maximum zVertex"};
62+
63+
// Track Parameters
64+
Configurable<float> minITSnCls{"minITSnCls", 3.0f, "min number of ITS clusters"};
65+
Configurable<float> minNCrossedRowsTPC{"minNCrossedRowsTPC", 80.0f, "min number of TPC crossed rows"};
66+
Configurable<float> minNCrossedRowsOverFindable{"minNCrossedRowsOverFindable", 0.8f, "min number of TPC crossed rows/findable"};
67+
Configurable<float> maxChi2TPC{"maxChi2TPC", 4.0f, "max chi2 per cluster TPC"};
68+
Configurable<float> maxChi2ITS{"maxChi2ITS", 36.0f, "max chi2 per cluster ITS"};
69+
Configurable<float> etaMin{"etaMin", -0.8f, "eta min"};
70+
Configurable<float> etaMax{"etaMax", +0.8f, "eta max"};
71+
Configurable<float> nsigmaTPCmin{"nsigmaTPCmin", -3.0f, "Minimum nsigma TPC"};
72+
Configurable<float> nsigmaTPCmax{"nsigmaTPCmax", +3.0f, "Maximum nsigma TPC"};
73+
Configurable<float> nsigmaTOFmin{"nsigmaTOFmin", -3.0f, "Minimum nsigma TOF"};
74+
Configurable<float> nsigmaTOFmax{"nsigmaTOFmax", +3.0f, "Maximum nsigma TOF"};
75+
Configurable<bool> requireTOF{"requireTOF", false, "require TOF hit"};
76+
Configurable<bool> requireItsHits{"requireItsHits", false, "require ITS hits"};
77+
Configurable<std::vector<float>> requiredHit{"requiredHit", {0, 0, 0, 1, 1, 1, 1}, "required ITS Hits"};
78+
79+
// V0 Parameters
80+
Configurable<float> minimumV0Radius{"minimumV0Radius", 0.5f, "Minimum V0 Radius"};
81+
Configurable<float> maximumV0Radius{"maximumV0Radius", 40.0f, "Maximum V0 Radius"};
82+
Configurable<float> dcanegtoPVmin{"dcanegtoPVmin", 0.1f, "Minimum DCA Neg To PV"};
83+
Configurable<float> dcapostoPVmin{"dcapostoPVmin", 0.1f, "Minimum DCA Pos To PV"};
84+
Configurable<float> v0cospaMin{"v0cospaMin", 0.99f, "Minimum V0 CosPA"};
85+
Configurable<float> dcaV0DaughtersMax{"dcaV0DaughtersMax", 0.5f, "Maximum DCA Daughters"};
86+
Configurable<float> mK0Min{"mK0Min", 0.48f, "K0 mass lower cut"};
87+
Configurable<float> mK0Max{"mK0Max", 0.52f, "K0 mass upper cut"};
88+
89+
void init(InitContext const&)
90+
{
91+
// Event Counters
92+
if (doprocessData) {
93+
registryData.add("number_of_events_data", "number of events in data", HistType::kTH1D, {{20, 0, 20, "Event Cuts"}});
94+
registryData.add("trkPionTpc", "trkPionTpc", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
95+
registryData.add("trkPionTpcIts", "trkPionTpcIts", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
96+
registryData.add("secPionTpc", "secPionTpc", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
97+
registryData.add("secPionTpcIts", "secPionTpcIts", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
98+
}
99+
100+
if (doprocessMC) {
101+
registryData.add("number_of_events_mc", "number of events in mc", HistType::kTH1D, {{20, 0, 20, "Event Cuts"}});
102+
registryData.add("trkPionTpcMc", "trkPionTpcMc", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
103+
registryData.add("trkPionTpcItsMc", "trkPionTpcItsMc", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
104+
registryData.add("secPionTpcMc", "secPionTpcMc", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
105+
registryData.add("secPionTpcItsMc", "secPionTpcItsMc", HistType::kTH1D, {{1000, 0, 10, "#it{p}_{T} (GeV/#it{c})"}});
106+
}
107+
}
108+
109+
bool hasHitOnITSlayer(uint8_t itsClsmap, int layer)
110+
{
111+
unsigned char testBit = 1 << layer;
112+
return (itsClsmap & testBit);
113+
}
114+
115+
template <typename TpcTrack>
116+
bool passedTrackSelectionTpc(const TpcTrack& track)
117+
{
118+
if (!track.hasTPC())
119+
return false;
120+
if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC)
121+
return false;
122+
if ((track.tpcNClsCrossedRows() / track.tpcNClsFindable()) < minNCrossedRowsOverFindable)
123+
return false;
124+
if (track.tpcChi2NCl() > maxChi2TPC)
125+
return false;
126+
if (track.eta() < etaMin || track.eta() > etaMax)
127+
return false;
128+
return true;
129+
}
130+
131+
// K0s Selections
132+
template <typename K0short>
133+
bool passedK0ShortSelection(const K0short& v0)
134+
{
135+
if (v0.v0cosPA() < v0cospaMin)
136+
return false;
137+
if (v0.v0radius() < minimumV0Radius || v0.v0radius() > maximumV0Radius)
138+
return false;
139+
if (v0.dcaV0daughters() > dcaV0DaughtersMax)
140+
return false;
141+
if (std::fabs(v0.dcapostopv()) < dcapostoPVmin)
142+
return false;
143+
if (std::fabs(v0.dcanegtopv()) < dcanegtoPVmin)
144+
return false;
145+
if (v0.mK0Short() < mK0Min || v0.mK0Short() > mK0Max)
146+
return false;
147+
148+
return true;
149+
}
150+
151+
template <typename pionTrack>
152+
bool passedPionSelection(const pionTrack& track)
153+
{
154+
// TPC Selection
155+
if (track.tpcNSigmaPi() < nsigmaTPCmin || track.tpcNSigmaPi() > nsigmaTPCmax)
156+
return false;
157+
158+
// TOF Selection
159+
if (requireTOF) {
160+
if (track.tofNSigmaPi() < nsigmaTOFmin || track.tofNSigmaPi() > nsigmaTOFmax)
161+
return false;
162+
}
163+
return true;
164+
}
165+
166+
template <typename ItsTrack>
167+
bool passedTrackSelectionIts(const ItsTrack& track)
168+
{
169+
if (!track.hasITS())
170+
return false;
171+
if (track.itsNCls() < minITSnCls)
172+
return false;
173+
if (track.itsChi2NCl() > maxChi2ITS)
174+
return false;
175+
176+
auto requiredItsHit = static_cast<std::vector<float>>(requiredHit);
177+
178+
if (requireItsHits) {
179+
for (int i = 0; i < 7; i++) {
180+
if (requiredItsHit[i] > 0 && !hasHitOnITSlayer(track.itsClusterMap(), i)) {
181+
return false;
182+
}
183+
}
184+
}
185+
186+
return true;
187+
}
188+
189+
void processData(SelCollisions::iterator const& collision, aod::V0Datas const& fullV0s, StrHadronDaughterTracks const& tracks)
190+
{
191+
registryData.fill(HIST("number_of_events_data"), 0.5);
192+
193+
// Event Selection
194+
if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx)
195+
return;
196+
registryData.fill(HIST("number_of_events_data"), 1.5);
197+
198+
for (const auto& track : tracks) {
199+
200+
if (!passedTrackSelectionTpc(track))
201+
continue;
202+
if (!passedPionSelection(track))
203+
continue;
204+
205+
registryData.fill(HIST("trkPionTpc"), track.pt());
206+
207+
if (!passedTrackSelectionIts(track))
208+
continue;
209+
210+
registryData.fill(HIST("trkPionTpcIts"), track.pt());
211+
}
212+
213+
for (const auto& v0 : fullV0s) {
214+
215+
const auto& posTrack = v0.posTrack_as<StrHadronDaughterTracks>();
216+
const auto& negTrack = v0.negTrack_as<StrHadronDaughterTracks>();
217+
if (!passedK0ShortSelection(v0))
218+
continue;
219+
220+
if (!passedTrackSelectionTpc(posTrack))
221+
continue;
222+
if (!passedTrackSelectionTpc(negTrack))
223+
continue;
224+
if (!passedPionSelection(posTrack))
225+
continue;
226+
if (!passedPionSelection(negTrack))
227+
continue;
228+
229+
registryData.fill(HIST("secPionTpc"), posTrack.pt());
230+
registryData.fill(HIST("secPionTpc"), negTrack.pt());
231+
232+
if (!passedTrackSelectionIts(posTrack))
233+
continue;
234+
registryData.fill(HIST("secPionTpcIts"), posTrack.pt());
235+
236+
if (!passedTrackSelectionIts(negTrack))
237+
continue;
238+
registryData.fill(HIST("secPionTpcIts"), negTrack.pt());
239+
}
240+
}
241+
PROCESS_SWITCH(LfITSTPCMatchingSecondaryTracksQA, processData, "Process data", true);
242+
243+
Preslice<aod::V0Datas> perCollisionV0 = o2::aod::v0data::collisionId;
244+
Preslice<MCTracks> perCollisionTrk = o2::aod::track::collisionId;
245+
246+
void processMC(SimCollisions const& collisions, MCTracks const& mcTracks, aod::V0Datas const& fullV0s, const aod::McParticles&)
247+
{
248+
for (const auto& collision : collisions) {
249+
registryMC.fill(HIST("number_of_events_mc"), 0.5);
250+
251+
if (!collision.sel8() || std::fabs(collision.posZ()) > zVtx)
252+
continue;
253+
registryMC.fill(HIST("number_of_events_mc"), 1.5);
254+
255+
auto v0sPerColl = fullV0s.sliceBy(perCollisionV0, collision.globalIndex());
256+
auto tracksPerColl = mcTracks.sliceBy(perCollisionTrk, collision.globalIndex());
257+
258+
for (const auto& track : tracksPerColl) {
259+
if (!passedTrackSelectionTpc(track))
260+
continue;
261+
if (!passedPionSelection(track))
262+
continue;
263+
if (!track.has_mcParticle())
264+
continue;
265+
const auto particle = track.mcParticle();
266+
if (std::fabs(particle.pdgCode()) != 211)
267+
continue;
268+
269+
registryMC.fill(HIST("trkPionTpcMc"), track.pt());
270+
if (!passedTrackSelectionIts(track))
271+
continue;
272+
273+
registryMC.fill(HIST("trkPionTpcItsMc"), track.pt());
274+
}
275+
276+
for (const auto& v0 : v0sPerColl) {
277+
278+
const auto& posTrack = v0.posTrack_as<MCTracks>();
279+
const auto& negTrack = v0.negTrack_as<MCTracks>();
280+
if (!passedK0ShortSelection(v0))
281+
continue;
282+
if (!passedTrackSelectionTpc(posTrack))
283+
continue;
284+
if (!passedTrackSelectionTpc(negTrack))
285+
continue;
286+
if (!passedPionSelection(posTrack))
287+
continue;
288+
if (!passedPionSelection(negTrack))
289+
continue;
290+
if (!posTrack.has_mcParticle())
291+
continue;
292+
if (!negTrack.has_mcParticle())
293+
continue;
294+
295+
auto posParticle = posTrack.mcParticle_as<aod::McParticles>();
296+
auto negParticle = negTrack.mcParticle_as<aod::McParticles>();
297+
if (!posParticle.has_mothers())
298+
continue;
299+
if (!negParticle.has_mothers())
300+
continue;
301+
302+
int pdgParent(0);
303+
for (const auto& particleMotherOfNeg : negParticle.mothers_as<aod::McParticles>()) {
304+
for (const auto& particleMotherOfPos : posParticle.mothers_as<aod::McParticles>()) {
305+
if (particleMotherOfNeg == particleMotherOfPos) {
306+
pdgParent = particleMotherOfNeg.pdgCode();
307+
}
308+
}
309+
}
310+
if (pdgParent != 310)
311+
continue;
312+
313+
registryMC.fill(HIST("secPionTpcMc"), posTrack.pt());
314+
registryMC.fill(HIST("secPionTpcMc"), negTrack.pt());
315+
316+
if (!passedTrackSelectionIts(posTrack))
317+
continue;
318+
registryMC.fill(HIST("secPionTpcItsMc"), posTrack.pt());
319+
320+
if (!passedTrackSelectionIts(negTrack))
321+
continue;
322+
registryMC.fill(HIST("secPionTpcItsMc"), negTrack.pt());
323+
}
324+
}
325+
}
326+
PROCESS_SWITCH(LfITSTPCMatchingSecondaryTracksQA, processMC, "Process MC", false);
327+
};
328+
329+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
330+
{
331+
return WorkflowSpec{adaptAnalysisTask<LfITSTPCMatchingSecondaryTracksQA>(cfgc)};
332+
}

0 commit comments

Comments
 (0)