From 75f9579036347563a7d0233d088b2a8871fe2056 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 8 Jul 2024 14:34:03 +0200 Subject: [PATCH] Pythia8 seeding improvements This commit improves the seeding of Pythia8 in O2. The seeding... (a) ... is now done as part of the object's Init function automatically. Users are no longer required to provide own seeding logic, which can significantly simplify the setup. By default, Pythia8 will seed against ROOT TRandom::GetSeed, which is itself set to values of the command line option `--seed`, used in the o2-sim ... or o2-sim-dpl-eventgen execetuables (which are the 2 places undertaking event generation). This setup guarantees that ``` o2-sim-dpl-eventgen --generator pythiapp --seed x ``` will result in different event sequences when x changes. (b) Users can simply set the seed via a `setInitialSeed` function on the GeneratorPythia8 object. The function must be called before GeneratorPythia8::Init is executed. So calling it right after the constructor is fine. Example code (e.g., inside user Generator macro) is: ``` auto mygen = new o2::eventgen::GeneratorPythia8(); long seed = atol(getenv(ALIEN_PROC_ID)); if(!mygen->setInitialSeed(seed)) { std::cerr << "seeding failed"; } ``` In result, the commit leads to a simplification of the Pythia8 setup also in GeneratorFactory. --- .../include/Generators/GeneratorPythia8.h | 15 ++++++ Generators/src/GeneratorFactory.cxx | 8 +--- Generators/src/GeneratorPythia8.cxx | 48 +++++++++++++++++++ 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/Generators/include/Generators/GeneratorPythia8.h b/Generators/include/Generators/GeneratorPythia8.h index a1c1ab0c87966..447f81b99b2c2 100644 --- a/Generators/include/Generators/GeneratorPythia8.h +++ b/Generators/include/Generators/GeneratorPythia8.h @@ -163,6 +163,12 @@ class GeneratorPythia8 : public Generator typedef std::function UserFilterFcn; + /// A function allowing to set the initial value used in seeding Pythia. + /// The function needs to be called before GeneratorPythia8::Init is invoked. + /// The function value will be true upon success, or false if either Init has already been called or if the see is smaller than 0. + /// For values of seed >= 0, a truncation to the range [0:90000000] will automatically take place via a modulus operation. + bool setInitialSeed(long seed); + protected: /** copy constructor **/ GeneratorPythia8(const GeneratorPythia8&); @@ -251,6 +257,9 @@ class GeneratorPythia8 : public Generator void getNfreeSpec(const Pythia8::Info& info, int& nFreenProj, int& nFreepProj, int& nFreenTarg, int& nFreepTarg); /** @} */ + /// performs seeding of the random state of Pythia (called from Init) + void seedGenerator(); + /** Pythia8 **/ Pythia8::Pythia mPythia; //! @@ -269,6 +278,12 @@ class GeneratorPythia8 : public Generator void initUserFilterCallback(); bool mApplyPruning = false; + bool mIsInitialized = false; // if Init function has been called + long mInitialRNGSeed = -1; // initial seed for Pythia random number state; + // will be transported to Pythia in the Init function through the Pythia::readString("Random:seed") mechanism. + // Value of -1 means unitialized; 0 will be time-dependent and values >1 <= MAX_SEED concrete reproducible seeding + + constexpr static long MAX_SEED = 900000000; ClassDefOverride(GeneratorPythia8, 1); diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index 85303e3cd6269..5b3a5b5330617 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -69,13 +69,9 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair auto makePythia8Gen = [](std::string& config) { auto gen = new o2::eventgen::GeneratorPythia8(); if (!config.empty()) { - LOG(info) << "Reading \'Pythia8\' base configuration: " << config << std::endl; - gen->readFile(config); + LOG(info) << "Setting \'Pythia8\' base configuration: " << config << std::endl; + gen->setConfig(config); // assign config; will be executed in Init function } - auto seed = (gRandom->TRandom::GetSeed() % 900000000); - LOG(info) << "Using random seed from gRandom % 900000000: " << seed; - gen->readString("Random:setSeed on"); - gen->readString("Random:seed " + std::to_string(seed)); return gen; }; #endif diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index a365301d2e02d..59cef6dae5813 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -71,6 +71,46 @@ GeneratorPythia8::GeneratorPythia8(const Char_t* name, const Char_t* title) : Ge mInterfaceName = "pythia8"; } +bool GeneratorPythia8::setInitialSeed(long seed) +{ + // check first of all if Init not yet called and seed not <0 + if (mIsInitialized) { + return false; + } + if (seed < 0) { + return false; + } + // sets the initial seed and applies the correct Pythia + // range + mInitialRNGSeed = seed % (MAX_SEED + 1); + LOG(info) << "GeneratorPythia8: Setting initial seed to " << mInitialRNGSeed; + return true; +} + +/*****************************************************************/ +void GeneratorPythia8::seedGenerator() +{ + /// Function is seeding the Pythia random numbers. + /// In case a completely different logic is required by users, + /// we could make this function virtual or allow to set/execute + /// a user-given lambda function instead. + + /// Note that this function is executed **before** the Pythia8 + /// user config file is read. So the config file should either not contain seeding information ... or can be used to override seeding logic. + + auto seed = mInitialRNGSeed; + if (seed == -1) { + // Will use the mInitialRNGSeed if it was set. + // Otherwise will seed the generator with the state of + // TRandom::GetSeed. This is the seed that is influenced from + // SimConfig --seed command line options options. + seed = (gRandom->TRandom::GetSeed() % (MAX_SEED + 1)); + LOG(info) << "GeneratorPythia8: Using random seed from gRandom % 900000001: " << seed; + } + mPythia.readString("Random:setSeed on"); + mPythia.readString("Random:seed " + std::to_string(seed)); +} + /*****************************************************************/ Bool_t GeneratorPythia8::Init() @@ -80,6 +120,12 @@ Bool_t GeneratorPythia8::Init() /** init base class **/ Generator::Init(); + /** Seed the Pythia random number state. + The user may override this seeding by providing separate + Random:setSeed configurations in the configuration file. + **/ + seedGenerator(); + /** read configuration **/ if (!mConfig.empty()) { std::stringstream ss(mConfig); @@ -147,6 +193,8 @@ Bool_t GeneratorPythia8::Init() initUserFilterCallback(); + mIsInitialized = true; + /** success **/ return true; }