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 mTPCLoopersGen->setGeomProtection(loopersParam.geomProtection);
199 const auto& intrate = loopersParam.intrate;
200 // Configure the generator with flat gas loopers defined per orbit with clusters/track info
201 // If intrate is negative (default), automatic IR from collisioncontext.root will be used
202 if (flat_gas) {
203 mTPCLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate);
204 mTPCLoopersGen->SetAdjust(loopersParam.adjust_flatgas);
205 } else {
206 // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used
207 // Multiplier is applied only with distribution sampling
208 // This configuration can be used for testing purposes, in all other cases flat gas is recommended
209 mTPCLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton);
210 mTPCLoopersGen->SetMultiplier(multiplier);
211 }
212 LOG(info) << "TPC Loopers generator initialized successfully";
213 } catch (const std::exception& e) {
214 LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what();
215 delete mTPCLoopersGen;
216 mTPCLoopersGen = nullptr;
217 return kFALSE;
218 }
219 return kTRUE;
220}
221#endif
222
223/*****************************************************************/
224
225Bool_t
227{
231 return kTRUE;
232}
233
234/*****************************************************************/
235
236Bool_t
238{
239#ifdef GENERATORS_WITH_TPCLOOPERS
240 if (mAddTPCLoopers) {
241 if (!mTPCLoopersGen) {
242 LOG(error) << "Loopers generator not initialized";
243 return kFALSE;
244 }
245
246 // Generate loopers using the initialized TPC loopers generator
247 if (!mTPCLoopersGen->generateEvent()) {
248 LOG(error) << "Failed to generate loopers event";
249 return kFALSE;
250 }
251 if (mTPCLoopersGen->getNLoopers() == 0) {
252 LOG(warning) << "No loopers generated for this event";
253 return kTRUE;
254 }
255 const auto& looperParticles = mTPCLoopersGen->importParticles();
256 if (looperParticles.empty()) {
257 LOG(error) << "Failed to import loopers particles";
258 return kFALSE;
259 }
260 // Append the generated looper particles to the main particle list
261 mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end());
262
263 LOG(debug) << "Added " << looperParticles.size() << " looper particles";
264 const auto skippedLoopers = mTPCLoopersGen->getNSkipped();
265 if (skippedLoopers > 0) {
266 LOG(debug) << "Geometrical protection skipped " << skippedLoopers << " loopers outside the TPC active volume";
267 }
268 }
269#endif
270 return kTRUE;
271}
272
273/*****************************************************************/
274
275Bool_t
277{
281 while (true) {
283
285 mParticles.clear();
286
288 mSubGeneratorId = -1;
289
291 if (!generateEvent()) {
292 LOG(error) << "ReadEvent failed in generateEvent";
293 return kFALSE;
294 }
295
297 if (!importParticles()) {
298 LOG(error) << "ReadEvent failed in importParticles";
299 return kFALSE;
300 }
301
303 if (!finalizeEvent()) {
304 LOG(error) << "ReadEvent failed in finalizeEvent";
305 return kFALSE;
306 }
307
308 if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) {
309 LOG(fatal) << "ReadEvent failed because no SubGenerator description given";
310 }
311
312 if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) {
313 LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set";
314 }
315
317 if (triggerEvent()) {
319 break;
320 } else {
322 }
323 }
324
326 if (!addTracks(primGen)) {
327 LOG(error) << "ReadEvent failed in addTracks";
328 return kFALSE;
329 }
330
332 auto header = primGen->GetEvent();
333 auto o2header = dynamic_cast<o2::dataformats::MCEventHeader*>(header);
334 if (!header) {
335 LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object";
336 return kFALSE;
337 }
338 updateHeader(o2header);
339 updateSubGeneratorInformation(o2header);
340
342 return kTRUE;
343}
344
345/*****************************************************************/
346
347Bool_t
349{
352 auto o2primGen = dynamic_cast<PrimaryGenerator*>(primGen);
353 if (!o2primGen) {
354 LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator";
355 return kFALSE;
356 }
357
359 for (const auto& particle : mParticles) {
360 o2primGen->AddTrack(particle.GetPdgCode(),
361 particle.Px() * mMomentumUnit,
362 particle.Py() * mMomentumUnit,
363 particle.Pz() * mMomentumUnit,
364 particle.Vx() * mPositionUnit,
365 particle.Vy() * mPositionUnit,
366 particle.Vz() * mPositionUnit,
367 particle.GetMother(0),
368 particle.GetMother(1),
369 particle.GetDaughter(0),
370 particle.GetDaughter(1),
371 particle.TestBit(ParticleStatus::kToBeDone),
372 particle.Energy() * mEnergyUnit,
373 particle.T() * mTimeUnit,
374 particle.GetWeight(),
375 (TMCProcess)particle.GetUniqueID(),
376 particle.GetStatusCode()); // generator status information passed as status code field
377 }
378
380 return kTRUE;
381}
382
383/*****************************************************************/
384
385Bool_t
387{
391 return kTRUE;
392}
393
394/*****************************************************************/
395
396Bool_t
398{
402 if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) {
403 return kTRUE;
404 }
405
407 Bool_t triggered;
408 if (mTriggerMode == kTriggerOFF) {
409 return kTRUE;
410 } else if (mTriggerMode == kTriggerOR) {
411 triggered = kFALSE;
412 } else if (mTriggerMode == kTriggerAND) {
413 triggered = kTRUE;
414 } else {
415 return kTRUE;
416 }
417
419 for (const auto& trigger : mTriggers) {
420 auto retval = trigger(mParticles);
421 if (mTriggerMode == kTriggerOR) {
422 triggered |= retval;
423 }
424 if (mTriggerMode == kTriggerAND) {
425 triggered &= retval;
426 }
427 }
428
430 for (const auto& trigger : mDeepTriggers) {
431 auto retval = trigger(mInterface, mInterfaceName);
432 if (mTriggerMode == kTriggerOR) {
433 triggered |= retval;
434 }
435 if (mTriggerMode == kTriggerAND) {
436 triggered &= retval;
437 }
438 }
439
441 return triggered;
442}
443
444/*****************************************************************/
445
446void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription)
447{
448 if (subGeneratorId < 0) {
449 LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId;
450 }
451 mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription});
452}
453
454/*****************************************************************/
455
456void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const
457{
458 if (mSubGeneratorId < 0) {
459 return;
460 }
461 header->putInfo<int>(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId);
462 header->putInfo<std::unordered_map<int, std::string>>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc);
463}
464
465/*****************************************************************/
466/*****************************************************************/
467
468} /* namespace eventgen */
469} /* namespace o2 */
470
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"