Skip to content

Commit dabc108

Browse files
authored
[PWGCF] Add a JCorran D-meson v02(pT) task. (#18362)
1 parent 3144327 commit dabc108

3 files changed

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

0 commit comments

Comments
 (0)