Skip to content

Commit 787df17

Browse files
authored
[PWGCF] calculate v2 correction factor from MC (#9742)
1 parent 774f932 commit 787df17

File tree

3 files changed

+623
-2
lines changed

3 files changed

+623
-2
lines changed

PWGCF/Flow/Tasks/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
o2physics_add_dpl_workflow(flow-pt-efficiency
1313
SOURCES flowPtEfficiency.cxx
14-
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore
14+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore
1515
COMPONENT_NAME Analysis)
1616

1717
o2physics_add_dpl_workflow(flow-task
@@ -24,6 +24,11 @@ o2physics_add_dpl_workflow(flow-runby-run
2424
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::GFWCore
2525
COMPONENT_NAME Analysis)
2626

27+
o2physics_add_dpl_workflow(flow-mc
28+
SOURCES flowMc.cxx
29+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore
30+
COMPONENT_NAME Analysis)
31+
2732
o2physics_add_dpl_workflow(flow-gfw-task
2833
SOURCES flowGfwTask.cxx
2934
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore

PWGCF/Flow/Tasks/flowMc.cxx

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
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 flowMc.cxx
13+
/// \author Zhiyong Lu (zhiyong.lu@cern.ch)
14+
/// \since Feb/5/2025
15+
/// \brief QC of synthetic flow exercise
16+
17+
#include <CCDB/BasicCCDBManager.h>
18+
#include <string>
19+
#include "Framework/AnalysisDataModel.h"
20+
#include "Framework/AnalysisTask.h"
21+
#include "Framework/HistogramRegistry.h"
22+
#include "Framework/runDataProcessing.h"
23+
#include "Framework/ASoAHelpers.h"
24+
#include "Framework/RunningWorkflowInfo.h"
25+
#include "Common/DataModel/TrackSelectionTables.h"
26+
#include "Common/Core/TrackSelection.h"
27+
#include "Common/Core/TrackSelectionDefaults.h"
28+
#include "Common/Core/trackUtilities.h"
29+
#include "ReconstructionDataFormats/Track.h"
30+
#include "DataFormatsParameters/GRPObject.h"
31+
#include "DataFormatsParameters/GRPMagField.h"
32+
#include "PWGLF/DataModel/LFStrangenessTables.h"
33+
#include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table
34+
#include "GFWPowerArray.h"
35+
#include "GFW.h"
36+
#include "GFWCumulant.h"
37+
#include "GFWWeights.h"
38+
39+
using namespace o2;
40+
using namespace o2::framework;
41+
using namespace o2::framework::expressions;
42+
43+
#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP};
44+
45+
struct FlowMc {
46+
HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject};
47+
48+
Configurable<float> minB{"minB", 0.0f, "min impact parameter"};
49+
Configurable<float> maxB{"maxB", 20.0f, "max impact parameter"};
50+
O2_DEFINE_CONFIGURABLE(cfgOutputNUAWeights, bool, false, "Fill and output NUA weights")
51+
O2_DEFINE_CONFIGURABLE(cfgCutPtRefMin, float, 0.2f, "Minimal pT for ref tracks")
52+
O2_DEFINE_CONFIGURABLE(cfgCutPtRefMax, float, 3.0f, "Maximal pT for ref tracks")
53+
O2_DEFINE_CONFIGURABLE(cfgFlowAcceptance, std::string, "", "CCDB path to acceptance object")
54+
O2_DEFINE_CONFIGURABLE(cfgFlowEfficiency, std::string, "", "CCDB path to efficiency object")
55+
56+
ConfigurableAxis axisB{"axisB", {100, 0.0f, 20.0f}, ""};
57+
ConfigurableAxis axisPhi{"axisPhi", {100, 0.0f, constants::math::TwoPI}, ""};
58+
ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "Nch in |eta|<0.8"};
59+
60+
ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}, "pt axis"};
61+
62+
// Corrections
63+
TH1D* mEfficiency = nullptr;
64+
GFWWeights* mAcceptance = nullptr;
65+
bool correctionsLoaded = false;
66+
67+
// Connect to ccdb
68+
Service<ccdb::BasicCCDBManager> ccdb;
69+
Configurable<int64_t> ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"};
70+
Configurable<std::string> ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"};
71+
72+
OutputObj<GFWWeights> fWeights{GFWWeights("weights")};
73+
74+
void init(InitContext&)
75+
{
76+
// pT histograms
77+
histos.add<TH1>("hImpactParameter", "hImpactParameter", HistType::kTH1D, {axisB});
78+
histos.add<TH2>("hNchVsImpactParameter", "hNchVsImpactParameter", HistType::kTH2D, {axisB, axisNch});
79+
histos.add<TH1>("hEventPlaneAngle", "hEventPlaneAngle", HistType::kTH1D, {axisPhi});
80+
histos.add<TH2>("hPtVsPhiGenerated", "hPtVsPhiGenerated", HistType::kTH2D, {axisPhi, axisPt});
81+
histos.add<TH2>("hPtVsPhiGlobal", "hPtVsPhiGlobal", HistType::kTH2D, {axisPhi, axisPt});
82+
histos.add<TH3>("hBVsPtVsPhiGenerated", "hBVsPtVsPhiGenerated", HistType::kTH3D, {axisB, axisPhi, axisPt});
83+
histos.add<TH3>("hBVsPtVsPhiGlobal", "hBVsPtVsPhiGlobal", HistType::kTH3D, {axisB, axisPhi, axisPt});
84+
histos.add<TH3>("hBVsPtVsPhiAny", "hBVsPtVsPhiAny", HistType::kTH3D, {axisB, axisPhi, axisPt});
85+
histos.add<TH3>("hBVsPtVsPhiTPCTrack", "hBVsPtVsPhiTPCTrack", HistType::kTH3D, {axisB, axisPhi, axisPt});
86+
histos.add<TH3>("hBVsPtVsPhiITSTrack", "hBVsPtVsPhiITSTrack", HistType::kTH3D, {axisB, axisPhi, axisPt});
87+
histos.add<TH3>("hBVsPtVsPhiITSABTrack", "hBVsPtVsPhiITSABTrack", HistType::kTH3D, {axisB, axisPhi, axisPt});
88+
89+
histos.add<TH3>("hBVsPtVsPhiGeneratedK0Short", "hBVsPtVsPhiGeneratedK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt});
90+
histos.add<TH3>("hBVsPtVsPhiGlobalK0Short", "hBVsPtVsPhiGlobalK0Short", HistType::kTH3D, {axisB, axisPhi, axisPt});
91+
histos.add<TH3>("hBVsPtVsPhiGeneratedLambda", "hBVsPtVsPhiGeneratedLambda", HistType::kTH3D, {axisB, axisPhi, axisPt});
92+
histos.add<TH3>("hBVsPtVsPhiGlobalLambda", "hBVsPtVsPhiGlobalLambda", HistType::kTH3D, {axisB, axisPhi, axisPt});
93+
94+
histos.add<TH3>("hBVsPtVsPhiGeneratedXi", "hBVsPtVsPhiGeneratedXi", HistType::kTH3D, {axisB, axisPhi, axisPt});
95+
histos.add<TH3>("hBVsPtVsPhiGlobalXi", "hBVsPtVsPhiGlobalXi", HistType::kTH3D, {axisB, axisPhi, axisPt});
96+
histos.add<TH3>("hBVsPtVsPhiGeneratedOmega", "hBVsPtVsPhiGeneratedOmega", HistType::kTH3D, {axisB, axisPhi, axisPt});
97+
histos.add<TH3>("hBVsPtVsPhiGlobalOmega", "hBVsPtVsPhiGlobalOmega", HistType::kTH3D, {axisB, axisPhi, axisPt});
98+
99+
histos.add<TH1>("hPhi", "#phi distribution", HistType::kTH1D, {axisPhi});
100+
histos.add<TH1>("hPhiWeighted", "corrected #phi distribution", HistType::kTH1D, {axisPhi});
101+
102+
if (cfgOutputNUAWeights) {
103+
o2::framework::AxisSpec axis = axisPt;
104+
int nPtBins = axis.binEdges.size() - 1;
105+
double* ptBins = &(axis.binEdges)[0];
106+
107+
fWeights->setPtBins(nPtBins, ptBins);
108+
fWeights->init(true, false);
109+
}
110+
}
111+
112+
void loadCorrections(uint64_t timestamp)
113+
{
114+
if (correctionsLoaded)
115+
return;
116+
if (cfgFlowAcceptance.value.empty() == false) {
117+
mAcceptance = ccdb->getForTimeStamp<GFWWeights>(cfgFlowAcceptance, timestamp);
118+
if (mAcceptance)
119+
LOGF(info, "Loaded acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), (void*)mAcceptance);
120+
else
121+
LOGF(warning, "Could not load acceptance weights from %s (%p)", cfgFlowAcceptance.value.c_str(), (void*)mAcceptance);
122+
}
123+
if (cfgFlowEfficiency.value.empty() == false) {
124+
mEfficiency = ccdb->getForTimeStamp<TH1D>(cfgFlowEfficiency, timestamp);
125+
if (mEfficiency == nullptr) {
126+
LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgFlowEfficiency.value.c_str());
127+
}
128+
LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgFlowEfficiency.value.c_str(), (void*)mEfficiency);
129+
}
130+
correctionsLoaded = true;
131+
}
132+
133+
bool setCurrentParticleWeights(float& weight_nue, float& weight_nua, float phi, float eta, float pt, float vtxz)
134+
{
135+
float eff = 1.;
136+
if (mEfficiency)
137+
eff = mEfficiency->GetBinContent(mEfficiency->FindBin(pt));
138+
else
139+
eff = 1.0;
140+
if (eff == 0)
141+
return false;
142+
weight_nue = 1. / eff;
143+
if (mAcceptance)
144+
weight_nua = mAcceptance->getNUA(phi, eta, vtxz);
145+
else
146+
weight_nua = 1;
147+
return true;
148+
}
149+
150+
using RecoTracks = soa::Join<aod::TracksIU, aod::TracksExtra>;
151+
152+
void process(aod::McCollision const& mcCollision, soa::Join<aod::McParticles, aod::ParticlesToTracks> const& mcParticles, RecoTracks const&)
153+
{
154+
155+
float imp = mcCollision.impactParameter();
156+
float evPhi = mcCollision.eventPlaneAngle();
157+
float vtxz = mcCollision.posZ();
158+
if (evPhi < 0)
159+
evPhi += constants::math::TwoPI;
160+
161+
int64_t nCh = 0;
162+
float weff = 1.;
163+
float wacc = 1.;
164+
auto bc = mcCollision.bc_as<aod::BCsWithTimestamps>();
165+
loadCorrections(bc.timestamp());
166+
167+
if (imp > minB && imp < maxB) {
168+
// event within range
169+
histos.fill(HIST("hImpactParameter"), imp);
170+
histos.fill(HIST("hEventPlaneAngle"), evPhi);
171+
172+
for (auto const& mcParticle : mcParticles) {
173+
// focus on bulk: e, mu, pi, k, p
174+
int pdgCode = std::abs(mcParticle.pdgCode());
175+
if (pdgCode != 11 && pdgCode != 13 && pdgCode != 211 && pdgCode != 321 && pdgCode != 2212)
176+
continue;
177+
178+
if (!mcParticle.isPhysicalPrimary())
179+
continue;
180+
if (std::fabs(mcParticle.eta()) > 0.8) // main acceptance
181+
continue;
182+
183+
float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle();
184+
if (deltaPhi < 0)
185+
deltaPhi += constants::math::TwoPI;
186+
if (deltaPhi > constants::math::TwoPI)
187+
deltaPhi -= constants::math::TwoPI;
188+
histos.fill(HIST("hPtVsPhiGenerated"), deltaPhi, mcParticle.pt());
189+
histos.fill(HIST("hBVsPtVsPhiGenerated"), imp, deltaPhi, mcParticle.pt());
190+
191+
nCh++;
192+
193+
bool validGlobal = false;
194+
bool validTrack = false;
195+
bool validTPCTrack = false;
196+
bool validITSTrack = false;
197+
bool validITSABTrack = false;
198+
if (mcParticle.has_tracks()) {
199+
auto const& tracks = mcParticle.tracks_as<RecoTracks>();
200+
for (auto const& track : tracks) {
201+
if (track.hasTPC() && track.hasITS()) {
202+
validGlobal = true;
203+
}
204+
if (track.hasTPC() || track.hasITS()) {
205+
validTrack = true;
206+
}
207+
if (track.hasTPC()) {
208+
validTPCTrack = true;
209+
}
210+
if (track.hasITS() && track.itsChi2NCl() > -1e-6) {
211+
validITSTrack = true;
212+
}
213+
if (track.hasITS() && track.itsChi2NCl() < -1e-6) {
214+
validITSABTrack = true;
215+
}
216+
}
217+
}
218+
219+
bool withinPtRef = (cfgCutPtRefMin < mcParticle.pt()) && (mcParticle.pt() < cfgCutPtRefMax); // within RF pT range
220+
if (cfgOutputNUAWeights && withinPtRef)
221+
fWeights->fill(mcParticle.phi(), mcParticle.eta(), vtxz, mcParticle.pt(), 0, 0);
222+
if (!setCurrentParticleWeights(weff, wacc, mcParticle.phi(), mcParticle.eta(), mcParticle.pt(), vtxz))
223+
continue;
224+
if (withinPtRef) {
225+
histos.fill(HIST("hPhi"), mcParticle.phi());
226+
histos.fill(HIST("hPhiWeighted"), mcParticle.phi(), wacc);
227+
}
228+
229+
// if valid global, fill
230+
if (validGlobal) {
231+
histos.fill(HIST("hPtVsPhiGlobal"), deltaPhi, mcParticle.pt(), wacc * weff);
232+
histos.fill(HIST("hBVsPtVsPhiGlobal"), imp, deltaPhi, mcParticle.pt(), wacc * weff);
233+
}
234+
// if any track present, fill
235+
if (validTrack)
236+
histos.fill(HIST("hBVsPtVsPhiAny"), imp, deltaPhi, mcParticle.pt(), wacc * weff);
237+
if (validTPCTrack)
238+
histos.fill(HIST("hBVsPtVsPhiTPCTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff);
239+
if (validITSTrack)
240+
histos.fill(HIST("hBVsPtVsPhiITSTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff);
241+
if (validITSABTrack)
242+
histos.fill(HIST("hBVsPtVsPhiITSABTrack"), imp, deltaPhi, mcParticle.pt(), wacc * weff);
243+
}
244+
}
245+
histos.fill(HIST("hNchVsImpactParameter"), imp, nCh);
246+
}
247+
248+
using LabeledCascades = soa::Join<aod::CascDataExt, aod::McCascLabels>;
249+
250+
void processCascade(aod::McParticle const& mcParticle, soa::SmallGroups<LabeledCascades> const& cascades, RecoTracks const&, aod::McCollisions const&)
251+
{
252+
auto mcCollision = mcParticle.mcCollision();
253+
float imp = mcCollision.impactParameter();
254+
255+
int pdgCode = std::abs(mcParticle.pdgCode());
256+
if (pdgCode != 3312 && pdgCode != 3334)
257+
return;
258+
259+
if (!mcParticle.isPhysicalPrimary())
260+
return;
261+
if (std::fabs(mcParticle.eta()) > 0.8)
262+
return;
263+
264+
float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle();
265+
if (deltaPhi < 0)
266+
deltaPhi += constants::math::TwoPI;
267+
if (deltaPhi > constants::math::TwoPI)
268+
deltaPhi -= constants::math::TwoPI;
269+
if (pdgCode == 3312)
270+
histos.fill(HIST("hBVsPtVsPhiGeneratedXi"), imp, deltaPhi, mcParticle.pt());
271+
if (pdgCode == 3334)
272+
histos.fill(HIST("hBVsPtVsPhiGeneratedOmega"), imp, deltaPhi, mcParticle.pt());
273+
274+
if (cascades.size() > 0) {
275+
if (pdgCode == 3312)
276+
histos.fill(HIST("hBVsPtVsPhiGlobalXi"), imp, deltaPhi, mcParticle.pt());
277+
if (pdgCode == 3334)
278+
histos.fill(HIST("hBVsPtVsPhiGlobalOmega"), imp, deltaPhi, mcParticle.pt());
279+
}
280+
}
281+
PROCESS_SWITCH(FlowMc, processCascade, "Process cascades", true);
282+
283+
using LabeledV0s = soa::Join<aod::V0Datas, aod::McV0Labels>;
284+
285+
void processV0s(aod::McParticle const& mcParticle, soa::SmallGroups<LabeledV0s> const& v0s, RecoTracks const&, aod::McCollisions const&)
286+
{
287+
auto mcCollision = mcParticle.mcCollision();
288+
float imp = mcCollision.impactParameter();
289+
290+
int pdgCode = std::abs(mcParticle.pdgCode());
291+
if (pdgCode != 310 && pdgCode != 3122)
292+
return;
293+
294+
if (!mcParticle.isPhysicalPrimary())
295+
return;
296+
if (std::fabs(mcParticle.eta()) > 0.8)
297+
return;
298+
299+
float deltaPhi = mcParticle.phi() - mcCollision.eventPlaneAngle();
300+
if (deltaPhi < 0)
301+
deltaPhi += constants::math::TwoPI;
302+
if (deltaPhi > constants::math::TwoPI)
303+
deltaPhi -= constants::math::TwoPI;
304+
if (pdgCode == 310)
305+
histos.fill(HIST("hBVsPtVsPhiGeneratedK0Short"), imp, deltaPhi, mcParticle.pt());
306+
if (pdgCode == 3122)
307+
histos.fill(HIST("hBVsPtVsPhiGeneratedLambda"), imp, deltaPhi, mcParticle.pt());
308+
309+
if (v0s.size() > 0) {
310+
if (pdgCode == 310)
311+
histos.fill(HIST("hBVsPtVsPhiGlobalK0Short"), imp, deltaPhi, mcParticle.pt());
312+
if (pdgCode == 3122)
313+
histos.fill(HIST("hBVsPtVsPhiGlobalLambda"), imp, deltaPhi, mcParticle.pt());
314+
}
315+
}
316+
PROCESS_SWITCH(FlowMc, processV0s, "Process V0s", true);
317+
};
318+
319+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
320+
{
321+
return WorkflowSpec{
322+
adaptAnalysisTask<FlowMc>(cfgc)};
323+
}

0 commit comments

Comments
 (0)