Skip to content

Commit f279b79

Browse files
committed
[PWGCF] Add a JCorran D-meson v02(pT) task.
Measure the spectra-flow cumulant from FT0 Q-vectors and CF2ProngTracks, and keep a synthetic closure for the charged-hadron and D0 estimators.
1 parent 177407e commit f279b79

3 files changed

Lines changed: 537 additions & 0 deletions

File tree

‎PWGCF/JCorran/Tasks/CMakeLists.txt‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ o2physics_add_dpl_workflow(epdzeroflow-analysis
3939
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore
4040
COMPONENT_NAME Analysis)
4141

42+
o2physics_add_dpl_workflow(j-v02-dmeson-analysis
43+
SOURCES jV02DmesonAnalysis.cxx
44+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore
45+
COMPONENT_NAME Analysis)
46+
47+
o2physics_add_dpl_workflow(j-v02-dmeson-toy
48+
SOURCES jV02DmesonToy.cxx
49+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore
50+
COMPONENT_NAME Analysis)
51+
4252
o2physics_add_dpl_workflow(j-fluc-efficiency-task
4353
SOURCES jFlucEfficiencyTask.cxx
4454
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::JCorran
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
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 jV02DmesonAnalysis.cxx
13+
/// \brief D0 v02(pT) on the JCorran derived tables
14+
/// \author Dong Jo Kim (djkim@jyu.fi)
15+
///
16+
/// v02(pT) = <X Y Z(pT)>_c / (<X Y>_c <Z(pT)>).
17+
/// X and Y are the corrected Q2 of two forward detectors (default FT0A x FT0C)
18+
/// from the combined Qvectors table, with the same indexing as jEPDzeroFlowAnalysis.
19+
/// Z_D(pT) = N_D(pT) / N_ch. N_D comes from CF2ProngTracks (D0 and D0bar).
20+
/// N_ch comes from CFTracks. Both derived tables are indexed to CFCollisions,
21+
/// so the original collision is matched through CFCollRefs (one row per kept
22+
/// collision, written by filter-correlations with cfgTransientTables).
23+
/// The D azimuth is not part of the Q-vector.
24+
/// Do not divide by an extra resolution: it cancels in the ratio.
25+
///
26+
/// Definition: arXiv:2506.18690, Appendix A.
27+
28+
#include "PWGCF/DataModel/CorrelationsDerived.h"
29+
30+
#include "Common/CCDB/EventSelectionParams.h"
31+
#include "Common/DataModel/Centrality.h"
32+
#include "Common/DataModel/EventSelection.h"
33+
#include "Common/DataModel/Qvectors.h"
34+
35+
#include <Framework/AnalysisDataModel.h>
36+
#include <Framework/AnalysisTask.h>
37+
#include <Framework/Configurable.h>
38+
#include <Framework/HistogramRegistry.h>
39+
#include <Framework/HistogramSpec.h>
40+
#include <Framework/InitContext.h>
41+
#include <Framework/runDataProcessing.h>
42+
43+
#include <TAxis.h>
44+
#include <TProfile2D.h>
45+
46+
#include <cmath>
47+
#include <cstdint>
48+
#include <random>
49+
#include <string>
50+
#include <unordered_set>
51+
#include <vector>
52+
53+
using namespace o2;
54+
using namespace o2::framework;
55+
56+
#define V02_FILL_QA(NAME, STEP) \
57+
for (int qaBin = 1; qaBin <= (STEP); ++qaBin) { \
58+
histos.fill(HIST(NAME), static_cast<float>(qaBin)); \
59+
}
60+
61+
struct JV02DmesonAnalysis {
62+
enum Detector {
63+
kFT0C = 0,
64+
kFT0A,
65+
kFT0M,
66+
kFV0A,
67+
kTPCpos,
68+
kTPCneg,
69+
kTPCall
70+
};
71+
static constexpr int NDetectors = 7;
72+
static constexpr int NCorrections = 4;
73+
static constexpr int FullyCorrected = 3;
74+
static constexpr int StepAccepted = 5;
75+
static constexpr float InvalidQvector = 900.f;
76+
77+
using MyCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::CentFT0Ms, aod::CentFT0Cs, aod::Qvectors>;
78+
79+
HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject};
80+
81+
Configurable<std::string> cfgCentEst{"cfgCentEst", "FT0C", "Centrality estimator: FT0C or FT0M"};
82+
Configurable<std::string> cfgRefAName{"cfgRefAName", "FT0A", "Reference detector A: FT0A, FT0C, FT0M, FV0A, TPCpos, TPCneg, TPCall"};
83+
Configurable<std::string> cfgRefBName{"cfgRefBName", "FT0C", "Reference detector B"};
84+
Configurable<int> cfgQvecMode{"cfgQvecMode", 0, "Harmonic slot in qvector-table cfgnMods. 0 is v2 when cfgnMods starts at 2"};
85+
Configurable<int> cfgNSubsample{"cfgNSubsample", 10, "Number of bootstrap subsamples"};
86+
Configurable<int> cfgSeed{"cfgSeed", 1, "Seed for the subsample index"};
87+
Configurable<int> cfgMaxOccupancy{"cfgMaxOccupancy", 999999, "Maximum track occupancy"};
88+
Configurable<int> cfgMinOccupancy{"cfgMinOccupancy", 0, "Minimum track occupancy"};
89+
Configurable<float> cfgVtxZ{"cfgVtxZ", 10.f, "Maximum |z_vtx| (cm)"};
90+
Configurable<float> cfgCentMin{"cfgCentMin", 0.f, "Minimum centrality"};
91+
Configurable<float> cfgCentMax{"cfgCentMax", 80.f, "Maximum centrality"};
92+
Configurable<float> cfgEtaMax{"cfgEtaMax", 0.8f, "Maximum |eta| of CF tracks used for N_ch"};
93+
Configurable<float> cfgPtMinCh{"cfgPtMinCh", 0.2f, "Minimum charged-track pT (GeV/c)"};
94+
Configurable<float> cfgPtMaxCh{"cfgPtMaxCh", 3.f, "Maximum charged-track pT (GeV/c)"};
95+
Configurable<float> cfgPtMinD{"cfgPtMinD", 1.f, "Minimum D0 pT (GeV/c)"};
96+
Configurable<float> cfgPtMaxD{"cfgPtMaxD", 24.f, "Maximum D0 pT (GeV/c)"};
97+
Configurable<float> cfgMinNch{"cfgMinNch", 10.f, "Minimum N_ch"};
98+
Configurable<float> cfgMinSumAmpl{"cfgMinSumAmpl", 1e-4f, "Minimum Q-vector amplitude"};
99+
Configurable<bool> cfgRequireSel8{"cfgRequireSel8", true, "Require sel8"};
100+
Configurable<bool> cfgCutNoSameBunchPileup{"cfgCutNoSameBunchPileup", true, "Require kNoSameBunchPileup"};
101+
Configurable<bool> cfgCutGoodZvtxFT0vsPV{"cfgCutGoodZvtxFT0vsPV", true, "Require kIsGoodZvtxFT0vsPV"};
102+
Configurable<bool> cfgCutNoTimeFrameBorder{"cfgCutNoTimeFrameBorder", true, "Require kNoTimeFrameBorder"};
103+
Configurable<bool> cfgCutNoITSROFrameBorder{"cfgCutNoITSROFrameBorder", true, "Require kNoITSROFrameBorder"};
104+
Configurable<bool> cfgRejectDaughters{"cfgRejectDaughters", false, "Drop D0 daughter CF tracks from N_ch"};
105+
106+
ConfigurableAxis cfgAxisCent{"cfgAxisCent", {8, 0., 80.}, "Centrality axis"};
107+
ConfigurableAxis cfgAxisPtD{"cfgAxisPtD", {VARIABLE_WIDTH, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 8.f, 12.f, 16.f, 24.f}, "D0 pT axis"};
108+
ConfigurableAxis cfgAxisPtHad{"cfgAxisPtHad", {VARIABLE_WIDTH, 0.2f, 0.4f, 0.6f, 0.8f, 1.f, 1.2f, 1.5f, 2.f, 2.5f, 3.f}, "Charged-hadron pT axis"};
109+
ConfigurableAxis cfgAxisMass{"cfgAxisMass", {70, 1.70, 2.05}, "D0 invariant-mass axis"};
110+
111+
int mRefA = kFT0A;
112+
int mRefB = kFT0C;
113+
int mNSubsample = 1;
114+
Preslice<aod::CFTracks> mPerCFTrack = aod::cftrack::cfCollisionId;
115+
Preslice<aod::CF2ProngTracks> mPerCFCand = aod::cftrack::cfCollisionId;
116+
const TAxis* mHadPtAxis = nullptr;
117+
std::vector<float> mHadCounts;
118+
std::mt19937 mRng{1};
119+
std::uniform_int_distribution<int> mSampleDist;
120+
121+
int detectorId(const std::string& name) const
122+
{
123+
if (name == "FT0C") {
124+
return kFT0C;
125+
}
126+
if (name == "FT0A") {
127+
return kFT0A;
128+
}
129+
if (name == "FT0M") {
130+
return kFT0M;
131+
}
132+
if (name == "FV0A") {
133+
return kFV0A;
134+
}
135+
if (name == "TPCpos") {
136+
return kTPCpos;
137+
}
138+
if (name == "TPCneg") {
139+
return kTPCneg;
140+
}
141+
if (name == "TPCall") {
142+
return kTPCall;
143+
}
144+
return -1;
145+
}
146+
147+
void init(InitContext const&)
148+
{
149+
mRefA = detectorId(cfgRefAName.value);
150+
mRefB = detectorId(cfgRefBName.value);
151+
if (mRefA < 0 || mRefB < 0 || mRefA == mRefB) {
152+
LOGF(fatal, "cfgRefAName and cfgRefBName must be two different detectors");
153+
}
154+
mNSubsample = cfgNSubsample > 0 ? cfgNSubsample.value : 1;
155+
mRng.seed(static_cast<std::mt19937::result_type>(cfgSeed));
156+
mSampleDist = std::uniform_int_distribution<int>(0, mNSubsample - 1);
157+
158+
const AxisSpec subsampleAxis{mNSubsample, 0., static_cast<double>(mNSubsample), "subsample"};
159+
const AxisSpec qaAxis{6, 0.5, 6.5, "1 seen; 2 sel8; 3 vertex; 4 quality; 5 centrality; 6 accepted"};
160+
161+
if (doprocessReference) {
162+
histos.add("hadron/hEventQa", "1 seen; 2 sel8; 3 vertex; 4 quality; 5 centrality; 6 accepted", {HistType::kTH1F, {qaAxis}});
163+
histos.add("hadron/hEvents", "Selected events;centrality (%);events", {HistType::kTH1F, {cfgAxisCent}});
164+
histos.add("hadron/Prof_XY", "Bulk #LTXY#GT;centrality (%);#LTXY#GT", {HistType::kTProfile, {cfgAxisCent}});
165+
histos.add("hadron/Prof_Nch", "N_{ch};centrality (%);#LTN_{ch}#GT", {HistType::kTProfile, {cfgAxisCent}});
166+
histos.add("hadron/Prof_Z", "Z = n(p_{T})/N_{ch};centrality (%);p_{T} (GeV/c);#LTZ#GT", {HistType::kTProfile2D, {cfgAxisCent, cfgAxisPtHad}});
167+
histos.add("hadron/Prof_XYZ", "XY Z;centrality (%);p_{T} (GeV/c);#LTXYZ#GT", {HistType::kTProfile2D, {cfgAxisCent, cfgAxisPtHad}});
168+
histos.add("hadron/Prof_XY_sub", "Bulk #LTXY#GT per subsample;subsample;centrality (%);#LTXY#GT", {HistType::kTProfile2D, {subsampleAxis, cfgAxisCent}});
169+
histos.add("hadron/Prof_Z_sub", "Z per subsample;subsample;centrality (%);p_{T} (GeV/c);#LTZ#GT", {HistType::kTProfile3D, {subsampleAxis, cfgAxisCent, cfgAxisPtHad}});
170+
histos.add("hadron/Prof_XYZ_sub", "XYZ per subsample;subsample;centrality (%);p_{T} (GeV/c);#LTXYZ#GT", {HistType::kTProfile3D, {subsampleAxis, cfgAxisCent, cfgAxisPtHad}});
171+
mHadPtAxis = histos.get<TProfile2D>(HIST("hadron/Prof_Z"))->GetYaxis();
172+
mHadCounts.assign(mHadPtAxis->GetNbins(), 0.f);
173+
}
174+
if (doprocessD0) {
175+
histos.add("D0/hEventQa", "1 seen; 2 sel8; 3 vertex; 4 quality; 5 centrality; 6 accepted", {HistType::kTH1F, {qaAxis}});
176+
histos.add("D0/hEvents", "Selected events;centrality (%);events", {HistType::kTH1F, {cfgAxisCent}});
177+
histos.add("D0/Prof_XY", "Bulk #LTXY#GT;centrality (%);#LTXY#GT", {HistType::kTProfile, {cfgAxisCent}});
178+
histos.add("D0/Prof_Nch", "N_{ch};centrality (%);#LTN_{ch}#GT", {HistType::kTProfile, {cfgAxisCent}});
179+
histos.add("D0/hMassRaw", "Weight 1/N_{ch};centrality (%);p_{T} (GeV/c);m (GeV/c^{2})", {HistType::kTH3F, {cfgAxisCent, cfgAxisPtD, cfgAxisMass}}, true);
180+
histos.add("D0/hMassCorr", "Weight XY/N_{ch};centrality (%);p_{T} (GeV/c);m (GeV/c^{2})", {HistType::kTH3F, {cfgAxisCent, cfgAxisPtD, cfgAxisMass}}, true);
181+
histos.add("D0/hMassRawSub", "Weight 1/N_{ch};subsample;centrality (%);p_{T} (GeV/c);m (GeV/c^{2})", {HistType::kTHnSparseF, {subsampleAxis, cfgAxisCent, cfgAxisPtD, cfgAxisMass}}, true);
182+
histos.add("D0/hMassCorrSub", "Weight XY/N_{ch};subsample;centrality (%);p_{T} (GeV/c);m (GeV/c^{2})", {HistType::kTHnSparseF, {subsampleAxis, cfgAxisCent, cfgAxisPtD, cfgAxisMass}}, true);
183+
}
184+
}
185+
186+
template <typename TCollision>
187+
float centralityOf(const TCollision& collision)
188+
{
189+
if (cfgCentEst.value == "FT0M") {
190+
return collision.centFT0M();
191+
}
192+
return collision.centFT0C();
193+
}
194+
195+
template <typename TCollision>
196+
int passedEventStep(const TCollision& collision, float& centrality)
197+
{
198+
if (cfgRequireSel8 && !collision.sel8()) {
199+
return 1;
200+
}
201+
if (std::abs(collision.posZ()) > cfgVtxZ) {
202+
return 2;
203+
}
204+
const bool rejected =
205+
(cfgCutNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) ||
206+
(cfgCutGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) ||
207+
(cfgCutNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) ||
208+
(cfgCutNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) ||
209+
collision.trackOccupancyInTimeRange() > cfgMaxOccupancy ||
210+
collision.trackOccupancyInTimeRange() < cfgMinOccupancy;
211+
if (rejected) {
212+
return 3;
213+
}
214+
centrality = centralityOf(collision);
215+
if (centrality < cfgCentMin || centrality > cfgCentMax) {
216+
return 4;
217+
}
218+
return 5;
219+
}
220+
221+
template <typename TCollision>
222+
bool referenceProduct(const TCollision& collision, float& xy)
223+
{
224+
const auto& re = collision.qvecRe();
225+
const auto& im = collision.qvecIm();
226+
const auto& amp = collision.qvecAmp();
227+
const int idxA = cfgQvecMode * NDetectors * NCorrections + mRefA * NCorrections + FullyCorrected;
228+
const int idxB = cfgQvecMode * NDetectors * NCorrections + mRefB * NCorrections + FullyCorrected;
229+
const int ampA = cfgQvecMode * NDetectors + mRefA;
230+
const int ampB = cfgQvecMode * NDetectors + mRefB;
231+
if (idxA >= static_cast<int>(re.size()) || idxB >= static_cast<int>(im.size()) || ampA >= static_cast<int>(amp.size()) || ampB >= static_cast<int>(amp.size())) {
232+
return false;
233+
}
234+
if (!(amp[ampA] > cfgMinSumAmpl) || !(amp[ampB] > cfgMinSumAmpl)) {
235+
return false;
236+
}
237+
if (re[idxA] > InvalidQvector || re[idxB] > InvalidQvector) {
238+
return false;
239+
}
240+
xy = re[idxA] * re[idxB] + im[idxA] * im[idxB];
241+
return std::isfinite(xy);
242+
}
243+
244+
template <typename TTracks>
245+
float countCharged(const TTracks& tracks, const std::unordered_set<int64_t>& daughters, bool differential)
246+
{
247+
float nch = 0.f;
248+
if (differential) {
249+
std::fill(mHadCounts.begin(), mHadCounts.end(), 0.f);
250+
}
251+
for (const auto& track : tracks) {
252+
const float pt = track.pt();
253+
if (track.sign() == 0 || pt < cfgPtMinCh || pt >= cfgPtMaxCh || std::abs(track.eta()) > cfgEtaMax) {
254+
continue;
255+
}
256+
if (cfgRejectDaughters && daughters.contains(static_cast<int64_t>(track.globalIndex()))) {
257+
continue;
258+
}
259+
nch += 1.f;
260+
if (differential && mHadPtAxis != nullptr) {
261+
const int bin = mHadPtAxis->FindBin(pt);
262+
if (bin >= 1 && bin <= mHadPtAxis->GetNbins()) {
263+
mHadCounts[bin - 1] += 1.f;
264+
}
265+
}
266+
}
267+
return nch;
268+
}
269+
270+
static bool isD0Decay(uint8_t decay)
271+
{
272+
return decay == aod::cf2prongtrack::D0ToPiK || decay == aod::cf2prongtrack::D0barToKPi || decay == aod::cf2prongtrack::D0barToKPiExclusive;
273+
}
274+
275+
template <typename TRefs>
276+
static int cfCollisionIndex(const TRefs& refs)
277+
{
278+
if (refs.size() != 1) {
279+
return -1;
280+
}
281+
return static_cast<int>(refs.begin().globalIndex());
282+
}
283+
284+
void processReference(MyCollisions::iterator const& collision, aod::BCs const&, aod::CFCollisions const&, aod::CFCollRefs const& refs, aod::CFTracks const& tracks)
285+
{
286+
float cent = -1.f;
287+
float xy = 0.f;
288+
const int step = passedEventStep(collision, cent);
289+
V02_FILL_QA("hadron/hEventQa", step);
290+
const int cfId = cfCollisionIndex(refs);
291+
if (step < StepAccepted || cfId < 0 || !referenceProduct(collision, xy)) {
292+
return;
293+
}
294+
const std::unordered_set<int64_t> noDaughters;
295+
const float nch = countCharged(tracks.sliceBy(mPerCFTrack, cfId), noDaughters, true);
296+
if (nch < cfgMinNch) {
297+
return;
298+
}
299+
histos.fill(HIST("hadron/hEventQa"), 6.f);
300+
const int sample = mSampleDist(mRng);
301+
histos.fill(HIST("hadron/hEvents"), cent);
302+
histos.fill(HIST("hadron/Prof_XY"), cent, xy);
303+
histos.fill(HIST("hadron/Prof_Nch"), cent, nch);
304+
histos.fill(HIST("hadron/Prof_XY_sub"), static_cast<float>(sample), cent, xy);
305+
const int nBins = mHadPtAxis->GetNbins();
306+
for (int ibin = 1; ibin <= nBins; ++ibin) {
307+
const float pt = static_cast<float>(mHadPtAxis->GetBinCenter(ibin));
308+
const float z = mHadCounts[ibin - 1] / nch;
309+
histos.fill(HIST("hadron/Prof_Z"), cent, pt, z);
310+
histos.fill(HIST("hadron/Prof_XYZ"), cent, pt, xy * z);
311+
histos.fill(HIST("hadron/Prof_Z_sub"), static_cast<float>(sample), cent, pt, z);
312+
histos.fill(HIST("hadron/Prof_XYZ_sub"), static_cast<float>(sample), cent, pt, xy * z);
313+
}
314+
}
315+
PROCESS_SWITCH(JV02DmesonAnalysis, processReference, "Charged-hadron v02(pT) closure", true);
316+
317+
void processD0(MyCollisions::iterator const& collision, aod::BCs const&, aod::CFCollisions const&, aod::CFCollRefs const& refs, aod::CF2ProngTracks const& candidates, aod::CFTracks const& tracks)
318+
{
319+
float cent = -1.f;
320+
float xy = 0.f;
321+
const int step = passedEventStep(collision, cent);
322+
V02_FILL_QA("D0/hEventQa", step);
323+
const int cfId = cfCollisionIndex(refs);
324+
if (step < StepAccepted || cfId < 0 || !referenceProduct(collision, xy)) {
325+
return;
326+
}
327+
auto eventCandidates = candidates.sliceBy(mPerCFCand, cfId);
328+
auto eventTracks = tracks.sliceBy(mPerCFTrack, cfId);
329+
330+
std::unordered_set<int64_t> daughters;
331+
if (cfgRejectDaughters) {
332+
for (const auto& cand : eventCandidates) {
333+
if (!isD0Decay(cand.decay())) {
334+
continue;
335+
}
336+
daughters.insert(static_cast<int64_t>(cand.cfTrackProng0Id()));
337+
daughters.insert(static_cast<int64_t>(cand.cfTrackProng1Id()));
338+
}
339+
}
340+
const float nch = countCharged(eventTracks, daughters, false);
341+
if (nch < cfgMinNch) {
342+
return;
343+
}
344+
histos.fill(HIST("D0/hEventQa"), 6.f);
345+
const int sample = mSampleDist(mRng);
346+
const float sampleCoord = static_cast<float>(sample);
347+
histos.fill(HIST("D0/hEvents"), cent);
348+
histos.fill(HIST("D0/Prof_XY"), cent, xy);
349+
histos.fill(HIST("D0/Prof_Nch"), cent, nch);
350+
351+
const float wRaw = 1.f / nch;
352+
const float wCorr = xy / nch;
353+
for (const auto& cand : eventCandidates) {
354+
if (!isD0Decay(cand.decay())) {
355+
continue;
356+
}
357+
const float pt = cand.pt();
358+
if (pt < cfgPtMinD || pt >= cfgPtMaxD) {
359+
continue;
360+
}
361+
const float mass = cand.invMass();
362+
histos.fill(HIST("D0/hMassRaw"), cent, pt, mass, wRaw);
363+
histos.fill(HIST("D0/hMassCorr"), cent, pt, mass, wCorr);
364+
histos.fill(HIST("D0/hMassRawSub"), sampleCoord, cent, pt, mass, wRaw);
365+
histos.fill(HIST("D0/hMassCorrSub"), sampleCoord, cent, pt, mass, wCorr);
366+
}
367+
}
368+
PROCESS_SWITCH(JV02DmesonAnalysis, processD0, "D0 and D0bar v02(pT) from CF2ProngTracks", true);
369+
};
370+
371+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
372+
{
373+
return WorkflowSpec{adaptAnalysisTask<JV02DmesonAnalysis>(cfgc)};
374+
}

0 commit comments

Comments
 (0)