Skip to content

Commit ee7ecd7

Browse files
Preet-BhanjanPreet Patialibuild
authored
[PWGCF] Flow for Phi meson using generic framework (#9406)
Co-authored-by: Preet Pati <preet@preet-2.local> Co-authored-by: ALICE Action Bot <alibuild@cern.ch>
1 parent 6f5d421 commit ee7ecd7

File tree

2 files changed

+346
-0
lines changed

2 files changed

+346
-0
lines changed

PWGCF/Flow/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,8 @@ o2physics_add_dpl_workflow(flow-sp
5858
SOURCES flowSP.cxx
5959
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore
6060
COMPONENT_NAME Analysis)
61+
62+
o2physics_add_dpl_workflow(resonances-gfw-flow
63+
SOURCES resonancesGfwFlow.cxx
64+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::GFWCore
65+
COMPONENT_NAME Analysis)
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
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 resonancesGfwFlow.cxx
13+
/// \brief PID flow for resonances using the generic framework
14+
/// \author Preet Bhanjan Pati <preet.bhanjan.pati@cern.ch>
15+
16+
#include <CCDB/BasicCCDBManager.h>
17+
#include <cmath>
18+
#include <vector>
19+
#include <utility>
20+
#include <array>
21+
#include <string>
22+
23+
#include "Math/Vector4D.h"
24+
25+
#include "Framework/runDataProcessing.h"
26+
#include "Framework/AnalysisTask.h"
27+
#include "Framework/ASoAHelpers.h"
28+
#include "Framework/RunningWorkflowInfo.h"
29+
#include "Framework/HistogramRegistry.h"
30+
#include "Framework/AnalysisDataModel.h"
31+
#include "Framework/StepTHn.h"
32+
33+
#include "Common/DataModel/EventSelection.h"
34+
#include "Common/Core/TrackSelection.h"
35+
#include "Common/DataModel/TrackSelectionTables.h"
36+
#include "Common/DataModel/Centrality.h"
37+
#include "Common/DataModel/PIDResponse.h"
38+
#include "Common/Core/trackUtilities.h"
39+
#include "Common/Core/RecoDecay.h"
40+
#include "Common/DataModel/Multiplicity.h"
41+
#include "PWGLF/DataModel/EPCalibrationTables.h"
42+
#include "CommonConstants/PhysicsConstants.h"
43+
44+
#include "ReconstructionDataFormats/Track.h"
45+
#include "ReconstructionDataFormats/PID.h"
46+
47+
#include <TProfile.h>
48+
#include <TRandom3.h>
49+
#include <TF1.h>
50+
51+
using namespace o2;
52+
using namespace o2::framework;
53+
using namespace o2::framework::expressions;
54+
using namespace std;
55+
56+
#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP};
57+
58+
struct ResonancesGfwFlow {
59+
Service<ccdb::BasicCCDBManager> ccdb;
60+
Configurable<int64_t> noLaterThan{"noLaterThan", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"};
61+
Configurable<std::string> ccdbUrl{"ccdbUrl", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"};
62+
63+
O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range")
64+
O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMin, float, 0.2f, "Minimal pT for poi tracks")
65+
O2_DEFINE_CONFIGURABLE(cfgCutPtPOIMax, float, 10.0f, "Maximal pT for poi tracks")
66+
O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for ref tracks")
67+
O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for ref tracks")
68+
O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks")
69+
O2_DEFINE_CONFIGURABLE(cfgCutChi2prTPCcls, float, 2.5, "Chi2 per TPC clusters")
70+
O2_DEFINE_CONFIGURABLE(cfgUseNch, bool, false, "Use Nch for flow observables")
71+
O2_DEFINE_CONFIGURABLE(cfgNbootstrap, int, 10, "Number of subsamples")
72+
O2_DEFINE_CONFIGURABLE(cfgTpcNsigmaCut, float, 3.0f, "TPC N-sigma cut for pions, kaons, protons")
73+
O2_DEFINE_CONFIGURABLE(cfgTofNsigmaCut, float, 3.0f, "TOF N-sigma cut for pions, kaons, protons")
74+
O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.5f, "Minimum pt to use TOF N-sigma")
75+
76+
O2_DEFINE_CONFIGURABLE(cfgUsePVContributor, bool, true, "Use PV contributor for tracks")
77+
O2_DEFINE_CONFIGURABLE(cfgFakePartCut, float, 0.1f, "Maximum difference in measured momentum and TPC inner ring momentum of particle")
78+
O2_DEFINE_CONFIGURABLE(cfgTpcCluster, int, 70, "Number of TPC clusters")
79+
O2_DEFINE_CONFIGURABLE(cfgUsePointingAngle, bool, false, "Use Pointing angle for resonances")
80+
O2_DEFINE_CONFIGURABLE(cfgPointingAnglePhi, float, 0.04f, "Minimum Pointing angle for Phi")
81+
O2_DEFINE_CONFIGURABLE(cfgPointingAngleKo, float, 0.97f, "Minimum Pointing angle for K0")
82+
O2_DEFINE_CONFIGURABLE(cfgPointingAngleLambda, float, 0.995f, "Minimum Pointing angle for Lambda")
83+
O2_DEFINE_CONFIGURABLE(cfgUseVoRadius, bool, true, "Use V0 radius for particle identification")
84+
O2_DEFINE_CONFIGURABLE(cfgVoRadiusMin, float, 0.5f, "Minimum V0 radius in cm")
85+
O2_DEFINE_CONFIGURABLE(cfgVoRadiusMax, float, 200.0f, "Maximum V0 radius in cm")
86+
O2_DEFINE_CONFIGURABLE(cfgUseProperLifetime, bool, true, "Use proper lifetime for particle identification")
87+
O2_DEFINE_CONFIGURABLE(cfgProperLtK0, float, 20.0f, "Minimum lifetime for K0 in cm")
88+
O2_DEFINE_CONFIGURABLE(cfgProperLtLambda, float, 30.0f, "Minimum lifetime for Lambda in cm")
89+
O2_DEFINE_CONFIGURABLE(cfgUseDCA, bool, true, "Use dca for daughter tracks")
90+
O2_DEFINE_CONFIGURABLE(cfgDCAtoPV, float, 0.06f, "Minimum DCA of daughter tracks to primary vertex in cm")
91+
O2_DEFINE_CONFIGURABLE(cfgDCABetDaug, int, 1, "Maximum DCA between daughter tracks")
92+
93+
O2_DEFINE_CONFIGURABLE(cfgCutDCAxy, float, 2.0f, "DCAxy range for tracks")
94+
O2_DEFINE_CONFIGURABLE(cfgCutDCAz, float, 2.0f, "DCAz range for tracks")
95+
O2_DEFINE_CONFIGURABLE(additionalEvsel, bool, false, "Additional event selcection")
96+
O2_DEFINE_CONFIGURABLE(useGlobalTrack, bool, true, "use Global track")
97+
O2_DEFINE_CONFIGURABLE(cfgITScluster, int, 0, "Number of ITS cluster")
98+
O2_DEFINE_CONFIGURABLE(cfgCutTOFBeta, float, 0.0, "cut TOF beta")
99+
O2_DEFINE_CONFIGURABLE(cfgCutOccupancy, int, 3000, "Occupancy cut")
100+
O2_DEFINE_CONFIGURABLE(ispTdepPID, bool, true, "pT dependent PID")
101+
O2_DEFINE_CONFIGURABLE(removefaketrack, bool, true, "Remove fake track from momentum difference")
102+
O2_DEFINE_CONFIGURABLE(confRapidity, float, 0.5, "Rapidity cut")
103+
104+
// Defining configurable axis
105+
ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"};
106+
ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, constants::math::TwoPI}, "phi axis for histograms"};
107+
ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"};
108+
ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.20, 1.40, 1.60, 1.80, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00, 3.50, 4.00, 5.00, 6.00, 8.00, 10.00}, "pt axis for histograms"};
109+
ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90}, "centrality axis for histograms"};
110+
ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"};
111+
ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"};
112+
ConfigurableAxis axisParticles{"axisParticles", {3, 0, 3}, "axis for different hadrons"};
113+
ConfigurableAxis axisPhiMass{"axisPhiMass", {50000, 0, 5}, "axis for invariant mass distibution for Phi"};
114+
ConfigurableAxis axisKoMass{"axisKoMass", {50000, 0, 5}, "axis for invariant mass distibution for K0"};
115+
ConfigurableAxis axisLambdaMass{"axisLambdaMass", {50000, 0, 5}, "axis for invariant mass distibution for Lambda"};
116+
ConfigurableAxis axisTPCsignal{"axisTPCsignal", {10000, 0, 1000}, "axis for TPC signal"};
117+
ConfigurableAxis axisTOFsignal{"axisTOFsignal", {10000, 0, 1000}, "axis for TOF signal"};
118+
119+
Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex;
120+
Filter trackFilter = (nabs(aod::track::dcaXY) < cfgCutDCAxy) && (nabs(aod::track::dcaZ) < cfgCutDCAz) && (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtPOIMin) && (aod::track::pt < cfgCutPtPOIMax);
121+
122+
using AodCollisions = soa::Filtered<soa::Join<aod::Collisions, aod::EvSels, aod::FT0Mults, aod::FV0Mults, aod::TPCMults, aod::CentFV0As, aod::CentFT0Ms, aod::CentFT0Cs, aod::CentFT0As, aod::Mults>>;
123+
using AodTracksWithoutBayes = soa::Filtered<soa::Join<aod::Tracks, aod::TrackSelection, aod::TracksExtra, aod::TracksDCA, aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, aod::pidTOFbeta, aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>>;
124+
125+
SliceCache cache;
126+
Partition<AodTracksWithoutBayes> posTracks = aod::track::signed1Pt > 0.0f;
127+
Partition<AodTracksWithoutBayes> negTracks = aod::track::signed1Pt < 0.0f;
128+
129+
HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject};
130+
131+
TAxis* fPtAxis;
132+
TRandom3* fRndm = new TRandom3(0);
133+
134+
// Event selection cuts - Alex
135+
TF1* fMultPVCutLow = nullptr;
136+
TF1* fMultPVCutHigh = nullptr;
137+
TF1* fMultCutLow = nullptr;
138+
TF1* fMultCutHigh = nullptr;
139+
TF1* fMultMultPVCut = nullptr;
140+
141+
void init(InitContext const&)
142+
{
143+
ccdb->setURL(ccdbUrl.value);
144+
ccdb->setCaching(true);
145+
ccdb->setCreatedNotAfter(noLaterThan.value);
146+
147+
histos.add("hPhi", "", {HistType::kTH1D, {axisPhi}});
148+
histos.add("hEta", "", {HistType::kTH1D, {axisEta}});
149+
histos.add("hVtxZ", "", {HistType::kTH1D, {axisVertex}});
150+
histos.add("hMult", "", {HistType::kTH1D, {{3000, 0.5, 3000.5}}});
151+
histos.add("hCent", "", {HistType::kTH1D, {{90, 0, 90}}});
152+
153+
histos.add("KaplusTPC", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}});
154+
histos.add("KaminusTPC", "", {HistType::kTH2D, {{axisPt, axisTPCsignal}}});
155+
histos.add("KaplusTOF", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}});
156+
histos.add("KaminusTOF", "", {HistType::kTH2D, {{axisPt, axisTOFsignal}}});
157+
histos.add("hPhiMass_sparse", "", {HistType::kTHnSparseD, {{axisPhiMass, axisPt, axisMultiplicity}}});
158+
159+
if (additionalEvsel) {
160+
fMultPVCutLow = new TF1("fMultPVCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100);
161+
fMultPVCutLow->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05);
162+
fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100);
163+
fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05);
164+
fMultCutLow = new TF1("fMultCutLow", "[0]+[1]*x+[2]*x*x+[3]*x*x*x - 2.5*([4]+[5]*x)", 0, 100);
165+
fMultCutLow->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253);
166+
fMultCutHigh = new TF1("fMultCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 3.*([4]+[5]*x)", 0, 100);
167+
fMultCutHigh->SetParameters(1893.94, -53.86, 0.502913, -0.0015122, 109.625, -1.19253);
168+
fMultMultPVCut = new TF1("fMultMultPVCut", "[0]+[1]*x+[2]*x*x", 0, 5000);
169+
fMultMultPVCut->SetParameters(-0.1, 0.785, -4.7e-05);
170+
}
171+
}
172+
173+
// deep angle cut on pair to remove photon conversion
174+
template <typename T1, typename T2>
175+
bool selectionPair(const T1& candidate1, const T2& candidate2)
176+
{
177+
double pt1, pt2, pz1, pz2, p1, p2, angle;
178+
pt1 = candidate1.pt();
179+
pt2 = candidate2.pt();
180+
pz1 = candidate1.pz();
181+
pz2 = candidate2.pz();
182+
p1 = candidate1.p();
183+
p2 = candidate2.p();
184+
angle = std::acos((pt1 * pt2 + pz1 * pz2) / (p1 * p2));
185+
if (cfgUsePointingAngle && angle < cfgPointingAnglePhi) {
186+
return false;
187+
}
188+
return true;
189+
}
190+
191+
template <typename TCollision>
192+
bool eventSelected(TCollision collision, const float& centrality)
193+
{
194+
auto multNTracksPV = collision.multNTracksPV();
195+
if (multNTracksPV < fMultPVCutLow->Eval(centrality))
196+
return 0;
197+
if (multNTracksPV > fMultPVCutHigh->Eval(centrality))
198+
return 0;
199+
200+
return 1;
201+
}
202+
203+
template <typename T>
204+
bool selectionTrack(const T& candidate)
205+
{
206+
if (useGlobalTrack && !(candidate.isGlobalTrack() && candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster && candidate.tpcNClsFound() > cfgTpcCluster)) {
207+
return false;
208+
}
209+
if (!useGlobalTrack && !(candidate.isPVContributor() && candidate.itsNCls() > cfgITScluster)) {
210+
return false;
211+
}
212+
return true;
213+
}
214+
215+
template <typename T>
216+
bool selectionPIDpTdependent(const T& candidate)
217+
{
218+
if (candidate.pt() < 0.5 && std::abs(candidate.tpcNSigmaKa()) < cfgTpcNsigmaCut) {
219+
return true;
220+
}
221+
if (candidate.pt() >= 0.5 && candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && std::abs(candidate.tpcNSigmaKa()) < cfgTpcNsigmaCut && std::abs(candidate.tofNSigmaKa()) < cfgTofNsigmaCut) {
222+
return true;
223+
}
224+
if (!useGlobalTrack && !candidate.hasTPC()) {
225+
return true;
226+
}
227+
return false;
228+
}
229+
template <typename T>
230+
bool selectionPID(const T& candidate)
231+
{
232+
if (!candidate.hasTOF() && std::abs(candidate.tpcNSigmaKa()) < cfgTpcNsigmaCut) {
233+
return true;
234+
}
235+
if (candidate.hasTOF() && candidate.beta() > cfgCutTOFBeta && std::abs(candidate.tpcNSigmaKa()) < cfgTpcNsigmaCut && std::abs(candidate.tofNSigmaKa()) < cfgTofNsigmaCut) {
236+
return true;
237+
}
238+
return false;
239+
}
240+
241+
template <typename T>
242+
bool isFakeKaon(T const& track)
243+
{
244+
const auto pglobal = track.p();
245+
const auto ptpc = track.tpcInnerParam();
246+
if (std::abs(pglobal - ptpc) > cfgFakePartCut) {
247+
return true;
248+
}
249+
return false;
250+
}
251+
252+
using BinningTypeVertexContributor = ColumnBinningPolicy<aod::collision::PosZ, aod::cent::CentFT0C, o2::aod::evsel::NumTracksInTimeRange>;
253+
ROOT::Math::PxPyPzMVector phiMom, kaonPlus, kaonminus;
254+
double massKaPlus = o2::constants::physics::MassKPlus;
255+
256+
void process(AodCollisions::iterator const& collision, aod::BCsWithTimestamps const&, AodTracksWithoutBayes const& tracks)
257+
{
258+
if (!collision.sel8() || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) || !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) {
259+
return;
260+
}
261+
262+
const auto cent = collision.centFT0C();
263+
int nTot = tracks.size();
264+
float vtxz = collision.posZ();
265+
int occupancy = collision.trackOccupancyInTimeRange();
266+
267+
if (occupancy > cfgCutOccupancy) {
268+
return;
269+
}
270+
271+
if (additionalEvsel && !eventSelected(collision, cent)) {
272+
return;
273+
}
274+
275+
histos.fill(HIST("hVtxZ"), vtxz);
276+
histos.fill(HIST("hMult"), nTot);
277+
histos.fill(HIST("hCent"), cent);
278+
279+
auto posSlicedTracks = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache);
280+
auto negSlicedTracks = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache);
281+
282+
for (auto const& track1 : posSlicedTracks) {
283+
// track selection
284+
if (!selectionTrack(track1)) {
285+
continue;
286+
}
287+
// PID check
288+
if (ispTdepPID && !selectionPIDpTdependent(track1)) {
289+
continue;
290+
}
291+
if (!ispTdepPID && !selectionPID(track1)) {
292+
continue;
293+
}
294+
histos.fill(HIST("KaplusTPC"), track1.pt(), track1.tpcNSigmaKa());
295+
histos.fill(HIST("KaplusTOF"), track1.pt(), track1.tofNSigmaKa());
296+
auto track1ID = track1.globalIndex();
297+
298+
for (auto const& track2 : negSlicedTracks) {
299+
// track selection
300+
if (!selectionTrack(track2)) {
301+
continue;
302+
}
303+
// PID check
304+
if (ispTdepPID && !selectionPIDpTdependent(track2)) {
305+
continue;
306+
}
307+
if (!ispTdepPID && !selectionPID(track2)) {
308+
continue;
309+
}
310+
auto track2ID = track2.globalIndex();
311+
if (track2ID == track1ID) {
312+
continue;
313+
}
314+
if (!selectionPair(track1, track2)) {
315+
continue;
316+
}
317+
if (removefaketrack && isFakeKaon(track1)) {
318+
continue;
319+
}
320+
if (removefaketrack && isFakeKaon(track2)) {
321+
continue;
322+
}
323+
histos.fill(HIST("KaminusTPC"), track2.pt(), track2.tpcNSigmaKa());
324+
histos.fill(HIST("KaminusTOF"), track2.pt(), track2.tofNSigmaKa());
325+
kaonPlus = ROOT::Math::PxPyPzMVector(track1.px(), track1.py(), track1.pz(), massKaPlus);
326+
kaonminus = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massKaPlus);
327+
phiMom = kaonPlus + kaonminus;
328+
if (std::abs(phiMom.Rapidity()) < confRapidity) {
329+
histos.fill(HIST("hPhiMass_sparse"), phiMom.M(), phiMom.Pt(), cent);
330+
histos.fill(HIST("hPhi"), phiMom.Phi());
331+
histos.fill(HIST("hEta"), phiMom.Eta());
332+
}
333+
} // end of track 2
334+
} // end of track 1
335+
} // end of process
336+
};
337+
338+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
339+
{
340+
return WorkflowSpec{adaptAnalysisTask<ResonancesGfwFlow>(cfgc)};
341+
}

0 commit comments

Comments
 (0)