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 const auto nCandidates = mTPCLoopersGen->getNLoopers();
252 if (nCandidates == 0) {
253 LOG(warning) << "No loopers generated for this event";
254 return kTRUE;
255 }
256 const auto& looperParticles = mTPCLoopersGen->importParticles();
257 const auto skippedLoopers = mTPCLoopersGen->getNSkipped();
258 if (looperParticles.empty()) {
259 if (skippedLoopers == nCandidates) {
260 // all candidate loopers were dropped by the geometrical protection
261 LOG(debug) << "All " << skippedLoopers << " candidate loopers were outside the TPC active volume; none added for this event";
262 return kTRUE;
263 }
264 LOG(error) << "Failed to import loopers particles";
265 return kFALSE;
266 }
267 // Append the generated looper particles to the main particle list
268 mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end());
269
270 LOG(debug) << "Added " << looperParticles.size() << " looper particles";
271 if (skippedLoopers > 0) {
272 LOG(debug) << "Geometrical protection skipped " << skippedLoopers << " loopers outside the TPC active volume";
273 }
274 }
275#endif
276 return kTRUE;
277}
278
279/*****************************************************************/
280
281Bool_t
283{
287 while (true) {
289
291 mParticles.clear();
292
294 mSubGeneratorId = -1;
295
297 if (!generateEvent()) {
298 LOG(error) << "ReadEvent failed in generateEvent";
299 return kFALSE;
300 }
301
303 if (!importParticles()) {
304 LOG(error) << "ReadEvent failed in importParticles";
305 return kFALSE;
306 }
307
309 if (!finalizeEvent()) {
310 LOG(error) << "ReadEvent failed in finalizeEvent";
311 return kFALSE;
312 }
313
314 if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) {
315 LOG(fatal) << "ReadEvent failed because no SubGenerator description given";
316 }
317
318 if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) {
319 LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set";
320 }
321
323 if (triggerEvent()) {
325 break;
326 } else {
328 }
329 }
330
332 if (!addTracks(primGen)) {
333 LOG(error) << "ReadEvent failed in addTracks";
334 return kFALSE;
335 }
336
338 auto header = primGen->GetEvent();
339 auto o2header = dynamic_cast<o2::dataformats::MCEventHeader*>(header);
340 if (!header) {
341 LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object";
342 return kFALSE;
343 }
344 updateHeader(o2header);
345 updateSubGeneratorInformation(o2header);
346
348 return kTRUE;
349}
350
351/*****************************************************************/
352
353Bool_t
355{
358 auto o2primGen = dynamic_cast<PrimaryGenerator*>(primGen);
359 if (!o2primGen) {
360 LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator";
361 return kFALSE;
362 }
363
365 for (const auto& particle : mParticles) {
366 o2primGen->AddTrack(particle.GetPdgCode(),
367 particle.Px() * mMomentumUnit,
368 particle.Py() * mMomentumUnit,
369 particle.Pz() * mMomentumUnit,
370 particle.Vx() * mPositionUnit,
371 particle.Vy() * mPositionUnit,
372 particle.Vz() * mPositionUnit,
373 particle.GetMother(0),
374 particle.GetMother(1),
375 particle.GetDaughter(0),
376 particle.GetDaughter(1),
377 particle.TestBit(ParticleStatus::kToBeDone),
378 particle.Energy() * mEnergyUnit,
379 particle.T() * mTimeUnit,
380 particle.GetWeight(),
381 (TMCProcess)particle.GetUniqueID(),
382 particle.GetStatusCode()); // generator status information passed as status code field
383 }
384
386 return kTRUE;
387}
388
389/*****************************************************************/
390
391Bool_t
393{
397 return kTRUE;
398}
399
400/*****************************************************************/
401
402Bool_t
404{
408 if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) {
409 return kTRUE;
410 }
411
413 Bool_t triggered;
414 if (mTriggerMode == kTriggerOFF) {
415 return kTRUE;
416 } else if (mTriggerMode == kTriggerOR) {
417 triggered = kFALSE;
418 } else if (mTriggerMode == kTriggerAND) {
419 triggered = kTRUE;
420 } else {
421 return kTRUE;
422 }
423
425 for (const auto& trigger : mTriggers) {
426 auto retval = trigger(mParticles);
427 if (mTriggerMode == kTriggerOR) {
428 triggered |= retval;
429 }
430 if (mTriggerMode == kTriggerAND) {
431 triggered &= retval;
432 }
433 }
434
436 for (const auto& trigger : mDeepTriggers) {
437 auto retval = trigger(mInterface, mInterfaceName);
438 if (mTriggerMode == kTriggerOR) {
439 triggered |= retval;
440 }
441 if (mTriggerMode == kTriggerAND) {
442 triggered &= retval;
443 }
444 }
445
447 return triggered;
448}
449
450/*****************************************************************/
451
452void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription)
453{
454 if (subGeneratorId < 0) {
455 LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId;
456 }
457 mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription});
458}
459
460/*****************************************************************/
461
462void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const
463{
464 if (mSubGeneratorId < 0) {
465 return;
466 }
467 header->putInfo<int>(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId);
468 header->putInfo<std::unordered_map<int, std::string>>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc);
469}
470
471/*****************************************************************/
472/*****************************************************************/
473
474} /* namespace eventgen */
475} /* namespace o2 */
476
std::ostringstream debug
int32_t i
ClassImp(o2::eventgen::Generator)
@ kToBeDone
static BasicCCDBManager & instance()
static SimConfig & Instance()
Definition SimConfig.h:112
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:131
Bool_t ReadEvent(FairPrimaryGenerator *primGen) final
static std::atomic< int > InstanceCounter
Definition Generator.h:158
std::vector< Trigger > mTriggers
Definition Generator.h:135
std::function< void(std::vector< TParticle > const &p, int eventCount)> mTriggerOkHook
Definition Generator.h:140
virtual Bool_t generateEvent()=0
std::vector< DeepTrigger > mDeepTriggers
Definition Generator.h:136
std::function< void(std::vector< TParticle > const &p, int eventCount)> mTriggerFalseHook
Definition Generator.h:141
void addSubGenerator(int subGeneratorId, std::string const &subGeneratorDescription)
ETriggerMode_t mTriggerMode
Definition Generator.h:134
Bool_t addTracks(FairPrimaryGenerator *primGen)
std::vector< TParticle > mParticles
Definition Generator.h:151
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"