Skip to content

Commit d57aba9

Browse files
committed
[PWGEM,Photon] Add new emcal mc task
- Add new EMCal MC task which for now just fills an M02 and eta and phi diff histograms for identified photons, electrons, pi0, eta, omega, charged pions, charged kaons and other particles
1 parent dffcb98 commit d57aba9

3 files changed

Lines changed: 380 additions & 25 deletions

File tree

PWGEM/PhotonMeson/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,8 @@ o2physics_add_dpl_workflow(emcal-mc-sanity-check
185185
SOURCES emcalMcSanityCheck.cxx
186186
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore
187187
COMPONENT_NAME Analysis)
188+
189+
o2physics_add_dpl_workflow(emcal-mc-task
190+
SOURCES emcalMcTask.cxx
191+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore
192+
COMPONENT_NAME Analysis)
Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
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 emcalMcTask.cxx
13+
/// \brief Analysis task for to obtain cluster properties from MC identified particles like photons and electrons
14+
/// \author M. Hemmer, marvin.hemmer@cern.ch
15+
16+
#include "PWGEM/PhotonMeson/Core/EMBitFlags.h"
17+
#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h"
18+
#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h"
19+
#include "PWGEM/PhotonMeson/DataModel/EventTables.h"
20+
#include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h"
21+
#include "PWGEM/PhotonMeson/Utils/EventHistograms.h"
22+
23+
#include <CommonConstants/PhysicsConstants.h>
24+
#include <Framework/AnalysisDataModel.h>
25+
#include <Framework/AnalysisTask.h>
26+
#include <Framework/Concepts.h>
27+
#include <Framework/Configurable.h>
28+
#include <Framework/HistogramRegistry.h>
29+
#include <Framework/HistogramSpec.h>
30+
#include <Framework/InitContext.h>
31+
#include <Framework/OutputObjHeader.h>
32+
#include <Framework/SliceCache.h>
33+
#include <Framework/runDataProcessing.h>
34+
35+
#include <TPDGCode.h>
36+
37+
#include <array>
38+
#include <cmath>
39+
#include <cstddef>
40+
#include <string>
41+
#include <string_view>
42+
#include <vector>
43+
44+
using namespace o2;
45+
using namespace o2::aod;
46+
using namespace o2::framework;
47+
using namespace o2::framework::expressions;
48+
using namespace o2::soa;
49+
using namespace o2::aod::pwgem::photon;
50+
51+
namespace o2::em::emcal::mc
52+
{
53+
54+
enum ParticleType : int {
55+
kPhoton = 0,
56+
kElectron,
57+
kPositron,
58+
kPi0,
59+
kEta,
60+
kOmega,
61+
kPion,
62+
kKaon,
63+
kOther,
64+
kNParticleTypes
65+
};
66+
} // namespace o2::em::emcal::mc
67+
68+
enum CentralityEstimator {
69+
None = 0,
70+
CFT0A = 1,
71+
CFT0C = 2,
72+
CFT0M = 3,
73+
NCentralityEstimators = 4
74+
};
75+
76+
enum class MapLevel {
77+
kGood = 1,
78+
kNoBad = 2,
79+
kInEMC = 3,
80+
kAll = 4
81+
};
82+
83+
struct EmcalMcTask {
84+
// configurable axis
85+
ConfigurableAxis thnConfigAxisE{"thnConfigAxisE", {400, 0., 20.}, "energy axis"};
86+
ConfigurableAxis thnConfigAxisEtaDiff{"thnConfigAxisEtaDiff", {300, -1., 2.}, "(eta rec - eta true)"};
87+
ConfigurableAxis thnConfigAxisPhiDiff{"thnConfigAxisPhiDiff", {300, -1., 2.}, "(phi rec - phi true"};
88+
ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {100, 0.0, 1.0}, "m02 mass axis"};
89+
ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, "centrality axis for the current event"};
90+
ConfigurableAxis thnConfigAxisMult{"thnConfigAxisMult", {60, 0., 60000.}, "multiplicity axis for the current event"};
91+
Configurable<bool> useCent{"useCent", false, "flag to enable usage of centrality instead of multiplicity as axis."};
92+
93+
EMPhotonEventCut fEMEventCut;
94+
struct : ConfigurableGroup {
95+
std::string prefix = "eventcuts";
96+
Configurable<float> cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"};
97+
Configurable<bool> cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"};
98+
Configurable<bool> cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"};
99+
Configurable<bool> cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"};
100+
Configurable<bool> cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"};
101+
Configurable<bool> cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"};
102+
Configurable<bool> cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV.
103+
Configurable<bool> cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"};
104+
Configurable<bool> cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", true, "require the EMC to be read out in an MB collision (kTVXinEMC)"};
105+
Configurable<bool> cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"};
106+
Configurable<float> cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -1, "min. FT0C occupancy"};
107+
Configurable<float> cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"};
108+
Configurable<float> cfgMinCent{"cfgMinCent", 0, "min. centrality (%)"};
109+
Configurable<float> cfgMaxCent{"cfgMaxCent", 90, "max. centrality (%)"};
110+
Configurable<int> centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"};
111+
} eventcuts;
112+
113+
EMCPhotonCut fEMCCut;
114+
struct : ConfigurableGroup {
115+
std::string prefix = "emccuts";
116+
Configurable<std::string> clusterDefinition{"clusterDefinition", "kV3MostSplitSmallestTimeDiff", "Clusterizer to be selected, e.g. V3Default"};
117+
Configurable<float> cfgEMCminTime{"cfgEMCminTime", -25., "Minimum cluster time for EMCal time cut"};
118+
Configurable<float> cfgEMCmaxTime{"cfgEMCmaxTime", +30., "Maximum cluster time for EMCal time cut"};
119+
Configurable<float> cfgEMCminM02{"cfgEMCminM02", 0.1, "Minimum M02 for EMCal M02 cut"};
120+
Configurable<float> cfgEMCmaxM02{"cfgEMCmaxM02", 0.7, "Maximum M02 for EMCal M02 cut"};
121+
Configurable<float> cfgEMCminE{"cfgEMCminE", 0.7, "Minimum cluster energy for EMCal energy cut"};
122+
Configurable<int> cfgEMCminNCell{"cfgEMCminNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"};
123+
Configurable<std::vector<float>> cfgEMCTMEta{"cfgEMCTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"};
124+
Configurable<std::vector<float>> cfgEMCTMPhi{"cfgEMCTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"};
125+
Configurable<std::vector<float>> emcSecTMEta{"emcSecTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"};
126+
Configurable<std::vector<float>> emcSecTMPhi{"emcSecTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"};
127+
Configurable<float> cfgEMCEoverp{"cfgEMCEoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"};
128+
Configurable<bool> cfgEMCUseExoticCut{"cfgEMCUseExoticCut", true, "FLag to use the EMCal exotic cluster cut"};
129+
Configurable<bool> cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"};
130+
Configurable<bool> emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"};
131+
Configurable<bool> cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"};
132+
} emccuts;
133+
134+
SliceCache cache;
135+
136+
using EMCalPhotons = soa::Join<aod::EMCEMEventIds, aod::MinClusters, aod::EMEMCClusterMCLabels>;
137+
138+
using Colls = soa::Join<aod::PMEvents, aod::EMEventsAlias, aod::EMEventsMult_000, aod::EMEventsCent_000, aod::EMMCEventLabels, aod::EmMagFields>;
139+
140+
using McColls = o2::soa::Join<o2::aod::EMMCEvents, o2::aod::BinnedGenPts>;
141+
using McParticles = EMMCParticles;
142+
143+
PresliceOptional<EMCalPhotons> perCollisionEMC = o2::aod::emccluster::pmeventId;
144+
PresliceOptional<MinMTracks> perEMCClusterMT = o2::aod::mintm::minClusterId;
145+
PresliceOptional<MinMSTracks> perEMCClusterMS = o2::aod::mintm::minClusterId;
146+
147+
HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false};
148+
149+
int mRunNumber{-1};
150+
float dBz{0.f};
151+
152+
static constexpr std::array<std::string_view, static_cast<size_t>(o2::em::emcal::mc::ParticleType::kNParticleTypes)> kSubDirs = {
153+
"photon/", "electron/", "positron/", "pi0/",
154+
"eta/", "omega/", "pion/", "kaon/", "other/"};
155+
156+
void defineEMEventCut()
157+
{
158+
fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut");
159+
fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8);
160+
fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND);
161+
fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax);
162+
fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB);
163+
fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB);
164+
fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup);
165+
fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC);
166+
fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV);
167+
fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB);
168+
fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered);
169+
}
170+
171+
void defineEMCCut()
172+
{
173+
fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut");
174+
175+
fEMCCut.SetTrackMatchingEtaParams(emccuts.cfgEMCTMEta->at(0), emccuts.cfgEMCTMEta->at(1), emccuts.cfgEMCTMEta->at(2));
176+
fEMCCut.SetTrackMatchingPhiParams(emccuts.cfgEMCTMPhi->at(0), emccuts.cfgEMCTMPhi->at(1), emccuts.cfgEMCTMPhi->at(2));
177+
178+
fEMCCut.SetSecTrackMatchingEtaParams(emccuts.emcSecTMEta->at(0), emccuts.emcSecTMEta->at(1), emccuts.emcSecTMEta->at(2));
179+
fEMCCut.SetSecTrackMatchingPhiParams(emccuts.emcSecTMPhi->at(0), emccuts.emcSecTMPhi->at(1), emccuts.emcSecTMPhi->at(2));
180+
fEMCCut.SetMinEoverP(emccuts.cfgEMCEoverp);
181+
182+
fEMCCut.SetMinE(emccuts.cfgEMCminE);
183+
fEMCCut.SetMinNCell(emccuts.cfgEMCminNCell);
184+
fEMCCut.SetM02Range(emccuts.cfgEMCminM02, emccuts.cfgEMCmaxM02);
185+
fEMCCut.SetTimeRange(emccuts.cfgEMCminTime, emccuts.cfgEMCmaxTime);
186+
fEMCCut.SetUseExoticCut(emccuts.cfgEMCUseExoticCut);
187+
fEMCCut.SetClusterizer(emccuts.clusterDefinition);
188+
fEMCCut.SetUseTM(emccuts.cfgEMCUseTM.value); // disables or enables TM
189+
fEMCCut.SetUseSecondaryTM(emccuts.emcUseSecondaryTM.value); // disables or enables secondary TM
190+
fEMCCut.SetDoQA(emccuts.cfgEnableQA.value);
191+
}
192+
193+
void init(InitContext&)
194+
{
195+
mRunNumber = 0;
196+
dBz = 0;
197+
198+
defineEMEventCut();
199+
defineEMCCut();
200+
fEMCCut.addQAHistograms(&registry);
201+
o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(&registry);
202+
203+
const AxisSpec thnAxisERec{thnConfigAxisE, "#it{E}_{Rec} (GeV)"};
204+
205+
const AxisSpec thnAxisM02{thnConfigAxisM02, "#it{M}_{02}"};
206+
207+
const AxisSpec thnAxisEtaDiff{thnConfigAxisEtaDiff, "#it{#eta}_{Rec} - #it{#eta}_{Gen}"};
208+
const AxisSpec thnAxisPhiDiff{thnConfigAxisPhiDiff, "#it{#varphi}_{Rec} - #it{#varphi}_{Gen}"};
209+
210+
AxisSpec thnAxisCentOrMult{1, 0., 1., "Centrality/Multiplicity"}; // placeholder, overwritten in init
211+
if (useCent.value) {
212+
// PbPb: use centrality
213+
thnAxisCentOrMult = {thnConfigAxisCent, "Centrality (%)"};
214+
} else {
215+
// pp: use multiplicity
216+
thnAxisCentOrMult = {thnConfigAxisMult, "FT0C Multiplicity"};
217+
}
218+
219+
registry.add("photon/hM02", "cluster m02 vs energy vs cent/mult", HistType::kTH3F, {thnAxisM02, thnAxisERec, thnAxisCentOrMult});
220+
registry.add("photon/hEtaRel", "relative #eta vs energy vs cent/mult", HistType::kTH3F, {thnAxisEtaDiff, thnAxisERec, thnAxisCentOrMult});
221+
registry.add("photon/hPhiRel", "relative #varphi vs energy vs cent/mult", HistType::kTH3F, {thnAxisPhiDiff, thnAxisERec, thnAxisCentOrMult});
222+
223+
registry.addClone("photon/", "electron/");
224+
registry.addClone("photon/", "positron/");
225+
registry.addClone("photon/", "pi0/");
226+
registry.addClone("photon/", "eta/");
227+
registry.addClone("photon/", "omega/");
228+
registry.addClone("photon/", "pion/");
229+
registry.addClone("photon/", "kaon/");
230+
registry.addClone("photon/", "other/");
231+
232+
}; // end init
233+
234+
template <o2::soa::is_iterator TCollision>
235+
float getCentralityOrMultiplicity(TCollision const& collision)
236+
{
237+
if (useCent.value) {
238+
return getCentrality(collision);
239+
}
240+
// pp: use raw FT0C multiplicity
241+
return collision.multFT0C();
242+
}
243+
244+
/// Get the centrality
245+
/// \param collision is the collision with the centrality information
246+
template <o2::soa::is_iterator TCollision>
247+
float getCentrality(TCollision const& collision)
248+
{
249+
float cent = -999.;
250+
switch (eventcuts.centEstimator) {
251+
case CentralityEstimator::CFT0M:
252+
cent = collision.centFT0M();
253+
break;
254+
case CentralityEstimator::CFT0A:
255+
cent = collision.centFT0A();
256+
break;
257+
case CentralityEstimator::CFT0C:
258+
cent = collision.centFT0C();
259+
break;
260+
default:
261+
LOG(warning) << "Centrality estimator not valid. Possible values are T0M, T0A, T0C. Fallback to T0C";
262+
cent = collision.centFT0C();
263+
break;
264+
}
265+
return cent;
266+
}
267+
268+
/// \brief check if standard event cuts + FT0 occupancy + centrality + QVec good is
269+
/// \param collision collision that will be checked
270+
/// \return true if collision survives all checks, otherwise false
271+
template <o2::soa::is_iterator TCollision>
272+
bool isFullEventSelected(TCollision const& collision, bool fillHisto = false)
273+
{
274+
if (fillHisto) {
275+
o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(&registry, collision);
276+
}
277+
if (!(fEMEventCut.IsSelected(collision))) {
278+
// general event selection
279+
return false;
280+
}
281+
if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) {
282+
// occupancy selection
283+
return false;
284+
}
285+
float centOrMult = getCentralityOrMultiplicity(collision);
286+
if (useCent && (centOrMult < eventcuts.cfgMinCent || centOrMult > eventcuts.cfgMaxCent)) {
287+
// event selection
288+
return false;
289+
}
290+
if (fillHisto) {
291+
o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(&registry, collision);
292+
registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted
293+
registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted
294+
}
295+
return true;
296+
}
297+
298+
// One templated fill function instead of 9 copy-pasted blocks
299+
template <const int type, o2::soa::is_iterator TCluster, o2::soa::is_iterator TMC>
300+
void fillClusterHistos(HistogramRegistry& registry, TCluster const& clu, TMC const& mcPart, float centOrMult)
301+
{
302+
static constexpr std::string_view subDir = kSubDirs[type];
303+
304+
registry.fill(HIST(subDir) + HIST("hM02"), clu.m02(), clu.e(), centOrMult);
305+
registry.fill(HIST(subDir) + HIST("hEtaRel"), clu.eta() - mcPart.eta(), clu.e(), centOrMult);
306+
registry.fill(HIST(subDir) + HIST("hPhiRel"), clu.phi() - mcPart.phi(), clu.e(), centOrMult);
307+
}
308+
309+
// PCM-EMCal same event
310+
void processEmcal(Colls const& collisions, EMCalPhotons const& clusters, MinMTracks const& matchedPrims, MinMSTracks const& matchedSeconds, EMMCParticles const& mcParticles)
311+
{
312+
if (clusters.size() <= 0) {
313+
LOG(info) << "Skipping DF because there are not photons!";
314+
return;
315+
}
316+
EMBitFlags emcFlags(clusters.size());
317+
if (clusters.size() > 0) {
318+
fEMCCut.AreSelectedRunning(emcFlags, clusters, matchedPrims, matchedSeconds, &registry);
319+
}
320+
321+
// create iterators for photon mc particles
322+
auto mcPhoton1 = mcParticles.begin();
323+
324+
for (const auto& collision : collisions) {
325+
isFullEventSelected(collision, true);
326+
327+
float centOrMult = getCentralityOrMultiplicity(collision);
328+
329+
auto photonsEMCPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex());
330+
331+
for (const auto& photonEMC : photonsEMCPerCollision) {
332+
if (!(emcFlags.test(photonEMC.globalIndex()))) {
333+
continue;
334+
}
335+
if (photonEMC.emmcparticleIds().empty()) {
336+
// this is a cluster with just noise, skip
337+
continue;
338+
}
339+
// we only want to look at the largest contribution
340+
mcPhoton1.setCursor(photonEMC.emmcparticleIds()[0]);
341+
342+
if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kGamma) {
343+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kPhoton>(registry, photonEMC, mcPhoton1, centOrMult);
344+
} else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kElectron) {
345+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kElectron>(registry, photonEMC, mcPhoton1, centOrMult);
346+
} else if (mcPhoton1.pdgCode() == -PDG_t::kElectron) {
347+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kPositron>(registry, photonEMC, mcPhoton1, centOrMult);
348+
} else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kPi0) {
349+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kPi0>(registry, photonEMC, mcPhoton1, centOrMult);
350+
} else if (std::abs(mcPhoton1.pdgCode()) == o2::constants::physics::Pdg::kEta) {
351+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kEta>(registry, photonEMC, mcPhoton1, centOrMult);
352+
} else if (std::abs(mcPhoton1.pdgCode()) == o2::constants::physics::Pdg::kOmega) {
353+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kOmega>(registry, photonEMC, mcPhoton1, centOrMult);
354+
} else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kPiPlus) {
355+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kPion>(registry, photonEMC, mcPhoton1, centOrMult);
356+
} else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kKPlus) {
357+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kKaon>(registry, photonEMC, mcPhoton1, centOrMult);
358+
} else {
359+
fillClusterHistos<o2::em::emcal::mc::ParticleType::kOther>(registry, photonEMC, mcPhoton1, centOrMult);
360+
}
361+
} // for (const auto& photonEMC : photonsEMCPerCollision) {
362+
}
363+
}
364+
PROCESS_SWITCH(EmcalMcTask, processEmcal, "Process for emcal", true);
365+
366+
}; // End struct EmcalMcTask
367+
368+
WorkflowSpec defineDataProcessing(ConfigContext const& context)
369+
{
370+
return WorkflowSpec{adaptAnalysisTask<EmcalMcTask>(context)};
371+
}

0 commit comments

Comments
 (0)