Back to home page

Project CMSSW displayed by LXR



File indexing completed on 2021-02-14 13:29:19

0001 #ifndef FWCore_Utilities_RandomNumberGenerator_h
0002 #define FWCore_Utilities_RandomNumberGenerator_h
0004 /** \class edm::RandomNumberGenerator
0006   Description: Interface for obtaining random number engines.
0008   Usage:  This class is the abstract interface to a Service
0009 which provides access to the random number engines which are
0010 used to generate random numbers. One accesses the service using
0011 the Service system.
0013   edm::Service<edm::RandomNumberGenerator> rng;
0014   CLHEP::HepRandomEngine& engine = rng->getEngine(streamID);
0015   or
0016   CLHEP::HepRandomEngine& engine = rng->getEngine(luminosityBlockIndex);
0018 The RandomNumberGenerator automatically knows what module is
0019 requesting an engine and will return the proper one for that
0020 module.
0022 For each module the service will hold one engine per stream.
0023 In addition, for each module the service will hold a number
0024 of engines equal to the number of LuminosityBlocks that can
0025 be processed concurrently. When running a multithreaded
0026 process the correct engine for the current module and
0027 streamID/luminosityBlockIndex must be used to avoid
0028 data races. This is also important for replay.
0030 A source cannot use this service and sources should not generate
0031 random numbers (otherwise replay will fail).
0033 Random numbers should only be generated in two functions of a
0034 module, the function used to process the Event and also the
0035 global beginLuminosityBlock function. Random numbers should
0036 not be generated at any other time, not in the constructor,
0037 not at beginJob, not at beginRun ... Note that this restriction
0038 applies to generating the random numbers. If one is only calling
0039 the function getEngine that takes a streamID argument then it is
0040 also OK to call it in the beginStream method, but only to get
0041 the reference to the engine and save it or save a pointer to
0042 it (but not to generate any random numbers in beginStream).
0044 The service owns the engines and handles memory management
0045 for them.
0047 The service does a lot of work behind the scenes to allow one
0048 to replay specific events of a prior process.  There are two
0049 different mechanisms.
0051 First, if the parameter named "saveFileName" is set the
0052 state of the random engines will be written to a text file
0053 before each event is processed.  This text file is overwritten
0054 at each event. If a job crashes while processing an event,
0055 then one can replay the processing of the event where the
0056 crash occurred and get the same random number sequences.
0057 For jobs with more than 1 thread or forked processes, the
0058 text files are named by appending "_" and a number
0059 to the "saveFileName" parameter, where the number is either
0060 the child index of the forked process or the streamID of
0061 the stream which processed the event.
0063 Second, if the RandomEngineStateProducer module is executed
0064 the state of all the engines managed by this service
0065 can be saved to both the Event and LuminosityBlock. Then in a
0066 later process, the RandomNumberGenerator is capable of restoring
0067 the state of the engines in order to be able to exactly replay
0068 the earlier process starting at any event without having to
0069 replay the entire process.
0071 This service performs its tasks so that the random sequences
0072 are independent sequences with different seeds for two cases:
0074 1.  Multiprocess jobs where processes are forked
0075 2.  Multithread jobs where multiple threads are used
0077 It is assumed that we will never run jobs that are both
0078 multiprocess and multithread. The service seeding algorithm
0079 will fail to produce independent sequences if that is
0080 attempted.
0082 Three warnings.
0084 1. When there is more than one LuminosityBlock in a single
0085 process, the random number engines used in global begin
0086 luminosity block are reset to the same starting state
0087 before each call to that function (except in replay mode).
0088 This allows the initialization performed in all of them
0089 to be identical. Don't expect unique sequences in different
0090 calls to beginLuminosityBlock.
0092 2. In multiprocess jobs, the engines are reinitialized
0093 after the processes are forked with new seeds equal to
0094 the original seed plus the child index. In multithread
0095 jobs, the stream sequences are initialized in a similar way
0096 by adding the streamID to the seed to form a new
0097 seed for each stream.  The seeds for the engines for
0098 the luminosity blocks are all the same and the original
0099 seed plus the number of streams or the number of forked
0100 child processes is used. In existing work management schemes
0101 this works well, because the initial configured seed is
0102 derived randomly and the seeds in different jobs should
0103 not be close to one another. If not using one of these
0104 work management schemes, one has to be careful to not
0105 configure seeds in multiple jobs that are close enough
0106 together to overlap (closer than the number of forked
0107 processes or streams). For example, if one generated
0108 the original configured seed for a job using the previous
0109 jobs seed and adding one, then there would be a problem.
0111 3. This service properly handles modules running concurrently
0112 and generating random numbers, but not concurrent submodule tasks.
0113 If a module creates its own subtasks that are run concurrently
0114 and generate numbers, then using the engines from the service
0115 will result in data races. If this design if ever needed,
0116 one possible approach would be for each submodule task that
0117 needs random numbers to create its own engine and seed it
0118 using a random number from the module random engine. There
0119 might be better ways.
0121 There are more details explaining this service on a TWIKI page
0122 which can be accessed through a link on the Framework TWIKI page
0123 of the SWGuide.
0125 \author Chris Jones and W. David Dagenhart, created March 7, 2006
0126 */
0128 #include <cstdint>
0129 #include <iosfwd>
0130 #include <memory>
0131 #include <vector>
0133 class RandomEngineState;
0135 namespace CLHEP {
0136   class HepRandomEngine;
0137 }
0139 namespace edm {
0141   class ConsumesCollector;
0142   class Event;
0143   class LuminosityBlock;
0144   class LuminosityBlockIndex;
0145   class StreamID;
0147   class RandomNumberGenerator {
0148   public:
0149     RandomNumberGenerator() {}
0150     RandomNumberGenerator(RandomNumberGenerator const&) = delete;
0151     RandomNumberGenerator const& operator=(RandomNumberGenerator const&) = delete;
0152     virtual ~RandomNumberGenerator();
0154     /// Use the next 2 functions to get the random number engine.
0155     /// These are the only functions most modules should call.
0157     /// Use this engine in event methods
0158     virtual CLHEP::HepRandomEngine& getEngine(StreamID const&) = 0;
0160     /// Use this engine in the global begin luminosity block method
0161     virtual CLHEP::HepRandomEngine& getEngine(LuminosityBlockIndex const&) = 0;
0163     /// This function is not intended for general use. It is intended for
0164     /// the special case where multiple instances of Pythia 8 will
0165     /// be run concurrently and we want them to be initialized exactly
0166     /// the same. In this special case, the luminosity block engine(s)
0167     /// owned by the service should not be used to generate random numbers
0168     /// in between calls to cloneEngine, because the clone will be in
0169     /// the state that existed at the moment of cloning.
0170     /// Before initializing Pythia, this function should be used to clone
0171     /// the engine owned by the service and the cloned random engine should be
0172     /// used to generate numbers for initialization so that all initializations
0173     /// in the process get identical sequences of random numbers.
0174     virtual std::unique_ptr<CLHEP::HepRandomEngine> cloneEngine(LuminosityBlockIndex const&) = 0;
0176     /// This returns the seed from the configuration. In the unusual case where an
0177     /// an engine type takes multiple seeds to initialize a sequence, this function
0178     /// only returns the first. As a general rule, this function should not be used,
0179     /// but is available for backward compatibility and debugging. It might be useful
0180     /// for some types of tests. Using this to seed engines constructed in modules is
0181     /// not recommended because (unless done very carefully) it will create duplicate
0182     /// sequences in different threads and/or data races. Also, if engines are created
0183     /// by modules the replay mechanism will be broken.
0184     /// Because it is dangerous and could be misused, this function might be deleted
0185     /// someday if we ever find time to delete all uses of it in CMSSW. There are of
0186     /// order 10 last time I checked ...
0187     virtual std::uint32_t mySeed() const = 0;
0189     // The following functions should not be used by general users.  They
0190     // should only be called by Framework code designed to work with the
0191     // service while it is saving the engine states or restoring them.
0192     // The first two are called by the EventProcessor at special times.
0193     // The next two are called by a dedicated producer module (RandomEngineStateProducer).
0195     virtual void preBeginLumi(LuminosityBlock const& lumi) = 0;
0196     virtual void postEventRead(Event const& event) = 0;
0198     virtual void setLumiCache(LuminosityBlockIndex, std::vector<RandomEngineState> const& iStates) = 0;
0199     virtual void setEventCache(StreamID, std::vector<RandomEngineState> const& iStates) = 0;
0201     virtual std::vector<RandomEngineState> const& getEventCache(StreamID const&) const = 0;
0202     virtual std::vector<RandomEngineState> const& getLumiCache(LuminosityBlockIndex const&) const = 0;
0204     virtual void consumes(ConsumesCollector&& iC) const = 0;
0206     /// For debugging purposes only.
0207     virtual void print(std::ostream& os) const = 0;
0208   };
0209 }  // namespace edm
0210 #endif