29 LOG(fatal) <<
"Failed to parse JSON configuration from input generators";
33 if (mConfigs.size() != mInputGens.size()) {
34 LOG(fatal) <<
"Number of configurations does not match the number of generators";
37 if (mConfigs.size() == 0) {
38 for (
auto gen : mInputGens) {
39 mConfigs.push_back(
"");
43 if (!(mRandomize || mGenerationMode == GenMode::kParallel)) {
45 if (mGroups.size() != mFractions.size()) {
46 LOG(fatal) <<
"Number of groups does not match the number of fractions";
50 if (mFractions.size() != mInputGens.size()) {
51 LOG(fatal) <<
"Number of fractions does not match the number of generators";
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";
61 for (
auto gen : mInputGens) {
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) {
68 gens.push_back(std::make_shared<o2::eventgen::BoxGenerator>());
71 int confBoxIndex = std::stoi(mConfigs[
index].substr(7));
72 gens.push_back(std::make_shared<o2::eventgen::BoxGenerator>(*mBoxGenConfigs[confBoxIndex]));
75 }
else if (
gen.compare(0, 7,
"pythia8") == 0) {
79 gens.push_back(std::make_shared<o2::eventgen::GeneratorPythia8>(pars));
82 int confPythia8Index = std::stoi(mConfigs[
index].substr(8));
83 gens.push_back(std::make_shared<o2::eventgen::GeneratorPythia8>(*mPythia8GenConfigs[confPythia8Index]));
85 mConfsPythia8.push_back(mConfigs[
index]);
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]));
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]));
95 }
else if (
gen.compare(
"external") == 0) {
96 int confextIndex = std::stoi(mConfigs[
index].substr(9));
98 if (mExternalGenConfigs[confextIndex]->iniFile.size() > 0) {
99 LOG(info) <<
"Setting up external gen using the given INI file";
106 std::string tmp_config_file =
"configkey_tmp_backup_" +
std::to_string(getpid()) + std::string(
".ini");
114 LOG(info) <<
"Setting up external generator with following parameters";
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"));
120 LOG(fatal) <<
"Failed to retrieve \'extgen\': problem with configuration ";
125 std::filesystem::remove(tmp_config_file);
127 gens.push_back(std::move(extgen));
128 mGens.push_back(
gen);
130 LOG(info) <<
"Setting up external gen using the given fileName and funcName";
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"));
136 LOG(fatal) <<
"Failed to load external generator from " << extgen_filename <<
" with function " << extgen_func;
138 gens.push_back(std::move(extGen));
139 mGens.push_back(
gen);
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>());
145 dynamic_cast<o2::eventgen::GeneratorHepMC*
>(gens.back().get())->setup(*mFileOrCmdGenConfigs[confHepMCIndex], *mHepMCGenConfigs[confHepMCIndex], globalConfig);
146 mGens.push_back(
gen);
149 LOG(fatal) <<
"Generator " <<
gen <<
" not found in the list of available generators \n";
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;
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;
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;
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;
187 gens[
count]->setTriggerMode(mTriggerModes[
count]);
188 LOG(info) <<
"Setting Trigger mode of generator " <<
gen <<
" to: " << mTriggerModes[
count];
191 for (
int trg = 0; trg < mTriggerMacros[
count].size(); 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");
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");
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";
209 LOG(info) <<
"Trigger " << trg <<
" of generator " <<
gen <<
" successfully set";
212 gens[
count]->addTrigger(trigger);
214 gens[
count]->addDeepTrigger(deeptrigger);
221 if (std::all_of(mFractions.begin(), mFractions.end(), [](
int i) { return i == 1; })) {
222 LOG(info) <<
"Full randomisation of generators order";
224 LOG(info) <<
"Randomisation based on fractions";
226 for (
auto&
f : mFractions) {
232 for (
int k = 0; k < mFractions.size(); k++) {
233 if (mFractions[k] == 0) {
235 mRngFractions.push_back(-1);
236 LOG(info) <<
"Generator " << mGens[k] <<
" will not be used";
238 chance =
static_cast<float>(mFractions[k]) / allfracs;
240 mRngFractions.push_back(
sum);
241 LOG(info) <<
"Generator " << (mConfigs[k] ==
"" ? mGens[k] : mConfigs[k]) <<
" has a " << chance * 100 <<
"% chance of being used";
246 LOG(info) <<
"Generators will be used in sequence, following provided fractions";
249 mGenIsInitialized.resize(gens.size(),
false);
250 if (mGenerationMode == GenMode::kParallel) {
252 mResultQueue.resize(1);
255 mResultQueue.resize(gens.size());
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];
275 bool isTriggered =
false;
276 while (!isTriggered) {
277 generator->clearParticles();
278 generator->generateEvent();
279 generator->importParticles();
280 isTriggered = generator->triggerEvent();
282 LOG(
debug) <<
"eventgen finished for task " << task;
284 if (mGenerationMode == GenMode::kParallel) {
285 mResultQueue[0].push(task);
287 mResultQueue[task].push(task);
293 auto worker_function = [
this, process_generator_task]() {
297 auto generators_copy = gens;
301 if (mInputTaskQueue.try_pop(task)) {
302 process_generator_task(generators_copy, task);
304 std::this_thread::sleep_for(std::chrono::milliseconds(10));
310 mTBBTaskPoolRunner = std::thread([
this, worker_function]() { mTaskArena.execute([&]() { tbb::parallel_for(0, mTaskArena.max_concurrency(), [&](
int) { worker_function(); }); }); });
311 mTBBTaskPoolRunner.detach();
315 for (
size_t genindex = 0; genindex < gens.size(); ++genindex) {
316 mInputTaskQueue.push(genindex);
319 mIsInitialized =
true;
325 if (!mIsInitialized) {
328 if (mGenerationMode == GenMode::kParallel) {
337 if (mRngFractions.size() != 0) {
339 float rnum = gRandom->Rndm();
341 for (
int k = 0; k < mRngFractions.size(); k++) {
342 if (rnum <= mRngFractions[k]) {
348 mIndex = gRandom->Integer(mFractions.size());
351 while (mFractions[mCurrentFraction] == 0 || mseqCounter == mFractions[mCurrentFraction]) {
352 if (mFractions[mCurrentFraction] != 0) {
355 mCurrentFraction = (mCurrentFraction + 1) % mFractions.size();
357 mIndex = mCurrentFraction;
367 std::vector<int> subGenIndex = {};
370 mResultQueue[0].pop(genIndex);
373 if (!mCocktailMode) {
374 mResultQueue[mIndex].pop(genIndex);
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]);
390 for (
auto subIndex : subGenIndex) {
391 LOG(info) <<
"Importing particles for task " << subIndex;
392 auto subParticles = gens[subIndex]->getParticles();
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);
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);
415 gens[subIndex]->updateHeader(&mMCEventHeader);
416 mInputTaskQueue.push(subIndex);
420 LOG(info) <<
"Importing particles for task " << genIndex;
424 gens[genIndex]->updateHeader(&mMCEventHeader);
425 mInputTaskQueue.push(genIndex);
432 LOG(info) <<
"HybridGen: Stopping TBB task pool";
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));
499 mConfigs.push_back(
"");
502 if (
name ==
"boxgen" ||
name ==
"pythia8" ||
name ==
"extkinO2" ||
name ==
"external" ||
name ==
"hepmc") {
503 LOG(fatal) <<
"No configuration provided for generator " <<
name;
506 mConfigs.push_back(
"");
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);
521 mTriggerMacros.back().push_back(
"");
524 mTriggerMacros.back().push_back(
"");
526 if (spec.HasMember(
"function")) {
527 const auto& function = spec[
"function"].GetString();
528 if (!(strcmp(function,
"") == 0)) {
529 mTriggerFuncs.back().push_back(function);
531 mTriggerFuncs.back().push_back(
"");
534 mTriggerFuncs.back().push_back(
"");
538 mTriggerMacros.back().push_back(
"");
539 mTriggerFuncs.back().push_back(
"");
542 if (trigger.HasMember(
"mode")) {
543 const auto& trmode = trigger[
"mode"].GetString();
544 if (strcmp(trmode,
"or") == 0) {
547 }
else if (strcmp(trmode,
"and") == 0) {
550 }
else if (strcmp(trmode,
"off") == 0) {
552 mTriggerMacros.push_back({
""});
553 mTriggerFuncs.push_back({
""});
555 LOG(warn) <<
"Wrong trigger mode provided for generator " <<
name <<
", keeping trigger OFF";
557 mTriggerMacros.push_back({
""});
558 mTriggerFuncs.push_back({
""});
561 LOG(warn) <<
"No trigger mode provided for generator " <<
name <<
", turning trigger OFF";
563 mTriggerMacros.push_back({
""});
564 mTriggerFuncs.push_back({
""});
568 mTriggerMacros.push_back({
""});
569 mTriggerFuncs.push_back({
""});
577 std::ifstream fileStream(
path, std::ios::in);
578 if (!fileStream.is_open()) {
579 LOG(error) <<
"Cannot open " <<
path;
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());
592 if (doc.HasMember(
"mode")) {
593 const auto&
mode = doc[
"mode"].GetString();
594 if (strcmp(
mode,
"sequential") == 0) {
596 mGenerationMode = GenMode::kSeq;
598 if (strcmp(
mode,
"parallel") == 0) {
601 mGenerationMode = GenMode::kParallel;
602 LOG(info) <<
"Setting mode to parallel";
607 if (doc.HasMember(
"generators")) {
608 const auto& gens = doc[
"generators"];
609 for (
const auto&
gen : gens.GetArray()) {
610 mGroups.push_back({});
612 if (
gen.HasMember(
"cocktail")) {
613 mCocktailMode =
true;
614 for (
const auto& subgen :
gen[
"cocktail"].GetArray()) {
616 mGroups.back().push_back(mInputGens.size() - 1);
629 mGroups.back().push_back(mInputGens.size() - 1);
635 if (doc.HasMember(
"fractions")) {
636 const auto& fractions = doc[
"fractions"];
637 for (
const auto& frac : fractions.GetArray()) {
638 mFractions.push_back(frac.GetInt());
642 const auto& gens = doc[
"generators"];
643 for (
const auto&
gen : gens.GetArray()) {
644 mFractions.push_back(1);