Project
Loading...
Searching...
No Matches
GeneratorFactory.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
16#include "FairGenerator.h"
18#include <fairlogger/Logger.h>
19#include <SimConfig/SimConfig.h>
23#ifdef GENERATORS_WITH_PYTHIA8
26#endif
30#ifdef GENERATORS_WITH_HEPMC3
33#endif
34#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
37#include <rapidjson/document.h>
38#include <rapidjson/writer.h>
39#include <rapidjson/ostreamwrapper.h>
40#include <fstream>
41#include <unistd.h>
42#endif
49
50#include "TRandom.h"
51
52namespace o2
53{
54namespace eventgen
55{
56
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//
64// Note on GeneratorHybrid.num_workers: expanding to 8 sub-generators does not by itself raise
65// the number of TBB workers that actually run them in parallel. This is controlled by
66// the parameter GeneratorHybrid.num_workers. On Hyperloop this will be part
67// of the standard train configuration
68std::string buildHyperloopExternalHybridConfig(GeneratorExternalParam const& extparams)
69{
70 rapidjson::Document doc;
71 doc.SetObject();
72 auto& alloc = doc.GetAllocator();
73 doc.AddMember("mode", "parallel", alloc);
74
75 rapidjson::Value generators(rapidjson::kArrayType);
76 rapidjson::Value fractions(rapidjson::kArrayType);
77 for (int i = 0; i < Generator::NHyperloopParallelGenerators; ++i) {
78 rapidjson::Value config(rapidjson::kObjectType);
79 config.AddMember("fileName", rapidjson::Value(extparams.fileName.c_str(), alloc), alloc);
80 config.AddMember("funcName", rapidjson::Value(extparams.funcName.c_str(), alloc), alloc);
81 config.AddMember("iniFile", "", alloc);
82
83 rapidjson::Value generator(rapidjson::kObjectType);
84 generator.AddMember("name", "external", alloc);
85 generator.AddMember("config", config, alloc);
86 generators.PushBack(generator, alloc);
87 fractions.PushBack(1, alloc);
88 }
89 doc.AddMember("generators", generators, alloc);
90 doc.AddMember("fractions", fractions, alloc);
91
92 // The generated config file is deliberatelly left on disk for possible inspection after the process ran.
93 std::string path = "hyperloop_exttohybrid_" + std::to_string(getpid()) + ".json";
94 std::ofstream ofs(path);
95 if (!ofs.is_open()) {
96 LOG(fatal) << "Failed to open " << path << " for writing the Hyperloop hybrid generator configuration";
97 exit(1);
98 }
99 rapidjson::OStreamWrapper osw(ofs);
100 rapidjson::Writer<rapidjson::OStreamWrapper> writer(osw);
101 doc.Accept(writer);
102 return path;
103}
104#endif
105
106// reusable helper class
107// main purpose is to init a FairPrimGen given some (Sim)Config
109{
110 if (!primGen) {
111 LOG(warning) << "No primary generator instance; Cannot setup";
112 return;
113 }
114
115 auto primGenO2 = dynamic_cast<PrimaryGenerator*>(primGen);
116
117 auto makeBoxGen = [](int pdgid, int mult, double etamin, double etamax, double pmin, double pmax, double phimin, double phimax) {
118 return new o2::eventgen::BoxGenerator(pdgid, mult, etamin, etamax, pmin, pmax, phimin, phimax);
119 };
120
121#ifdef GENERATORS_WITH_PYTHIA8
122 auto makePythia8Gen = [](std::string& config) {
123 auto& singleton = GeneratorPythia8Param::Instance();
125 .config = config.size() > 0 ? config : singleton.config,
126 .hooksFileName = singleton.hooksFileName,
127 .hooksFuncName = singleton.hooksFuncName,
128 .includePartonEvent = singleton.includePartonEvent,
129 .particleFilter = singleton.particleFilter,
130 .verbose = singleton.verbose,
131 };
132 auto gen = new o2::eventgen::GeneratorPythia8(pars);
133 if (!config.empty()) {
134 LOG(info) << "Setting \'Pythia8\' base configuration: " << config << std::endl;
135 gen->setConfig(config); // assign config; will be executed in Init function
136 }
137 return gen;
138 };
139#endif
140
143 o2::O2DatabasePDG::Instance(); //--> ALICE particles are added once in this call
144 auto genconfig = conf.getGenerator();
145#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
146 std::string hyperloopExtHybridConfigFile; // set when IS_HYPERLOOP is defined
147 if (genconfig.compare("external") == 0 || genconfig.compare("extgen") == 0) {
148 if (GeneratorHybridParam::Instance().switchExtToHybrid) {
149 LOG(info) << "Switching external generator to hybrid mode";
150 genconfig = "hybrid";
151 } else if (Generator::isHyperloop()) {
152 // Running under Hyperloop: transparently expand the single external generator
153 // configuration into a parallel hybrid of Generator::NHyperloopParallelGenerators
154 // clones, to increase on-the-fly MC-generation throughput.
155 LOG(info) << "IS_HYPERLOOP detected: expanding external generator into "
156 << Generator::NHyperloopParallelGenerators << " parallel hybrid sub-generators";
157 hyperloopExtHybridConfigFile = buildHyperloopExternalHybridConfig(GeneratorExternalParam::Instance());
158 genconfig = "hybrid";
159 }
160 }
161#endif
162 LOG(info) << "** Generator to use: '" << genconfig << "'";
163 if (genconfig.compare("boxgen") == 0) {
164 // a simple "box" generator configurable via BoxGunparam
165 auto& boxparam = BoxGunParam::Instance();
166 LOG(info) << "Init generic box generator with following parameters";
167 LOG(info) << boxparam;
168 auto boxGen = makeBoxGen(boxparam.pdg, boxparam.number, boxparam.eta[0], boxparam.eta[1], boxparam.prange[0], boxparam.prange[1], boxparam.phirange[0], boxparam.phirange[1]);
169 primGen->AddGenerator(boxGen);
170 } else if (genconfig.compare("fwmugen") == 0) {
171 // a simple "box" generator for forward muons
172 LOG(info) << "Init box forward muons generator";
173 auto boxGen = makeBoxGen(13, 1, -4, -2.5, 50., 50., 0., 360);
174 primGen->AddGenerator(boxGen);
175 } else if (genconfig.compare("hmpidgun") == 0) {
176 // a simple "box" generator for forward muons
177 LOG(info) << "Init hmpid gun generator";
178 auto boxGen = makeBoxGen(-211, 100, -0.5, -0.5, 2, 5, -5, 60);
179 primGen->AddGenerator(boxGen);
180 } else if (genconfig.compare("fwpigen") == 0) {
181 // a simple "box" generator for forward pions
182 LOG(info) << "Init box forward pions generator";
183 auto boxGen = makeBoxGen(-211, 10, -4, -2.5, 7, 7, 0, 360);
184 primGen->AddGenerator(boxGen);
185 } else if (genconfig.compare("fwrootino") == 0) {
186 // a simple "box" generator for forward rootinos
187 LOG(info) << "Init box forward rootinos generator";
188 auto boxGen = makeBoxGen(0, 1, -4, -2.5, 1, 5, 0, 360);
189 primGen->AddGenerator(boxGen);
190 } else if (genconfig.compare("zdcgen") == 0) {
191 // a simple "box" generator for forward neutrons
192 LOG(info) << "Init box forward/backward zdc generator";
193 auto boxGenC = makeBoxGen(2112 /*neutrons*/, 1, -8, -9999, 500, 1000, 0., 360.);
194 auto boxGenA = makeBoxGen(2112 /*neutrons*/, 1, 8, 9999, 500, 1000, 0., 360.);
195 primGen->AddGenerator(boxGenC);
196 primGen->AddGenerator(boxGenA);
197 } else if (genconfig.compare("emcgenele") == 0) {
198 // box generator with one electron per event
199 LOG(info) << "Init box generator for electrons in EMCAL";
200 // using phi range of emcal
201 auto elecgen = makeBoxGen(11, 1, -0.67, 0.67, 15, 15, 80, 187);
202 primGen->AddGenerator(elecgen);
203 } else if (genconfig.compare("emcgenphoton") == 0) {
204 LOG(info) << "Init box generator for photons in EMCAL";
205 auto photongen = makeBoxGen(22, 1, -0.67, 0.67, 15, 15, 80, 187);
206 primGen->AddGenerator(photongen);
207 } else if (genconfig.compare("fddgen") == 0) {
208 LOG(info) << "Init box FDD generator";
209 auto boxGenFDC = makeBoxGen(13, 1000, -7, -4.8, 10, 500, 0, 360.);
210 auto boxGenFDA = makeBoxGen(13, 1000, 4.9, 6.3, 10, 500, 0., 360);
211 primGen->AddGenerator(boxGenFDA);
212 primGen->AddGenerator(boxGenFDC);
213 } else if (genconfig.compare("extkin") == 0) {
214 // external kinematics
215 // needs precense of a kinematics file "Kinematics.root"
216 // TODO: make this configurable and check for presence
217 auto extGen = new o2::eventgen::GeneratorFromFile(conf.getExtKinematicsFileName().c_str());
218 extGen->SetStartEvent(conf.getStartEvent());
219 primGen->AddGenerator(extGen);
220 LOG(info) << "using external kinematics";
221 } else if (genconfig.compare("extkinO2") == 0) {
222 // external kinematics from previous O2 output
223 auto& singleton = GeneratorFromO2KineParam::Instance();
224 auto name1 = singleton.fileName;
225 auto name2 = conf.getExtKinematicsFileName();
226 auto pars = O2KineGenConfig{
227 .skipNonTrackable = singleton.skipNonTrackable,
228 .continueMode = singleton.continueMode,
229 .roundRobin = singleton.roundRobin,
230 .randomize = singleton.randomize,
231 .rngseed = singleton.rngseed,
232 .randomphi = singleton.randomphi,
233 .fileName = name1.size() > 0 ? name1.c_str() : name2.c_str()};
234 auto extGen = new o2::eventgen::GeneratorFromO2Kine(pars);
235 extGen->SetStartEvent(conf.getStartEvent());
236 primGen->AddGenerator(extGen);
237 if (pars.continueMode) {
238 auto o2PrimGen = dynamic_cast<o2::eventgen::PrimaryGenerator*>(primGen);
239 if (o2PrimGen) {
240 o2PrimGen->setApplyVertex(false);
241 }
242 }
243 LOG(info) << "using external O2 kinematics";
244 } else if (genconfig.compare("evtpool") == 0) {
245 // case of an "event-pool" which is a specialization of extkinO2
246 // with some additional logic in file management and less configurability
247 // and not features such as "continue transport"
249 primGen->AddGenerator(extGen);
250 LOG(info) << "using the eventpool generator";
251 } else if (genconfig.compare("tparticle") == 0) {
252 // External ROOT file(s) with tree of TParticle in clones array,
253 // or external program generating such a file
254 auto& param0 = GeneratorFileOrCmdParam::Instance();
256 LOG(info) << "Init 'GeneratorTParticle' with the following parameters";
257 LOG(info) << param0;
258 LOG(info) << param;
259 auto tgen = new o2::eventgen::GeneratorTParticle();
260 tgen->setup(param0, param, conf);
261 primGen->AddGenerator(tgen);
262#ifdef GENERATORS_WITH_HEPMC3
263 } else if (genconfig.compare("hepmc") == 0) {
264 // external HepMC file, or external program writing HepMC event
265 // records to standard output.
266 auto& param0 = GeneratorFileOrCmdParam::Instance();
268 LOG(info) << "Init \'GeneratorHepMC\' with following parameters";
269 LOG(info) << param0;
270 LOG(info) << param;
271 auto hepmcGen = new o2::eventgen::GeneratorHepMC();
272 hepmcGen->setup(param0, param, conf);
273 primGen->AddGenerator(hepmcGen);
274#endif
275#ifdef GENERATORS_WITH_PYTHIA8
276 } else if (genconfig.compare("alldets") == 0) {
277 // a simple generator for test purposes - making sure to generate hits
278 // in all detectors
279 // I compose it of:
280 // 1) pythia8
281 auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_inel.cfg";
282 auto py8 = makePythia8Gen(py8config);
283 primGen->AddGenerator(py8);
284 // 2) forward muons
285 auto muon = makeBoxGen(13, 100, -2.5, -4.0, 100, 100, 0., 360);
286 primGen->AddGenerator(muon);
287 } else if (genconfig.compare("pythia8") == 0) {
288 auto py8config = std::string();
289 auto py8 = makePythia8Gen(py8config);
290 primGen->AddGenerator(py8);
291 } else if (genconfig.compare("pythia8pp") == 0) {
292 auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_inel.cfg";
293 auto py8 = makePythia8Gen(py8config);
294 primGen->AddGenerator(py8);
295 } else if (genconfig.compare("pythia8hf") == 0) {
296 // pythia8 pp (HF production)
297 // configures pythia for HF production in pp collisions at 14 TeV
298 auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_hf.cfg";
299 auto py8 = makePythia8Gen(py8config);
300 primGen->AddGenerator(py8);
301 } else if (genconfig.compare("pythia8hi") == 0) {
302 // pythia8 heavy-ion
303 // exploits pythia8 heavy-ion machinery (available from v8.230)
304 // configures pythia for min.bias Pb-Pb collisions at 5.52 TeV
305 auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_hi.cfg";
306 auto py8 = makePythia8Gen(py8config);
307 primGen->AddGenerator(py8);
308 } else if (genconfig.compare("pythia8powheg") == 0) {
309 // pythia8 with powheg
310 auto py8config = std::string(std::getenv("O2_ROOT")) + "/share/Generators/egconfig/pythia8_powheg.cfg";
311 auto py8 = makePythia8Gen(py8config);
312 primGen->AddGenerator(py8);
313#endif
314 } else if (genconfig.compare("external") == 0 || genconfig.compare("extgen") == 0) {
315 // external generator via configuration macro
317 LOG(info) << "Setting up external generator with following parameters";
318 LOG(info) << params;
319 auto extgen_filename = params.fileName;
320 auto extgen_func = params.funcName;
321 auto extgen = o2::conf::GetFromMacro<FairGenerator*>(extgen_filename, extgen_func, "FairGenerator*", "extgen");
322 if (!extgen) {
323 LOG(fatal) << "Failed to retrieve \'extgen\': problem with configuration ";
324 }
325 primGen->AddGenerator(extgen);
326 } else if (genconfig.compare("toftest") == 0) { // 1 muon per sector and per module
327 LOG(info) << "Init tof test generator -> 1 muon per sector and per module";
328 for (int i = 0; i < 18; i++) {
329 for (int j = 0; j < 5; j++) {
330 auto boxGen = makeBoxGen(13 /*muons*/, 1, -0.8 + 0.32 * j + 0.15, -0.8 + 0.32 * j + 0.17, 9, 10, 10 + 20. * i - 1, 10 + 20. * i + 1);
331 primGen->AddGenerator(boxGen);
332 }
333 }
334#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
335 } else if (genconfig.compare("hybrid") == 0) { // hybrid using multiple generators
336 LOG(info) << "Init hybrid generator";
337 std::string config = !hyperloopExtHybridConfigFile.empty() ? hyperloopExtHybridConfigFile : GeneratorHybridParam::Instance().configFile;
338 // check if config string points to an existing and not empty file
339 if (config.empty()) {
340 LOG(fatal) << "No configuration file provided for hybrid generator";
341 return;
342 }
343 auto& hybrid = o2::eventgen::GeneratorHybrid::Instance(config);
344 primGen->AddGenerator(&hybrid);
345#endif
346 } else {
347 LOG(fatal) << "Invalid generator";
348 }
349
351 // to be set via GeneratorFactory only if generator is not hybrid
352 // external settings via JSON are supported in the latter
353
354 Trigger trigger = nullptr;
355 DeepTrigger deeptrigger = nullptr;
356 if (!(genconfig.compare("hybrid") == 0)) {
357 auto trgconfig = conf.getTrigger();
358 if (trgconfig.empty()) {
359 return;
360 } else if (trgconfig.compare("particle") == 0) {
362 } else if (trgconfig.compare("external") == 0) {
363 // external trigger via configuration macro
365 LOG(info) << "Setting up external trigger with following parameters";
366 LOG(info) << params;
367 auto external_trigger_filename = params.fileName;
368 auto external_trigger_func = params.funcName;
369 trigger = o2::conf::GetFromMacro<o2::eventgen::Trigger>(external_trigger_filename, external_trigger_func, "o2::eventgen::Trigger", "trigger");
370 if (!trigger) {
371 LOG(info) << "Trying to retrieve a \'o2::eventgen::DeepTrigger\' type" << std::endl;
372 deeptrigger = o2::conf::GetFromMacro<o2::eventgen::DeepTrigger>(external_trigger_filename, external_trigger_func, "o2::eventgen::DeepTrigger", "deeptrigger");
373 }
374 if (!trigger && !deeptrigger) {
375 LOG(fatal) << "Failed to retrieve \'external trigger\': problem with configuration ";
376 }
377 } else {
378 LOG(fatal) << "Invalid trigger";
379 }
380
382 auto generators = primGen->GetListOfGenerators();
383 for (int igen = 0; igen < generators->GetEntries(); ++igen) {
384 auto generator = dynamic_cast<o2::eventgen::Generator*>(generators->At(igen));
385 if (!generator) {
386 LOG(fatal) << "request to add a trigger to an unsupported generator";
387 return;
388 }
390 if (trigger) {
391 generator->addTrigger(trigger);
392 }
393 if (deeptrigger) {
394 generator->addDeepTrigger(deeptrigger);
395 }
396 }
397 }
398}
399
400} // end namespace eventgen
401} // end namespace o2
default_random_engine gen(dev())
int32_t i
uint32_t j
Definition RawData.h:0
static TDatabasePDG * Instance()
std::string getExtKinematicsFileName() const
Definition SimConfig.h:159
unsigned int getStartEvent() const
Definition SimConfig.h:161
std::string getTrigger() const
Definition SimConfig.h:156
std::string getGenerator() const
Definition SimConfig.h:155
static GeneratorHybrid & Instance(const std::string &inputgens="")
void setTriggerMode(ETriggerMode_t val)
Definition Generator.h:94
static constexpr int NHyperloopParallelGenerators
Definition Generator.h:110
static bool isHyperloop()
Definition Generator.cxx:49
GLenum const GLfloat * params
Definition glcorearb.h:272
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLenum GLfloat param
Definition glcorearb.h:271
std::function< bool(void *, std::string)> DeepTrigger
Definition Trigger.h:26
std::function< bool(const std::vector< TParticle > &)> Trigger
Definition Trigger.h:25
Trigger TriggerParticle(const TriggerParticleParam &param)
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
static void setPrimaryGenerator(o2::conf::SimConfig const &, FairPrimaryGenerator *)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"