Skip to content

Commit 12aea96

Browse files
abmodakalibuild
andauthored
[PWGLF] Add new task to study multiplicity distributions (#12958)
Co-authored-by: ALICE Action Bot <alibuild@cern.ch>
1 parent 14baa65 commit 12aea96

File tree

2 files changed

+347
-0
lines changed

2 files changed

+347
-0
lines changed

PWGLF/Tasks/GlobalEventProperties/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ o2physics_add_dpl_workflow(flattenicty-pikp
2828
SOURCES flattenictyPikp.cxx
2929
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB
3030
COMPONENT_NAME Analysis)
31+
32+
o2physics_add_dpl_workflow(study-pnch
33+
SOURCES studyPnch.cxx
34+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
35+
COMPONENT_NAME Analysis)
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
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 studyPnch.cxx
13+
///
14+
/// \brief task for analysis of charged-particle multiplicity distributions
15+
/// \author Abhi Modak (abhi.modak@cern.ch)
16+
/// \since September 10, 2025
17+
18+
#include "PWGLF/DataModel/LFStrangenessTables.h"
19+
#include "PWGMM/Mult/DataModel/Index.h"
20+
#include "PWGMM/Mult/DataModel/bestCollisionTable.h"
21+
22+
#include "Common/CCDB/EventSelectionParams.h"
23+
#include "Common/Core/TrackSelection.h"
24+
#include "Common/Core/trackUtilities.h"
25+
#include "Common/DataModel/Centrality.h"
26+
#include "Common/DataModel/EventSelection.h"
27+
#include "Common/DataModel/Multiplicity.h"
28+
#include "Common/DataModel/PIDResponse.h"
29+
#include "Common/DataModel/TrackSelectionTables.h"
30+
31+
#include "CCDB/BasicCCDBManager.h"
32+
#include "CommonConstants/MathConstants.h"
33+
#include "Framework/ASoAHelpers.h"
34+
#include "Framework/AnalysisDataModel.h"
35+
#include "Framework/AnalysisTask.h"
36+
#include "Framework/Configurable.h"
37+
#include "Framework/O2DatabasePDGPlugin.h"
38+
#include "Framework/runDataProcessing.h"
39+
#include "ReconstructionDataFormats/GlobalTrackID.h"
40+
#include "ReconstructionDataFormats/Track.h"
41+
42+
#include <TPDGCode.h>
43+
44+
#include <cmath>
45+
#include <cstdlib>
46+
#include <vector>
47+
48+
using namespace o2;
49+
using namespace o2::framework;
50+
using namespace o2::framework::expressions;
51+
using namespace o2::aod::track;
52+
using namespace o2::aod::evsel;
53+
54+
using ColDataTable = soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::PVMults>;
55+
using TrackDataTable = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection>;
56+
using FilTrackDataTable = soa::Filtered<TrackDataTable>;
57+
using ColMCTrueTable = aod::McCollisions;
58+
using TrackMCTrueTable = aod::McParticles;
59+
using ColMCRecTable = soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions, aod::EvSels, aod::Mults, aod::PVMults>>;
60+
using TrackMCRecTable = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::McTrackLabels, aod::TrackSelection>;
61+
using FilTrackMCRecTable = soa::Filtered<TrackMCRecTable>;
62+
63+
static constexpr TrackSelectionFlags::flagtype TrackSelectionIts =
64+
TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF |
65+
TrackSelectionFlags::kITSHits;
66+
static constexpr TrackSelectionFlags::flagtype TrackSelectionTpc =
67+
TrackSelectionFlags::kTPCNCls |
68+
TrackSelectionFlags::kTPCCrossedRowsOverNCls |
69+
TrackSelectionFlags::kTPCChi2NDF;
70+
static constexpr TrackSelectionFlags::flagtype TrackSelectionDca =
71+
TrackSelectionFlags::kDCAz | TrackSelectionFlags::kDCAxy;
72+
static constexpr TrackSelectionFlags::flagtype TrackSelectionDcaxyOnly =
73+
TrackSelectionFlags::kDCAxy;
74+
75+
AxisSpec axisEvent{10, 0.5, 10.5, "#Event", "EventAxis"};
76+
AxisSpec axisVtxZ{40, -20, 20, "Vertex Z", "VzAxis"};
77+
AxisSpec axisEta{40, -2, 2, "#eta", "EtaAxis"};
78+
AxisSpec axisPhi{629, 0, o2::constants::math::TwoPI, "#phi"};
79+
auto static constexpr kMinCharge = 3.f;
80+
81+
struct StudyPnch {
82+
83+
HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject};
84+
Service<o2::framework::O2DatabasePDG> pdg;
85+
Preslice<TrackMCRecTable> perCollision = aod::track::collisionId;
86+
87+
Configurable<float> etaRange{"etaRange", 1.0f, "Eta range to consider"};
88+
Configurable<float> vtxRange{"vtxRange", 10.0f, "Vertex Z range to consider"};
89+
Configurable<float> dcaZ{"dcaZ", 0.2f, "Custom DCA Z cut (ignored if negative)"};
90+
Configurable<float> extraphicut1{"extraphicut1", 3.07666f, "Extra Phi cut 1"};
91+
Configurable<float> extraphicut2{"extraphicut2", 3.12661f, "Extra Phi cut 2"};
92+
Configurable<float> extraphicut3{"extraphicut3", 0.03f, "Extra Phi cut 3"};
93+
Configurable<float> extraphicut4{"extraphicut4", 6.253f, "Extra Phi cut 4"};
94+
ConfigurableAxis multHistBin{"multHistBin", {501, -0.5, 500.5}, ""};
95+
ConfigurableAxis pvHistBin{"pvHistBin", {501, -0.5, 500.5}, ""};
96+
ConfigurableAxis fv0aMultHistBin{"fv0aMultHistBin", {501, -0.5, 500.5}, ""};
97+
ConfigurableAxis ft0aMultHistBin{"ft0aMultHistBin", {501, -0.5, 500.5}, ""};
98+
ConfigurableAxis ft0cMultHistBin{"ft0cMultHistBin", {501, -0.5, 500.5}, ""};
99+
ConfigurableAxis ptHistBin{"ptHistBin", {200, 0., 20.}, ""};
100+
101+
Configurable<bool> isApplyTFcut{"isApplyTFcut", true, "Enable TimeFrameBorder cut"};
102+
Configurable<bool> isApplyITSROcut{"isApplyITSROcut", true, "Enable ITS ReadOutFrameBorder cut"};
103+
Configurable<bool> isApplySameBunchPileup{"isApplySameBunchPileup", true, "Enable SameBunchPileup cut"};
104+
Configurable<bool> isApplyInelgt0{"isApplyInelgt0", false, "Enable INEL > 0 condition"};
105+
Configurable<bool> isApplyExtraPhiCut{"isApplyExtraPhiCut", false, "Enable extra phi cut"};
106+
107+
void init(InitContext const&)
108+
{
109+
AxisSpec axisMult = {multHistBin, "Mult", "MultAxis"};
110+
AxisSpec axisPV = {pvHistBin, "PV", "PVAxis"};
111+
AxisSpec axisFv0aMult = {fv0aMultHistBin, "fv0a", "FV0AMultAxis"};
112+
AxisSpec axisFt0aMult = {ft0aMultHistBin, "ft0a", "FT0AMultAxis"};
113+
AxisSpec axisFt0cMult = {ft0cMultHistBin, "ft0c", "FT0CMultAxis"};
114+
AxisSpec axisPt = {ptHistBin, "pT", "pTAxis"};
115+
116+
histos.add("EventHist", "EventHist", kTH1D, {axisEvent}, false);
117+
histos.add("VtxZHist", "VtxZHist", kTH1D, {axisVtxZ}, false);
118+
119+
auto hstat = histos.get<TH1>(HIST("EventHist"));
120+
auto* x = hstat->GetXaxis();
121+
x->SetBinLabel(1, "All events");
122+
x->SetBinLabel(2, "kIsTriggerTVX");
123+
x->SetBinLabel(3, "kNoTimeFrameBorder");
124+
x->SetBinLabel(4, "kNoITSROFrameBorder");
125+
x->SetBinLabel(5, "kNoSameBunchPileup"); // reject collisions in case of pileup with another collision in the same foundBC
126+
x->SetBinLabel(6, "INEL > 0");
127+
x->SetBinLabel(7, "|vz| < 10");
128+
129+
if (doprocessData || doprocessCorrelation || doprocessMonteCarlo) {
130+
histos.add("PhiVsEtaHist", "PhiVsEtaHist", kTH2F, {axisPhi, axisEta}, false);
131+
}
132+
if (doprocessData) {
133+
histos.add("hMultiplicityData", "hMultiplicityData", kTH1F, {axisMult}, true);
134+
}
135+
if (doprocessCorrelation) {
136+
histos.add("GlobalMult_vs_FT0A", "GlobalMult_vs_FT0A", kTH2F, {axisMult, axisFt0aMult}, true);
137+
histos.add("GlobalMult_vs_FT0C", "GlobalMult_vs_FT0C", kTH2F, {axisMult, axisFt0cMult}, true);
138+
histos.add("GlobalMult_vs_FV0A", "GlobalMult_vs_FV0A", kTH2F, {axisMult, axisFv0aMult}, true);
139+
histos.add("NPVtracks_vs_FT0C", "NPVtracks_vs_FT0C", kTH2F, {axisPV, axisFt0cMult}, true);
140+
histos.add("NPVtracks_vs_GlobalMult", "NPVtracks_vs_GlobalMult", kTH2F, {axisPV, axisMult}, true);
141+
}
142+
if (doprocessMonteCarlo) {
143+
histos.add("hMultiplicityMCrec", "hMultiplicityMCrec", kTH1F, {axisMult}, true);
144+
histos.add("hMultiplicityMCgen", "hMultiplicityMCgen", kTH1F, {axisMult}, true);
145+
histos.add("hResponseMatrix", "hResponseMatrix", kTH2F, {axisMult, axisMult}, true);
146+
}
147+
if (doprocessEvtLossSigLossMC) {
148+
histos.add("MCEventHist", "MCEventHist", kTH1F, {axisEvent}, false);
149+
auto hstat = histos.get<TH1>(HIST("MCEventHist"));
150+
auto* x = hstat->GetXaxis();
151+
x->SetBinLabel(1, "All MC events");
152+
x->SetBinLabel(2, "MC events with atleast one reco event");
153+
histos.add("hMultiplicityMCgenAll", "hMultiplicityMCgenAll", kTH1F, {axisMult}, true);
154+
histos.add("hMultiplicityMCgenSel", "hMultiplicityMCgenSel", kTH1F, {axisMult}, true);
155+
}
156+
}
157+
158+
template <typename CheckCol>
159+
bool isEventSelected(CheckCol const& col)
160+
{
161+
histos.fill(HIST("EventHist"), 1);
162+
if (!col.selection_bit(o2::aod::evsel::kIsTriggerTVX)) {
163+
return false;
164+
}
165+
histos.fill(HIST("EventHist"), 2);
166+
if (isApplyTFcut && !col.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) {
167+
return false;
168+
}
169+
histos.fill(HIST("EventHist"), 3);
170+
if (isApplyITSROcut && !col.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) {
171+
return false;
172+
}
173+
histos.fill(HIST("EventHist"), 4);
174+
if (isApplySameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) {
175+
return false;
176+
}
177+
histos.fill(HIST("EventHist"), 5);
178+
if (isApplyInelgt0 && !col.isInelGt0()) {
179+
return false;
180+
}
181+
histos.fill(HIST("EventHist"), 6);
182+
if (std::abs(col.posZ()) >= vtxRange) {
183+
return false;
184+
}
185+
histos.fill(HIST("EventHist"), 7);
186+
histos.fill(HIST("VtxZHist"), col.posZ());
187+
return true;
188+
}
189+
190+
template <typename CheckTrack>
191+
bool isTrackSelected(CheckTrack const& track)
192+
{
193+
if (std::abs(track.eta()) >= etaRange) {
194+
return false;
195+
}
196+
if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) {
197+
return false;
198+
}
199+
return true;
200+
}
201+
202+
template <typename CheckGenTrack>
203+
bool isGenTrackSelected(CheckGenTrack const& track)
204+
{
205+
if (!track.isPhysicalPrimary()) {
206+
return false;
207+
}
208+
if (!track.producedByGenerator()) {
209+
return false;
210+
}
211+
auto pdgTrack = pdg->GetParticle(track.pdgCode());
212+
if (pdgTrack == nullptr) {
213+
return false;
214+
}
215+
if (std::abs(pdgTrack->Charge()) < kMinCharge) {
216+
return false;
217+
}
218+
if (std::abs(track.eta()) >= etaRange) {
219+
return false;
220+
}
221+
if (isApplyExtraPhiCut && ((track.phi() > extraphicut1 && track.phi() < extraphicut2) || track.phi() <= extraphicut3 || track.phi() >= extraphicut4)) {
222+
return false;
223+
}
224+
return true;
225+
}
226+
227+
template <typename countTrk>
228+
int countNTracks(countTrk const& tracks)
229+
{
230+
auto nTrk = 0;
231+
for (const auto& track : tracks) {
232+
if (!isTrackSelected(track)) {
233+
continue;
234+
}
235+
histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta());
236+
nTrk++;
237+
}
238+
return nTrk;
239+
}
240+
241+
template <typename countTrk>
242+
int countGenTracks(countTrk const& tracks)
243+
{
244+
auto nTrk = 0;
245+
for (const auto& track : tracks) {
246+
if (!isGenTrackSelected(track)) {
247+
continue;
248+
}
249+
histos.fill(HIST("PhiVsEtaHist"), track.phi(), track.eta());
250+
nTrk++;
251+
}
252+
return nTrk;
253+
}
254+
255+
Filter fTrackSelectionITS = ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) &&
256+
ncheckbit(aod::track::trackCutFlag, TrackSelectionIts);
257+
Filter fTrackSelectionTPC = ifnode(ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::TPC),
258+
ncheckbit(aod::track::trackCutFlag, TrackSelectionTpc), true);
259+
Filter fTrackSelectionDCA = ifnode(dcaZ.node() > 0.f, nabs(aod::track::dcaZ) <= dcaZ && ncheckbit(aod::track::trackCutFlag, TrackSelectionDcaxyOnly),
260+
ncheckbit(aod::track::trackCutFlag, TrackSelectionDca));
261+
262+
void processData(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks)
263+
{
264+
if (!isEventSelected(cols)) {
265+
return;
266+
}
267+
auto mult = countNTracks(tracks);
268+
histos.fill(HIST("hMultiplicityData"), mult);
269+
}
270+
271+
void processCorrelation(ColDataTable::iterator const& cols, FilTrackDataTable const& tracks)
272+
{
273+
if (!isEventSelected(cols)) {
274+
return;
275+
}
276+
auto mult = countNTracks(tracks);
277+
histos.fill(HIST("GlobalMult_vs_FT0A"), mult, cols.multFT0A());
278+
histos.fill(HIST("GlobalMult_vs_FT0C"), mult, cols.multFT0C());
279+
histos.fill(HIST("GlobalMult_vs_FV0A"), mult, cols.multFV0A());
280+
histos.fill(HIST("NPVtracks_vs_FT0C"), cols.multNTracksPV(), cols.multFT0C());
281+
histos.fill(HIST("NPVtracks_vs_GlobalMult"), cols.multNTracksPV(), mult);
282+
}
283+
284+
void processMonteCarlo(ColMCTrueTable::iterator const&, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles, FilTrackMCRecTable const& RecTracks)
285+
{
286+
for (const auto& RecCol : RecCols) {
287+
if (!isEventSelected(RecCol)) {
288+
continue;
289+
}
290+
auto recTracksPart = RecTracks.sliceBy(perCollision, RecCol.globalIndex());
291+
auto multrec = countNTracks(recTracksPart);
292+
histos.fill(HIST("hMultiplicityMCrec"), multrec);
293+
auto multgen = countGenTracks(GenParticles);
294+
histos.fill(HIST("hMultiplicityMCgen"), multgen);
295+
histos.fill(HIST("hResponseMatrix"), multrec, multgen);
296+
}
297+
}
298+
299+
void processEvtLossSigLossMC(soa::Join<ColMCTrueTable, aod::MultMCExtras>::iterator const& mcCollision, ColMCRecTable const& RecCols, TrackMCTrueTable const& GenParticles)
300+
{
301+
if (isApplyInelgt0 && !mcCollision.isInelGt0()) {
302+
return;
303+
}
304+
if (std::abs(mcCollision.posZ()) >= vtxRange) {
305+
return;
306+
}
307+
// All generated events
308+
histos.fill(HIST("MCEventHist"), 1);
309+
auto multAll = countGenTracks(GenParticles);
310+
histos.fill(HIST("hMultiplicityMCgenAll"), multAll);
311+
312+
bool atLeastOne = false;
313+
auto numcontributors = -999;
314+
for (const auto& RecCol : RecCols) {
315+
if (!isEventSelected(RecCol)) {
316+
continue;
317+
}
318+
if (RecCol.numContrib() <= numcontributors) {
319+
continue;
320+
} else {
321+
numcontributors = RecCol.numContrib();
322+
}
323+
atLeastOne = true;
324+
}
325+
326+
if (atLeastOne) {
327+
histos.fill(HIST("MCEventHist"), 2);
328+
auto multSel = countGenTracks(GenParticles);
329+
histos.fill(HIST("hMultiplicityMCgenSel"), multSel);
330+
}
331+
}
332+
333+
PROCESS_SWITCH(StudyPnch, processData, "process data CentFT0C", false);
334+
PROCESS_SWITCH(StudyPnch, processCorrelation, "do correlation study in data", false);
335+
PROCESS_SWITCH(StudyPnch, processMonteCarlo, "process MC CentFT0C", false);
336+
PROCESS_SWITCH(StudyPnch, processEvtLossSigLossMC, "process Signal Loss, Event Loss", false);
337+
};
338+
339+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
340+
{
341+
return WorkflowSpec{adaptAnalysisTask<StudyPnch>(cfgc)};
342+
}

0 commit comments

Comments
 (0)