Project
Loading...
Searching...
No Matches
GeneratorHybrid.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
13#include <fairlogger/Logger.h>
14#include <algorithm>
15#include <tbb/concurrent_queue.h>
16#include <tbb/task_arena.h>
17#include <tbb/parallel_for.h>
19#include <filesystem>
20
21namespace o2
22{
23namespace eventgen
24{
25
26GeneratorHybrid::GeneratorHybrid(const std::string& inputgens)
27{
28 if (!parseJSON(inputgens)) {
29 LOG(fatal) << "Failed to parse JSON configuration from input generators";
30 exit(1);
31 }
32 mRandomize = GeneratorHybridParam::Instance().randomize;
33 if (mConfigs.size() != mInputGens.size()) {
34 LOG(fatal) << "Number of configurations does not match the number of generators";
35 exit(1);
36 }
37 if (mConfigs.size() == 0) {
38 for (auto gen : mInputGens) {
39 mConfigs.push_back("");
40 }
41 }
42 int index = 0;
43 if (!(mRandomize || mGenerationMode == GenMode::kParallel)) {
44 if (mCocktailMode) {
45 if (mGroups.size() != mFractions.size()) {
46 LOG(fatal) << "Number of groups does not match the number of fractions";
47 return;
48 }
49 } else {
50 if (mFractions.size() != mInputGens.size()) {
51 LOG(fatal) << "Number of fractions does not match the number of generators";
52 return;
53 }
54 }
55 // Check if all elements of mFractions are 0
56 if (std::all_of(mFractions.begin(), mFractions.end(), [](int i) { return i == 0; })) {
57 LOG(fatal) << "All fractions provided are 0, no simulation will be performed";
58 return;
59 }
60 }
61 for (auto gen : mInputGens) {
62 // Search if the generator name is inside generatorNames (which is a vector of strings)
63 LOG(info) << "Checking if generator " << gen << " is in the list of available generators \n";
64 if (std::find(generatorNames.begin(), generatorNames.end(), gen) != generatorNames.end()) {
65 LOG(info) << "Found generator " << gen << " in the list of available generators \n";
66 if (gen.compare("boxgen") == 0) {
67 if (mConfigs[index].compare("") == 0) {
68 gens.push_back(std::make_shared<o2::eventgen::BoxGenerator>());
69 } else {
70 // Get the index of boxgen configuration
71 int confBoxIndex = std::stoi(mConfigs[index].substr(7));
72 gens.push_back(std::make_shared<o2::eventgen::BoxGenerator>(*mBoxGenConfigs[confBoxIndex]));
73 }
74 mGens.push_back(gen);
75 } else if (gen.compare(0, 7, "pythia8") == 0) {
76 // Check if mConfigs[index] contains pythia8_ and a number
77 if (mConfigs[index].compare("") == 0) {
78 auto pars = Pythia8GenConfig();
79 gens.push_back(std::make_shared<o2::eventgen::GeneratorPythia8>(pars));
80 } else {
81 // Get the index of pythia8 configuration
82 int confPythia8Index = std::stoi(mConfigs[index].substr(8));
83 gens.push_back(std::make_shared<o2::eventgen::GeneratorPythia8>(*mPythia8GenConfigs[confPythia8Index]));
84 }
85 mConfsPythia8.push_back(mConfigs[index]);
86 mGens.push_back(gen);
87 } else if (gen.compare("extkinO2") == 0) {
88 int confO2KineIndex = std::stoi(mConfigs[index].substr(9));
89 gens.push_back(std::make_shared<o2::eventgen::GeneratorFromO2Kine>(*mO2KineGenConfigs[confO2KineIndex]));
90 mGens.push_back(gen);
91 } else if (gen.compare("evtpool") == 0) {
92 int confEvtPoolIndex = std::stoi(mConfigs[index].substr(8));
93 gens.push_back(std::make_shared<o2::eventgen::GeneratorFromEventPool>(mEventPoolConfigs[confEvtPoolIndex]));
94 mGens.push_back(gen);
95 } else if (gen.compare("external") == 0) {
96 int confextIndex = std::stoi(mConfigs[index].substr(9));
97 // we need analyse the ini file to update the config key param
98 if (mExternalGenConfigs[confextIndex]->iniFile.size() > 0) {
99 LOG(info) << "Setting up external gen using the given INI file";
100
101 // this means that we go via the ConfigurableParam system ---> in order not to interfere with other
102 // generators we use an approach with backup and restore of the system
103
104 // we write the current state to a file
105 // create a tmp file name
106 std::string tmp_config_file = "configkey_tmp_backup_" + std::to_string(getpid()) + std::string(".ini");
108
109 auto expandedFileName = o2::utils::expandShellVarsInFileName(mExternalGenConfigs[confextIndex]->iniFile);
111 // toDo: check that this INI file makes sense
112
114 LOG(info) << "Setting up external generator with following parameters";
115 LOG(info) << params;
116 auto extgen_filename = params.fileName;
117 auto extgen_func = params.funcName;
118 auto extgen = std::shared_ptr<o2::eventgen::Generator>(o2::conf::GetFromMacro<o2::eventgen::Generator*>(extgen_filename, extgen_func, "FairGenerator*", "extgen"));
119 if (!extgen) {
120 LOG(fatal) << "Failed to retrieve \'extgen\': problem with configuration ";
121 }
122 // restore old state
124 // delete tmp file
125 std::filesystem::remove(tmp_config_file);
126
127 gens.push_back(std::move(extgen));
128 mGens.push_back(gen);
129 } else {
130 LOG(info) << "Setting up external gen using the given fileName and funcName";
131 // we need to restore the config key param system to what is was before
132 auto& extgen_filename = mExternalGenConfigs[confextIndex]->fileName;
133 auto& extgen_func = mExternalGenConfigs[confextIndex]->funcName;
134 auto extGen = std::shared_ptr<o2::eventgen::Generator>(o2::conf::GetFromMacro<o2::eventgen::Generator*>(extgen_filename, extgen_func, "FairGenerator*", "extgen"));
135 if (!extGen) {
136 LOG(fatal) << "Failed to load external generator from " << extgen_filename << " with function " << extgen_func;
137 }
138 gens.push_back(std::move(extGen));
139 mGens.push_back(gen);
140 }
141 } else if (gen.compare("hepmc") == 0) {
142 int confHepMCIndex = std::stoi(mConfigs[index].substr(6));
143 gens.push_back(std::make_shared<o2::eventgen::GeneratorHepMC>());
144 auto& globalConfig = o2::conf::SimConfig::Instance();
145 dynamic_cast<o2::eventgen::GeneratorHepMC*>(gens.back().get())->setup(*mFileOrCmdGenConfigs[confHepMCIndex], *mHepMCGenConfigs[confHepMCIndex], globalConfig);
146 mGens.push_back(gen);
147 }
148 } else {
149 LOG(fatal) << "Generator " << gen << " not found in the list of available generators \n";
150 exit(1);
151 }
152 index++;
153 }
154}
155
157{
158 LOG(info) << "Destructor of generator hybrid called";
159 mStopFlag = true;
160}
161
163{
164 // init all sub-gens
165 int count = 0;
166 for (auto& gen : mGens) {
167 if (gen == "pythia8pp") {
168 auto config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_inel.cfg";
169 LOG(info) << "Setting \'Pythia8\' base configuration: " << config << std::endl;
170 dynamic_cast<o2::eventgen::GeneratorPythia8*>(gens[count].get())->setConfig(config);
171 } else if (gen == "pythia8hf") {
172 auto config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_hf.cfg";
173 LOG(info) << "Setting \'Pythia8\' base configuration: " << config << std::endl;
174 dynamic_cast<o2::eventgen::GeneratorPythia8*>(gens[count].get())->setConfig(config);
175 } else if (gen == "pythia8hi") {
176 auto config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_hi.cfg";
177 LOG(info) << "Setting \'Pythia8\' base configuration: " << config << std::endl;
178 dynamic_cast<o2::eventgen::GeneratorPythia8*>(gens[count].get())->setConfig(config);
179 } else if (gen == "pythia8powheg") {
180 auto config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_powheg.cfg";
181 LOG(info) << "Setting \'Pythia8\' base configuration: " << config << std::endl;
182 dynamic_cast<o2::eventgen::GeneratorPythia8*>(gens[count].get())->setConfig(config);
183 }
184 gens[count]->Init(); // TODO: move this to multi-threaded
186 if (mTriggerModes[count] != o2::eventgen::Generator::kTriggerOFF) {
187 gens[count]->setTriggerMode(mTriggerModes[count]);
188 LOG(info) << "Setting Trigger mode of generator " << gen << " to: " << mTriggerModes[count];
189 o2::eventgen::Trigger trigger = nullptr;
190 o2::eventgen::DeepTrigger deeptrigger = nullptr;
191 for (int trg = 0; trg < mTriggerMacros[count].size(); trg++) {
192 if (mTriggerMacros[count][trg].empty() || mTriggerFuncs[count][trg].empty()) {
193 continue;
194 }
195 std::string expandedMacro = o2::utils::expandShellVarsInFileName(mTriggerMacros[count][trg]);
196 LOG(info) << "Setting trigger " << trg << " of generator " << gen << " with following parameters";
197 LOG(info) << "Macro filename: " << expandedMacro;
198 LOG(info) << "Function name: " << mTriggerFuncs[count][trg];
199 trigger = o2::conf::GetFromMacro<o2::eventgen::Trigger>(expandedMacro, mTriggerFuncs[count][trg], "o2::eventgen::Trigger", "trigger");
200 if (!trigger) {
201 LOG(info) << "Trying to retrieve a \'o2::eventgen::DeepTrigger\' type";
202 deeptrigger = o2::conf::GetFromMacro<o2::eventgen::DeepTrigger>(expandedMacro, mTriggerFuncs[count][trg], "o2::eventgen::DeepTrigger", "deeptrigger");
203 }
204 if (!trigger && !deeptrigger) {
205 LOG(warn) << "Failed to retrieve \'external trigger\': problem with configuration";
206 LOG(warn) << "Trigger " << trg << " of generator " << gen << " will not be included";
207 continue;
208 } else {
209 LOG(info) << "Trigger " << trg << " of generator " << gen << " successfully set";
210 }
211 if (trigger) {
212 gens[count]->addTrigger(trigger);
213 } else {
214 gens[count]->addDeepTrigger(deeptrigger);
215 }
216 }
217 }
218 count++;
219 }
220 if (mRandomize) {
221 if (std::all_of(mFractions.begin(), mFractions.end(), [](int i) { return i == 1; })) {
222 LOG(info) << "Full randomisation of generators order";
223 } else {
224 LOG(info) << "Randomisation based on fractions";
225 int allfracs = 0;
226 for (auto& f : mFractions) {
227 allfracs += f;
228 }
229 // Assign new rng fractions
230 float sum = 0;
231 float chance = 0;
232 for (int k = 0; k < mFractions.size(); k++) {
233 if (mFractions[k] == 0) {
234 // Generator will not be used if fraction is 0
235 mRngFractions.push_back(-1);
236 LOG(info) << "Generator " << mGens[k] << " will not be used";
237 } else {
238 chance = static_cast<float>(mFractions[k]) / allfracs;
239 sum += chance;
240 mRngFractions.push_back(sum);
241 LOG(info) << "Generator " << (mConfigs[k] == "" ? mGens[k] : mConfigs[k]) << " has a " << chance * 100 << "% chance of being used";
242 }
243 }
244 }
245 } else {
246 LOG(info) << "Generators will be used in sequence, following provided fractions";
247 }
248
249 mGenIsInitialized.resize(gens.size(), false);
250 if (mGenerationMode == GenMode::kParallel) {
251 // in parallel mode we just use one queue --> collaboration
252 mResultQueue.resize(1);
253 } else {
254 // in sequential mode we have one queue per generator
255 mResultQueue.resize(gens.size());
256 }
257 // Create a task arena with a specified number of threads
258 mTaskArena.initialize(GeneratorHybridParam::Instance().num_workers);
259
260 // the process task function actually calls event generation
261 // when it is done it notifies the outside world by pushing it's index into an appropriate queue
262 // This should be a lambda, which can be given at TaskPool creation time
263 auto process_generator_task = [this](std::vector<std::shared_ptr<o2::eventgen::Generator>> const& generatorvec, int task) {
264 LOG(debug) << "Starting eventgen for task " << task;
265 auto& generator = generatorvec[task];
266 if (!mStopFlag) {
267 // TODO: activate this once we are use Init is threadsafe
268 // if (!mGenIsInitialized[task]) {
269 // if(!generator->Init()) {
270 // LOG(error) << "failed to init generator " << task;
271 // }
272 // mGenIsInitialized[task] = true;
273 // }
274 }
275 bool isTriggered = false;
276 while (!isTriggered) {
277 generator->clearParticles();
278 generator->generateEvent();
279 generator->importParticles();
280 isTriggered = generator->triggerEvent();
281 }
282 LOG(debug) << "eventgen finished for task " << task;
283 if (!mStopFlag) {
284 if (mGenerationMode == GenMode::kParallel) {
285 mResultQueue[0].push(task);
286 } else {
287 mResultQueue[task].push(task);
288 }
289 }
290 };
291
292 // fundamental tbb thread-worker function
293 auto worker_function = [this, process_generator_task]() {
294 // we increase the reference count in the generator pointers
295 // by making a copy of the vector. In this way we ensure that the lifetime
296 // of the generators is no shorter than the lifetime of the thread for this worker function
297 auto generators_copy = gens;
298
299 while (!mStopFlag) {
300 int task;
301 if (mInputTaskQueue.try_pop(task)) {
302 process_generator_task(generators_copy, task); // Process the task
303 } else {
304 std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Wait if no task
305 }
306 }
307 };
308
309 // let the TBB task system run in it's own thread
310 mTBBTaskPoolRunner = std::thread([this, worker_function]() { mTaskArena.execute([&]() { tbb::parallel_for(0, mTaskArena.max_concurrency(), [&](int) { worker_function(); }); }); });
311 mTBBTaskPoolRunner.detach(); // detaching because we don't like to wait on the thread to finish
312 // some of the generators might still be generating when we are done
313
314 // let's also push initial generation tasks for each event generator
315 for (size_t genindex = 0; genindex < gens.size(); ++genindex) {
316 mInputTaskQueue.push(genindex);
317 mTasksStarted++;
318 }
319 mIsInitialized = true;
320 return Generator::Init();
321}
322
324{
325 if (!mIsInitialized) {
326 Init();
327 }
328 if (mGenerationMode == GenMode::kParallel) {
329 mIndex = -1; // this means any index is welcome
330 notifySubGenerator(0); // we shouldn't distinguish the sub-gen ids
331 } else {
332 // Order randomisation or sequence of generators
333 // following provided fractions, if not generators are used in proper sequence
334 // Order randomisation or sequence of generators
335 // following provided fractions. If not available generators will be used sequentially
336 if (mRandomize) {
337 if (mRngFractions.size() != 0) {
338 // Generate number between 0 and 1
339 float rnum = gRandom->Rndm();
340 // Find generator index
341 for (int k = 0; k < mRngFractions.size(); k++) {
342 if (rnum <= mRngFractions[k]) {
343 mIndex = k;
344 break;
345 }
346 }
347 } else {
348 mIndex = gRandom->Integer(mFractions.size());
349 }
350 } else {
351 while (mFractions[mCurrentFraction] == 0 || mseqCounter == mFractions[mCurrentFraction]) {
352 if (mFractions[mCurrentFraction] != 0) {
353 mseqCounter = 0;
354 }
355 mCurrentFraction = (mCurrentFraction + 1) % mFractions.size();
356 }
357 mIndex = mCurrentFraction;
358 }
359 notifySubGenerator(mIndex);
360 }
361 return true;
362}
363
365{
366 int genIndex = -1;
367 std::vector<int> subGenIndex = {};
368 if (mIndex == -1) {
369 // this means parallel mode ---> we have a common queue
370 mResultQueue[0].pop(genIndex);
371 } else {
372 // need to pop from a particular queue
373 if (!mCocktailMode) {
374 mResultQueue[mIndex].pop(genIndex);
375 } else {
376 // in cocktail mode we need to pop from the group queue
377 subGenIndex.resize(mGroups[mIndex].size());
378 for (size_t pos = 0; pos < mGroups[mIndex].size(); ++pos) {
379 int subIndex = mGroups[mIndex][pos];
380 LOG(info) << "Getting generator " << mGens[subIndex] << " from cocktail group " << mIndex;
381 mResultQueue[subIndex].pop(subGenIndex[pos]);
382 }
383 }
384 }
385 // Clear particles and event header
386 mParticles.clear();
387 mMCEventHeader.clearInfo();
388 if (mCocktailMode) {
389 // in cocktail mode we need to merge the particles from the different generators
390 for (auto subIndex : subGenIndex) {
391 LOG(info) << "Importing particles for task " << subIndex;
392 auto subParticles = gens[subIndex]->getParticles();
393
394 // The particles carry mother and daughter indices, which are relative
395 // to the sub-generator. We need to adjust these indices to reflect that particles
396 // are now embedded into a cocktail.
397 auto offset = mParticles.size();
398 for (auto& p : subParticles) {
399 for (int i = 0; i < 2; ++i) {
400 if (p.GetMother(i) != -1) {
401 const auto newindex = p.GetMother(i) + offset;
402 p.SetMother(i, newindex);
403 }
404 }
405 if (p.GetNDaughters() > 0) {
406 for (int i = 0; i < 2; ++i) {
407 const auto newindex = p.GetDaughter(i) + offset;
408 p.SetDaughter(i, newindex);
409 }
410 }
411 }
412
413 mParticles.insert(mParticles.end(), subParticles.begin(), subParticles.end());
414 // fetch the event Header information from the underlying generator
415 gens[subIndex]->updateHeader(&mMCEventHeader);
416 mInputTaskQueue.push(subIndex);
417 mTasksStarted++;
418 }
419 } else {
420 LOG(info) << "Importing particles for task " << genIndex;
421 // at this moment the mIndex-th generator is ready to be used
422 mParticles = gens[genIndex]->getParticles();
423 // fetch the event Header information from the underlying generator
424 gens[genIndex]->updateHeader(&mMCEventHeader);
425 mInputTaskQueue.push(genIndex);
426 mTasksStarted++;
427 }
428
429 mseqCounter++;
430 mEventCounter++;
431 if (mEventCounter == getTotalNEvents()) {
432 LOG(info) << "HybridGen: Stopping TBB task pool";
433 mStopFlag = true;
434 }
435
436 return true;
437}
438
440{
441 if (eventHeader) {
442 // we forward the original header information if any
443 eventHeader->copyInfoFrom(mMCEventHeader);
444
445 // put additional information about
446 eventHeader->putInfo<std::string>("forwarding-generator", "HybridGen");
447 }
448}
449
450template <typename T>
452{
453 rapidjson::StringBuffer buffer;
454 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
455 value.Accept(writer);
456 return buffer.GetString();
457}
458
460{
461 std::string name = gen["name"].GetString();
462 mInputGens.push_back(name);
463 if (gen.HasMember("config")) {
464 if (name == "boxgen") {
465 const auto& boxconf = gen["config"];
466 auto boxConfig = TBufferJSON::FromJSON<o2::eventgen::BoxGenConfig>(jsonValueToString(boxconf).c_str());
467 mBoxGenConfigs.push_back(std::move(boxConfig));
468 mConfigs.push_back("boxgen_" + std::to_string(mBoxGenConfigs.size() - 1));
469 } else if (name == "pythia8") {
470 const auto& pythia8conf = gen["config"];
471 auto pythia8Config = TBufferJSON::FromJSON<o2::eventgen::Pythia8GenConfig>(jsonValueToString(pythia8conf).c_str());
472 mPythia8GenConfigs.push_back(std::move(pythia8Config));
473 mConfigs.push_back("pythia8_" + std::to_string(mPythia8GenConfigs.size() - 1));
474 } else if (name == "extkinO2") {
475 const auto& o2kineconf = gen["config"];
476 auto o2kineConfig = TBufferJSON::FromJSON<o2::eventgen::O2KineGenConfig>(jsonValueToString(o2kineconf).c_str());
477 mO2KineGenConfigs.push_back(std::move(o2kineConfig));
478 mConfigs.push_back("extkinO2_" + std::to_string(mO2KineGenConfigs.size() - 1));
479 } else if (name == "evtpool") {
480 const auto& o2kineconf = gen["config"];
481 auto poolConfig = TBufferJSON::FromJSON<o2::eventgen::EventPoolGenConfig>(jsonValueToString(o2kineconf).c_str());
482 mEventPoolConfigs.push_back(*poolConfig);
483 mConfigs.push_back("evtpool_" + std::to_string(mEventPoolConfigs.size() - 1));
484 } else if (name == "external") {
485 const auto& extconf = gen["config"];
486 auto extConfig = TBufferJSON::FromJSON<o2::eventgen::ExternalGenConfig>(jsonValueToString(extconf).c_str());
487 mExternalGenConfigs.push_back(std::move(extConfig));
488 mConfigs.push_back("external_" + std::to_string(mExternalGenConfigs.size() - 1));
489 } else if (name == "hepmc") {
490 const auto& genconf = gen["config"];
491 const auto& cmdconf = genconf["configcmd"];
492 const auto& hepmcconf = genconf["confighepmc"];
493 auto cmdConfig = TBufferJSON::FromJSON<o2::eventgen::FileOrCmdGenConfig>(jsonValueToString(cmdconf).c_str());
494 auto hepmcConfig = TBufferJSON::FromJSON<o2::eventgen::HepMCGenConfig>(jsonValueToString(hepmcconf).c_str());
495 mFileOrCmdGenConfigs.push_back(std::move(cmdConfig));
496 mHepMCGenConfigs.push_back(std::move(hepmcConfig));
497 mConfigs.push_back("hepmc_" + std::to_string(mFileOrCmdGenConfigs.size() - 1));
498 } else {
499 mConfigs.push_back("");
500 }
501 } else {
502 if (name == "boxgen" || name == "pythia8" || name == "extkinO2" || name == "external" || name == "hepmc") {
503 LOG(fatal) << "No configuration provided for generator " << name;
504 return false;
505 } else {
506 mConfigs.push_back("");
507 }
508 }
509 if (gen.HasMember("triggers")) {
510 const auto& trigger = gen["triggers"];
511 auto trigger_specs = [this, &trigger]() {
512 mTriggerMacros.push_back({});
513 mTriggerFuncs.push_back({});
514 if (trigger.HasMember("specs")) {
515 for (auto& spec : trigger["specs"].GetArray()) {
516 if (spec.HasMember("macro")) {
517 const auto& macro = spec["macro"].GetString();
518 if (!(strcmp(macro, "") == 0)) {
519 mTriggerMacros.back().push_back(macro);
520 } else {
521 mTriggerMacros.back().push_back("");
522 }
523 } else {
524 mTriggerMacros.back().push_back("");
525 }
526 if (spec.HasMember("function")) {
527 const auto& function = spec["function"].GetString();
528 if (!(strcmp(function, "") == 0)) {
529 mTriggerFuncs.back().push_back(function);
530 } else {
531 mTriggerFuncs.back().push_back("");
532 }
533 } else {
534 mTriggerFuncs.back().push_back("");
535 }
536 }
537 } else {
538 mTriggerMacros.back().push_back("");
539 mTriggerFuncs.back().push_back("");
540 }
541 };
542 if (trigger.HasMember("mode")) {
543 const auto& trmode = trigger["mode"].GetString();
544 if (strcmp(trmode, "or") == 0) {
545 mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOR);
546 trigger_specs();
547 } else if (strcmp(trmode, "and") == 0) {
548 mTriggerModes.push_back(o2::eventgen::Generator::kTriggerAND);
549 trigger_specs();
550 } else if (strcmp(trmode, "off") == 0) {
551 mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF);
552 mTriggerMacros.push_back({""});
553 mTriggerFuncs.push_back({""});
554 } else {
555 LOG(warn) << "Wrong trigger mode provided for generator " << name << ", keeping trigger OFF";
556 mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF);
557 mTriggerMacros.push_back({""});
558 mTriggerFuncs.push_back({""});
559 }
560 } else {
561 LOG(warn) << "No trigger mode provided for generator " << name << ", turning trigger OFF";
562 mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF);
563 mTriggerMacros.push_back({""});
564 mTriggerFuncs.push_back({""});
565 }
566 } else {
567 mTriggerModes.push_back(o2::eventgen::Generator::kTriggerOFF);
568 mTriggerMacros.push_back({""});
569 mTriggerFuncs.push_back({""});
570 }
571 return true;
572}
573
574Bool_t GeneratorHybrid::parseJSON(const std::string& path)
575{
576 // Parse JSON file to build map
577 std::ifstream fileStream(path, std::ios::in);
578 if (!fileStream.is_open()) {
579 LOG(error) << "Cannot open " << path;
580 return false;
581 }
582 rapidjson::IStreamWrapper isw(fileStream);
583 rapidjson::Document doc;
584 doc.ParseStream(isw);
585 if (doc.HasParseError()) {
586 LOG(error) << "Error parsing provided json file " << path;
587 LOG(error) << " - Error -> " << rapidjson::GetParseError_En(doc.GetParseError());
588 return false;
589 }
590
591 // check if there is a mode field
592 if (doc.HasMember("mode")) {
593 const auto& mode = doc["mode"].GetString();
594 if (strcmp(mode, "sequential") == 0) {
595 // events are generated in the order given by fractions or random weight
596 mGenerationMode = GenMode::kSeq;
597 }
598 if (strcmp(mode, "parallel") == 0) {
599 // events are generated fully in parallel and the order will be random
600 // this is mainly for event pool generation or mono-type generators
601 mGenerationMode = GenMode::kParallel;
602 LOG(info) << "Setting mode to parallel";
603 }
604 }
605
606 // Put the generator names in mInputGens
607 if (doc.HasMember("generators")) {
608 const auto& gens = doc["generators"];
609 for (const auto& gen : gens.GetArray()) {
610 mGroups.push_back({});
611 // Check if gen is an array (cocktail mode)
612 if (gen.HasMember("cocktail")) {
613 mCocktailMode = true;
614 for (const auto& subgen : gen["cocktail"].GetArray()) {
615 if (confSetter(subgen)) {
616 mGroups.back().push_back(mInputGens.size() - 1);
617 } else {
618 return false;
619 }
620 }
621 } else {
622 if (!confSetter(gen)) {
623 return false;
624 }
625 // Groups are created in case cocktail mode is activated, this way
626 // cocktails can be declared anywhere in the JSON file, without the need
627 // of grouping single generators. If no cocktail is defined
628 // groups will be ignored nonetheless.
629 mGroups.back().push_back(mInputGens.size() - 1);
630 }
631 }
632 }
633
634 // Get fractions and put them in mFractions
635 if (doc.HasMember("fractions")) {
636 const auto& fractions = doc["fractions"];
637 for (const auto& frac : fractions.GetArray()) {
638 mFractions.push_back(frac.GetInt());
639 }
640 } else {
641 // Set fractions to unity for all generators in case they are not provided
642 const auto& gens = doc["generators"];
643 for (const auto& gen : gens.GetArray()) {
644 mFractions.push_back(1);
645 }
646 }
647 return true;
648}
649
650} // namespace eventgen
651} // namespace o2
652
default_random_engine gen(dev())
int32_t i
ClassImp(o2::eventgen::GeneratorHybrid)
uint16_t pos
Definition RawData.h:3
std::ostringstream debug
static void writeINI(std::string const &filename, std::string const &keyOnly="")
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static SimConfig & Instance()
Definition SimConfig.h:111
void copyInfoFrom(MCEventHeader const &other)
inits info fields from another Event header
void putInfo(std::string const &key, T const &value)
Bool_t parseJSON(const std::string &path)
std::string jsonValueToString(const T &value)
void updateHeader(o2::dataformats::MCEventHeader *eventHeader) override
Bool_t confSetter(const auto &gen)
void notifySubGenerator(int subGeneratorId)
Definition Generator.h:116
static unsigned int getTotalNEvents()
Definition Generator.h:93
void addSubGenerator(int subGeneratorId, std::string const &subGeneratorDescription)
std::vector< TParticle > mParticles
Definition Generator.h:140
Bool_t Init() override
Definition Generator.cxx:57
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
GLenum mode
Definition glcorearb.h:266
GLint GLsizei count
Definition glcorearb.h:399
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble f
Definition glcorearb.h:310
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum const GLfloat * params
Definition glcorearb.h:272
GLintptr offset
Definition glcorearb.h:660
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
std::function< bool(void *, std::string)> DeepTrigger
Definition Trigger.h:26
std::function< bool(const std::vector< TParticle > &)> Trigger
Definition Trigger.h:25
std::string expandShellVarsInFileName(std::string const &input)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
void empty(int)
void compare(std::string_view s1, std::string_view s2)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"