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