Skip to content

Commit 5c65381

Browse files
committed
Edited POWHEG using parallel generation and manyseeds
1 parent 8e6e7ab commit 5c65381

File tree

1 file changed

+138
-30
lines changed

1 file changed

+138
-30
lines changed

MC/config/PWGGAJE/external/generator/generator_pythia8_powheg.C

Lines changed: 138 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ R__ADD_INCLUDE_PATH($O2DPG_MC_CONFIG_ROOT)
44
#include "Pythia8/Pythia.h"
55
#include "Generators/GeneratorPythia8Param.h"
66
#include "CommonUtils/FileSystemUtils.h"
7+
#include <thread>
78
// Pythia8 generator with POWHEG
89
//
910
// Author: Marco Giacalone (marco.giacalone@cern.ch)
@@ -13,7 +14,7 @@ R__ADD_INCLUDE_PATH($O2DPG_MC_CONFIG_ROOT)
1314
generator/generator_pythia8_powheg.C;GeneratorExternal.funcName=\
1415
getGeneratorJEPythia8POWHEG(\"powheg.input\",\"${O2DPG_MC_CONFIG_ROOT}/MC/config/PWGGAJE/pythia8/generator/pythia8_powheg.cfg\")"
1516
// or with iniFile
16-
// o2-sim -g external --noGeant -n 2 -j 8 --configFile $O2DPG_MC_CONFIG_ROOT/MC/config/PWGGAJE/ini/GeneratorPythia8POWHEG.ini
17+
// o2-sim -g external --noGeant -n 2 -j 8 --configFile $O2DPG_MC_CONFIG_ROOT/MC/config/PWGGAJE/ini/GeneratorPythia8POWHEG_beauty.ini
1718

1819
namespace o2
1920
{
@@ -22,10 +23,11 @@ namespace eventgen
2223

2324
using namespace Pythia8;
2425

25-
// Pythia8 generator using POWHEG data that are generated during the initialization
26-
// of the external generator. The POWHEG configuration file is copied to the current
27-
// directory with the right name and the POWHEG events are generated using the executable
28-
// specified via the type parameter, namely:
26+
// Pythia8 generator using POWHEG data that are generated partially during the initialization
27+
// of the external generator and then during the generateEvent when mNMaxPerJob is reached. The first time
28+
// all the configuration files are created so that the other jobs can be run much faster (and in parallel in the future)
29+
// The POWHEG configuration file is copied to the current directory with the right name and the POWHEG events are generated
30+
// using the executable specified via the type parameter, namely:
2931
// 0: pwhg_main_hvq
3032
// 1: pwhg_main_W
3133
// 2: pwhg_main_Z
@@ -35,31 +37,66 @@ class GeneratorJEPythia8POWHEG : public o2::eventgen::GeneratorPythia8
3537
{
3638
public:
3739
/// default constructor
38-
GeneratorJEPythia8POWHEG(std::string confpath = "pwgpath", short int type = 0)
40+
GeneratorJEPythia8POWHEG(std::string confpath = "pwgpath", short int type = 0, int maxEventsPerJob = 50)
3941
{
4042
// Assign events to generate with POWHEG
4143
unsigned int nPowhegEvents = getTotalNEvents();
4244
if (nPowhegEvents == 0) {
4345
LOG(fatal) << "Number of events not set or set to 0.";
4446
exit(1);
4547
}
46-
// Check on nEvents to generate with POWHEG
47-
// due to integer limit hardcoded in the generator
48-
if (nPowhegEvents > std::numeric_limits<int>::max()) {
49-
LOG(fatal) << "Number of events for POWHEG exceeds the maximum allowed value";
48+
// POWHEG has an integer limit hardcoded for the nEvents, but
49+
// with the multiple jobs setup this is not an issue (an error will automatically be thrown)
50+
mNMaxPerJob = maxEventsPerJob;
51+
if (mNMaxPerJob < 1) {
52+
LOG(fatal) << "Number of events per job are set to 0 or lower.";
5053
exit(1);
5154
}
55+
mNFiles = nPowhegEvents / mNMaxPerJob;
56+
if (nPowhegEvents % mNMaxPerJob != 0)
57+
{
58+
mNFiles++;
59+
}
60+
gRandom->SetSeed(0);
61+
if(!confMaker(confpath))
62+
{
63+
LOG(fatal) << "Failed to edit POWHEG configuration file";
64+
exit(1);
65+
}
66+
mPowhegConf = confpath;
67+
// Get POWHEG executable to use
68+
if (type >= mPowhegGen.size()) {
69+
LOG(warn) << "Available POWHEG generators are:";
70+
for (int k = 0; k < mPowhegGen.size(); k++)
71+
{
72+
LOG(warn) << "\t" << k << ": " << mPowhegGen[k];
73+
}
74+
LOG(fatal) << "POWHEG generator type " << type << " not found";
75+
exit(1);
76+
} else {
77+
LOG(info) << "Running POWHEG using the " << mPowhegGen[type] << " executable";
78+
// Generate the POWHEG events
79+
mExePOW = mPowhegGen[type] + " &";
80+
system(mExePOW.c_str());
81+
}
82+
};
83+
84+
Bool_t confMaker(std::string confpath = "pwgpath", bool parallel = false)
85+
{
5286
// Check if file exist and is not empty
5387
if (std::filesystem::exists(confpath) && std::filesystem::file_size(confpath) > 0) {
5488
// Copy the file to the current directory
5589
ifstream src(confpath);
5690
ofstream dst("powheg.input");
57-
gRandom->SetSeed(0);
5891
int seed = gRandom->Integer(900000000);
5992
bool isseed = false;
6093
bool isnumevts = false;
94+
if (mCurrFile == mNFiles - 1 && getTotalNEvents() % mNMaxPerJob != 0) {
95+
mNMaxPerJob = getTotalNEvents() % mNMaxPerJob;
96+
}
6197
std::string line;
62-
while (std::getline(src, line)) {
98+
while (std::getline(src, line))
99+
{
63100
if (line.find("iseed") != std::string::npos)
64101
{
65102
// Set the seed to the random number
@@ -69,56 +106,127 @@ public:
69106
if (line.find("numevts") != std::string::npos)
70107
{
71108
// Set the number of events to the number of events defined in the configuration
72-
line = "numevts " + std::to_string(nPowhegEvents);
109+
line = "numevts " + std::to_string(mNMaxPerJob);
73110
// replace it in the file
74111
isnumevts = true;
75112
}
76113
dst << line << std::endl;
77114
}
78-
if (!isseed) {
115+
if (!isseed)
116+
{
79117
dst << "iseed " << seed << std::endl;
80118
}
81-
if (!isnumevts) {
82-
dst << "numevts " << nPowhegEvents << std::endl;
119+
if (!isnumevts)
120+
{
121+
dst << "numevts " << mNMaxPerJob << std::endl;
122+
}
123+
if (parallel)
124+
{
125+
dst << "manyseeds 1" << std::endl; // Enables the usage of pwgseeds.dat file to set the seed in parallel mode
126+
dst << "parallelstage 4" << std::endl; // Allows event generation based on pre-generated POWHEG configuration files (needed for certain configurations)
83127
}
84128
src.close();
85129
dst.close();
86130
} else {
87131
LOG(fatal) << "POWHEG configuration file not found or empty" << std::endl;
88-
exit(1);
132+
return false;
89133
}
90-
// Get POWHEG executable to use
91-
if (type >= mPowhegGen.size()) {
92-
LOG(warn) << "Available POWHEG generators are:";
93-
for (int k = 0; k < mPowhegGen.size(); k++)
94-
{
95-
LOG(warn) << "\t" << k << ": " << mPowhegGen[k];
134+
return true;
135+
}
136+
137+
Bool_t startPOW()
138+
{
139+
if(mCurrFile == 1) {
140+
if (!confMaker(mPowhegConf, true)) {
141+
LOG(fatal) << "Failed to edit POWHEG configuration with parallelisation";
142+
return false;
96143
}
97-
LOG(fatal) << "POWHEG generator type " << type << " not found";
98-
exit(1);
144+
}
145+
LOG(info) << "Starting POWHEG job " << mCurrFile+1 << " of " << mNFiles;
146+
system(("echo " + std::to_string(mCurrFile - 1) + " | " + mExePOW).c_str());
147+
return true;
148+
}
149+
150+
Bool_t POWchecker() {
151+
// Check if the POWHEG events file exists
152+
LOG(info) << "Waiting for " << mLHEFoutput << " to exist";
153+
while (!std::filesystem::exists(mLHEFoutput.c_str()))
154+
{
155+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
156+
}
157+
LOG(info) << "POWHEG events file for job " << mCurrFile << " found";
158+
return true;
159+
}
160+
161+
// Check for the POWHEG events file existance
162+
Bool_t Init() override
163+
{
164+
// Check if the POWHEG events file exists
165+
if(POWchecker()) {
166+
return GeneratorPythia8::Init();
99167
} else {
100-
LOG(info) << "Running POWHEG using the " << mPowhegGen[type] << " executable";
101-
// Generate the POWHEG events
102-
system(mPowhegGen[type].c_str());
168+
return false;
169+
}
170+
};
171+
172+
// Set Generator ReadEvent to wait for the POWHEG events
173+
Bool_t generateEvent() override
174+
{
175+
/** Reinitialise when EOF is reached **/
176+
if (mPythia.info.atEndOfFile())
177+
{
178+
if(mCurrFile == 0)
179+
{
180+
mPythia.readString("Beams:newLHEFsameInit = on");
181+
// Create pwgseeds.dat file with a random seed for each line
182+
std::ofstream seedfile("pwgseeds.dat");
183+
for (int i = 0; i < mNFiles - 1; i++)
184+
{
185+
seedfile << gRandom->Integer(900000000) << std::endl;
186+
}
187+
seedfile.close();
188+
}
189+
mCurrFile++;
190+
mLHEFoutput = Form("pwgevents-%04d.lhe", mCurrFile - 1);
191+
mPythia.readString(Form("Beams:LHEF = %s", mLHEFoutput.c_str()));
192+
if(!startPOW())
193+
{
194+
return false;
195+
}
196+
if (POWchecker()) {
197+
// If Pythia fails to initialize, exit with error.
198+
if (!mPythia.init())
199+
{
200+
LOG(fatal) << "Failed to init \'Pythia8\': init returned with error";
201+
return false;
202+
}
203+
}
103204
}
205+
return GeneratorPythia8::generateEvent();
104206
};
105207

106208
private:
107209
const std::vector<std::string> mPowhegGen = {"pwhg_main_hvq", "pwhg_main_W", "pwhg_main_Z", "pwhg_main_dijet", "pwhg_main_directphoton"}; // POWHEG executables
210+
short int mNFiles = 1;
211+
short int mCurrFile = 0;
212+
std::string mExePOW = "";
213+
std::string mPowhegConf = "";
214+
std::string mLHEFoutput = "pwgevents.lhe";
215+
int mNMaxPerJob = 50;
108216
};
109217

110218
} // namespace eventgen
111219
} // namespace o2
112220

113221
/** generator instance and settings **/
114222

115-
FairGenerator *getGeneratorJEPythia8POWHEG(std::string powhegconf = "pwgpath", std::string pythia8conf = "", short int type = 0)
223+
FairGenerator *getGeneratorJEPythia8POWHEG(std::string powhegconf = "pwgpath", std::string pythia8conf = "", short int type = 0, int maxEventsPerJob = 1e4)
116224
{
117225
using namespace o2::eventgen;
118226
// Expand paths for the POWHEG configuration file
119227
powhegconf = o2::utils::expandShellVarsInFileName(powhegconf);
120228
LOG(info) << "Using POWHEG configuration file: " << powhegconf;
121-
auto myGen = new GeneratorJEPythia8POWHEG(powhegconf, type);
229+
auto myGen = new GeneratorJEPythia8POWHEG(powhegconf, type, maxEventsPerJob);
122230
if(GeneratorPythia8Param::Instance().config.empty() && pythia8conf.empty()) {
123231
LOG(fatal) << "No configuration provided for Pythia8";
124232
}

0 commit comments

Comments
 (0)