Random Number Generator Service

Complete: 5

Introduction

The Random Number Generator Service provides a central location for managing the engines used to generate random numbers. The service creates a set of engines for each module label in its configuration and initializes them. When configured for replay, it saves and restores the engine states as necessary. The service automatically keeps track of which module is active and when a module asks for an engine, it automatically returns an engine associated with that module. The module needs to supply the current StreamID or LuminosityBlockIndex when requesting an engine. The module should only generate random numbers with an engine when the module is processing an event associated with the StreamID used to get the engine or during a global beginLuminosityBlock method associated with the LuminosityBlockIndex used to get the engine. Random numbers should not be generated at other times. The module can use the engine directly to generate random numbers or instantiate a CLHEP distribution with the engine and use the distribution to generate random numbers.

The service supports:

  • Configurable seeds and engine types.

  • Replay of the last event of a prior process. This is useful for debugging problems when a process terminates abnormally.

  • Replay of one or more events in a prior process, where one can start at any particular event in the prior process. This is useful for studying events that are particularly interesting without spending the time to replay all the events in the prior process.

  • Multithread mode where events and/or luminosity blocks are processed concurrently. The service ensures the same engine is not run on more than one thread at a time to avoid data races. The service ensures the different engines used for streams and concurrent luminosity blocks have unique seeds and generate distinct sequences of random numbers.

The service was modified significantly in CMSSW release 3_11_X and again in 7_1_X. If you are trying to use a release earlier than 7_1_X, please look at the last section below on backward compatibility.

Example: C++ Code for a Module Using the Service

Here are the critical two lines of code one needs to use the service.

   edm::Service<edm::RandomNumberGenerator> rng;
   CLHEP::HepRandomEngine& engine = rng->getEngine(event.streamID());

Here are these two lines put in the context of a module's function definitions:

#include "FWCore/Framework/interface/Event.h"
#include "FWCore/ServiceRegistry/interface/Service.h"
#include "FWCore/Utilities/interface/Exception.h"
#include "FWCore/Utilities/interface/RandomNumberGenerator.h"
#include "CLHEP/Random/RandomEngine.h"

// module constructor
MyModule::MyModule(edm::ParameterSet const& pset) {
  edm::Service<edm::RandomNumberGenerator> rng;
  if(!rng.isAvailable()) {
    throw cms::Exception("Configuration")
      << "MyModule requires the RandomNumberGeneratorService,\n"
         "which is not present in the configuration file. You must add\n"
         "the service in the configuration file or remove the modules that\n"
         "require it.\n";
  }
}

// The method processing the event (could be analyze or produce or filter)
bool MyModule::filter(edm::Event& event, edm::EventSetup const&) {
  edm::Service<edm::RandomNumberGenerator> rng;
  CLHEP::HepRandomEngine& engine = rng->getEngine(event.streamID());
  double randomNumber = engine.flat();
...

Most modules will not need this, but it is also possible to get an engine during the global beginLuminosityBlock method as shown below. In beginLuminosityBlock the random numbers are intended to be used for some type of initialization. Within a process for a particular module, the sequences are reset at the beginning of each call to intentionally give the same random sequences. This provides the same initialization on different threads and helps replay succeed after the output from the different threads is combined.

void MyModule::beginLuminosityBlock(edm::LuminosityBlock const& lumi, edm::EventSetup const&) {
  edm::Service<edm::RandomNumberGenerator> rng;
  CLHEP::HepRandomEngine& engine = rng->getEngine(lumi.index());
...

Each engine has a function named flat that will return a random number whose probability distribution is uniformly distributed between 0 and 1. Often you will want some other distribution and CLHEP provides a set of distribution classes that transforms the output of the engine to have different probability distributions. For example for a flat distribution over range from 0 to 100 the following will work:

#include "CLHEP/Random/RandFlat.h"
...
double min = 0.0;
double max = 100.0;
// ALWAYS pass a pointer to an engine to shoot!!!
double randomNumber2 = CLHEP::RandFlat::shoot(&engine, min, max) ;
...

It is important to always pass a pointer to an engine to a call to a CLHEP shoot method. If the engine argument is omitted the code will compile and probably run. But the problem is that a global engine will be used. This causes two problems. First, the seed assigned to the module is not used by that engine. This could lead to duplicate random sequences being generated which causes serious statistical problems. It also breaks replay. (OscarProducer is a special exception to this rule as it explicitly sets this global engine because GEANT uses it)

Here is another way to use a distribution:

#include "CLHEP/Random/RandPoissonQ.h"
...
float meanNumberOfNoisyChannels = ...
edm::Service<edm::RandomNumberGenerator> rng;
CLHEP::HepRandomEngine& engine = rng->getEngine(event.streamID());
// ALWAYS pass a reference to the engine to a distribution constructor!!!
CLHEP::RandPoissonQ randPoissonQ(engine, meanNumberOfNoisyChannels);
int numberOfNoisyChannels = randPoissonQ.fire();
...

It is very important to always pass a reference to the engine to the constructor of a CLHEP distribution. If you pass a pointer instead of a reference, the distribution will think it owns it and destroy the engine in its destructor. The service owns it and will also destroy it. This will crash the entire program because of a double delete memory error.

There are several other types of distributions available in CLHEP and any should work. Consult the CLHEP code or documentation for details. Often it does not matter if you use shoot or fire. In some cases there are performance differences. If that is an issue it is probably worth inspecting the CLHEP code to see how the distribution is implemented.

There are two places in CLHEP distributions that could cause problems because they could cache values in one event and use them in the next. This breaks replay. The RandGauss distribution does this unless a function is called to clear the cache by each module when it starts to process each event. In the RandFlat and RandBit distributions, the shootBit and fireBit functions cannot be used safely ever.

Note that CLHEP has been updated for its Random distributions to be thread safe when different distribution objects are used concurrently. Often this was done by making static or global variables thread local, because this was the easiest way to implement the code. There may be room for further performance improvements in this implementation of the distributions and this might be worth pursuing if profiling ever shows them to be using significant cpu time.

It is normally not worth the effort, but one might gain in performance if one cached either the engines or the distributions. One would have to use a stream specific cache or a vector indexed by the value in the StreamID. One has to be careful implementing this caching in a module to always use the engine or distribution associated with the current stream to generate random numbers. Otherwise data races could result. And the caching mechanism itself would need to avoid thread safety issues.

Sources and Other Objects

Sources are not allowed to generate random numbers. If a source calls the getEngine function of the service an exception will be thrown. If a source generates random numbers without using the service, then the replay feature will not work for processes that use that source.

Only modules are allowed to generate random numbers. Specifically these inherit from EDAnalyzer, EDFilter, EDProducer, or OutputModule. No other objects are allowed to use random numbers. If something else tries, the result will be the same as if a source tried.

Example: Configuration File for a Process That Generates Random Numbers

Here is an example of a complete configuration file with comments that explain the details and various options available.

import FWCore.ParameterSet.Config as cms
process = cms.Process("XXXX")

process.RandomNumberGeneratorService = cms.Service("RandomNumberGeneratorService",

    # Include a PSet for each module label that needs a
    # random engine.  The name is the module label.
    # You must supply a seed or seeds.
    # Optionally an engine type can be specified
    t1 = cms.PSet(
        initialSeed = cms.untracked.uint32(81)
    ),
    t2 = cms.PSet(
        initialSeed = cms.untracked.uint32(83),
        engineName = cms.untracked.string('TRandom3')
    ),
    t3 = cms.PSet(
        engineName = cms.untracked.string('HepJamesRandom'),
        initialSeed = cms.untracked.uint32(84)
    ),
    t4 = cms.PSet(
        engineName = cms.untracked.string('RanecuEngine'),
        initialSeedSet = cms.untracked.vuint32(1, 2)
    ),

    # This is optional.  If you want the service to save the state
    # of all engines to a separate text file which is overwritten before
    # modules begin processing on each event. The text file is only
    # needed for one type of replay. The filename can be anything
    # you want but the replay process will need to reference it.
    saveFileName = cms.untracked.string('RandomEngineStates.txt')
)

# These module labels and the module class are included just
# as an example.  They should be replaced with whatever module
# labels and classes are actually needed.
process.t1 = cms.EDAnalyzer("TestRandomNumberServiceAnalyzer")
process.t2 = cms.EDAnalyzer("TestRandomNumberServiceAnalyzer")
process.t3 = cms.EDAnalyzer("TestRandomNumberServiceAnalyzer")
process.t4 = cms.EDAnalyzer("TestRandomNumberServiceAnalyzer")


# This is optional.  If you want the service to save the state
# of all engines to each Event and LuminosityBlock, then
# include this producer here and in the path.  This is only
# needed for one type of replay.  The module label can be
# anything, but the replay process will need to reference it.
process.randomEngineStateProducer = cms.EDProducer("RandomEngineStateProducer")

# The RandomNumberGeneratorService should work with
# any kind of source
process.source = cms.Source("EmptySource")

process.maxEvents = cms.untracked.PSet(
    input = cms.untracked.int32(5)
)

process.out = cms.OutputModule("PoolOutputModule",
    fileName = cms.untracked.string('xxxx.root')
)

process.p = cms.Path(process.t1+process.t2+process.t3+process.t4+process.randomEngineStateProducer)
process.o = cms.EndPath(process.out)

Engine Types

If you do not specify an engine type, the service will use the type HepJamesRandom. There are currently 4 possible types: TRandom3, HepJamesRandom, MixMaxRng, and RanecuEngine. The first two are used often in CMS, but no one is using RanecuEngine. It would be easy to implement any of the other CLHEP engine types if there was a request for it.

TRandom3 has the best random properties, but also the largest state. It will accept one 32 bit integer as seed. HepJamesRandom also has excellent random properties and its state is not as large as TRandom3. It will accept one integer from 0 to 900,000,000 as a seed. RanecuEngine has a very small state but inferior random properties. It requires two seeds, both integers that fit in 31 bits.

Underneath, the TRandom3 engine is the one from ROOT. It has been wrapped underneath a CLHEP interface to make it work nicely in the service, although only the functions the service uses were actually implemented. The following is from the header of the TRandom3 class in ROOT:

 Random number generator class based on
   M. Matsumoto and T. Nishimura,
   Mersenne Twistor: A 623-diminsionally equidistributed
   uniform pseudorandom number generator
   ACM Transactions on Modeling and Computer Simulation,
   Vol. 8, No. 1, January 1998, pp 3--30.

 For more information see the Mersenne Twistor homepage
   http://www.math.keio.ac.jp/~matumoto/emt.html

 Advantage: large period 2**19937-1
            relativly fast
              (only two times slower than TRandom, but
               two times faster than TRandom2)
 Drawback:  a relative large internal state of 624 integers

The article by F. James (Comp. Phys. Comm. 60 (1990) 329) reviews some random engine types, including HepJamesRandom (also known as RANMAR) and RanecuEngine. Here is a brief summary.

The HepJamesRandom engine provides 900,000,000 independent pseudorandom sequences with a length of on average 1e30. These are initialized by selecting an integer between 0 and 900,000,000 as a seed. Given the same seed the engines will repeat the same sequence bitwise on different machines. The algorithm is fast and produces good pseudorandom sequences. The only downside is that to store the internal state of the engine requires a little more than 200 integers (4 bytes each) for each engine.

The algorithm used by RanecuEngine has the advantage that its internal state is entirely stored in two 4-byte integers, which makes it convenient to store. But this only allows 2e19 possible states. There are known issues with how long the individual subsequences are and how one selects seeds that do not result in overlapping sequences. One initializes the generator by specifying 2 positive integers (they must fit in 31 bits). Do not use this one unless you understand what you are doing and are sure its random properties are good enough for your purpose.

Support for the MixMaxRng was added in 2017. Some information about it can be found here: https://indico.cern.ch/event/679788/contributions/2784242/attachments/1556849/2449087/VIGeant4Valid.pdf

Ensuring Events are Generated with Distinct Sequences of Random Numbers

Next, I'll described how the sequences are managed in a simple job that does not involve replay, continuation, multiple threads, or the eventSeedOffset parameter. In this case, the engines will deliver to the function processing events random numbers that are continually stepping forward through the sequences. On the other hand if there is more than one beginLuminosityBlock, all of them will repeat the same sequence of random numbers as the first. What occurs during beginLuminosityBlock is initialization and it is intentional that the results of this are the same for all of them in the same process.

  1. During the preallocate signal (just before beginJob after all modules have been constructed), two engines are constructed for each module. One is used for events and is initialized using the seed passed in configuration. The other is used for beginLuminosityBlock and is initialized with the seed from the configuration plus one.
  2. The state of the engines used for beginLuminosityBlock is saved in a luminosity cache, also during the preallocate signal.
  3. Just before every beginLuminosityBlock the state of the engines used in beginLuminosityBlock is restored from the cache to their original state.
  4. The modules generate random numbers in beginLuminosityBlock
  5. After the input source reads the event but before any modules process the event, the state of all the engines used during event processing is saved to an event cache. This event cache and also the lumi cache are used by the separate producer that saves the engine states to the Event and LuminosityBlock.
  6. The modules generate random numbers during events

The reason all the luminosity blocks need to have the same sequences is that when files are merged the luminosity blocks are merged. If the saved states in the luminosity blocks are not the same, then replay becomes impossible.

At the moment (January 2011), these complexities are all irrelevant for standard simulation production because there is only one luminosity block per process and each process gets a different luminosity block number.

Before the Service Sees the Configuration

When producing a simulated dataset using many processes, it is important that the random seeds in the different processes be different. Otherwise the same events might be generated in the different processes, which will lead to incorrect physics results.

One way to do this is to manually edit the python configuration files and make the seeds for each process different. If there are many processes this is both time consuming and error prone. So the systems that manage many processes are designed to modify the seeds automatically

The details related to how each system does this are beyond scope of this TWIKI and probably will change more often than this TWIKI will be updated. It happens before the service ever sees the configuration and the service has no control over it. I will try to discuss it a little bit here, but users should understand what the system they are using does to avoid using the same seeds for different processes. Prod Agent, WM Agent, and CRAB are the three systems that I aware of, but there may be others. There is also nothing to prevent users or groups from writing their own scripts.

For example, CRAB will by default set the seeds in the different processes to random numbers. CRAB also has options that allow the seeds to pass through unmodified or increment each seed by one from one process to the next. See more details here CRAB documentation about incremental seeds.

WARNING Do not use the increment seeds option in CRAB if you also using the multithreaded mode, multicore mode or the eventSeedOffset parameter in your process, unless you understand exactly what you are doing. This can lead to multiple processes having the same seed.

Many of these systems use the python utility described here to reset the seeds: SWGuidePythonTips documentation about resetting seeds

Multithreaded Mode

The service automatically takes care of modifying the seeds when the process is run in multiple threads. This is a mode in which events and/or luminosity blocks can be processed concurrently on different threads. The advantage of this mode over simply runnning multiple independent processes concurrently is that the processes can partially share the same memory and reduce the overall memory resources required for a machine.

One issue with this mode is that a single engine object cannot be concurrently used on multiple threads. There will be data races (undefined behavior) if you try. One can safely create multiple engine objects of the same type and concurrently use those to generate random numbers different threads. The same is true of the distributions.

When using multiple engine objects, one has ensure they have different seeds so they do not produce the same random sequences. When saving and restoring the engine states one has to be careful to do the proper bookkeeping to save and restore the proper one. The service takes care of this automatically.

This is implemented as follows. The number of events that can be processed concurrently equals the number of streams. The service will create one engine for each stream. Each stream is given a unique StreamID. They are number from 0 to one less than the number of streams. In the preallocate signal (just before beginJob), each engine is reinitialized with a seed equal to the configured seed for the module plus the value in the StreamID. The service also creates additional engines, one for each possible concurrent luminosity block. The number of possible concurrent luminosity blocks is a separate configurable parameter independent of the number of streams. All these engines are given the same seed, which is the configured seed for the module plus the total number of streams.

Everything else works as described above. The event engines will proceed through their sequences without interuption until the process ends. The luminosity block engines are all reinitialized to the beginning of their sequences before all beginLuminosityBlock calls.

WARNING Do not use the increment seeds option in CRAB if you are also using the multithread mode. If you are using the eventSeedOffset parameter in your process, make sure it is always larger than the total number of streams . If either of these rules is violated, then multiple threads will have the same seed and generate the same events.

The ouput of a multithread process is combined into one output file. This is why it is important that the pseudorandom sequences in all the beginLuminosityBlock methods are the same. If this were not true, there would be problems with replay.

The parameter eventSeedOffset

If you run multiple processes on the same luminosity block and then merge them together and use random numbers and want to be able to use the replay features of the service, then you will need to use the eventSeedOffset parameter. (Note that here I am NOT discussing multiple threads, I am discussing multiple independent processes. In our current production workflows this does not happen and this parameter is not needed.)

To use this, first assign all the processes that process the same luminosity block the same seeds. Then give each a different value for the eventSeedOffset parameter.

Internally, the service will add this parameter to the seed for the engines that are used to process events, but not the engines used for luminosity blocks. This is very similar to what is done in multithread mode. If this is used in multithread mode, then it is very important that the value of the eventSeedOffset be greater than the number of streams.

This is a new parameter that did not exist before release 3_11_0_pre3. The work management systems like CRAB, Prod Agent, and WM Agent are not currently designed to use it yet. It is possible that it will be eliminated or its behavior modified in the future if it turns out that something different would work better with those systems. Time will tell.

WARNING Be very careful using this with a work management system. Because they randomize the seeds for every process it would be impossible to ensure independent processes handling the same luminosity block are given the same seed. So replay would not work.

WARNING If you use this parameter and are also using multithread mode, then make sure the value of eventSeedOffset is greater than the number of streams. Otherwise, multiple processes will end up using the same seeds and generate the same events.

What happens if multiple processes process the same luminosity block, but use different seeds? There will be message logger errors printed when the files are merged. And attempts to replay will be given different random numbers and not reproduce the prior process (except the events associated with the first luminosity block, replay would work for them anyway). Those would be the only two negative effects.

Finally, I should repeat that in the current production generation of simulation each process is assigned a different luminosity block number and this parameter is not needed in that case.

Replay

For this service, the goal of replay is to deliver exactly the same sequence of random numbers to each module for each event and also for the initialization that occurs in beginLuminosityBlock. Often in replay, the overall goal is to bitwise reproduce every calculation and result of a prior process. Sometimes the goal is only to reproduce some subset of the prior process. For example, one could replay one module only if that module's calculations did not depend on the output of any other module in the process.

For replay to work, a lot of things must be true that are outside of the control of the random number generator service.

  1. Only modules can be generating random numbers.
  2. All the modules must be using the engines in the service exclusively to generate their random numbers. It is not enough to get the seed from the service.
  3. The processing of an event in a module cannot depend on previous events.
  4. Random numbers can only be generated in the method that processes events and beginLuminosityBlock
  5. Any initialization done in beginLuminosityBlock that depends on random numbers must be repeated each time that method is called.

Instead of initializing in every beginLuminosityBlock, a module could check to see if the random number sequence would be the same as in the previous initialization and only initialize if it would be different. To do this, the module could generate one random number at the beginning of beginLuminosityBlock. In the first call and also if the initialization was performed, the value of that random number would need to be saved. The initialization would need to be performed if the value of the first random number was different than the value saved from the previous initialization and also the module would need to initialize the first time.

Replay will not work properly if random numbers are generated outside the event and global beginLuminosityBlock methods. If the following parameter is set in the configuration, then the service will throw an exception if any random numbers are generated in the begin and end methods for the stream itself, the stream run, or the stream luminosity block.

    enableChecking = cms.untracked.bool(True)

The engines have not been created yet when module constructors are running and there is no easy way to access them at other times.

There are other things that can cause an attempt to reproduce a prior process to fail.

  1. If a different machine is used, a single bit difference in the result of a calculation due to rounding or an algorithm difference in the chip might or might not cause a difference.
  2. It is conceivable a different compiler, environment, or operating system could also make a difference.
  3. Hardware problems can cause bit errors in processing. Even with good hardware this can happen at some low rate.
  4. Reading input sequentially from some external file other than the primary input by sequentially reading through input records and not having a mechanism to store which data was read and replay it in the replay job. Some pileup and nuclear interaction mixing has this problem now.
  5. Using RandGauss without each module clearing the cache on each event. Using shootBit or fireBit from RandFlat or RandBit.

Once something is slightly different then a single change in one of the millions of logical decisions can throw things out of sync completely. Note that these problems are more likely to cause a module to ask for an additional random number or not ask for one than to actually modify the sequence of random numbers.

There are probably other things that can cause reproducibility problems. It is a difficult thing to attempt. Someone will need to study this with CMS processes and if the replays fail it will take some careful study to determine whether the service is at fault or a module or something else. There are existing unit tests in the IOMC/RandomEngine package that demonstrate the service can reproduce the random sequences exactly in some simple use cases.

The normal thing one expects in a replay is to keep the configuration as similar as possible in the original and replay modes, but this is not necessary. Modules can be added or deleted. The user has to be aware of what he is doing and decide whether or not the change will disturb the replay. In the service, it is OK for there to be a different list of module labels configured for replay. When restoring the states in the replay process, the service will only restore the states for the engines for the module labels that were in both the original and replay service configurations. These engines are required to have the same engine type in both configurations. The seed needs to exist in the replay configuration but in the replay the seed value from the configuration is not used. If there were more module labels in the service configuration of the original process, those module labels are ignored in the replay. If there are new module labels in the service configuration of the replay process, then their engines generate new sequences as if a replay was not being done.

There are two replay modes and the next two subsections describe them.

Replay from the States in the Event and LuminosityBlock

To run a replay using the states stored in the Event and LuminosityBlock, one starts with the original configuration and makes the following changes:

  1. Add the restoreStateLabel parameter to the service configuration
  2. Change the source so that it is a PoolSource reading the output of the previous process
  3. Adjust the source to process the events of interest
  4. Change the process name so it does not conflict with the previous process name
  5. Change the output filename so the output module does not overwrite the input file

That is the minimum. Other changes can be made, but the user has to use his own judgement as to what effect those changes might have on the replay.

The restoreStateLabel parameter looks like the following in the configuration. The value is the module label used in the previous process that you wish to restore. Note that this label can be changed at each step of a series of processes. If it is not changed the service will pick up the most recent one that is still in the data.

    restoreStateLabel = cms.untracked.string('randomEngineStateProducer')

Since CMSSW release 5_2_0 there has been an alternative parameter which one can use instead of restoreStateLabel. It works in exactly the same way, except that it allows setting the process name of the previous process also. Note that the instance name in the input tag should always be the empty string.

    restoreStateTag = cms.untracked.InputTag('randomEngineStateProducer', '', 'PROD')

Any subset of events in the input file can be replayed. It can be one event, but it can also be more. There is no requirement they be sequential.

For this mode of replay to work, all of the products that are needed must have been written to the output file by the original process. If required products were dropped, then this will not work.

Replay of the Last Event of an Earlier Process

In this replay mode, the last event of a prior process is replayed. The random engine states are read from a text file written just before the last event of the earlier process was written. The intended purpose for this is to debug the problem when processing for an event terminated abnormally (segfault, exception ...) .

This replay mode is designed and tested to work for one event. Although in some simple cases it might work if one continued to process more events, in general it will not.

Here is how to run this mode of replay. Start with the python configuration file of the original process and make the following changes.

  1. Add the parameter restoreFileName to the service configuration
  2. Advance the source so the first event processed is the last event of the previous process
  3. Set the source to process only one event
  4. If the original process was a multithread process, then the configuration needs to be modified so that there is only one stream. Also in this case, there will be a set of files containing the state of the engines at the end of each stream. The file names will have a suffix that is the stream ID value and you will have to determine the correct one to use for the event you are interested in.

That is the minimum. Other changes can be made, but the user has to use his own judgement as to what effect those changes might have on the replay.

The restoreFileName parameter looks like the following in the configuration. The value is the filename of the file produced in the previous process that you wish to restore (the saveFileName parameter in that process).

restoreFileName = cms.untracked.string('whatever.txt')

It depends on the source how one advances to the proper event. For PoolSource, using skipEvents should work. Alternately using both lumisToProcess and eventsToProcess together should work. For EmptySource, using firstRun, firstLuminosityBlock, and firstEvent should work (I suspect in most cases the run, lumi, and event numbers make no difference in the problem you are trying to debug and you can do nothing in the EmptySource case).

If you want to avoid overwriting the output of the original process you might also change things like the output filename, although this will not affect the replay itself.

A Process that Continues the Random Sequences of a Previous Process

The service does not support running a process that continues the random sequences from a previous process. The replay mode using a text file will always repeat the last event of the previous process and for that reason it should not be used for this purpose. It is technically possible to implement this feature, but we decided that this feature was not needed. If you have a genuine need submit a request to the Framework group along with some justification and it might get implemented

The designers of the service tried to imagine why a user would want this feature and we could imagine one reason. A user could be running a series of interactive jobs with the desire that the jobs produce different events (with different random numbers). But this use case is better supported by a python utility that randomizes the seeds for each process. Just add the following to the configuration file:

from IOMC.RandomEngine.RandomServiceHelper import RandomNumberServiceHelper
randSvc = RandomNumberServiceHelper(process.RandomNumberGeneratorService)
randSvc.populate()

Randomizing the seeds is easier and just as effective as trying to continue the sequences. It was our belief that there was no reason to expend effort to develop and support an unneeded feature.

Backward Compatibility and Historical Notes

The changes to the service in the 7_1_X release were primarily to support multithreading. Python configurations should not change at all as a result of this. The main interface change is in the C++ function a module uses to get an engine. The getEngine function before 7_1_X had no arguments, but in 7_1_X and later either a stream ID or luminosity block index is required as an argument. This is a trivial modification if getEngine was already being called from the function that processes the event. One can access the StreamID from the Event with the streamID() function. Before 7_1_X modules would commonly get the engine in their constructor. To migrate code to use the modified service, that call and the things that depend on it need to be moved to the event function or the global beginLuminosityBlock function, which in some cases is nontrivial. All code in the repository was centrally migrated to this new interface, but there are likely many modules not in the official release that were broken when this interface changed.

Prior to 3_11_X the service did not support the enableChecking parameter, multicore mode, the eventSeedOffset parameter, or generation of random numbers during beginLuminosityBlock. Prior to 3_11_X replay was only supported when random numbers were only generated during the event.

The format which the states are saved in changed in 3_11_X. The service can read data files written with releases before 3_11_X and replay them if the states were saved in the Event in the older format. Note that the states are not saved in the LuminosityBlock at all for releases prior to 3_11_X. The text file mode of replay will not work at all for a process using release 3_11_X or later and trying to read a text file written with a release before 3_11_X. This format did not change in the 7_1_X revision to the service.

Prior to release 6_2_X, the service allowed an alternate form of declaring seeds to the service that used parameters named moduleSeeds and sourceSeed. Starting in 6_2_X an exception will be thrown when trying to use either moduleSeeds or sourceSeed. This old form was deprecated in 2006, but allowed up until release cycle 6_2_X because there were hundreds of configuration files in the code repository using this format. Most of them were obsolete but even now they still exist. If you need to run one of these configurations you will need to migrate it to the interface described in the earlier sections (delete sourceSeed and replace the moduleSeeds). The old style looks like this:

process.RandomNumberGeneratorService = cms.Service("RandomNumberGeneratorService",
    moduleSeeds = cms.PSet(
        t1 = cms.untracked.uint32(81),
        t3 = cms.untracked.uint32(83),
        t4 = cms.untracked.uint32(84),
        t5 = cms.untracked.uint32(100)
    ),
    sourceSeed = cms.untracked.uint32(123456781)
)

The old style was dangerous because work management systems like CRAB did not know how to randomize the initial seeds in the configuration, which could lead someone to accidently run many processes with identical seeds. With the older style, there was no way to declare different engine types or more than one seed. It was also illegal to mix the old and current style in the same configuration file. An exception would get thrown if you tried. For a long time before 6_2_X, the sourceSeed parameter had no effect and was just ignored.

TWIKI pages maintain a history of all their saved versions. If you are interested in older versions see the links near the bottom of this page. The r41 version of this TWIKI describes the version of the service used starting in 3_11_X and before 7_1_X. The r26 version of this TWIKI page describes the version of the service used before 3_11_X.

Review Status

Reviewer/Editor and Date (copy from screen) Comments
Main.wdd - 24 Oct 2006 page author (W David Dagenhart)
JennyWilliams - 31 Jan 2007 editing to include in SWGuide
JohnMarraffino - 1 Feb 2008 edited to reflect recent round of updates
JohnMarraffino - 9 Feb 2008 edited to introduce new engine parameter format
JohnMarraffino - 25 Apr 2008 edited to clarify the use of the new SaveState function
JohnMarraffino - 29 Apr 2008 Remove discussion of alternate form of cfg parameters
JohnMarraffino - 6 May 2008 Restore discussion of alternate form of cfg parameters
SudhirMalik - 13 April 2010 Changed the python examples from OLD to NEW styyle
W. David Dagenhart - 7 January 2011 Major rewrite
W. David Dagenhart - 10 March 2014 Major revisions after multithreading support was added
W. David Dagenhart - 21 December 2018 Remove parts describing support for forking mode

Responsible: DavidDagenhart
Last reviewed by: Reviewer DavidDagenhart 21 March 2018

Edit | Attach | Watch | Print version | History: r49 < r48 < r47 < r46 < r45 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r49 - 2018-12-21 - DavidDagenhart



 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMSPublic All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback