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