Seeding algorithm PRNG
Correctly seeding pseudo-random number generators (PRNG) is important to ensuring reproducible and good-quality randomness. A common pattern is to reinitialize each algorithm’s PRNG with a unique seed for each processed event.
UniqueIDGenSvc service
The UniqueIDGenSvc
Gaudi service can generate unique size_t
values that can be used as PRNG seeds, based on an event number, run number, and algorithm name.
The service can be included in a steering file by:
from Configurables import UniqueIDGenSvc
uidgen_svc = UniqueIDGenSvc()
The service can be configured with a central seed from which the unique values will be derived. This seed can be configured with the Seed
property:
uidgen_svc.Seed = 987654321
k4run <steering-file> --UniqueIDGenSvc.Seed 987654321
Using UniqueIDGenSvc in algorithms
To use the UniqueIDGenSvc
in a Gaudi algorithm first include the header file and declare a member variable:
#include <k4Interface/IUniqueIDGenSvc.h>
SmartIF<IUniqueIDGenSvc> m_service;
Then, initialize the service in:
StatusCode ExampleAlgorithm::initialize() {
m_service = service("UniqueIDGenSvc");
Then, use the service during execution (execute
member function for the algorithms derived from Gaudi::Algorithm
or operator()
for functional algorithms):
StatusCode ExampleAlgorithm::execute(const EventContext&) const {
// Instead of passing event number and run number separately,
// an overload accepting EventHeader or EventHeaderCollection can be also used.
StatusCode sc = m_service->getUniqueID(1, 2, name());
m_service->getUniqueID(1, 2, name());
}
Seeding functional algorithm example
In the EDM4hep data model, the event number and run number can be obtained from an EventHeaderCollection
.
The following is an example of a functional algorithm using EventHeaderCollection
and UniqueIDGenSvc
service to seed a PRNG.
To begin, some boilerplate code is needed to declare the EventHeaderCollection
as an algorithm input. In this example, the algorithm will also generate and produce a podio::UserDataCollection<double>
containing random numbers generated during its execution.
The name of input EventHeaderCollection
object can be customized using the EventHeaderCollection
property, with EventHeader
set as the default name. Similarly, the name of the output podio::UserDataCollection<double>
object can be adjusted via the OutputCollection
property, which defaults to RandomNumbers
.
class ExampleRNGSeedingAlg final
: public k4FWCore::Transformer<podio::UserDataCollection<double>(const edm4hep::EventHeaderCollection&)> {
public:
ExampleRNGSeedingAlg(const std::string& name, ISvcLocator* svcLoc)
: Transformer(name, svcLoc, {KeyValues("EventHeaderCollection", {"EventHeader"})},
{KeyValues("OutputCollection", {"RandomNumbers"})}) {}
Then, declare a member variable for the service interface and locate the service during algorithm initialization:
private:
SmartIF<IUniqueIDGenSvc> m_uniqueIDSvc{nullptr};
public:
StatusCode initialize() final {
m_uniqueIDSvc = service("UniqueIDGenSvc");
if (!m_uniqueIDSvc) {
error() << "Unable to locate the UniqueIDGenSvc" << endmsg;
return StatusCode::FAILURE;
}
return StatusCode::SUCCESS;
}
During algorithm execution the EventHeaderCollection
can be used to obtain a unique value from the m_uniqueIDSvc
, then the value can be used as a seed for PRNG. In this example the PRNG is then used to generate a random value and push it to an output collection.
public:
podio::UserDataCollection<double> operator()(const edm4hep::EventHeaderCollection& evtHeader) const final {
// obtain unique value from the first header in a collection
auto uid = m_uniqueIDSvc->getUniqueID(evtHeader, name());
// or from a given EventHeader object
// auto uid = m_uniqueIDSvc->getUniqueID(evtHeader[0], name());
// seed TRandom3 or some other PRNG of your choice
auto prng = TRandom3(uid);
auto coll = podio::UserDataCollection<double>();
coll.push_back(prng.Rndm());
return coll;
}
A complete code example can be found here.