3434#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
3535#include < Generators/GeneratorHybrid.h>
3636#include < Generators/GeneratorHybridParam.h>
37+ #include < rapidjson/document.h>
38+ #include < rapidjson/writer.h>
39+ #include < rapidjson/ostreamwrapper.h>
40+ #include < fstream>
41+ #include < unistd.h>
3742#endif
3843#include < Generators/PrimaryGenerator.h>
3944#include < Generators/BoxGunParam.h>
@@ -49,6 +54,48 @@ namespace o2
4954namespace eventgen
5055{
5156
57+ #if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
58+ // Builds a parallel GeneratorHybrid JSON configuration out of
59+ // 8 (Generator::NHyperloopParallelGenerators) identical "external" sub-generator entries,
60+ // using the configured GeneratorExternalParam. This makes the simulation parallelisation automatic
61+ // on Hyperloop.
62+ // To-do: Define the behaviour with ini configuration which are already definining a hybrid gen
63+ std::string buildHyperloopExternalHybridConfig (GeneratorExternalParam const & extparams)
64+ {
65+ rapidjson::Document doc;
66+ doc.SetObject ();
67+ auto & alloc = doc.GetAllocator ();
68+ doc.AddMember (" mode" , " parallel" , alloc);
69+
70+ rapidjson::Value generators (rapidjson::kArrayType );
71+ rapidjson::Value fractions (rapidjson::kArrayType );
72+ for (int i = 0 ; i < Generator::NHyperloopParallelGenerators; ++i) {
73+ rapidjson::Value config (rapidjson::kObjectType );
74+ config.AddMember (" fileName" , rapidjson::Value (extparams.fileName .c_str (), alloc), alloc);
75+ config.AddMember (" funcName" , rapidjson::Value (extparams.funcName .c_str (), alloc), alloc);
76+ config.AddMember (" iniFile" , " " , alloc);
77+
78+ rapidjson::Value generator (rapidjson::kObjectType );
79+ generator.AddMember (" name" , " external" , alloc);
80+ generator.AddMember (" config" , config, alloc);
81+ generators.PushBack (generator, alloc);
82+ fractions.PushBack (1 , alloc);
83+ }
84+ doc.AddMember (" generators" , generators, alloc);
85+ doc.AddMember (" fractions" , fractions, alloc);
86+
87+ std::string path = " hyperloop_exttohybrid_" + std::to_string (getpid ()) + " .json" ;
88+ std::ofstream ofs (path);
89+ if (!ofs.is_open ()) {
90+ LOG (fatal) << " Failed to open " << path << " for writing the Hyperloop hybrid generator configuration" ;
91+ }
92+ rapidjson::OStreamWrapper osw (ofs);
93+ rapidjson::Writer<rapidjson::OStreamWrapper> writer (osw);
94+ doc.Accept (writer);
95+ return path;
96+ }
97+ #endif
98+
5299// reusable helper class
53100// main purpose is to init a FairPrimGen given some (Sim)Config
54101void GeneratorFactory::setPrimaryGenerator (o2::conf::SimConfig const & conf, FairPrimaryGenerator* primGen)
@@ -94,9 +141,20 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair
94141 o2::O2DatabasePDG::addALICEParticles (TDatabasePDG::Instance ());
95142 auto genconfig = conf.getGenerator ();
96143#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
97- if (GeneratorHybridParam::Instance ().switchExtToHybrid && (genconfig.compare (" external" ) == 0 || genconfig.compare (" extgen" ) == 0 )) {
98- LOG (info) << " Switching external generator to hybrid mode" ;
99- genconfig = " hybrid" ;
144+ std::string hyperloopExtHybridConfigFile; // set when IS_HYPERLOOP is defined
145+ if (genconfig.compare (" external" ) == 0 || genconfig.compare (" extgen" ) == 0 ) {
146+ if (GeneratorHybridParam::Instance ().switchExtToHybrid ) {
147+ LOG (info) << " Switching external generator to hybrid mode" ;
148+ genconfig = " hybrid" ;
149+ } else if (Generator::isHyperloop ()) {
150+ // Running under Hyperloop: transparently expand the single external generator
151+ // configuration into a parallel hybrid of Generator::NHyperloopParallelGenerators
152+ // clones, to increase on-the-fly MC-generation throughput.
153+ LOG (info) << " IS_HYPERLOOP detected: expanding external generator into "
154+ << Generator::NHyperloopParallelGenerators << " parallel hybrid sub-generators" ;
155+ hyperloopExtHybridConfigFile = buildHyperloopExternalHybridConfig (GeneratorExternalParam::Instance ());
156+ genconfig = " hybrid" ;
157+ }
100158 }
101159#endif
102160 LOG (info) << " ** Generator to use: '" << genconfig << " '" ;
@@ -278,8 +336,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair
278336#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
279337 } else if (genconfig.compare (" hybrid" ) == 0 ) { // hybrid using multiple generators
280338 LOG (info) << " Init hybrid generator" ;
281- auto & hybridparam = GeneratorHybridParam::Instance ();
282- std::string config = hybridparam.configFile ;
339+ std::string config = !hyperloopExtHybridConfigFile.empty () ? hyperloopExtHybridConfigFile : GeneratorHybridParam::Instance ().configFile ;
283340 // check if config string points to an existing and not empty file
284341 if (config.empty ()) {
285342 LOG (fatal) << " No configuration file provided for hybrid generator" ;
0 commit comments