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)
@@ -89,9 +136,20 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair
89136 o2::O2DatabasePDG::addALICEParticles (TDatabasePDG::Instance ());
90137 auto genconfig = conf.getGenerator ();
91138#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
92- if (GeneratorHybridParam::Instance ().switchExtToHybrid && (genconfig.compare (" external" ) == 0 || genconfig.compare (" extgen" ) == 0 )) {
93- LOG (info) << " Switching external generator to hybrid mode" ;
94- genconfig = " hybrid" ;
139+ std::string hyperloopExtHybridConfigFile; // set when IS_HYPERLOOP is defined
140+ if (genconfig.compare (" external" ) == 0 || genconfig.compare (" extgen" ) == 0 ) {
141+ if (GeneratorHybridParam::Instance ().switchExtToHybrid ) {
142+ LOG (info) << " Switching external generator to hybrid mode" ;
143+ genconfig = " hybrid" ;
144+ } else if (Generator::isHyperloop ()) {
145+ // Running under Hyperloop: transparently expand the single external generator
146+ // configuration into a parallel hybrid of Generator::NHyperloopParallelGenerators
147+ // clones, to increase on-the-fly MC-generation throughput.
148+ LOG (info) << " IS_HYPERLOOP detected: expanding external generator into "
149+ << Generator::NHyperloopParallelGenerators << " parallel hybrid sub-generators" ;
150+ hyperloopExtHybridConfigFile = buildHyperloopExternalHybridConfig (GeneratorExternalParam::Instance ());
151+ genconfig = " hybrid" ;
152+ }
95153 }
96154#endif
97155 LOG (info) << " ** Generator to use: '" << genconfig << " '" ;
@@ -269,8 +327,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair
269327#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
270328 } else if (genconfig.compare (" hybrid" ) == 0 ) { // hybrid using multiple generators
271329 LOG (info) << " Init hybrid generator" ;
272- auto & hybridparam = GeneratorHybridParam::Instance ();
273- std::string config = hybridparam.configFile ;
330+ std::string config = !hyperloopExtHybridConfigFile.empty () ? hyperloopExtHybridConfigFile : GeneratorHybridParam::Instance ().configFile ;
274331 // check if config string points to an existing and not empty file
275332 if (config.empty ()) {
276333 LOG (fatal) << " No configuration file provided for hybrid generator" ;
0 commit comments