Skip to content

Commit ea60b56

Browse files
committed
Integrated code review by Sandro + improvements
1 parent 6ef3475 commit ea60b56

12 files changed

Lines changed: 1773 additions & 143 deletions

File tree

‎Generators/CMakeLists.txt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ if(doBuildSimulation)
152152
PUBLIC_LINK_LIBRARIES O2::Generators)
153153
endif()
154154

155+
if(pythia_FOUND AND HepMC3_FOUND)
156+
o2_add_test(GeneratorHybridEventPool NAME test_Generator_test_GeneratorHybridEventPool
157+
SOURCES test/test_GeneratorHybridEventPool.cxx
158+
COMPONENT_NAME Generator
159+
LABELS generator
160+
PUBLIC_LINK_LIBRARIES O2::Generators)
161+
endif()
162+
155163
# o2_add_test(GeneratorPythia8Param NAME test_Generator_test_GeneratorPythia8Param
156164
# SOURCES test/test_GeneratorPythia8Param.cxx
157165
# COMPONENT_NAME Generator

‎Generators/include/Generators/Generator.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "TParticle.h"
1919
#include "Generators/Trigger.h"
2020
#include <functional>
21+
#include <optional>
2122
#include <vector>
2223
#include <unordered_map>
2324

@@ -94,10 +95,13 @@ class Generator : public FairGenerator
9495
void addDeepTrigger(DeepTrigger trigger) { mDeepTriggers.push_back(trigger); };
9596
// setter for global number of events
9697
static void setTotalNEvents(unsigned int& n) { gTotalNEvents = n; }
98+
// number of events this generator instance is expected to serve; 0 means unknown
99+
void setExpectedNEvents(unsigned int n) { mExpectedNEvents = n; }
97100

98101
/** getters **/
99102
const std::vector<TParticle>& getParticles() const { return mParticles; }; //!
100103
static unsigned int getTotalNEvents() { return gTotalNEvents; };
104+
unsigned int getExpectedNEvents() const { return mExpectedNEvents.value_or(gTotalNEvents); }
101105

102106
/** other **/
103107
void clearParticles() { mParticles.clear(); };
@@ -170,6 +174,8 @@ class Generator : public FairGenerator
170174

171175
// global static information about (upper limit of) number of events to be generated
172176
static unsigned int gTotalNEvents;
177+
// number of events expected to be served by this instance. Number of events of the job if unset
178+
std::optional<unsigned int> mExpectedNEvents; //!
173179

174180
// Loopers generator instance
175181
o2::eventgen::GenTPCLoopers* mTPCLoopersGen = nullptr;

‎Generators/include/Generators/GeneratorHybrid.h‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <iostream>
4545
#include <thread>
4646
#include <atomic>
47+
#include <exception>
4748

4849
namespace o2
4950
{
@@ -74,6 +75,12 @@ class GeneratorHybrid : public Generator
7475
private:
7576
GeneratorHybrid(const std::string& inputgens);
7677
~GeneratorHybrid();
78+
// number of events each sub-generator is expected to serve (0 == unknown)
79+
std::vector<unsigned int> expectedNEventsPerGenerator(unsigned int nevents) const;
80+
// schedules the generation of an event by a sub-generator, within its request budget
81+
void requestEvent(int genIndex);
82+
// re-raises, in the calling thread, a failure of a sub-generator during the generation of its event
83+
void rethrowSubGeneratorFailure(int genIndex);
7784
o2::eventgen::Generator* currentgen = nullptr;
7885
std::vector<std::shared_ptr<o2::eventgen::Generator>> gens;
7986
const std::vector<std::string> generatorNames = {"evtpool", "boxgen", "external", "hepmc", "pythia8", "pythia8pp", "pythia8hi", "pythia8hf", "pythia8powheg"};
@@ -101,6 +108,9 @@ class GeneratorHybrid : public Generator
101108
int mIndex = 0;
102109
int mEventCounter = 0;
103110
int mTasksStarted = 0;
111+
// number of events which are requested from each sub-generator. This is used if the share of
112+
// each sub-generator is known exactly (fixed fractions, sequential or cocktail mode), empty otherwise
113+
std::vector<unsigned int> mRequestBudget;
104114

105115
// Cocktail mode
106116
bool mCocktailMode = false;
@@ -117,6 +127,8 @@ class GeneratorHybrid : public Generator
117127
std::vector<tbb::concurrent_bounded_queue<int>> mResultQueue;
118128
tbb::task_arena mTaskArena;
119129
std::atomic<bool> mStopFlag;
130+
// failure of the last event generation of each sub-generator in a worker thread
131+
std::vector<std::exception_ptr> mGenFailures;
120132
bool mIsInitialized = false;
121133

122134
o2::dataformats::MCEventHeader mMCEventHeader; // to capture event headers

‎Generators/src/GeneratorFromFile.cxx‎

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ void GeneratorFromO2Kine::closeCurrentFile()
217217
mEventOrder.clear();
218218
mEventsAvailable = 0;
219219
mEventCounter = 0;
220+
// the header read from the previous file must not leak into events of the next one
221+
mOrigMCEventHeader.reset();
220222
if (mCurrentFile) {
221223
mCurrentFile->Close();
222224
delete mCurrentFile;
@@ -242,44 +244,46 @@ bool GeneratorFromO2Kine::openFile(int index)
242244
{
243245
// opens one file of the list, connects the branches to it and fixes the
244246
// order in which its events are going to be served;
245-
// any previously open file is closed first, so that we never keep more than
246-
// one input file open at a time
247-
closeCurrentFile();
247+
// the file which is currently open is only closed once the new one has been found usable
248+
// In the standard case never more than one input file is open at a time
248249
if (index < 0 || index >= (int)mFileNames.size()) {
249250
return false;
250251
}
251252
auto const& name = mFileNames[index];
252253

253-
mCurrentFile = TFile::Open(name.c_str());
254-
if (mCurrentFile == nullptr || mCurrentFile->IsZombie()) {
254+
std::unique_ptr<TFile> file(TFile::Open(name.c_str()));
255+
if (file == nullptr || file->IsZombie()) {
255256
LOG(error) << "EventFile " << name << " could not be opened";
256-
closeCurrentFile();
257257
return false;
258258
}
259259
// the kinematics will be stored inside a branch MCTrack
260260
// different events are stored inside different entries
261-
auto tree = (TTree*)mCurrentFile->Get("o2sim");
261+
auto tree = (TTree*)file->Get("o2sim");
262262
if (!tree) {
263263
LOG(error) << "EventFile " << name << " does not contain an 'o2sim' tree";
264-
closeCurrentFile();
265264
return false;
266265
}
267-
mEventBranch = tree->GetBranch("MCTrack");
268-
if (!mEventBranch) {
266+
auto eventBranch = tree->GetBranch("MCTrack");
267+
if (!eventBranch) {
269268
LOG(error) << "No MCTrack branch found in " << name;
270-
closeCurrentFile();
271269
return false;
272270
}
273-
mEventsAvailable = mEventBranch->GetEntries();
274-
if (mEventsAvailable <= 0) {
271+
auto eventsAvailable = eventBranch->GetEntries();
272+
if (eventsAvailable <= 0) {
275273
LOG(warn) << "EventFile " << name << " does not contain any event";
276-
closeCurrentFile();
277274
return false;
278275
}
279-
mMCHeaderBranch = tree->GetBranch("MCEventHeader.");
280-
if (!mMCHeaderBranch) {
276+
auto mcHeaderBranch = tree->GetBranch("MCEventHeader.");
277+
if (!mcHeaderBranch) {
281278
LOG(warn) << "No MCEventHeader branch found in kinematics input file";
282279
}
280+
281+
// the new file is good: release the previous one and take over
282+
closeCurrentFile();
283+
mCurrentFile = file.release();
284+
mEventBranch = eventBranch;
285+
mEventsAvailable = eventsAvailable;
286+
mMCHeaderBranch = mcHeaderBranch;
283287
establishEventOrder();
284288
mCurrentFileIndex = index;
285289
mEventCounter = 0;
@@ -303,7 +307,7 @@ bool GeneratorFromO2Kine::openNextFile(bool wrapAround)
303307
if (!wrapAround) {
304308
return false;
305309
}
306-
if (trial == 0) {
310+
if (next == numFiles) {
307311
LOG(info) << "Reached the end of the input file list; reusing events from the beginning";
308312
}
309313
next = next % numFiles;
@@ -380,19 +384,22 @@ bool GeneratorFromO2Kine::Init()
380384
}
381385
mCurrentFileIndex = -1;
382386
if (!openNextFile(false)) {
383-
LOG(error) << "Problem reading events from the given kinematics input";
387+
LOG(fatal) << "Problem reading events from the given kinematics input: none of the " << mFileNames.size()
388+
<< " input file(s) can be used";
384389
return false;
385390
}
386391
if (mStartEvent > 0) {
387-
if (mStartEvent < mEventsAvailable) {
392+
if (mRandomize) {
393+
LOG(warn) << "Start event " << mStartEvent << " ignored: the events are served in random order (randomize)";
394+
} else if (mStartEvent < mEventsAvailable) {
388395
mEventCounter = mStartEvent;
389396
} else {
390397
LOG(error) << "start event bigger than available events";
391398
}
392399
}
393400
// Simple estimate of events without checking all the files.
394401
// To be discussed if we want instead to do this, or provide an additional file with the pools
395-
auto requested = getTotalNEvents();
402+
auto requested = getExpectedNEvents();
396403
if (requested > 0 && !mRoundRobin && mEventsAvailable > 0) {
397404
auto estimate = (size_t)mEventsAvailable * mFileNames.size();
398405
if (estimate < requested) {
@@ -422,7 +429,7 @@ bool GeneratorFromO2Kine::importParticles()
422429
// Next file in the list opened when the events of the current one are used up
423430
if (mEventCounter >= mEventsAvailable) {
424431
if (!openNextFile(mRoundRobin)) {
425-
auto requested = getTotalNEvents();
432+
auto requested = getExpectedNEvents();
426433
LOG(fatal) << "GeneratorFromO2Kine: ran out of events after " << mEventsServed
427434
<< " event(s) from " << mFilesUsed << " input file(s)"
428435
<< (requested > 0 ? " (" + std::to_string(requested) + " were requested)" : "")
@@ -584,7 +591,7 @@ bool GeneratorFromEventPool::Init()
584591
mPoolFilesAvailable = setupFileUniverse(expPath.Data());
585592

586593
if (mPoolFilesAvailable.size() == 0) {
587-
LOG(error) << "No file found that can be used with EventPool generator";
594+
LOG(fatal) << "No file found that can be used with EventPool generator (eventPoolPath: " << mConfig.eventPoolPath << ")";
588595
return false;
589596
}
590597
LOG(info) << "Found " << mPoolFilesAvailable.size() << " available event pool files";
@@ -602,14 +609,18 @@ bool GeneratorFromEventPool::Init()
602609
.rngseed = mConfig.rngseed,
603610
.randomphi = mConfig.randomphi};
604611
mO2KineGenerator.reset(new GeneratorFromO2Kine(kine_config, mFilesChosen));
612+
// the internal generator serves the events of this one
613+
mO2KineGenerator->setExpectedNEvents(getExpectedNEvents());
605614
return mO2KineGenerator->Init();
606615
}
607616

608617
std::vector<std::string> GeneratorFromEventPool::selectFiles(std::vector<std::string> const& universe)
609618
{
610619
// shuffles the whole pool universe so that different jobs go through it in a
611-
// different order
620+
// different order. Sorting first as a directory listing (or alien find) gives no fixed order,
621+
// and the same rngseed must give the same order everywhere
612622
auto result = universe;
623+
std::sort(result.begin(), result.end());
613624
std::shuffle(result.begin(), result.end(), mRandomEngine);
614625
return result;
615626
}

‎Generators/src/GeneratorHepMC.cxx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ Bool_t GeneratorHepMC::generateEventOrdered()
706706
// The entry to be read is fixed by the event order established at file opening
707707
if (mEventCounter >= (int)mEventOrder.size()) {
708708
if (not mRoundRobin) {
709-
auto requested = getTotalNEvents();
709+
auto requested = getExpectedNEvents();
710710
LOG(fatal) << "GeneratorHepMC: ran out of events after " << mEventsServed
711711
<< " event(s) from " << mCurrentFileName
712712
<< (requested > 0 ? " (" + std::to_string(requested) + " were requested)" : "")
@@ -863,7 +863,7 @@ Bool_t GeneratorHepMC::Init()
863863
return false;
864864
}
865865
establishEventOrder();
866-
auto requested = getTotalNEvents();
866+
auto requested = getExpectedNEvents();
867867
if (requested > 0 and not mRoundRobin and mEventOrder.size() < requested) {
868868
LOG(warn) << "This job will request " << requested << " events, but the input holds "
869869
<< "only " << mEventOrder.size() << " usable event(s). The job will stop "

0 commit comments

Comments
 (0)