Skip to content

Commit d52ac29

Browse files
committed
Implementation of cocktail generation
Works for sequence generation * Updated Hybrid example
1 parent a14603d commit d52ac29

File tree

7 files changed

+236
-21
lines changed

7 files changed

+236
-21
lines changed

Generators/include/Generators/GeneratorHybrid.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ class GeneratorHybrid : public Generator
9898
int mEventCounter = 0;
9999
int mTasksStarted = 0;
100100

101+
// Cocktail mode
102+
bool mCocktailMode = false;
103+
std::vector<std::vector<int>> mGroups;
104+
101105
// Create a task arena with a specified number of threads
102106
std::thread mTBBTaskPoolRunner;
103107
tbb::concurrent_bounded_queue<int> mInputTaskQueue;

Generators/src/GeneratorHybrid.cxx

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include "Generators/GeneratorHybrid.h"
1313
#include <fairlogger/Logger.h>
1414
#include <algorithm>
15-
15+
#include <unordered_set>
1616
#include <tbb/concurrent_queue.h>
1717
#include <tbb/task_arena.h>
1818
#include <tbb/parallel_for.h>
@@ -42,9 +42,16 @@ GeneratorHybrid::GeneratorHybrid(const std::string& inputgens)
4242
}
4343
int index = 0;
4444
if (!(mRandomize || mGenerationMode == GenMode::kParallel)) {
45-
if (mFractions.size() != mInputGens.size()) {
46-
LOG(fatal) << "Number of fractions does not match the number of generators";
47-
return;
45+
if (mCocktailMode) {
46+
if (mGroups.size() != mFractions.size()) {
47+
LOG(fatal) << "Number of groups does not match the number of fractions";
48+
return;
49+
}
50+
} else {
51+
if (mFractions.size() != mInputGens.size()) {
52+
LOG(fatal) << "Number of fractions does not match the number of generators";
53+
return;
54+
}
4855
}
4956
// Check if all elements of mFractions are 0
5057
if (std::all_of(mFractions.begin(), mFractions.end(), [](int i) { return i == 0; })) {
@@ -303,7 +310,7 @@ bool GeneratorHybrid::generateEvent()
303310
}
304311
}
305312
} else {
306-
mIndex = gRandom->Integer(mGens.size());
313+
mIndex = gRandom->Integer(mFractions.size());
307314
}
308315
} else {
309316
while (mFractions[mCurrentFraction] == 0 || mseqCounter == mFractions[mCurrentFraction]) {
@@ -322,32 +329,55 @@ bool GeneratorHybrid::generateEvent()
322329
bool GeneratorHybrid::importParticles()
323330
{
324331
int genIndex = -1;
332+
std::vector<int> subGenIndex = {};
325333
if (mIndex == -1) {
326334
// this means parallel mode ---> we have a common queue
327335
mResultQueue[0].pop(genIndex);
328336
} else {
329337
// need to pop from a particular queue
330-
mResultQueue[mIndex].pop(genIndex);
338+
if (!mCocktailMode) {
339+
mResultQueue[mIndex].pop(genIndex);
340+
} else {
341+
// in cocktail mode we need to pop from the group queue
342+
subGenIndex.resize(mGroups[mIndex].size());
343+
for (size_t pos = 0; pos < mGroups[mIndex].size(); ++pos) {
344+
int subIndex = mGroups[mIndex][pos];
345+
LOG(info) << "Getting generator " << mGens[subIndex] << " from cocktail group " << mIndex;
346+
mResultQueue[subIndex].pop(subGenIndex[pos]);
347+
}
348+
}
331349
}
332-
LOG(info) << "Importing particles for task " << genIndex;
333-
334-
// at this moment the mIndex-th generator is ready to be used
350+
// Clear particles and event header
335351
mParticles.clear();
336-
mParticles = gens[genIndex]->getParticles();
337-
338-
// fetch the event Header information from the underlying generator
339352
mMCEventHeader.clearInfo();
340-
gens[genIndex]->updateHeader(&mMCEventHeader);
341-
342-
mInputTaskQueue.push(genIndex);
343-
mTasksStarted++;
353+
if (mCocktailMode) {
354+
// in cocktail mode we need to merge the particles from the different generators
355+
for (auto subIndex : subGenIndex) {
356+
LOG(info) << "Importing particles for task " << subIndex;
357+
auto subParticles = gens[subIndex]->getParticles();
358+
mParticles.insert(mParticles.end(), subParticles.begin(), subParticles.end());
359+
// fetch the event Header information from the underlying generator
360+
gens[subIndex]->updateHeader(&mMCEventHeader);
361+
mInputTaskQueue.push(subIndex);
362+
mTasksStarted++;
363+
}
364+
} else {
365+
LOG(info) << "Importing particles for task " << genIndex;
366+
// at this moment the mIndex-th generator is ready to be used
367+
mParticles = gens[genIndex]->getParticles();
368+
// fetch the event Header information from the underlying generator
369+
gens[genIndex]->updateHeader(&mMCEventHeader);
370+
mInputTaskQueue.push(genIndex);
371+
mTasksStarted++;
372+
}
344373

345374
mseqCounter++;
346375
mEventCounter++;
347376
if (mEventCounter == mNEvents) {
348377
LOG(info) << "HybridGen: Stopping TBB task pool";
349378
mStopFlag = true;
350379
}
380+
351381
return true;
352382
}
353383

@@ -465,6 +495,46 @@ Bool_t GeneratorHybrid::parseJSON(const std::string& path)
465495
}
466496
}
467497

498+
if (doc.HasMember("cocktail")) {
499+
mCocktailMode = true;
500+
const auto& groups = doc["cocktail"];
501+
for (const auto& group : groups.GetArray()) {
502+
if (!group.HasMember("group")) {
503+
LOG(fatal) << "Group not provided for cocktail";
504+
return false;
505+
}
506+
const auto& sets = group["group"];
507+
mGroups.push_back({});
508+
for (const auto& subset : sets.GetArray()) {
509+
mGroups.back().push_back(subset.GetInt());
510+
}
511+
}
512+
// Check if mGroups items contain the same number twice and ensure all items are unique across groups
513+
std::unordered_set<int> allItems;
514+
for (const auto& group : mGroups) {
515+
std::unordered_set<int> uniqueItems;
516+
for (const auto& item : group) {
517+
if (!uniqueItems.insert(item).second) {
518+
LOG(fatal) << "Duplicate generator index " << item << " found in a cocktail group";
519+
return false;
520+
}
521+
if (!allItems.insert(item).second) {
522+
LOG(fatal) << "Duplicate generator index " << item << " found in the cocktails";
523+
return false;
524+
}
525+
}
526+
}
527+
// Check if allItems is missing any generator index and create single gen groups for them
528+
// Fractions for these generators are the back ones in mFractions
529+
for (int i = 0; i < mInputGens.size(); i++) {
530+
if (allItems.find(i) == allItems.end()) {
531+
LOG(info) << "Generator index " << i << " is missing in the cocktails";
532+
LOG(info) << "Setting up a group for generator " << mInputGens[i];
533+
mGroups.push_back({i});
534+
}
535+
}
536+
}
537+
468538
// Get fractions and put them in mFractions
469539
if (doc.HasMember("fractions")) {
470540
const auto& fractions = doc["fractions"];

run/SimExamples/Hybrid/README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
\page refrunSimExamplesHybrid Example Hybrid
33
/doxy -->
44

5-
The usage of the Hybrid generator with the o2-sim is presented in this short manual.
5+
The usage of the Hybrid generator with o2-sim is presented in this short manual.
66
All the other generators are implemented as sub-generators and they can be called thanks to a
77
JSON file, fed to o2-sim via the GeneratorHybrid.configFile parameter. The O2sim package needs to be loaded in order to use this example.
88

@@ -13,6 +13,4 @@ available generators in O2. The JSON template can be generated using the ${O2DPG
1313

1414
- **runo2sim.sh** &rarr; allows to use the hybrid generator example
1515
- **hybridconfig.json** &rarr; example JSON file for the hybrid generator configuration
16-
- **example.optns** &rarr; options file to be used in EPOS4 implemented as subgenerator in this example (the .optns must be available in the current working directory)
17-
- **evtpool.root** &rarr; cached events to be used with the extkinO2 generator
18-
- **epos4.hepmc** &rarr; EPOS4 events stored as hepmc file
16+
- **example.optns** &rarr; options file to be used in EPOS4 implemented as subgenerator in this example (the .optns must be available in the current working directory)

run/SimExamples/Hybrid/hybridconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
"name": "external",
5454
"config": {
5555
"fileName": "${O2DPG_ROOT}/MC/config/PWGDQ/external/generator/GeneratorParamPromptJpsiToElectronEvtGen_pp13TeV.C",
56-
"funcName": "GeneratorParamPromptJpsiToElectronEvtGen_pp13TeV()"
56+
"funcName": "GeneratorParamPromptJpsiToElectronEvtGen_pp13TeV()",
57+
"iniFile": ""
5758
}
5859
},
5960
{
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!-- doxy
2+
\page refrunSimExamplesHybrid Example Hybrid_cocktail
3+
/doxy -->
4+
5+
The usage of the Hybrid generator using cocktails is presented in this example.
6+
The syntax of the JSON file shows how the cocktails can be grouped. Each generator will be pulled exactly once in order for each cocktail event generation.
7+
The basic Hybrid Generator mechanisms are shown in the Hybrid and Hybrid_parallel example folders.
8+
The cocktail configuration can not be setup with the template script for now.
9+
10+
# Files description
11+
12+
- **runo2sim.sh** &rarr; allows to use the hybrid generator example
13+
- **hybridcocktail.json** &rarr; example JSON file for the hybrid generator configuration using cocktails
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"generators": [
3+
{
4+
"name": "pythia8",
5+
"config": {
6+
"config": "$O2_ROOT/share/Generators/egconfig/pythia8_inel.cfg",
7+
"hooksFileName": "",
8+
"hooksFuncName": "",
9+
"includePartonEvent": false,
10+
"particleFilter": "",
11+
"verbose": 0
12+
}
13+
},
14+
{
15+
"name": "external",
16+
"config": {
17+
"fileName": "${O2DPG_ROOT}/MC/config/PWGDQ/external/generator/GeneratorParamPromptJpsiToElectronEvtGen_pp13TeV.C",
18+
"funcName": "GeneratorParamPromptJpsiToElectronEvtGen_pp13TeV()",
19+
"iniFile": ""
20+
}
21+
},
22+
{
23+
"name": "pythia8pp"
24+
},
25+
{
26+
"name": "extkinO2",
27+
"config": {
28+
"skipNonTrackable": true,
29+
"continueMode": false,
30+
"roundRobin": false,
31+
"randomize": false,
32+
"rngseed": 0,
33+
"randomphi": false,
34+
"fileName": "${PWD}/evtpool.root"
35+
}
36+
},
37+
{
38+
"name": "pythia8hf",
39+
"config": ""
40+
}
41+
],
42+
"cocktail": [
43+
{
44+
"group": [
45+
0,
46+
1
47+
]
48+
},
49+
{
50+
"group": [
51+
2,
52+
3
53+
]
54+
}
55+
],
56+
"fractions": [
57+
1,
58+
1,
59+
1
60+
]
61+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Hybrid generator simulation example using cocktails:
4+
# the simulation is configured using a JSON file (hybridcocktail.json in this folder)
5+
set -x
6+
if [ ! "${O2DPG_ROOT}" ]; then
7+
echo "This needs O2DPG loaded; alienv enter ..."
8+
exit 1
9+
fi
10+
11+
[ ! "${O2_ROOT}" ] && echo "Error: This needs O2 loaded" && exit 2
12+
13+
NEV=-1
14+
more=""
15+
JOBS=2
16+
17+
usage()
18+
{
19+
cat <<EOF
20+
Usage: $0 [OPTIONS]
21+
22+
Options:
23+
24+
-m,--more CONFIG More configurations ($more)
25+
-n,--nevents EVENTS Number of events ($NEV)
26+
-j,--jobs JOBS Number of jobs ($JOBS)
27+
-h,--help Print these instructions
28+
-- Rest of command line sent to o2-sim
29+
30+
COMMAND must be quoted if it contains spaces or other special
31+
characters
32+
33+
Below follows the help output of o2-sim
34+
35+
EOF
36+
}
37+
38+
if [ "$#" -lt 2 ]; then
39+
echo "Running with default values"
40+
fi
41+
42+
while test $# -gt 0 ; do
43+
case $1 in
44+
-m|--more) more="$2" ; shift ;;
45+
-n|--nevents) NEV=$2 ; shift ;;
46+
-j|--jobs) JOBS=$2 ; shift ;;
47+
-h|--help) usage; o2-sim --help full ; exit 0 ;;
48+
--) shift ; break ;;
49+
*) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr
50+
exit 3
51+
;;
52+
esac
53+
shift
54+
done
55+
56+
# Set number of events in optns file
57+
if [ ! $NEV -eq -1 ]; then
58+
echo "Setting number of events to $NEV"
59+
else
60+
echo "Number of events not set, defaulting to 10..."
61+
NEV=10
62+
fi
63+
64+
# Generation of event pool with pythia8 (10000 events) in a evtpool.root file
65+
${O2DPG_ROOT}/MC/run/examples/event_pool.sh --make
66+
67+
# Starting simulation with Hybrid generator
68+
${O2_ROOT}/bin/o2-sim --noGeant -j $JOBS --field ccdb --vertexMode kCCDB --run 300000 --configKeyValues "MFTBase.buildAlignment=true;GeneratorHybrid.configFile=$PWD/hybridcocktail.json;GeneratorHybrid.randomize=false;${more}" -g hybrid -o genevents --timestamp 1546300800000 --seed 836302859 -n $NEV

0 commit comments

Comments
 (0)