LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
RandomNumberGenerator.h
Go to the documentation of this file.
1 #ifndef art_Framework_Services_Optional_RandomNumberGenerator_h
2 #define art_Framework_Services_Optional_RandomNumberGenerator_h
3 
4 // ======================================================================
5 //
6 // A Service to maintain multiple independent random number engines.
7 //
8 // ======================================================================
9 // Introduction
10 // ------------
11 //
12 // Via this RandomNumberGenerator, the CLHEP random number engines are
13 // made available such that a client module may establish and
14 // subsequently employ any number of independent engines, each of any
15 // of the CLHEP engine types.
16 //
17 // Any producer, analyzer, or filter module may freely use this
18 // Service as desired. However, by design, source modules are
19 // permitted to make no use of this Service.
20 //
21 // ======================================================================
22 // Creating an engine
23 // ------------------
24 //
25 // Each engine to be used by a module must be created in that module's
26 // constructor. Creating an engine involves specifying:
27 // - An integer seed value to initialize the engine's state
28 // - The desired kind of engine ("HepJamesRandom" by default)
29 // - A label string (empty by default)
30 // Within a module, no two engines may share an identical label.
31 //
32 // The above three items of information are supplied in a single call
33 // to a function named createEngine(). Because two of the three items
34 // have defaults (and may therefore be omitted), the call may take any
35 // of several forms; the following three examples therefore have
36 // equivalent effect:
37 //
38 // createEngine(seed)
39 // createEngine(seed, "HepJamesRandom")
40 // createEngine(seed, "HepJamesRandom", "")
41 //
42 // As a convenience, each such call returns a reference to the newly-
43 // created engine; this is the same reference that would be returned
44 // from each subsequent corresponding getEngine() call (see below).
45 // Therefore, if it is convenient to do so, the reference returned
46 // from a call to createEngine() can be safely used right away as
47 // illustrated below. If there is no immediate need for it, this
48 // returned reference can instead be safely ignored.
49 //
50 // Note that the createEngine() function is implicitly available to
51 // any producer, analyzer, or filter module; no additional header need
52 // be #included.
53 //
54 // Here is an example of a recommended practice in which the result of
55 // a createEngine() call is used right away (arguments elided for
56 // clarity):
57 //
58 // CLHEP::RandFlat dist {createEngine(...)};
59 //
60 // ======================================================================
61 // Creating the global engine
62 // --------------------------
63 //
64 // CLHEP provides the notion of a global engine, and Geant4 makes use
65 // of this feature. It is recommended that the designated Geant4
66 // module (and no other) should create this global engine.
67 //
68 // The Service recognizes the notation "G4Engine" to create the engine
69 // that is used by Geant4. It is strongly recommended to ignore the
70 // resulting engine reference, leaving exclusive future engine use to
71 // Geant4 itself:
72 //
73 // createEngine(seed, "G4Engine");
74 //
75 // ======================================================================
76 // Digression: obtaining a seed value
77 // ----------------------------------
78 //
79 // As noted above, creating an engine involves specifying a seed
80 // value. Determining this value is at the discretion of the module
81 // creating the engine, and can be done in any of several manners.
82 // Here are some possibilities to get you started:
83 //
84 // - Each CLHEP engine has a default seed value. To specify the use
85 // of this default seed, use the magic value -1 as the seed
86 // argument in the createEngine() call:
87 //
88 // createEngine(-1);
89 //
90 // - Specify a (non-negative) constant of your choice as the seed
91 // argument in the createEngine() call:
92 //
93 // createEngine(13597);
94 //
95 // - Obtain a seed value from the module's ParameterSet, typically
96 // with some fallback value in case the ParameterSet omits the
97 // specified parameter:
98 //
99 // createEngine(pset.get<int>("seed",13597));
100 //
101 // - Obtain a seed value from the module's ParameterSet via a helper
102 // function, get_seed_value(), provided by the framework. Since
103 // this helper has defaults, each of the following calls has
104 // equivalent effect:
105 //
106 // createEngine(get_seed_value(pset));
107 // createEngine(get_seed_value(pset,"seed"));
108 // createEngine(get_seed_value(pset,"seed",-1));
109 //
110 // ======================================================================
111 // Service handles
112 // ---------------
113 //
114 // To gain general access to this RandomNumberGenerator, a module uses
115 // the facilities of the Service subsystem. Thus, after #including
116 // the RandomNumberGenerator header, a variable definition such as the
117 // following will obtain a handle to this Service:
118 //
119 // art::ServiceHandle<art::RandomNumberGenerator> rng;
120 //
121 // Thereafter, most functionality of this Service is available via
122 // this variable. All handles to this Service are equivalent; a
123 // client may define as many or as few handles as desired.
124 //
125 // A module that has no need for this Service need not obtain any such
126 // handle at all. Similarly, a module that creates an engine and
127 // makes use of the reference returned by the createEngine() call will
128 // also likely need obtain no handle.
129 //
130 // ======================================================================
131 // Accessing an engine
132 // -------------------
133 //
134 // To obtain access to a previously-established engine (see above),
135 // call the Service's getEngine function. The call takes a single
136 // argument, namely the label that had been used when the engine was
137 // established. If omitted, an empty label is used by default:
138 //
139 // auto& engine = rng->getEngine();
140 //
141 // Note that the Service automatically knows which module is making
142 // the access request, and will return a reference to the proper
143 // engine for the current module, using the label to disambiguate if
144 // the module has established more than one engine.
145 //
146 // ======================================================================
147 // Configuring the Service
148 // -----------------------
149 //
150 // TODO: draft this section
151 // ======================================================================
152 // TODO: assess the following remarks from the placeholder
153 // implementation and determine whether they are still valid/useful.
154 //
155 // When a separate Producer module is also included in the path, the
156 // state of all the engines managed by this service can be saved to
157 // the event. Then in a later process, the RandomNumberGenerator is
158 // capable of restoring the state of the engines from the event in
159 // order to be able to exactly reproduce the earlier process.
160 //
161 // ======================================================================
162 
163 #include "CLHEP/Random/RandomEngine.h"
168 #include "fhiclcpp/types/Atom.h"
169 #include "fhiclcpp/types/Name.h"
170 
171 #include <map>
172 #include <memory>
173 #include <string>
174 #include <vector>
175 
176 namespace art {
177  class ActivityRegistry;
178  class Event;
179  class EventID;
180  class Timestamp;
181 
182  class EngineCreator; // to be granted friendship
183  class EventProcessor; // to be granted friendship
184  class RandomNumberSaver; // to be granted friendship
185 
186  namespace test {
187  class ConcurrentEngineRetrieval; // to be granted friendship only for
188  // testing
189  }
190 
191  class RandomNumberGenerator;
192 }
193 
194 // ======================================================================
195 
197  friend class EngineCreator;
198  friend class EventProcessor;
199  friend class RandomNumberSaver;
200  friend class test::ConcurrentEngineRetrieval;
201 
202  // --- Prevent copying:
204  RandomNumberGenerator& operator=(RandomNumberGenerator const&) = delete;
205 
206 public:
207  // --- CLHEP engine characteristics:
208  using base_engine_t = CLHEP::HepRandomEngine;
209  using seed_t = long;
211 
212  // --- Internal state characteristics:
213  enum init_t { VIA_SEED = 1, VIA_FILE, VIA_PRODUCT };
215  using eptr_t = std::shared_ptr<base_engine_t>;
216  using dict_t = std::map<label_t, eptr_t>;
217  using tracker_t = std::map<label_t, init_t>;
218  using kind_t = std::map<label_t, std::string>;
219  using snapshot_t = std::vector<RNGsnapshot>;
220 
221  // --- Allowed configuration
222  struct Config {
223  fhicl::Atom<std::string> restoreStateLabel{fhicl::Name{"restoreStateLabel"},
224  ""};
225  fhicl::Atom<std::string> saveTo{fhicl::Name{"saveTo"}, ""};
226  fhicl::Atom<std::string> restoreFrom{fhicl::Name{"restoreFrom"}, ""};
227  fhicl::Atom<unsigned> nPrint{fhicl::Name{"nPrint"}, 10u};
229  };
230 
233 
234  // --- Engine access:
235 
236  // TODO: Could remove if we do not need to support access from
237  // engines restored from file.
238  base_engine_t& getEngine() const;
239  base_engine_t& getEngine(label_t const& engine_label) const;
240 
241 private:
242  // --- Engine establishment:
243  base_engine_t& createEngine(ScheduleID schedule_id, seed_t seed);
244  base_engine_t& createEngine(ScheduleID schedule_id,
245  seed_t seed,
246  std::string const& kind_of_engine_to_make);
247  base_engine_t& createEngine(ScheduleID schedule_id,
248  seed_t seed,
249  std::string kind_of_engine_to_make,
250  label_t const& engine_label);
251 
252  base_engine_t& getEngine(ScheduleID schedule_id,
253  label_t const& engine_label = {}) const;
254 
255  // --- MT-TODO: Only for testing
256  // For testing multi-schedule parallization of this service, the
257  // requested number of schedules is not expanded UNLESS the
258  // expandToNSchedules() function is called by a friend.
259  void
260  expandToNSchedules(std::size_t const n)
261  {
262  data_.resize(n);
263  }
264 
265  // --- Snapshot management helpers:
266  void takeSnapshot_(ScheduleID scheduleID);
267  void restoreSnapshot_(ScheduleID scheduleID, art::Event const&);
268  snapshot_t const&
269  accessSnapshot_(ScheduleID const schedule_id) const
270  {
271  return data_[schedule_id.id()].snapshot_;
272  }
273 
274  // --- File management helpers:
275  // TODO: Determine if this facility is necessary.
276  void saveToFile_();
277  void restoreFromFile_();
278 
279  // --- Debugging helpers:
280  void print_() const;
281  bool invariant_holds_(ScheduleID::size_type scheduleID);
282 
283  // --- Callbacks:
284  void preProcessEvent(art::Event const&);
285  void postProcessEvent(art::Event const&);
286  void postBeginJob();
287  void postEndJob();
288 
289  // --- Guard against tardy engine creation:
290  bool engine_creation_is_okay_{true};
291 
292  // Per-schedule information
293  struct ScheduleData {
294  // --- Per-module-instance information:
295  dict_t dict_{};
296  tracker_t tracker_{};
297  kind_t kind_{};
298 
299  // --- Snapshot information:
300  snapshot_t snapshot_{};
301  };
302  std::vector<ScheduleData> data_;
303 
304  // --- Product key for restoring from a snapshot:
306 
307  // --- File names for saving/restoring state:
308  std::string const saveToFilename_;
309  std::string const restoreFromFilename_;
310 
311  // --- Tracing and debug controls:
312  unsigned const nPrint_;
313  bool const debug_;
314 
315 }; // RandomNumberGenerator
316 
317 // ======================================================================
318 
320 #endif /* art_Framework_Services_Optional_RandomNumberGenerator_h */
321 
322 // Local Variables:
323 // mode: c++
324 // End:
std::shared_ptr< base_engine_t > eptr_t
std::map< label_t, eptr_t > dict_t
void expandToNSchedules(std::size_t const n)
std::string const restoreFromFilename_
constexpr id_type id() const
Definition: ScheduleID.h:70
#define DECLARE_ART_SERVICE(svc, scope)
Definition: ServiceMacros.h:91
std::vector< RNGsnapshot > snapshot_t
std::vector< ScheduleData > data_
DebugStuff debug
Definition: DebugStruct.cxx:4
long seed
Definition: chem4.cc:68
std::vector< CLHEP_t > engine_state_t
Definition: RNGsnapshot.h:44
std::map< label_t, std::string > kind_t
CLHEP::HepRandomEngine base_engine_t
snapshot_t const & accessSnapshot_(ScheduleID const schedule_id) const
RNGsnapshot::engine_state_t engine_state_t
id_type size_type
Definition: ScheduleID.h:27
std::string label_t
Definition: RNGsnapshot.h:49
std::map< label_t, init_t > tracker_t
HLT enums.
Char_t n[5]