Project
Loading...
Searching...
No Matches
Generator.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
15#include "Generators/Trigger.h"
20#include <SimConfig/SimConfig.h>
21#include "FairPrimaryGenerator.h"
22#include <fairlogger/Logger.h>
23#include <cmath>
24#include "TClonesArray.h"
25#include "TParticle.h"
26#include "TString.h"
27#include "TSystem.h"
28#include "TGrid.h"
30#include <filesystem>
31#ifdef GENERATORS_WITH_TPCLOOPERS
34#endif
35
36namespace o2
37{
38namespace eventgen
39{
40
41std::atomic<int> Generator::InstanceCounter{0};
42unsigned int Generator::gTotalNEvents = 0;
43/*****************************************************************/
44/*****************************************************************/
45
46Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"),
47 mBoost(0.)
48{
52#ifdef GENERATORS_WITH_TPCLOOPERS
53 const auto& simConfig = o2::conf::SimConfig::Instance();
54 const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance();
55 if (!loopersParam.loopersVeto) {
56 bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine");
57 if (transport) {
58 bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end());
59 if (tpcActive) {
60 if (initTPCLoopersGen()) {
61 mAddTPCLoopers = kTRUE;
62 }
63 } else {
64 LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled.";
65 }
66 }
67 } else {
68 LOG(info) << "Loopers fast generator turned OFF with veto flag.";
69 }
70#endif
71}
72
73/*****************************************************************/
74
75Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(name, title),
76 mBoost(0.)
77{
81#ifdef GENERATORS_WITH_TPCLOOPERS
82 const auto& simConfig = o2::conf::SimConfig::Instance();
83 const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance();
84 if (!loopersParam.loopersVeto) {
85 bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine");
86 if (transport) {
87 bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end());
88 if (tpcActive) {
89 if (initTPCLoopersGen()) {
90 mAddTPCLoopers = kTRUE;
91 }
92 } else {
93 LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled.";
94 }
95 }
96 } else {
97 LOG(info) << "Loopers fast generator turned OFF with veto flag.";
98 }
99#endif
100}
101
102/*****************************************************************/
103
105{
107#ifdef GENERATORS_WITH_TPCLOOPERS
108 if (mTPCLoopersGen) {
109 delete mTPCLoopersGen;
110 mTPCLoopersGen = nullptr;
111 }
112#endif
113}
114
115/*****************************************************************/
116#ifdef GENERATORS_WITH_TPCLOOPERS
117bool Generator::initTPCLoopersGen()
118{
119 // Expand all environment paths
120 const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance();
121 auto expandPathName = [](const std::string& path) {
122 TString expandedPath = path;
123 gSystem->ExpandPathName(expandedPath);
124 return std::string(expandedPath.Data());
125 };
126 std::string model_pairs = expandPathName(loopersParam.model_pairs);
127 std::string model_compton = expandPathName(loopersParam.model_compton);
128 std::string nclxrate = expandPathName(loopersParam.nclxrate);
129 const std::string scaler_pair = expandPathName(loopersParam.scaler_pair);
130 const std::string scaler_compton = expandPathName(loopersParam.scaler_compton);
131 const std::string poisson = expandPathName(loopersParam.poisson);
132 const std::string gauss = expandPathName(loopersParam.gauss);
133 const auto& flat_gas = loopersParam.flat_gas;
134 const auto& colsys = loopersParam.colsys;
135 if (flat_gas) {
136 if (colsys != "PbPb" && colsys != "pp") {
137 LOG(warning) << "Automatic background loopers configuration supports only 'pp' and 'PbPb' systems.";
138 LOG(warning) << "Fast loopers generator will remain OFF.";
139 return kFALSE;
140 }
141 bool isContext = std::filesystem::exists("collisioncontext.root");
142 if (!isContext) {
143 LOG(warning) << "Warning: No collisioncontext.root file found!";
144 LOG(warning) << "Loopers will be kept OFF.";
145 return kFALSE;
146 }
147 }
148 std::array<float, 2> multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]};
149 unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0];
150 unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1];
151 const std::array<std::string, 3> models = {model_pairs, model_compton, nclxrate};
152 const std::array<std::string, 3> local_names = {"WGANpair.onnx", "WGANcompton.onnx", "nclxrate.root"};
153 const std::array<bool, 3> isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://"), models[2].starts_with("alien://")};
154 const std::array<bool, 3> isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://"), models[2].starts_with("ccdb://")};
155 if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) {
156 if (!gGrid) {
157 TGrid::Connect("alien://");
158 if (!gGrid) {
159 LOG(fatal) << "AliEn connection failed, check token.";
160 exit(1);
161 }
162 }
163 for (size_t i = 0; i < models.size(); ++i) {
164 if (isAlien[i] && !TFile::Cp(models[i].c_str(), local_names[i].c_str())) {
165 LOG(fatal) << "Error: Model file " << models[i] << " does not exist!";
166 exit(1);
167 }
168 }
169 }
170 if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) {
172 ccdb.setURL("http://alice-ccdb.cern.ch");
173 // Get underlying CCDB API from BasicCCDBManager
174 auto& ccdb_api = ccdb.getCCDBAccessor();
175 for (size_t i = 0; i < models.size(); ++i) {
176 if (isCCDB[i]) {
177 auto model_path = models[i].substr(7); // Remove "ccdb://"
178 // Treat filename if provided in the CCDB path
179 auto extension = model_path.find(".onnx");
180 if (extension != std::string::npos) {
181 auto last_slash = model_path.find_last_of('/');
182 model_path = model_path.substr(0, last_slash);
183 }
184 std::map<std::string, std::string> filter;
185 if (!ccdb_api.retrieveBlob(model_path, "./", filter, o2::ccdb::getCurrentTimestamp(), false, local_names[i].c_str())) {
186 LOG(fatal) << "Error: issues in retrieving " << model_path << " from CCDB!";
187 exit(1);
188 }
189 }
190 }
191 }
192 model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs;
193 model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton;
194 nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate;
195 try {
196 // Create the TPC loopers generator with the provided parameters
197 mTPCLoopersGen = new o2::eventgen::GenTPCLoopers(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton);
198 const auto& intrate = loopersParam.intrate;
199 // Configure the generator with flat gas loopers defined per orbit with clusters/track info
200 // If intrate is negative (default), automatic IR from collisioncontext.root will be used
201 if (flat_gas) {
202 mTPCLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate);
203 mTPCLoopersGen->SetAdjust(loopersParam.adjust_flatgas);
204 } else {
205 // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used
206 // Multiplier is applied only with distribution sampling
207 // This configuration can be used for testing purposes, in all other cases flat gas is recommended
208 mTPCLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton);
209 mTPCLoopersGen->SetMultiplier(multiplier);
210 }
211 LOG(info) << "TPC Loopers generator initialized successfully";
212 } catch (const std::exception& e) {
213 LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what();
214 delete mTPCLoopersGen;
215 mTPCLoopersGen = nullptr;
216 return kFALSE;
217 }
218 return kTRUE;
219}
220#endif
221
222/*****************************************************************/
223
224Bool_t
226{
230 return kTRUE;
231}
232
233/*****************************************************************/
234
235Bool_t
237{
238#ifdef GENERATORS_WITH_TPCLOOPERS
239 if (mAddTPCLoopers) {
240 if (!mTPCLoopersGen) {
241 LOG(error) << "Loopers generator not initialized";
242 return kFALSE;
243 }
244
245 // Generate loopers using the initialized TPC loopers generator
246 if (!mTPCLoopersGen->generateEvent()) {
247 LOG(error) << "Failed to generate loopers event";
248 return kFALSE;
249 }
250 if (mTPCLoopersGen->getNLoopers() == 0) {
251 LOG(warning) << "No loopers generated for this event";
252 return kTRUE;
253 }
254 const auto& looperParticles = mTPCLoopersGen->importParticles();
255 if (looperParticles.empty()) {
256 LOG(error) << "Failed to import loopers particles";
257 return kFALSE;
258 }
259 // Append the generated looper particles to the main particle list
260 mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end());
261
262 LOG(debug) << "Added " << looperParticles.size() << " looper particles";
263 }
264#endif
265 return kTRUE;
266}
267
268/*****************************************************************/
269
270Bool_t
272{
276 while (true) {
278
280 mParticles.clear();
281
283 mSubGeneratorId = -1;
284
286 if (!generateEvent()) {
287 LOG(error) << "ReadEvent failed in generateEvent";
288 return kFALSE;
289 }
290
292 if (!importParticles()) {
293 LOG(error) << "ReadEvent failed in importParticles";
294 return kFALSE;
295 }
296
298 if (!finalizeEvent()) {
299 LOG(error) << "ReadEvent failed in finalizeEvent";
300 return kFALSE;
301 }
302
303 if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) {
304 LOG(fatal) << "ReadEvent failed because no SubGenerator description given";
305 }
306
307 if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) {
308 LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set";
309 }
310
312 if (triggerEvent()) {
314 break;
315 } else {
317 }
318 }
319
321 if (!addTracks(primGen)) {
322 LOG(error) << "ReadEvent failed in addTracks";
323 return kFALSE;
324 }
325
327 auto header = primGen->GetEvent();
328 auto o2header = dynamic_cast<o2::dataformats::MCEventHeader*>(header);
329 if (!header) {
330 LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object";
331 return kFALSE;
332 }
333 updateHeader(o2header);
334 updateSubGeneratorInformation(o2header);
335
337 return kTRUE;
338}
339
340/*****************************************************************/
341
342Bool_t
344{
347 auto o2primGen = dynamic_cast<PrimaryGenerator*>(primGen);
348 if (!o2primGen) {
349 LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator";
350 return kFALSE;
351 }
352
354 for (const auto& particle : mParticles) {
355 o2primGen->AddTrack(particle.GetPdgCode(),
356 particle.Px() * mMomentumUnit,
357 particle.Py() * mMomentumUnit,
358 particle.Pz() * mMomentumUnit,
359 particle.Vx() * mPositionUnit,
360 particle.Vy() * mPositionUnit,
361 particle.Vz() * mPositionUnit,
362 particle.GetMother(0),
363 particle.GetMother(1),
364 particle.GetDaughter(0),
365 particle.GetDaughter(1),
366 particle.TestBit(ParticleStatus::kToBeDone),
367 particle.Energy() * mEnergyUnit,
368 particle.T() * mTimeUnit,
369 particle.GetWeight(),
370 (TMCProcess)particle.GetUniqueID(),
371 particle.GetStatusCode()); // generator status information passed as status code field
372 }
373
375 return kTRUE;
376}
377
378/*****************************************************************/
379
380Bool_t
382{
386 return kTRUE;
387}
388
389/*****************************************************************/
390
391Bool_t
393{
397 if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) {
398 return kTRUE;
399 }
400
402 Bool_t triggered;
403 if (mTriggerMode == kTriggerOFF) {
404 return kTRUE;
405 } else if (mTriggerMode == kTriggerOR) {
406 triggered = kFALSE;
407 } else if (mTriggerMode == kTriggerAND) {
408 triggered = kTRUE;
409 } else {
410 return kTRUE;
411 }
412
414 for (const auto& trigger : mTriggers) {
415 auto retval = trigger(mParticles);
416 if (mTriggerMode == kTriggerOR) {
417 triggered |= retval;
418 }
419 if (mTriggerMode == kTriggerAND) {
420 triggered &= retval;
421 }
422 }
423
425 for (const auto& trigger : mDeepTriggers) {
426 auto retval = trigger(mInterface, mInterfaceName);
427 if (mTriggerMode == kTriggerOR) {
428 triggered |= retval;
429 }
430 if (mTriggerMode == kTriggerAND) {
431 triggered &= retval;
432 }
433 }
434
436 return triggered;
437}
438
439/*****************************************************************/
440
441void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription)
442{
443 if (subGeneratorId < 0) {
444 LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId;
445 }
446 mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription});
447}
448
449/*****************************************************************/
450
451void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const
452{
453 if (mSubGeneratorId < 0) {
454 return;
455 }
456 header->putInfo<int>(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId);
457 header->putInfo<std::unordered_map<int, std::string>>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc);
458}
459
460/*****************************************************************/
461/*****************************************************************/
462
463} /* namespace eventgen */
464} /* namespace o2 */
465
std::ostringstream debug
int32_t i
ClassImp(o2::eventgen::Generator)
@ kToBeDone
static BasicCCDBManager & instance()
static SimConfig & Instance()
Definition SimConfig.h:111
void putInfo(std::string const &key, T const &value)
virtual void updateHeader(o2::dataformats::MCEventHeader *eventHeader)
Definition Generator.h:79
std::string mInterfaceName
Definition Generator.h:127
Bool_t ReadEvent(FairPrimaryGenerator *primGen) final
static std::atomic< int > InstanceCounter
Definition Generator.h:154
std::vector< Trigger > mTriggers
Definition Generator.h:131
std::function< void(std::vector< TParticle > const &p, int eventCount)> mTriggerOkHook
Definition Generator.h:136
virtual Bool_t generateEvent()=0
std::vector< DeepTrigger > mDeepTriggers
Definition Generator.h:132
std::function< void(std::vector< TParticle > const &p, int eventCount)> mTriggerFalseHook
Definition Generator.h:137
void addSubGenerator(int subGeneratorId, std::string const &subGeneratorDescription)
ETriggerMode_t mTriggerMode
Definition Generator.h:130
Bool_t addTracks(FairPrimaryGenerator *primGen)
std::vector< TParticle > mParticles
Definition Generator.h:147
virtual Bool_t importParticles()=0
Bool_t Init() override
void AddTrack(Int_t pdgid, Double_t px, Double_t py, Double_t pz, Double_t vx, Double_t vy, Double_t vz, Int_t mother1=-1, Int_t mother2=-1, Int_t daughter1=-1, Int_t daughter2=-1, Bool_t wanttracking=true, Double_t e=-9e9, Double_t tof=0., Double_t weight=0., TMCProcess proc=kPPrimary, Int_t generatorStatus=0)
static constexpr Property SUBGENERATORID
static constexpr Property SUBGENERATORDESCRIPTIONMAP
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
long getCurrentTimestamp()
returns the timestamp in long corresponding to "now"
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"