Project
Loading...
Searching...
No Matches
test_cmv_generator.cxx
Go to the documentation of this file.
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
23
25#include "Framework/Task.h"
29#include "Framework/Logger.h"
30#include "Headers/DataHeader.h"
32#include "TPCBase/CRU.h"
33#include "DataFormatsTPC/CMV.h"
41#include <fmt/format.h>
42#include <fmt/ranges.h>
43
44#include <vector>
45#include <chrono>
46#include <thread>
47#include <cmath>
48#include <memory>
49#include <limits>
50#include <random>
51#include <stdexcept>
52#include <string>
53#include <unordered_set>
54
55using namespace o2::framework;
57
58// ─────────────────────────────────────────────────────────────────────────────
59// workflow options
60// ─────────────────────────────────────────────────────────────────────────────
61void customize(std::vector<ConfigParamSpec>& workflowOptions)
62{
63 const std::string cruDefault = "0-" + std::to_string(o2::tpc::CRU::MaxCRU - 1);
64 std::vector<ConfigParamSpec> options{
65 {"crus", VariantType::String, cruDefault.c_str(), {"List of CRUs, comma-separated ranges, e.g. 0-3,7,9-15"}},
66 {"timeframes", VariantType::Int, 100, {"Number of TFs to generate; use -1 to run indefinitely"}},
67 {"delay", VariantType::Bool, false, {"Add delay after sending all CRUs"}},
68 {"delayTime", VariantType::Int, 1, {"Duration of the global per-TF delay in ms (requires --delay true)"}},
69 {"delayEveryN", VariantType::Int, 1, {"Apply the global delay only on average once every N TFs, randomly chosen (1 = every TF, requires --delay true)"}},
70 {"delayCRUs", VariantType::String, "", {"CRUs for which to add an extra per-CRU delay before sending, comma-separated ranges"}},
71 {"delayTimeCRUs", VariantType::Int, 1, {"Duration of the per-CRU delay in ms (requires --delayCRUs)"}},
72 {"dropTFsRandom", VariantType::Int, 0, {"Drop a whole TF randomly: on average one every N TFs (0 = disabled)"}},
73 {"dropTFsRange", VariantType::String, "", {"Drop all TFs in this range, e.g. 10-12"}},
74 {"tfLength", VariantType::Float, 0.f, {"Minimum wall-clock time between consecutively sent TFs in ms (rate limiter); the generator sleeps if a TF is produced faster than this (0 = disabled)"}},
75 {"seed", VariantType::Int, 42, {"RNG seed for CMV value generation"}},
76 {"amplitude", VariantType::Float, 5.0f, {"Amplitude of the sinusoidal CMV signal (ADC units); ignored when --input-file is set"}},
77 {"noise", VariantType::Float, 1.0f, {"Gaussian noise std-dev added per time bin (ADC units); used as the smearing width in --input-file mode"}},
78 {"input-file", VariantType::String, "", {"ROOT file with a CMV 'ccdb_object' tree; the template TF (see --input-entry) is decoded once and re-emitted, smeared per generated TF. Empty = synthetic sinusoidal signal"}},
79 {"input-entry", VariantType::Int, 0, {"Tree entry (TF index) used as the template when --input-file is set"}},
80 {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}};
82 std::swap(workflowOptions, options);
83}
84
86
87// ─────────────────────────────────────────────────────────────────────────────
88// generator device
89// ─────────────────────────────────────────────────────────────────────────────
91{
92 public:
93 static constexpr uint32_t sOrbitsPerPacket = 8;
94
95 CMVGeneratorDevice(const std::vector<uint32_t>& crus,
96 const std::unordered_set<uint32_t>& delayCRUs,
97 unsigned int maxTFs,
98 bool delay,
99 int delayTime,
100 int delayEveryN,
101 int delayTimeCRUs,
102 int dropTFsRandom,
103 const std::vector<int>& rangeTFsDrop,
104 float tfLength,
105 float amplitude,
106 float noise,
107 int seed,
108 const std::string& inputFile,
109 long long inputEntry)
110 : mCRUs(crus), mDelayCRUs(delayCRUs), mMaxTFs(maxTFs), mDelay(delay), mDelayTime(delayTime), mDelayEveryN(delayEveryN), mDelayTimeCRUs(delayTimeCRUs), mDropTFsRandom(dropTFsRandom), mRangeTFsDrop(rangeTFsDrop), mTFLength(tfLength), mAmplitude(amplitude), mNoise(noise), mRng(static_cast<std::mt19937::result_type>(seed)), mInputFileName(inputFile), mInputEntry(inputEntry) {}
111
113 {
114 mTimer100TFs = std::chrono::high_resolution_clock::now();
115 mLastTFTime = std::chrono::high_resolution_clock::now();
116
117 if (!mCRUs.empty()) {
118 LOGP(info, "crus: {}", fmt::join(mCRUs, ", "));
119 }
120 if (!mDelayCRUs.empty()) {
121 const std::vector<uint32_t> delayCRUsSorted(mDelayCRUs.begin(), mDelayCRUs.end());
122 LOGP(info, "delayCRUs: {}", fmt::join(delayCRUsSorted, ", "));
123 }
124
125 mWriteDebug = ic.options().get<bool>("write-debug");
126 if (mWriteDebug) {
127 mDebugStreamFileName = ic.options().get<std::string>("debug-file-name");
128 LOGP(info, "Creating debug stream {}", mDebugStreamFileName);
129 mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugStreamFileName.data(), "recreate");
130 }
131
132 if (!mInputFileName.empty()) {
134 if (!handle.open(mInputFileName)) {
135 throw std::runtime_error("CMV generator: failed to open input file " + mInputFileName);
136 }
137 const auto nEntries = handle.tree->GetEntries();
138 if (mInputEntry < 0 || mInputEntry >= nEntries) {
139 const auto msg = fmt::format("CMV generator: --input-entry {} out of range [0, {}) in {}", mInputEntry, nEntries, mInputFileName);
140 handle.close();
141 throw std::runtime_error(msg);
142 }
143 const o2::tpc::CMVPerTF* tmpl = handle.getEntry(mInputEntry);
144 if (!tmpl) {
145 handle.close();
146 throw std::runtime_error("CMV generator: failed to read/decode entry from " + mInputFileName);
147 }
148 // When noise is enabled we keep the per-CRU float template and re-encode it
149 // (template + noise) every TF. When noise is disabled the output is identical
150 // for every TF, so we encode it once here and just re-snapshot it in run().
151 const bool addNoise = (mNoise > 0.f);
152 if (addNoise) {
153 mBaseCMVFloat.resize(mCRUs.size());
154 for (size_t iCRU = 0; iCRU < mCRUs.size(); ++iCRU) {
155 const auto cru = mCRUs[iCRU];
156 auto& base = mBaseCMVFloat[iCRU];
157 base.resize(o2::tpc::cmv::NTimeBinsPerTF);
158 for (uint32_t tb = 0; tb < o2::tpc::cmv::NTimeBinsPerTF; ++tb) {
159 base[tb] = tmpl->getCMVFloat(static_cast<int>(cru), static_cast<int>(tb));
160 }
161 }
162 } else {
163 mBaseCMVEncoded.resize(mCRUs.size());
164 for (size_t iCRU = 0; iCRU < mCRUs.size(); ++iCRU) {
165 const auto cru = mCRUs[iCRU];
166 auto& enc = mBaseCMVEncoded[iCRU];
167 enc.resize(o2::tpc::cmv::NTimeBinsPerTF);
168 for (uint32_t tb = 0; tb < o2::tpc::cmv::NTimeBinsPerTF; ++tb) {
170 d.setCMVFloat(tmpl->getCMVFloat(static_cast<int>(cru), static_cast<int>(tb)));
171 enc[tb] = d.getCMV();
172 }
173 }
174 }
175 handle.close();
176 mUseInputFile = true;
177 LOGP(info, "Loaded CMV template from {} (entry {}): {} CRUs x {} bins, noise sigma {} ADC ({})",
178 mInputFileName, mInputEntry, mCRUs.size(), o2::tpc::cmv::NTimeBinsPerTF, mNoise,
179 addNoise ? "re-smeared per TF" : "encoded once, replayed verbatim");
180 }
181 }
182
184 {
185 using timer = std::chrono::high_resolution_clock;
187
188 // ── TF dropping ──────────────────────────────────────────────────────────
189 // Note: RangeTokenizer guarantees sorted output, so front()/back() are min/max.
190 if (!mRangeTFsDrop.empty() && tf >= static_cast<uint32_t>(mRangeTFsDrop.front()) && tf <= static_cast<uint32_t>(mRangeTFsDrop.back())) {
191 LOGP(info, "Dropping TF {} (range drop)", tf);
192 return;
193 }
194 if (mDropTFsRandom > 0 && std::uniform_int_distribution<int>{0, mDropTFsRandom - 1}(mRng) == 0) {
195 LOGP(info, "Dropping TF {} (random drop)", tf);
196 return;
197 }
198
199 auto start = timer::now();
200
201 // ── CMV values ───────────────────────────────────────────────────────────
202 // NTimeBinsPerTF = NPacketsPerTFPerCRU (4) * NTimeBinsPerPacket (3564) = 14256
203 // - synthetic mode: shared cmvVec = sinusoidal signal + noise (same for all CRUs)
204 // - input-file mode: per-CRU template + the shared noise vector
205 const bool addNoise = (mNoise > 0.f); // skip all RNG when --noise 0
206 std::normal_distribution<float> noiseDist{0.f, mNoise};
207 std::vector<uint16_t> cmvVec(o2::tpc::cmv::NTimeBinsPerTF);
208 std::vector<float> noiseVec; // only populated in input-file mode when noise is enabled
209 if (mUseInputFile) {
210 if (addNoise) {
211 noiseVec.resize(o2::tpc::cmv::NTimeBinsPerTF);
212 for (auto& n : noiseVec) {
213 n = noiseDist(mRng);
214 }
215 }
216 } else {
217 const float signal = -std::abs(mAmplitude * std::sin(tf * 0.05f));
218 for (auto& v : cmvVec) {
220 d.setCMVFloat(addNoise ? (signal + noiseDist(mRng)) : signal);
221 v = d.getCMV();
222 }
223 }
224
225 // ── Orbit / BC info (same for all CRUs) ──────────────────────────────────
226 // One packed (orbit<<32|bc) entry per CMV packet (4 per TF).
227 // Each packet covers 8 heartbeat orbits (NTimeBinsPerPacket = 3564 = 8 LHC orbits),
228 // so the orbit advances by 8 per packet and by NPacketsPerTFPerCRU*8 = 32 per TF.
229 std::vector<uint64_t> orbitBCVec(o2::tpc::cmv::NPacketsPerTFPerCRU);
230 for (uint32_t pkt = 0; pkt < o2::tpc::cmv::NPacketsPerTFPerCRU; ++pkt) {
231 const uint32_t orbit = static_cast<uint32_t>(tf * o2::tpc::cmv::NPacketsPerTFPerCRU * sOrbitsPerPacket + pkt * sOrbitsPerPacket);
232 orbitBCVec[pkt] = uint64_t(orbit) << 32; // bc = 0
233 }
234
235 for (size_t iCRU = 0; iCRU < mCRUs.size(); ++iCRU) {
236 const auto cru = mCRUs[iCRU];
237 const o2::header::DataHeader::SubSpecificationType subSpec{cru << 7};
238
239 // ── per-CRU delay ────────────────────────────────────────────────────
240 if (mDelayCRUs.count(cru)) {
241 LOGP(info, "Delaying CRU {} by {} ms (TF {})", cru, mDelayTimeCRUs, tf);
242 std::this_thread::sleep_for(std::chrono::milliseconds(mDelayTimeCRUs));
243 }
244
245 // Select the vector to emit: the precomputed template (no noise) is sent
246 // verbatim; otherwise this CRU's template is smeared with the shared noise.
247 std::vector<uint16_t>* out = &cmvVec;
248 if (mUseInputFile && !addNoise) {
249 out = &mBaseCMVEncoded[iCRU]; // encoded once in init(), reused every TF
250 } else if (mUseInputFile) {
251 const auto& base = mBaseCMVFloat[iCRU];
252 for (uint32_t tb = 0; tb < o2::tpc::cmv::NTimeBinsPerTF; ++tb) {
254 d.setCMVFloat(base[tb] + noiseVec[tb]);
255 cmvVec[tb] = d.getCMV();
256 }
257 }
258
259 ctx.outputs().snapshot(Output{gDataOriginTPC, "CMVVECTOR", subSpec}, *out);
260 ctx.outputs().snapshot(Output{gDataOriginTPC, "CMVORBITS", subSpec}, orbitBCVec);
261
262 if (mWriteDebug) {
263 auto& stream = (*mDebugStream) << "cmvs";
264 stream << "cru=" << cru
265 << "tfCounter=" << tf
266 << "nCMVs=" << out->size()
267 << "cmvs=" << *out
268 << "\n";
269 }
270 }
271
272 if (!(tf % 100)) {
273 const auto elapsed100 = std::chrono::duration_cast<std::chrono::milliseconds>(timer::now() - mTimer100TFs).count();
274 LOGP(info, "Generated CMV data for TF {} ({} ms for last 100 TFs)", tf, elapsed100);
275 mTimer100TFs = timer::now();
276 }
277
278 // ── global delay ─────────────────────────────────────────────────────────
279 if (mDelay && (mDelayEveryN <= 1 || std::uniform_int_distribution<int>{0, mDelayEveryN - 1}(mRng) == 0)) {
280 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(timer::now() - start).count();
281 if (elapsed < mDelayTime) {
282 LOGP(info, "Delaying TF {} by {} ms", tf, mDelayTime - elapsed);
283 std::this_thread::sleep_for(std::chrono::milliseconds(mDelayTime - elapsed));
284 }
285 }
286
287 // ── rate limiting ────────────────────────────────────────────────────────
288 // Enforce a minimum wall-clock spacing between consecutively sent TFs.
289 if (mTFLength > 0.f) {
290 const auto elapsedSinceLast = std::chrono::duration_cast<std::chrono::microseconds>(timer::now() - mLastTFTime).count();
291 const auto tfLengthUs = static_cast<int64_t>(mTFLength * 1000.f);
292 if (elapsedSinceLast < tfLengthUs) {
293 const auto waitUs = tfLengthUs - elapsedSinceLast;
294 LOGP(info, "Rate limiting TF {}: waiting {} us (tfLength={} ms)", tf, waitUs, mTFLength);
295 std::this_thread::sleep_for(std::chrono::microseconds(waitUs));
296 }
297 mLastTFTime = timer::now();
298 }
299
300 // endOfStream() propagates the EoS signal to downstream devices (required for source devices).
301 if (mMaxTFs != std::numeric_limits<unsigned int>::max() && tf >= mMaxTFs - 1) {
302 ctx.services().get<ControlService>().endOfStream();
303 ctx.services().get<ControlService>().readyToQuit(QuitRequest::Me);
304 }
305 }
306
307 void endOfStream(o2::framework::EndOfStreamContext&) final { closeFiles(); }
308 void stop() final { closeFiles(); }
309
310 private:
311 void closeFiles()
312 {
313 if (mDebugStream) {
314 auto& stream = (*mDebugStream) << "cmvs";
315 auto& tree = stream.getTree();
316 tree.SetAlias("sector", "int(cru/10)");
317 mDebugStream->Close();
318 mDebugStream.reset(nullptr);
319 }
320 }
321
322 const std::vector<uint32_t> mCRUs{};
323 const std::unordered_set<uint32_t> mDelayCRUs{};
324 const unsigned int mMaxTFs{};
325 const bool mDelay{false};
326 const int mDelayTime{1};
327 const int mDelayEveryN{1};
328 const int mDelayTimeCRUs{1};
329 const int mDropTFsRandom{0};
330 const std::vector<int> mRangeTFsDrop{};
331 const float mTFLength{0.f};
332 const float mAmplitude{5.f};
333 const float mNoise{1.f};
334 std::mt19937 mRng{};
335 const std::string mInputFileName{};
336 const long long mInputEntry{0};
337 bool mUseInputFile{false};
338 std::vector<std::vector<float>> mBaseCMVFloat;
339 std::vector<std::vector<uint16_t>> mBaseCMVEncoded;
340 std::chrono::high_resolution_clock::time_point mTimer100TFs{};
341 std::chrono::high_resolution_clock::time_point mLastTFTime{};
342 bool mWriteDebug{false};
343 std::string mDebugStreamFileName{};
344 std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugStream{};
345};
346
347// ─────────────────────────────────────────────────────────────────────────────
348DataProcessorSpec generateCMVsCRU(const std::vector<uint32_t>& crus,
349 const std::unordered_set<uint32_t>& delayCRUs,
350 unsigned int maxTFs,
351 bool delay,
352 int delayTime,
353 int delayEveryN,
354 int delayTimeCRUs,
355 int dropTFsRandom,
356 const std::vector<int>& rangeTFsDrop,
357 float tfLength,
358 float amplitude,
359 float noise,
360 int seed,
361 const std::string& inputFile,
362 long long inputEntry)
363{
364 std::vector<OutputSpec> outputSpecs;
365 outputSpecs.reserve(crus.size() * 2);
366 for (const auto cru : crus) {
367 const o2::header::DataHeader::SubSpecificationType subSpec{cru << 7};
368 outputSpecs.emplace_back(gDataOriginTPC, "CMVVECTOR", subSpec, Lifetime::Timeframe);
369 outputSpecs.emplace_back(gDataOriginTPC, "CMVORBITS", subSpec, Lifetime::Timeframe);
370 }
371
372 return DataProcessorSpec{
373 "tpc-cmv-generator",
374 Inputs{},
375 outputSpecs,
376 AlgorithmSpec{adaptFromTask<CMVGeneratorDevice>(crus, delayCRUs, maxTFs, delay, delayTime, delayEveryN, delayTimeCRUs, dropTFsRandom, rangeTFsDrop, tfLength, amplitude, noise, seed, inputFile, inputEntry)},
377 Options{
378 {"write-debug", VariantType::Bool, false, {"Write a debug output tree"}},
379 {"debug-file-name", VariantType::String, "./cmv_generator_debug.root", {"Name of the debug output file"}},
380 }};
381}
382
383// ─────────────────────────────────────────────────────────────────────────────
385{
386 const auto tpcCRUs = o2::RangeTokenizer::tokenize<int>(config.options().get<std::string>("crus"));
387 const std::vector<uint32_t> crus(tpcCRUs.begin(), tpcCRUs.end());
388
389 const auto delayCRUsStr = config.options().get<std::string>("delayCRUs");
390 std::unordered_set<uint32_t> delayCRUs;
391 if (!delayCRUsStr.empty()) {
392 for (const auto cru : o2::RangeTokenizer::tokenize<int>(delayCRUsStr)) {
393 delayCRUs.insert(static_cast<uint32_t>(cru));
394 }
395 }
396
397 const auto dropTFsRangeStr = config.options().get<std::string>("dropTFsRange");
398 const auto rangeTFsDrop = dropTFsRangeStr.empty() ? std::vector<int>{} : o2::RangeTokenizer::tokenize<int>(dropTFsRangeStr);
399 const int timeframesInt = config.options().get<int>("timeframes");
400 // -1 means run indefinitely; map to UINT_MAX so the termination check never fires.
401 const auto timeframes = (timeframesInt < 0) ? std::numeric_limits<unsigned int>::max() : static_cast<unsigned int>(timeframesInt);
402 const auto delay = config.options().get<bool>("delay");
403 const auto delayTime = config.options().get<int>("delayTime");
404 const auto delayEveryN = config.options().get<int>("delayEveryN");
405 const auto delayTimeCRUs = config.options().get<int>("delayTimeCRUs");
406 const auto dropTFsRandom = config.options().get<int>("dropTFsRandom");
407 const auto tfLength = config.options().get<float>("tfLength");
408 const auto seed = config.options().get<int>("seed");
409 const auto amplitude = config.options().get<float>("amplitude");
410 const auto noise = config.options().get<float>("noise");
411 const auto inputFile = config.options().get<std::string>("input-file");
412 const auto inputEntry = static_cast<long long>(config.options().get<int>("input-entry"));
413
414 o2::conf::ConfigurableParam::updateFromString(config.options().get<std::string>("configKeyValues"));
415
416 WorkflowSpec workflow;
417 workflow.emplace_back(generateCMVsCRU(crus, delayCRUs, timeframes, delay, delayTime, delayEveryN, delayTimeCRUs, dropTFsRandom, rangeTFsDrop, tfLength, amplitude, noise, seed, inputFile, inputEntry));
418
419 auto& hbfu = o2::raw::HBFUtils::Instance();
420 long startTime = hbfu.startTime > 0 ? hbfu.startTime : std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
421 o2::conf::ConfigurableParam::updateFromString(fmt::format("HBFUtils.startTime={}", startTime).data());
422 o2::conf::ConfigurableParam::updateFromString(fmt::format("HBFUtils.nHBFPerTF={}", hbfu.nHBFPerTF).data());
423 o2::raw::HBFUtilsInitializer hbfIni(config, workflow);
424
425 return workflow;
426}
Structs for storing CMVs to the CCDB.
Helper utilities for reading CMV ROOT files.
Common mode values data format definition.
uint64_t orbit
Definition RawEventData.h:6
Helper function to tokenize sequences and ranges of integral numbers.
void init(o2::framework::InitContext &ic) final
CMVGeneratorDevice(const std::vector< uint32_t > &crus, const std::unordered_set< uint32_t > &delayCRUs, unsigned int maxTFs, bool delay, int delayTime, int delayEveryN, int delayTimeCRUs, int dropTFsRandom, const std::vector< int > &rangeTFsDrop, float tfLength, float amplitude, float noise, int seed, const std::string &inputFile, long long inputEntry)
static constexpr uint32_t sOrbitsPerPacket
each CMV packet covers 8 heartbeat orbits
void endOfStream(o2::framework::EndOfStreamContext &) final
This is invoked whenever we have an EndOfStream event.
void stop() final
This is invoked on stop.
void run(o2::framework::ProcessingContext &ctx) final
static void updateFromString(std::string const &)
ConfigParamRegistry & options() const
@ MaxCRU
Definition CRU.h:31
GLdouble n
Definition glcorearb.h:1982
const GLdouble * v
Definition glcorearb.h:832
GLboolean * data
Definition glcorearb.h:298
GLuint start
Definition glcorearb.h:469
GLuint GLuint stream
Definition glcorearb.h:1806
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< DataProcessorSpec > WorkflowSpec
std::vector< InputSpec > Inputs
uint32_t getCurrentTF(o2::framework::ProcessingContext &pc)
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
std::unique_ptr< GPUReconstructionTimeframe > tf
uint32_t SubSpecificationType
Definition DataHeader.h:622
static void addConfigOption(std::vector< o2::framework::ConfigParamSpec > &opts, const std::string &defOpt=std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE))
const CMVPerTF * getEntry(long long iEntry)
Load entry iEntry and return a pointer to the decoded CMVPerTF, or nullptr on error.
Definition CMVHelper.cxx:68
bool open(const std::string &path)
Open path and set up branch addresses. Returns false on any error.
Definition CMVHelper.cxx:26
void close()
Release all resources.
Definition CMVHelper.cxx:81
float getCMVFloat(const int cru, const int timeBin) const
Return the float CMV value for a given CRU and timebin within this TF.
CMV single data container.
Definition CMV.h:74
uint16_t getCMV() const
raw 16-bit integer representation
Definition CMV.h:77
void setCMVFloat(float value)
Definition CMV.h:89
DataProcessorSpec generateCMVsCRU(const std::vector< uint32_t > &crus, const std::unordered_set< uint32_t > &delayCRUs, unsigned int maxTFs, bool delay, int delayTime, int delayEveryN, int delayTimeCRUs, int dropTFsRandom, const std::vector< int > &rangeTFsDrop, float tfLength, float amplitude, float noise, int seed, const std::string &inputFile, long long inputEntry)
WorkflowSpec defineDataProcessing(ConfigContext const &config)
This function hooks up the the workflow specifications into the DPL driver.
void customize(std::vector< ConfigParamSpec > &workflowOptions)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
uint64_t const void const *restrict const msg
Definition x9.h:153