LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
NuRandomService.cc
Go to the documentation of this file.
1 
9 // NuRandomService header
11 
12 // Art include files
21 
22 // Supporting library include files
24 
25 // CLHEP libraries
26 #include "CLHEP/Random/RandomEngine.h" // CLHEP::HepRandomEngine
27 
28 // C++ include files
29 #include <iostream>
30 #include <iomanip>
31 
32 namespace rndm {
33 
34  //----------------------------------------------------------------------------
36  (fhicl::ParameterSet const& paramSet, art::ActivityRegistry& iRegistry)
37  : seeds(paramSet)
38  , state()
39  , verbosity(paramSet.get<int>("verbosity", 0))
40  , bPrintEndOfJobSummary(paramSet.get<bool>("endOfJobSummary",false))
41  {
42  state.transit_to(NuRandomServiceHelper::ArtState::inServiceConstructor);
43 
44  // Register callbacks.
45  iRegistry.sPreModuleConstruction.watch (this, &NuRandomService::preModuleConstruction );
46  iRegistry.sPostModuleConstruction.watch (this, &NuRandomService::postModuleConstruction );
47  iRegistry.sPreModuleBeginRun.watch (this, &NuRandomService::preModuleBeginRun );
48  iRegistry.sPostModuleBeginRun.watch (this, &NuRandomService::postModuleBeginRun );
49  iRegistry.sPreProcessEvent.watch (this, &NuRandomService::preProcessEvent );
50  iRegistry.sPreModule.watch (this, &NuRandomService::preModule );
51  iRegistry.sPostModule.watch (this, &NuRandomService::postModule );
52  iRegistry.sPostProcessEvent.watch (this, &NuRandomService::postProcessEvent );
53  iRegistry.sPreModuleEndJob.watch (this, &NuRandomService::preModuleEndJob );
54  iRegistry.sPostModuleEndJob.watch (this, &NuRandomService::postModuleEndJob );
55  iRegistry.sPostEndJob.watch (this, &NuRandomService::postEndJob );
56 
57  } // NuRandomService::NuRandomService()
58 
59 
60 
61  //----------------------------------------------------------------------------
62  NuRandomService::EngineId NuRandomService::qualify_engine_label
63  (std::string moduleLabel, std::string instanceName) const
64  { return { moduleLabel, instanceName }; }
65 
66  NuRandomService::EngineId NuRandomService::qualify_engine_label
67  (std::string instanceName /* = "" */) const
68  { return qualify_engine_label( state.moduleLabel(), instanceName); }
69 
70  //----------------------------------------------------------------------------
71  auto NuRandomService::getSeed
72  (std::string instanceName /* = "" */) -> seed_t
73  {
74  return getSeed(qualify_engine_label(instanceName));
75  } // NuRandomService::getSeed(string)
76 
77 
78  //----------------------------------------------------------------------------
79  auto NuRandomService::getSeed
80  (std::string const& moduleLabel, std::string const& instanceName) -> seed_t
81  { return getSeed(qualify_engine_label(moduleLabel, instanceName)); }
82 
83 
84  //----------------------------------------------------------------------------
85  auto NuRandomService::getGlobalSeed(std::string instanceName) -> seed_t {
86  EngineId ID(instanceName, EngineId::global);
87  MF_LOG_DEBUG("NuRandomService")
88  << "NuRandomService::getGlobalSeed(\"" << instanceName << "\")";
89  return getSeed(ID);
90  } // NuRandomService::getGlobalSeed()
91 
92 
93  //----------------------------------------------------------------------------
94  NuRandomService::seed_t NuRandomService::getSeed(EngineId const& id) {
95 
96  // We require an engine to have been registered before we yield seeds;
97  // this should minimise unexpected conflicts.
98  if (hasEngine(id)) return querySeed(id); // ask the seed to seed master
99 
100  // if it hasn't been declared, we declare it now
101  // (this is for backward compatibility with the previous behaviour).
102  // registerEngineID() will eventually call this function again to get the
103  // seed... so we return it directly.
104  // Also note that this effectively "freezes" the engine since no seeder
105  // is specified.
106  return registerEngineID(id);
107 
108  } // NuRandomService::getSeed(EngineId)
109 
110 
111  NuRandomService::seed_t NuRandomService::querySeed(EngineId const& id) {
112  return seeds.getSeed(id); // ask the seed to seed master
113  } // NuRandomService::querySeed()
114 
115 
116  auto NuRandomService::extractSeed
117  (EngineId const& id, std::optional<seed_t> seed) -> std::pair<seed_t, bool>
118  {
119  // if we got a valid seed, use it as frozen
120  if (seed && (seed.value() != InvalidSeed))
121  return { seed.value(), true };
122 
123  // seed was not good enough; get the seed from the master
124  return { querySeed(id), false };
125  } // NuRandomService::extractSeed()
126 
127 
128  NuRandomService::seed_t NuRandomService::registerEngine(
129  SeedMaster_t::Seeder_t seeder, std::string const instance /* = "" */,
130  std::optional<seed_t> const seed /* = std::nullopt */
131  ) {
132  EngineId id = qualify_engine_label(instance);
133  registerEngineIdAndSeeder(id, seeder);
134  auto const [ seedValue, frozen ] = extractSeed(id, seed);
135  seedEngine(id); // seed it before freezing
136  if (frozen) freezeSeed(id, seedValue);
137  return seedValue;
138  } // NuRandomService::registerEngine(Seeder_t, string, ParameterSet, init list)
139 
140 
141  NuRandomService::seed_t NuRandomService::registerEngine(
142  SeedMaster_t::Seeder_t seeder, std::string instance,
143  fhicl::ParameterSet const& pset, std::initializer_list<std::string> pnames
144  )
145  {
146  return registerEngine(seeder, instance, readSeedParameter(pset, pnames));
147  } // NuRandomService::registerEngine(Seeder_t, string, ParameterSet, init list)
148 
149 
150  NuRandomService::seed_t NuRandomService::registerEngine(
151  SeedMaster_t::Seeder_t seeder, std::string instance,
152  SeedAtom const& seedParam
153  )
154  {
155  return registerEngine(seeder, instance, readSeedParameter(seedParam));
156  } // NuRandomService::registerEngine(Seeder_t, string, ParameterSet, init list)
157 
158 
159  NuRandomService::seed_t NuRandomService::declareEngine(std::string instance) {
160  return registerEngine(SeedMaster_t::Seeder_t(), instance);
161  } // NuRandomService::declareEngine(string)
162 
163 
164  NuRandomService::seed_t NuRandomService::declareEngine(
165  std::string instance,
166  fhicl::ParameterSet const& pset, std::initializer_list<std::string> pnames
167  ) {
168  return registerEngine(SeedMaster_t::Seeder_t(), instance, pset, pnames);
169  } // NuRandomService::declareEngine(string, ParameterSet, init list)
170 
171 
172  NuRandomService::seed_t NuRandomService::defineEngine
173  (SeedMaster_t::Seeder_t seeder, std::string instance /* = {} */)
174  {
175  return defineEngineID(qualify_engine_label(instance), seeder);
176  } // NuRandomService::defineEngine(string, Seeder_t)
177 
178 
179  //----------------------------------------------------------------------------
180  NuRandomService::seed_t NuRandomService::registerEngineID(
181  EngineId const& id,
182  SeedMaster_t::Seeder_t seeder /* = SeedMaster_t::Seeder_t() */
183  ) {
184  prepareEngine(id, seeder);
185  return seedEngine(id);
186  } // NuRandomService::registerEngineID()
187 
188 
189  NuRandomService::seed_t NuRandomService::defineEngineID
190  (EngineId const& id, SeedMaster_t::Seeder_t seeder)
191  {
192  if (!hasEngine(id)) {
194  << "Attempted to define engine '" << id.artName()
195  << "', that was not declared\n";
196  }
197 
198  if (seeds.hasSeeder(id)) {
200  << "Attempted to redefine engine '" << id.artName()
201  << "', that has already been defined\n";
202  }
203 
204  ensureValidState();
205 
206  seeds.registerSeeder(id, seeder);
207  seed_t const seed = seedEngine(id);
208  return seed;
209  } // NuRandomService::defineEngineID()
210 
211 
212  //----------------------------------------------------------------------------
213  void NuRandomService::ensureValidState(bool bGlobal /* = false */) const {
214  if (bGlobal) {
215  // registering engines may only happen in a service c'tor
216  // In all other cases, throw.
217  if ( (state.state() != NuRandomServiceHelper::ArtState::inServiceConstructor))
218  {
220  << "NuRandomService: not in a service constructor."
221  << " May not register \"global\" engines.\n";
222  }
223  }
224  else { // context-aware engine
225  // registering engines may only happen in a c'tor
226  // (disabling the ability to do that or from a beginRun method)
227  // In all other cases, throw.
228  if ( (state.state() != NuRandomServiceHelper::ArtState::inModuleConstructor)
229  // && (state.state() != NuRandomServiceHelper::ArtState::inModuleBeginRun)
230  )
231  {
233  << "NuRandomService: not in a module constructor."
234  << " May not register engines.\n";
235  }
236  } // if
237  } // NuRandomService::ensureValidState()
238 
239 
240  //----------------------------------------------------------------------------
241  NuRandomService::seed_t NuRandomService::reseedInstance(EngineId const& id) {
242  // get all the information on the current process, event and module from
243  // ArtState:
244  SeedMaster_t::EventData_t const data(state.getEventSeedInputData());
245  seed_t const seed = seeds.reseedEvent(id, data);
246  if (seed == InvalidSeed) {
247  mf::LogDebug("NuRandomService")
248  << "No random seed specific to this event for engine '" << id << "'";
249  }
250  else {
251  mf::LogInfo("NuRandomService") << "Random seed for this event, engine '"
252  << id << "': " << seed;
253  }
254  return seed;
255  } // NuRandomService::reseedInstance()
256 
257 
258  void NuRandomService::reseedModule(std::string currentModule) {
259  for (EngineId const& ID: seeds.engineIDsRange()) {
260  if (ID.moduleLabel != currentModule) continue; // not our module? neeext!!
261  reseedInstance(ID);
262  } // for
263  } // NuRandomService::reseedModule(string)
264 
265  void NuRandomService::reseedModule() { reseedModule(state.moduleLabel()); }
266 
267 
268  void NuRandomService::reseedGlobal() {
269  for (EngineId const& ID: seeds.engineIDsRange()) {
270  if (!ID.isGlobal()) continue; // not global? neeext!!
271  reseedInstance(ID);
272  } // for
273  } // NuRandomService::reseedGlobal()
274 
275 
276  //----------------------------------------------------------------------------
277  void NuRandomService::registerEngineIdAndSeeder
278  (EngineId const& id, SeedMaster_t::Seeder_t seeder)
279  {
280  // Are we being called from the right place?
281  ensureValidState(id.isGlobal());
282 
283  if (hasEngine(id)) {
285  << "NuRandomService: an engine with ID '" << id.artName()
286  << "' has already been created!\n";
287  }
288  seeds.registerNewSeeder(id, seeder);
289  } // NuRandomService::registerEngineIdAndSeeder()
290 
291 
292  //----------------------------------------------------------------------------
293  void NuRandomService::freezeSeed(EngineId const& id, seed_t frozen_seed)
294  { seeds.freezeSeed(id, frozen_seed); }
295 
296 
297  //----------------------------------------------------------------------------
298  NuRandomService::seed_t NuRandomService::prepareEngine
299  (EngineId const& id, SeedMaster_t::Seeder_t seeder)
300  {
301  registerEngineIdAndSeeder(id, seeder);
302  return querySeed(id);
303  } // NuRandomService::prepareEngine()
304 
305 
306  //----------------------------------------------------------------------------
307  std::optional<seed_t> NuRandomService::readSeedParameter(
308  fhicl::ParameterSet const& pset,
309  std::initializer_list<std::string> pnames
310  ) {
311  seed_t seed;
312  for (std::string const& key: pnames)
313  if (pset.get_if_present(key, seed)) return { seed };
314  return std::nullopt;
315  } // NuRandomService::readSeedParameter(ParameterSet, strings)
316 
317 
318  //----------------------------------------------------------------------------
319  std::optional<seed_t> NuRandomService::readSeedParameter
320  (SeedAtom const& param)
321  {
322  seed_t seed;
323  return param(seed)? std::make_optional(seed): std::nullopt;
324  } // NuRandomService::readSeedParameter(SeedAtom)
325 
326 
327  //----------------------------------------------------------------------------
328  // Callbacks called by art. Used to maintain information about state.
329  void NuRandomService::preModuleConstruction(art::ModuleDescription const& md) {
330  state.transit_to(NuRandomServiceHelper::ArtState::inModuleConstructor);
331  state.set_module(md);
332  } // NuRandomService::preModuleConstruction()
333 
334  void NuRandomService::postModuleConstruction(art::ModuleDescription const&) {
335  state.reset_state();
336  } // NuRandomService::postModuleConstruction()
337 
338  void NuRandomService::preModuleBeginRun(art::ModuleContext const& mc) {
339  state.transit_to(NuRandomServiceHelper::ArtState::inModuleBeginRun);
340  state.set_module(mc.moduleDescription());
341  } // NuRandomService::preModuleBeginRun()
342 
343  void NuRandomService::postModuleBeginRun(art::ModuleContext const&) {
344  state.reset_state();
345  } // NuRandomService::postModuleBeginRun()
346 
347  void NuRandomService::preProcessEvent(art::Event const& evt, art::ScheduleContext) {
348  state.transit_to(NuRandomServiceHelper::ArtState::inEvent);
349  state.set_event(evt);
350  seeds.onNewEvent(); // inform the seed master that a new event has come
351 
352  MF_LOG_DEBUG("NuRandomService") << "preProcessEvent(): will reseed global engines";
353  reseedGlobal(); // why don't we do them all?!?
354 
355  } // NuRandomService::preProcessEvent()
356 
357  void NuRandomService::preModule(art::ModuleContext const& mc) {
358  state.transit_to(NuRandomServiceHelper::ArtState::inModuleEvent);
359  state.set_module(mc.moduleDescription());
360 
361  // Reseed all the engine of this module... maybe
362  // (that is, if the current policy alows it).
363  MF_LOG_DEBUG("NuRandomService") << "preModule(): will reseed engines for module '"
364  << mc.moduleLabel() << "'";
365  reseedModule(mc.moduleLabel());
366  } // NuRandomService::preModule()
367 
368  void NuRandomService::postModule(art::ModuleContext const&) {
369  state.reset_module();
370  state.reset_state();
371  } // NuRandomService::postModule()
372 
373  void NuRandomService::postProcessEvent(art::Event const&, art::ScheduleContext) {
374  state.reset_event();
375  state.reset_state();
376  } // NuRandomService::postProcessEvent()
377 
378  void NuRandomService::preModuleEndJob(art::ModuleDescription const& md) {
379  state.transit_to(NuRandomServiceHelper::ArtState::inEndJob);
380  state.set_module(md);
381  } // NuRandomService::preModuleBeginRun()
382 
383  void NuRandomService::postModuleEndJob(art::ModuleDescription const&) {
384  state.reset_state();
385  } // NuRandomService::preModuleBeginRun()
386 
387  void NuRandomService::postEndJob() {
388  if ((verbosity > 0) || bPrintEndOfJobSummary)
389  print(); // framework logger decides whether and where it shows up
390  } // NuRandomService::postEndJob()
391 
392  //----------------------------------------------------------------------------
393 
394 } // end namespace rndm
GlobalSignal< detail::SignalResponseType::FIFO, void(ModuleContext const &)> sPreModuleBeginRun
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
GlobalSignal< detail::SignalResponseType::FIFO, void(ModuleDescription const &)> sPreModuleConstruction
GlobalSignal< detail::SignalResponseType::LIFO, void()> sPostEndJob
GlobalSignal< detail::SignalResponseType::FIFO, void(ModuleContext const &)> sPreModule
const std::string instance
NuRandomService(const fhicl::ParameterSet &, art::ActivityRegistry &)
GlobalSignal< detail::SignalResponseType::LIFO, void(ModuleDescription const &)> sPostModuleConstruction
long seed
Definition: chem4.cc:67
std::function< void(EngineId const &, seed_t)> Seeder_t
type of a function setting a seed
Definition: SeedMaster.h:206
typename PolicyImpl_t::EventData_t EventData_t
type of data used for event seeds
Definition: SeedMaster.h:245
Identifier for a engine, made of module name and optional instance name.
Definition: EngineId.h:22
GlobalSignal< detail::SignalResponseType::LIFO, void(ModuleContext const &)> sPostModuleBeginRun
GlobalSignal< detail::SignalResponseType::FIFO, void(Event const &, ScheduleContext)> sPreProcessEvent
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
GlobalSignal< detail::SignalResponseType::FIFO, void(ModuleDescription const &)> sPreModuleEndJob
GlobalSignal< detail::SignalResponseType::LIFO, void(Event const &, ScheduleContext)> sPostProcessEvent
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:14
GlobalSignal< detail::SignalResponseType::LIFO, void(ModuleContext const &)> sPostModule
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
Definition: StdUtils.h:120
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
std::optional< T > get_if_present(std::string const &key) const
Definition: ParameterSet.h:267
auto const & moduleDescription() const
Definition: ModuleContext.h:38
#define MF_LOG_DEBUG(id)
auto const & moduleLabel() const
Definition: ModuleContext.h:43
GlobalSignal< detail::SignalResponseType::LIFO, void(ModuleDescription const &)> sPostModuleEndJob
TCEvent evt
Definition: DataStructs.cxx:8
art::detail::EngineCreator::seed_t seed_t