Skip to content

Commit ff4fa88

Browse files
committed
Implementation of cocktail generation
Works for sequence generation. SubFractions JSON syntax is implemented, but it does not work yet during the generation. * Updated Hybrid example
1 parent a14603d commit ff4fa88

File tree

7 files changed

+262
-21
lines changed

7 files changed

+262
-21
lines changed

Generators/include/Generators/GeneratorHybrid.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ 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+
std::vector<std::vector<int>> mCocktailFractions;
105+
101106
// Create a task arena with a specified number of threads
102107
std::thread mTBBTaskPoolRunner;
103108
tbb::concurrent_bounded_queue<int> mInputTaskQueue;

Generators/src/GeneratorHybrid.cxx

Lines changed: 103 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,63 @@ 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+
if (group.HasMember("fractions")) {
512+
const auto& subfrac = group["fractions"];
513+
mCocktailFractions.push_back({});
514+
for (const auto& frac : subfrac.GetArray()) {
515+
mCocktailFractions.back().push_back(frac.GetInt());
516+
}
517+
if (mGroups.back().size() != mCocktailFractions.back().size()) {
518+
LOG(fatal) << "Number of fractions does not match the number of generators in the cocktail";
519+
return false;
520+
}
521+
} else {
522+
LOG(warn) << "Fractions not provided for cocktail group " << mGroups.size() - 1 << " setting all fractions to 1";
523+
mCocktailFractions.push_back({});
524+
for (int i = 0; i < mGroups.back().size(); i++) {
525+
mCocktailFractions.back().push_back(1);
526+
}
527+
}
528+
}
529+
// Check if mGroups items contain the same number twice and ensure all items are unique across groups
530+
std::unordered_set<int> allItems;
531+
for (const auto& group : mGroups) {
532+
std::unordered_set<int> uniqueItems;
533+
for (const auto& item : group) {
534+
if (!uniqueItems.insert(item).second) {
535+
LOG(fatal) << "Duplicate generator index " << item << " found in a cocktail group";
536+
return false;
537+
}
538+
if (!allItems.insert(item).second) {
539+
LOG(fatal) << "Duplicate generator index " << item << " found in the cocktails";
540+
return false;
541+
}
542+
}
543+
}
544+
// Check if allItems is missing any generator index and create single gen groups for them
545+
// Fractions for these generators are the back ones in mFractions
546+
for (int i = 0; i < mInputGens.size(); i++) {
547+
if (allItems.find(i) == allItems.end()) {
548+
LOG(info) << "Generator index " << i << " is missing in the cocktails";
549+
LOG(info) << "Setting up a group for generator " << mInputGens[i];
550+
mGroups.push_back({i});
551+
}
552+
}
553+
}
554+
468555
// Get fractions and put them in mFractions
469556
if (doc.HasMember("fractions")) {
470557
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. Subfractions are still not implemented, but the JSON syntax to be used is already in place. For now 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: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
"fractions": [
49+
1,
50+
1
51+
]
52+
},
53+
{
54+
"group": [
55+
2,
56+
3
57+
],
58+
"fractions": [
59+
1,
60+
1
61+
]
62+
}
63+
],
64+
"fractions": [
65+
1,
66+
1,
67+
1
68+
]
69+
}
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)