35 LOG(fatal) <<
"Failed to parse JSON configuration from input generators";
39 if (mConfigs.size() != mInputGens.size()) {
40 LOG(fatal) <<
"Number of configurations does not match the number of generators";
43 if (mConfigs.size() == 0) {
44 for (
auto gen : mInputGens) {
45 mConfigs.push_back(
"");
49 if (!(mRandomize || mGenerationMode == GenMode::kParallel)) {
51 if (mGroups.size() != mFractions.size()) {
52 LOG(fatal) <<
"Number of groups does not match the number of fractions";
56 if (mFractions.size() != mInputGens.size()) {
57 LOG(fatal) <<
"Number of fractions does not match the number of generators";
62 if (std::all_of(mFractions.begin(), mFractions.end(), [](
int i) { return i == 0; })) {
63 LOG(fatal) <<
"All fractions provided are 0, no simulation will be performed";
67 for (
auto gen : mInputGens) {
69 LOG(info) <<
"Checking if generator " <<
gen <<
" is in the list of available generators \n";
70 if (std::find(generatorNames.begin(), generatorNames.end(),
gen) != generatorNames.end()) {
71 LOG(info) <<
"Found generator " <<
gen <<
" in the list of available generators \n";
72 if (
gen.compare(
"boxgen") == 0) {
74 gens.push_back(std::make_shared<o2::eventgen::BoxGenerator>());
77 int confBoxIndex = std::stoi(mConfigs[
index].substr(7));
78 gens.push_back(std::make_shared<o2::eventgen::BoxGenerator>(*mBoxGenConfigs[confBoxIndex]));
81 }
else if (
gen.compare(0, 7,
"pythia8") == 0) {
85 gens.push_back(std::make_shared<o2::eventgen::GeneratorPythia8>(pars));
88 int confPythia8Index = std::stoi(mConfigs[
index].substr(8));
89 gens.push_back(std::make_shared<o2::eventgen::GeneratorPythia8>(*mPythia8GenConfigs[confPythia8Index]));
91 mConfsPythia8.push_back(mConfigs[
index]);
93 }
else if (
gen.compare(
"extkinO2") == 0) {
94 int confO2KineIndex = std::stoi(mConfigs[
index].substr(9));
95 gens.push_back(std::make_shared<o2::eventgen::GeneratorFromO2Kine>(*mO2KineGenConfigs[confO2KineIndex]));
97 }
else if (
gen.compare(
"evtpool") == 0) {
98 int confEvtPoolIndex = std::stoi(mConfigs[
index].substr(8));
99 gens.push_back(std::make_shared<o2::eventgen::GeneratorFromEventPool>(mEventPoolConfigs[confEvtPoolIndex]));
100 mGens.push_back(
gen);
101 }
else if (
gen.compare(
"external") == 0) {
102 int confextIndex = std::stoi(mConfigs[
index].substr(9));
104 if (mExternalGenConfigs[confextIndex]->iniFile.size() > 0) {
105 LOG(info) <<
"Setting up external gen using the given INI file";
112 std::string tmp_config_file =
"configkey_tmp_backup_" +
std::to_string(getpid()) + std::string(
".ini");
120 LOG(info) <<
"Setting up external generator with following parameters";
122 auto extgen_filename =
params.fileName;
123 auto extgen_func =
params.funcName;
124 auto extgen = std::shared_ptr<o2::eventgen::Generator>(o2::conf::GetFromMacro<o2::eventgen::Generator*>(extgen_filename, extgen_func,
"FairGenerator*",
"extgen"));
126 LOG(fatal) <<
"Failed to retrieve \'extgen\': problem with configuration ";
131 std::filesystem::remove(tmp_config_file);
133 gens.push_back(std::move(extgen));
134 mGens.push_back(
gen);
136 LOG(info) <<
"Setting up external gen using the given fileName and funcName";
138 auto& extgen_filename = mExternalGenConfigs[confextIndex]->fileName;
139 auto& extgen_func = mExternalGenConfigs[confextIndex]->funcName;
140 auto extGen = std::shared_ptr<o2::eventgen::Generator>(o2::conf::GetFromMacro<o2::eventgen::Generator*>(extgen_filename, extgen_func,
"FairGenerator*",
"extgen"));
142 LOG(fatal) <<
"Failed to load external generator from " << extgen_filename <<
" with function " << extgen_func;
144 gens.push_back(std::move(extGen));
145 mGens.push_back(
gen);
147 }
else if (
gen.compare(
"hepmc") == 0) {
148 int confHepMCIndex = std::stoi(mConfigs[
index].substr(6));
149 gens.push_back(std::make_shared<o2::eventgen::GeneratorHepMC>());
151 dynamic_cast<o2::eventgen::GeneratorHepMC*
>(gens.back().get())->setup(*mFileOrCmdGenConfigs[confHepMCIndex], *mHepMCGenConfigs[confHepMCIndex], globalConfig);
152 mGens.push_back(
gen);
155 LOG(fatal) <<
"Generator " <<
gen <<
" not found in the list of available generators \n";
172 for (
auto&
gen : mGens) {
173 if (
gen ==
"pythia8pp") {
174 auto config = std::string(std::getenv(
"O2_ROOT")) +
"/share/Generators/egconfig/pythia8_inel.cfg";
175 LOG(info) <<
"Setting \'Pythia8\' base configuration: " << config << std::endl;
177 }
else if (
gen ==
"pythia8hf") {
178 auto config = std::string(std::getenv(
"O2_ROOT")) +
"/share/Generators/egconfig/pythia8_hf.cfg";
179 LOG(info) <<
"Setting \'Pythia8\' base configuration: " << config << std::endl;
181 }
else if (
gen ==
"pythia8hi") {
182 auto config = std::string(std::getenv(
"O2_ROOT")) +
"/share/Generators/egconfig/pythia8_hi.cfg";
183 LOG(info) <<
"Setting \'Pythia8\' base configuration: " << config << std::endl;
185 }
else if (
gen ==
"pythia8powheg") {
186 auto config = std::string(std::getenv(
"O2_ROOT")) +
"/share/Generators/egconfig/pythia8_powheg.cfg";
187 LOG(info) <<
"Setting \'Pythia8\' base configuration: " << config << std::endl;
193 gens[
count]->setTriggerMode(mTriggerModes[
count]);
194 LOG(info) <<
"Setting Trigger mode of generator " <<
gen <<
" to: " << mTriggerModes[
count];
197 for (
int trg = 0; trg < mTriggerMacros[
count].size(); trg++) {
202 LOG(info) <<
"Setting trigger " << trg <<
" of generator " <<
gen <<
" with following parameters";
203 LOG(info) <<
"Macro filename: " << expandedMacro;
204 LOG(info) <<
"Function name: " << mTriggerFuncs[
count][trg];
205 trigger = o2::conf::GetFromMacro<o2::eventgen::Trigger>(expandedMacro, mTriggerFuncs[
count][trg],
"o2::eventgen::Trigger",
"trigger");
207 LOG(info) <<
"Trying to retrieve a \'o2::eventgen::DeepTrigger\' type";
208 deeptrigger = o2::conf::GetFromMacro<o2::eventgen::DeepTrigger>(expandedMacro, mTriggerFuncs[
count][trg],
"o2::eventgen::DeepTrigger",
"deeptrigger");
210 if (!trigger && !deeptrigger) {
211 LOG(warn) <<
"Failed to retrieve \'external trigger\': problem with configuration";
212 LOG(warn) <<
"Trigger " << trg <<
" of generator " <<
gen <<
" will not be included";
215 LOG(info) <<
"Trigger " << trg <<
" of generator " <<
gen <<
" successfully set";
218 gens[
count]->addTrigger(trigger);
220 gens[
count]->addDeepTrigger(deeptrigger);
227 if (std::all_of(mFractions.begin(), mFractions.end(), [](
int i) { return i == 1; })) {
228 LOG(info) <<
"Full randomisation of generators order";
230 LOG(info) <<
"Randomisation based on fractions";
232 for (
auto&
f : mFractions) {
238 for (
int k = 0; k < mFractions.size(); k++) {
239 if (mFractions[k] == 0) {
241 mRngFractions.push_back(-1);
242 LOG(info) <<
"Generator " << mGens[k] <<
" will not be used";
244 chance =
static_cast<float>(mFractions[k]) / allfracs;
246 mRngFractions.push_back(
sum);
247 LOG(info) <<
"Generator " << (mConfigs[k] ==
"" ? mGens[k] : mConfigs[k]) <<
" has a " << chance * 100 <<
"% chance of being used";
252 LOG(info) <<
"Generators will be used in sequence, following provided fractions";
255 mGenIsInitialized.resize(gens.size(),
false);
256 if (mGenerationMode == GenMode::kParallel) {
258 mResultQueue.resize(1);
261 mResultQueue.resize(gens.size());
269 auto process_generator_task = [
this](std::vector<std::shared_ptr<o2::eventgen::Generator>>
const& generatorvec,
int task) {
270 LOG(
debug) <<
"Starting eventgen for task " << task;
271 auto& generator = generatorvec[task];
281 bool isTriggered =
false;
282 while (!isTriggered) {
283 generator->clearParticles();
284 generator->generateEvent();
285 generator->importParticles();
286 isTriggered = generator->triggerEvent();
288 LOG(
debug) <<
"eventgen finished for task " << task;
290 if (mGenerationMode == GenMode::kParallel) {
291 mResultQueue[0].push(task);
293 mResultQueue[task].push(task);
299 auto worker_function = [
this, process_generator_task]() {
303 auto generators_copy = gens;
307 if (mInputTaskQueue.try_pop(task)) {
308 process_generator_task(generators_copy, task);
310 std::this_thread::sleep_for(std::chrono::milliseconds(10));
316 mTBBTaskPoolRunner = std::thread([
this, worker_function]() { mTaskArena.execute([&]() { tbb::parallel_for(0, mTaskArena.max_concurrency(), [&](
int) { worker_function(); }); }); });
317 mTBBTaskPoolRunner.detach();
321 for (
size_t genindex = 0; genindex < gens.size(); ++genindex) {
322 mInputTaskQueue.push(genindex);
325 mIsInitialized =
true;
331 if (!mIsInitialized) {
334 if (mGenerationMode == GenMode::kParallel) {
343 if (mRngFractions.size() != 0) {
345 float rnum = gRandom->Rndm();
347 for (
int k = 0; k < mRngFractions.size(); k++) {
348 if (rnum <= mRngFractions[k]) {
354 mIndex = gRandom->Integer(mFractions.size());
357 while (mFractions[mCurrentFraction] == 0 || mseqCounter == mFractions[mCurrentFraction]) {
358 if (mFractions[mCurrentFraction] != 0) {
361 mCurrentFraction = (mCurrentFraction + 1) % mFractions.size();
363 mIndex = mCurrentFraction;
373 std::vector<int> subGenIndex = {};
376 mResultQueue[0].pop(genIndex);
379 if (!mCocktailMode) {
380 mResultQueue[mIndex].pop(genIndex);
383 subGenIndex.resize(mGroups[mIndex].
size());
384 for (
size_t pos = 0;
pos < mGroups[mIndex].size(); ++
pos) {
385 int subIndex = mGroups[mIndex][
pos];
386 LOG(info) <<
"Getting generator " << mGens[subIndex] <<
" from cocktail group " << mIndex;
387 mResultQueue[subIndex].pop(subGenIndex[
pos]);
392 auto unit_transformer = [](
auto& p,
auto pos_unit,
auto time_unit,
auto en_unit,
auto mom_unit) {
393 p.SetMomentum(p.Px() * mom_unit, p.Py() * mom_unit, p.Pz() * mom_unit, p.Energy() * en_unit);
394 p.SetProductionVertex(p.Vx() * pos_unit, p.Vy() * pos_unit, p.Vz() * pos_unit, p.T() * time_unit);
397 auto index_transformer = [](
auto& p,
int offset) {
398 for (
int i = 0;
i < 2; ++
i) {
399 if (p.GetMother(
i) != -1) {
400 const auto newindex = p.GetMother(
i) +
offset;
401 p.SetMother(
i, newindex);
404 if (p.GetNDaughters() > 0) {
405 for (
int i = 0;
i < 2; ++
i) {
406 const auto newindex = p.GetDaughter(
i) +
offset;
407 p.SetDaughter(
i, newindex);
417 for (
auto subIndex : subGenIndex) {
418 LOG(info) <<
"Importing particles for task " << subIndex;
419 auto subParticles = gens[subIndex]->getParticles();
421 auto time_unit = gens[subIndex]->getTimeUnit();
422 auto pos_unit = gens[subIndex]->getPositionUnit();
423 auto mom_unit = gens[subIndex]->getMomentumUnit();
424 auto energy_unit = gens[subIndex]->getEnergyUnit();
430 for (
auto& p : subParticles) {
432 index_transformer(p,
offset);
434 unit_transformer(p, pos_unit, time_unit, energy_unit, mom_unit);
439 gens[subIndex]->updateHeader(&mMCEventHeader);
440 mInputTaskQueue.push(subIndex);
444 LOG(info) <<
"Importing particles for task " << genIndex;
448 auto time_unit = gens[genIndex]->getTimeUnit();
449 auto pos_unit = gens[genIndex]->getPositionUnit();
450 auto mom_unit = gens[genIndex]->getMomentumUnit();
451 auto energy_unit = gens[genIndex]->getEnergyUnit();
456 unit_transformer(p, pos_unit, time_unit, energy_unit, mom_unit);
460 gens[genIndex]->updateHeader(&mMCEventHeader);
461 mInputTaskQueue.push(genIndex);
468 LOG(info) <<
"HybridGen: Stopping TBB task pool";
497 std::string
name =
gen[
"name"].GetString();
498 mInputGens.push_back(
name);
499 if (
gen.HasMember(
"config")) {
500 if (
name ==
"boxgen") {
501 const auto& boxconf =
gen[
"config"];
502 auto boxConfig = TBufferJSON::FromJSON<o2::eventgen::BoxGenConfig>(
jsonValueToString(boxconf).c_str());
503 mBoxGenConfigs.push_back(std::move(boxConfig));
504 mConfigs.push_back(
"boxgen_" +
std::to_string(mBoxGenConfigs.size() - 1));
505 }
else if (
name ==
"pythia8") {
506 const auto& pythia8conf =
gen[
"config"];
507 auto pythia8Config = TBufferJSON::FromJSON<o2::eventgen::Pythia8GenConfig>(
jsonValueToString(pythia8conf).c_str());
508 mPythia8GenConfigs.push_back(std::move(pythia8Config));
509 mConfigs.push_back(
"pythia8_" +
std::to_string(mPythia8GenConfigs.size() - 1));
510 }
else if (
name ==
"extkinO2") {
511 const auto& o2kineconf =
gen[
"config"];
512 auto o2kineConfig = TBufferJSON::FromJSON<o2::eventgen::O2KineGenConfig>(
jsonValueToString(o2kineconf).c_str());
513 mO2KineGenConfigs.push_back(std::move(o2kineConfig));
514 mConfigs.push_back(
"extkinO2_" +
std::to_string(mO2KineGenConfigs.size() - 1));
515 }
else if (
name ==
"evtpool") {
516 const auto& o2kineconf =
gen[
"config"];
517 auto poolConfig = TBufferJSON::FromJSON<o2::eventgen::EventPoolGenConfig>(
jsonValueToString(o2kineconf).c_str());
518 mEventPoolConfigs.push_back(*poolConfig);
519 mConfigs.push_back(
"evtpool_" +
std::to_string(mEventPoolConfigs.size() - 1));
520 }
else if (
name ==
"external") {
521 const auto& extconf =
gen[
"config"];
522 auto extConfig = TBufferJSON::FromJSON<o2::eventgen::ExternalGenConfig>(
jsonValueToString(extconf).c_str());
523 mExternalGenConfigs.push_back(std::move(extConfig));
524 mConfigs.push_back(
"external_" +
std::to_string(mExternalGenConfigs.size() - 1));
525 }
else if (
name ==
"hepmc") {
526 const auto& genconf =
gen[
"config"];
527 const auto& cmdconf = genconf[
"configcmd"];
528 const auto& hepmcconf = genconf[
"confighepmc"];
529 auto cmdConfig = TBufferJSON::FromJSON<o2::eventgen::FileOrCmdGenConfig>(
jsonValueToString(cmdconf).c_str());
530 auto hepmcConfig = TBufferJSON::FromJSON<o2::eventgen::HepMCGenConfig>(
jsonValueToString(hepmcconf).c_str());
531 mFileOrCmdGenConfigs.push_back(std::move(cmdConfig));
532 mHepMCGenConfigs.push_back(std::move(hepmcConfig));
533 mConfigs.push_back(
"hepmc_" +
std::to_string(mFileOrCmdGenConfigs.size() - 1));
535 mConfigs.push_back(
"");
538 if (
name ==
"boxgen" ||
name ==
"pythia8" ||
name ==
"extkinO2" ||
name ==
"external" ||
name ==
"hepmc") {
539 LOG(fatal) <<
"No configuration provided for generator " <<
name;
542 mConfigs.push_back(
"");
545 if (
gen.HasMember(
"triggers")) {
546 const auto& trigger =
gen[
"triggers"];
547 auto trigger_specs = [
this, &trigger]() {
548 mTriggerMacros.push_back({});
549 mTriggerFuncs.push_back({});
550 if (trigger.HasMember(
"specs")) {
551 for (
auto& spec : trigger[
"specs"].GetArray()) {
552 if (spec.HasMember(
"macro")) {
553 const auto& macro = spec[
"macro"].GetString();
554 if (!(strcmp(macro,
"") == 0)) {
555 mTriggerMacros.back().push_back(macro);
557 mTriggerMacros.back().push_back(
"");
560 mTriggerMacros.back().push_back(
"");
562 if (spec.HasMember(
"function")) {
563 const auto& function = spec[
"function"].GetString();
564 if (!(strcmp(function,
"") == 0)) {
565 mTriggerFuncs.back().push_back(function);
567 mTriggerFuncs.back().push_back(
"");
570 mTriggerFuncs.back().push_back(
"");
574 mTriggerMacros.back().push_back(
"");
575 mTriggerFuncs.back().push_back(
"");
578 if (trigger.HasMember(
"mode")) {
579 const auto& trmode = trigger[
"mode"].GetString();
580 if (strcmp(trmode,
"or") == 0) {
583 }
else if (strcmp(trmode,
"and") == 0) {
586 }
else if (strcmp(trmode,
"off") == 0) {
588 mTriggerMacros.push_back({
""});
589 mTriggerFuncs.push_back({
""});
591 LOG(warn) <<
"Wrong trigger mode provided for generator " <<
name <<
", keeping trigger OFF";
593 mTriggerMacros.push_back({
""});
594 mTriggerFuncs.push_back({
""});
597 LOG(warn) <<
"No trigger mode provided for generator " <<
name <<
", turning trigger OFF";
599 mTriggerMacros.push_back({
""});
600 mTriggerFuncs.push_back({
""});
604 mTriggerMacros.push_back({
""});
605 mTriggerFuncs.push_back({
""});
613 std::ifstream fileStream(
path, std::ios::in);
614 if (!fileStream.is_open()) {
615 LOG(error) <<
"Cannot open " <<
path;
618 rapidjson::IStreamWrapper isw(fileStream);
619 rapidjson::Document doc;
620 doc.ParseStream(isw);
621 if (doc.HasParseError()) {
622 LOG(error) <<
"Error parsing provided json file " <<
path;
623 LOG(error) <<
" - Error -> " << rapidjson::GetParseError_En(doc.GetParseError());
628 if (doc.HasMember(
"mode")) {
629 const auto&
mode = doc[
"mode"].GetString();
630 if (strcmp(
mode,
"sequential") == 0) {
632 mGenerationMode = GenMode::kSeq;
634 if (strcmp(
mode,
"parallel") == 0) {
637 mGenerationMode = GenMode::kParallel;
638 LOG(info) <<
"Setting mode to parallel";
643 if (doc.HasMember(
"generators")) {
644 const auto& gens = doc[
"generators"];
645 for (
const auto&
gen : gens.GetArray()) {
646 mGroups.push_back({});
648 if (
gen.HasMember(
"cocktail")) {
649 mCocktailMode =
true;
650 for (
const auto& subgen :
gen[
"cocktail"].GetArray()) {
652 mGroups.back().push_back(mInputGens.size() - 1);
665 mGroups.back().push_back(mInputGens.size() - 1);
671 if (doc.HasMember(
"fractions")) {
672 const auto& fractions = doc[
"fractions"];
673 for (
const auto& frac : fractions.GetArray()) {
674 mFractions.push_back(frac.GetInt());
678 const auto& gens = doc[
"generators"];
679 for (
const auto&
gen : gens.GetArray()) {
680 mFractions.push_back(1);