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.