LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
SeedMaster.h
Go to the documentation of this file.
1 
9 #ifndef NURANDOM_RANDOMUTILS_PROVIDERS_SEEDMASTER_H
10 #define NURANDOM_RANDOMUTILS_PROVIDERS_SEEDMASTER_H 1
11 
12 // C/C++ standard libraries
13 #include <vector>
14 #include <string>
15 #include <map>
16 #include <memory> // std::unique_ptr<>
17 #include <utility> // std::forward()
18 
19 // From art and its tool chain
20 #include "fhiclcpp/ParameterSet.h"
22 
23 // Some helper classes
24 #include "nurandom/RandomUtils/Providers/PolicyFactory.h" // makeRandomSeedPolicy
25 #include "nurandom/RandomUtils/Providers/PolicyNames.h" // rndm::details::Policy
30 
31 // more headers included in the implementation section below
32 
33 
34 namespace rndm {
35 
197  template <typename SEED>
198  class SeedMaster {
199  public:
200  using seed_t = SEED;
202 
204 
206  using Seeder_t = std::function<void(EngineId const&, seed_t)>;
207 
208  private:
211 
213  using map_type = std::map<EngineId, seed_t>;
214 
216  struct EngineInfo_t {
217  public:
218  bool hasSeeder() const { return bool(seeder); }
219  bool isFrozen() const { return !autoseed; }
220 
221  void freeze(bool doFreeze = true) { autoseed = !doFreeze; }
222  void setSeeder(Seeder_t new_seeder) { seeder = new_seeder; }
223 
225  template <typename... Args>
226  void applySeed(Args... args) const
227  { if (hasSeeder()) seeder(std::forward<Args>(args)...); }
228 
230  template <typename... Args>
231  void autoApplySeed(Args... args) const
232  { if (!isFrozen()) applySeed(std::forward<Args>(args)...); }
233 
234  private:
236  bool autoseed = true;
237 
238  }; // EngineInfo_t
239 
241  using EngineData_t = std::map<EngineId, EngineInfo_t>;
242 
243  public:
246 
249 
252 
253  static const std::vector<std::string>& policyNames();
254 
258 
260 
261  // Accept compiler written c'tors, assignments and d'tor.
262 
264  bool hasEngine(EngineId const& id) const
265  { return engineData.count(id) > 0; }
266 
268  bool hasSeeder(EngineId const& id) const
269  {
270  auto iEngineInfo = engineData.find(id);
271  return
272  (iEngineInfo != engineData.end()) && iEngineInfo->second.hasSeeder();
273  }
274 
276  seed_t getSeed(std::string moduleLabel);
277 
279  seed_t getSeed(std::string moduleLabel, std::string instanceName);
280 
282  seed_t getSeed(EngineId const&);
283 
287  (EventData_t const& data, std::string instanceName);
288  seed_t getEventSeed(EventData_t const& data, EngineId const& id);
290 
292  seed_t getCurrentSeed(EngineId const& id) const
293  { return getSeedFromMap(currentSeeds, id); }
294 
295 
306  void registerSeeder(EngineId const& id, Seeder_t seeder);
307 
308 
320  void registerNewSeeder(EngineId const& id, Seeder_t seeder);
321 
322 
324  void freezeSeed(EngineId const& id, seed_t seed);
325 
326 
335  seed_t reseed(EngineId const& id);
336 
346  seed_t reseedEvent(EngineId const& id, EventData_t const& data);
347 
349  template<typename Stream> void print(Stream&&) const;
350 
353 
355  void onNewEvent();
356 
358  void print() const { print(mf::LogVerbatim("SEEDS")); }
359 
360  private:
363 
366 
369 
372 
375 
377 
379  void setPolicy(std::string policyName);
380 
385  void ensureUnique
386  (EngineId const& id, seed_t seed, map_type const& map) const;
387  void ensureUnique(EngineId const& id, seed_t seed) const
388  { return ensureUnique(id, seed, configuredSeeds); }
390 
392  std::unique_ptr<PolicyImpl_t> policy_impl;
393 
394 
396  static seed_t getSeedFromMap(map_type const& seeds, EngineId const& id)
397  {
398  auto iSeed = seeds.find(id);
399  return (iSeed == seeds.end())? InvalidSeed: iSeed->second;
400  }
401 
402  }; // class SeedMaster
403 
404 } // namespace rndm
405 
406 
407 //==============================================================================
408 //=== Template implementation
409 //===
410 
411 
412 // C++ include files
413 #include <ostream>
414 #include <iomanip> // std::setw()
415 #include <ostream> // std::endl
416 #include <algorithm> // std::find(), std::copy()
417 #include <iterator> // std::ostream_iterator<>, std::distance()
418 
419 // Supporting library include files
421 
422 // Art include files
424 
425 
426 //----------------------------------------------------------------------------
427 template <typename SEED>
428 std::vector<std::string> const& rndm::SeedMaster<SEED>::policyNames()
429  { return details::policyNames(); }
430 
431 
432 
433 //----------------------------------------------------------------------------
434 template <typename SEED>
436  verbosity(pSet.get<int>("verbosity",0)),
437  policy(Policy::unDefined),
438  configuredSeeds(),
439  knownEventSeeds(),
440  currentSeeds(),
441  engineData()
442 {
443 
444  policy_impl = std::move(details::makeRandomSeedPolicy<seed_t>(pSet).ptr);
445 
446  if ( verbosity > 0 )
447  print(mf::LogVerbatim("SeedMaster"));
448 
449 } // SeedMaster<SEED>::SeedMaster()
450 
451 
452 
453 //----------------------------------------------------------------------------
454 template <typename SEED>
455 inline typename rndm::SeedMaster<SEED>::seed_t
457  (std::string moduleLabel)
458 {
459  return getSeed(EngineId(moduleLabel));
460 } // SeedMaster<SEED>::getSeed(string)
461 
462 
463 //----------------------------------------------------------------------------
464 template <typename SEED>
466  (std::string moduleLabel, std::string instanceName)
467 {
468  return getSeed(EngineId(moduleLabel,instanceName));
469 } // SeedMaster<SEED>::getSeed(string, string)
470 
471 
472 //----------------------------------------------------------------------------
473 template <typename SEED>
475  (EngineId const& id, Seeder_t seeder)
476 {
477  engineData[id].setSeeder(seeder); // creates anew and sets
478 } // SeedMaster<SEED>::registerSeeder()
479 
480 
481 //----------------------------------------------------------------------------
482 template <typename SEED>
484  (EngineId const& id, Seeder_t seeder)
485 {
486  if (hasEngine(id)) {
488  << "SeedMaster(): Engine with ID='" << id << "' already registered";
489  }
490  registerSeeder(id, seeder);
491 } // SeedMaster<SEED>::registerNewSeeder()
492 
493 
494 //----------------------------------------------------------------------------
495 template <typename SEED>
497  engineData.at(id).freeze();
498  configuredSeeds[id] = seed;
499  currentSeeds[id] = seed;
500 } // SeedMaster<>::freezeSeed()
501 
502 
503 //----------------------------------------------------------------------------
504 template <typename SEED>
506  (EngineId const& id)
507 {
508  auto const& engineInfo = engineData.at(id);
509  if (engineInfo.isFrozen()) return InvalidSeed;
510  seed_t seed = getSeed(id);
511  if (seed != InvalidSeed) { // reseed
512  engineInfo.applySeed(id, seed);
513  }
514  return seed;
515 } // SeedMaster<SEED>::reseed()
516 
517 
518 template <typename SEED>
520  (EngineId const& id, EventData_t const& data)
521 {
522  auto const& engineInfo = engineData.at(id);
523  if (engineInfo.isFrozen()) return InvalidSeed;
524  seed_t seed = getEventSeed(data, id);
525  if (seed != InvalidSeed) { // reseed
526  engineInfo.autoApplySeed(id, seed);
527  }
528  return seed;
529 } // SeedMaster<SEED>::reseedEvent()
530 
531 
532 
533 //----------------------------------------------------------------------------
534 template <typename SEED> template <typename Stream>
535 void rndm::SeedMaster<SEED>::print(Stream&& log) const {
536  log << "\nSummary of seeds computed by the NuRandomService";
537 
538  // allow the policy implementation to print whatever it feels to
539  std::ostringstream sstr;
540  policy_impl->print(sstr);
541  if (!sstr.str().empty()) log << '\n' << sstr.str();
542 
543  if ( !currentSeeds.empty() ) {
544 
545  constexpr unsigned int ConfSeedWidth = 18;
546  constexpr unsigned int SepWidth1 = 2;
547  constexpr unsigned int LastSeedWidth = 18;
548  constexpr unsigned int SepWidth2 = SepWidth1 + 1;
549 
550  log << "\n "
551  << std::setw(ConfSeedWidth) << "Configured value"
552  << std::setw(SepWidth1) << ""
553  << std::setw(LastSeedWidth) << "Last value"
554  << std::setw(SepWidth2) << ""
555  << "ModuleLabel.InstanceName";
556 
557  for (auto const& p: currentSeeds) {
558  EngineId const& ID = p.first;
559  seed_t configuredSeed = getSeedFromMap(configuredSeeds, ID);
560  seed_t currentSeed = p.second;
561 
562  if (configuredSeed == InvalidSeed) {
563  if (currentSeed == InvalidSeed) {
564  log << "\n "
565  << std::setw(ConfSeedWidth) << "INVALID!!!"
566  << std::setw(SepWidth1) << ""
567  << std::setw(LastSeedWidth) << ""
568  << std::setw(SepWidth2) << ""
569  << ID;
570  }
571  else { // if seed was configured, it should be that one all the way!!
572  log << "\n "
573  << std::setw(ConfSeedWidth) << "(per event)"
574  << std::setw(SepWidth1) << ""
575  << std::setw(LastSeedWidth) << currentSeed
576  << std::setw(SepWidth2) << ""
577  << ID;
578  }
579  }
580  else {
581  if (configuredSeed == currentSeed) {
582  log << "\n "
583  << std::setw(ConfSeedWidth) << configuredSeed
584  << std::setw(SepWidth1) << ""
585  << std::setw(LastSeedWidth) << "(same)"
586  << std::setw(SepWidth2) << ""
587  << ID;
588  }
589  else { // if seed was configured, it should be that one all the way!!
590  log << "\n "
591  << std::setw(ConfSeedWidth) << configuredSeed
592  << std::setw(SepWidth1) << ""
593  << std::setw(LastSeedWidth) << currentSeed
594  << std::setw(SepWidth2) << ""
595  << ID << " [[ERROR!!!]]";
596  }
597  } // if per job
598  if (ID.isGlobal()) log << " (global)";
599  if (hasEngine(ID) && engineData.at(ID).isFrozen()) log << " [overridden]";
600  } // for all seeds
601  } // if any seed
602  log << '\n' << std::endl;
603 } // SeedMaster<SEED>::print(Stream)
604 
605 
606 //----------------------------------------------------------------------------
607 template <typename SEED>
609  (EngineId const& id)
610 {
611  // Check for an already computed seed.
612  typename map_type::const_iterator iSeed = configuredSeeds.find(id);
614  if (iSeed != configuredSeeds.end()) return iSeed->second;
615 
616  // Compute the seed.
617  seed = policy_impl->getSeed(id);
618  if (policy_impl->yieldsUniqueSeeds()) ensureUnique(id, seed);
619 
620  // Save the result.
621  configuredSeeds[id] = seed;
622 
623  // for per-event policies, configured seed is invalid;
624  // in that case we don't expect to change the seed,
625  // and we should not record it as current; this should not matter anyway
626  // we still store it if there is nothing (emplace does not overwrite)
627  if (seed != InvalidSeed) currentSeeds[id] = seed;
628  else currentSeeds.emplace(id, seed);
629 
630  return seed;
631 } // SeedMaster<SEED>::getSeed()
632 
633 
634 //----------------------------------------------------------------------------
635 template <typename SEED>
637  (EventData_t const& data, EngineId const& id)
638 {
639  // Check for an already computed seed.
640  typename map_type::iterator iSeed = knownEventSeeds.find(id);
642  if (iSeed != knownEventSeeds.end()) return iSeed->second;
643 
644  // Compute the seed.
645  seed = policy_impl->getEventSeed(id, data);
646  if ((seed != InvalidSeed) && policy_impl->yieldsUniqueSeeds())
647  ensureUnique(id, seed, knownEventSeeds);
648 
649  // Save the result.
650  knownEventSeeds[id] = seed;
651 
652  // for configured-seed policies, per-event seed is invalid;
653  // in that case we don't expect to change the seed,
654  // and we should not record it as current
655  // we still store it if there is nothing (emplace does not overwrite)
656  if (seed != InvalidSeed) currentSeeds[id] = seed;
657  else currentSeeds.emplace(id, seed);
658 
659  return seed;
660 } // SeedMaster<SEED>::getEventSeed(EngineId)
661 
662 
663 template <typename SEED>
665  (EventData_t const& data, std::string instanceName)
666 {
667  return getEventSeed(data, EngineId(data.moduleLabel, instanceName));
668 } // SeedMaster<SEED>::getEventSeed(string)
669 
670 
671 
672 //----------------------------------------------------------------------------
673 template <typename SEED>
675  // forget all we know about the current event
676  knownEventSeeds.clear();
677 } // SeedMaster<SEED>::onNewEvent()
678 
679 
680 //----------------------------------------------------------------------------
681 template <typename SEED>
683 
684  policy = details::policyFromName(policyName);
685 
686 } // SeedMaster<SEED>::setPolicy()
687 
688 
689 //----------------------------------------------------------------------------
690 template <typename SEED>
692  (EngineId const& id, seed_t seed, map_type const& seeds) const
693 {
694 
695  for (auto const& p: seeds) {
696 
697  // Do not compare to self
698  if ( p.first == id ) continue;
699 
700  if ( p.second == seed ){
702  << "NuRandomService::ensureUnique() seed: "<<seed
703  << " already used by module.instance: " << p.first << "\n"
704  << "May not be reused by module.instance: " << id;
705  }
706  } // for
707 } // SeedMaster<SEED>::ensureUnique()
708 
709 
710 #endif // NURANDOM_RANDOMUTILS_PROVIDERS_SEEDMASTER_H
std::vector< std::string > const & policyNames()
Returns a list of names of policies, in the same order as Policy enum.
Definition: PolicyNames.cxx:52
void setPolicy(std::string policyName)
Helper function to parse the policy name.
Definition: SeedMaster.h:682
A class to assist in the distribution of guaranteed unique seeds to all engine IDs.
Definition: SeedMaster.h:198
intermediate_table::iterator iterator
void applySeed(Args...args) const
Execute the seeder (whatever arguments it has...)
Definition: SeedMaster.h:226
NuRandomServiceHelper::EventSeedInputData EventData_t
type of data used for event seeds
Definition: BasePolicies.h:48
bool autoseed
whether seeding can be automatic
Definition: SeedMaster.h:236
Declaration of policy enumerator and names.
std::map< EngineId, EngineInfo_t > EngineData_t
type of map of seeders associated with the engines
Definition: SeedMaster.h:241
void print() const
Prints to the framework Info logger.
Definition: SeedMaster.h:358
bool hasSeeder(EngineId const &id) const
Returns whether the specified engine has a valid seeder.
Definition: SeedMaster.h:268
Policy
Enumeration of all supported random seed policies.
Definition: PolicyNames.h:38
map_type knownEventSeeds
List of event seeds already computed.
Definition: SeedMaster.h:371
int verbosity
Control the level of information messages.
Definition: SeedMaster.h:362
static constexpr seed_t InvalidSeed
An invalid seed.
Definition: SeedMaster.h:248
intermediate_table::const_iterator const_iterator
std::string const & policyName(Policy policy)
Returns the name of the specified policy.
Definition: PolicyNames.cxx:56
std::map< EngineId, seed_t > map_type
Type for seed data base.
Definition: SeedMaster.h:213
seed_t getEventSeed(EventData_t const &data, std::string instanceName)
Returns the seed value for the event with specified data.
Definition: SeedMaster.h:665
map_type currentSeeds
List of seeds already computed.
Definition: SeedMaster.h:374
bool hasEngine(EngineId const &id) const
Returns whether the specified engine is already registered.
Definition: SeedMaster.h:264
static seed_t getSeedFromMap(map_type const &seeds, EngineId const &id)
Returns a seed from the specified map, or InvalidSeed if not present.
Definition: SeedMaster.h:396
seed_t seed_t
type of served seeds
Definition: SeedMaster.h:200
SeedMasterHelper::EngineId EngineId
type of engine ID
Definition: SeedMaster.h:203
void registerNewSeeder(EngineId const &id, Seeder_t seeder)
Register the specified function to reseed the engine id.
Definition: SeedMaster.h:484
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
Collection of all the random seed assignment policies.
typename PolicyImpl_t::EventData_t EventData_t
type of data used for event seeds
Definition: SeedMaster.h:245
void freezeSeed(EngineId const &id, seed_t seed)
Forces SeedMaster not to change the seed of a registered engine.
Definition: SeedMaster.h:496
Identifier for a engine, made of module name and optional instance name.
Definition: EngineId.h:22
static const std::vector< std::string > & policyNames()
Definition: SeedMaster.h:428
void freeze(bool doFreeze=true)
Definition: SeedMaster.h:221
Provides a key iterator from a map-type object.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:14
Policy policy
Which of the supported policies to use?
Definition: SeedMaster.h:365
SeedMaster(const fhicl::ParameterSet &)
Definition: SeedMaster.h:435
Helper to instantiate a random number policy class.
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
Definition: StdUtils.h:120
seed_t reseedEvent(EngineId const &id, EventData_t const &data)
Reseeds the specified engine with an event seed (if any)
Definition: SeedMaster.h:520
seed_t getSeed(std::string moduleLabel)
Returns the seed value for this module label.
Definition: SeedMaster.h:457
void onNewEvent()
Prepares for a new event.
Definition: SeedMaster.h:674
void ensureUnique(EngineId const &id, seed_t seed, map_type const &map) const
Throws if the seed has already been used.
Definition: SeedMaster.h:692
bool isGlobal() const
Returns whether the label is "global" (no module context)
Definition: EngineId.h:45
static constexpr seed_t InvalidSeed
An invalid seed.
Definition: BasePolicies.h:51
Seeder_t seeder
engine seeder
Definition: SeedMaster.h:235
map_type configuredSeeds
List of seeds computed from configuration information.
Definition: SeedMaster.h:368
void setSeeder(Seeder_t new_seeder)
Definition: SeedMaster.h:222
std::unique_ptr< PolicyImpl_t > policy_impl
the instance of the random policy
Definition: SeedMaster.h:392
EngineInfoIteratorBox engineIDsRange() const
Returns an object to iterate in range-for through configured engine IDs.
Definition: SeedMaster.h:352
EngineData_t engineData
list of all engine information
Definition: SeedMaster.h:376
void registerSeeder(EngineId const &id, Seeder_t seeder)
Register the specified function to reseed the engine id.
Definition: SeedMaster.h:475
seed_t reseed(EngineId const &id)
Reseeds the specified engine with a global seed (if any)
Definition: SeedMaster.h:506
A data object holding enough data to define a event seed.
seed_t getCurrentSeed(EngineId const &id) const
Returns the last computed seed value for the specified engine ID.
Definition: SeedMaster.h:292
void autoApplySeed(Args...args) const
Applies the seed unless frozen.
Definition: SeedMaster.h:231
void ensureUnique(EngineId const &id, seed_t seed) const
Throws if the seed has already been used.
Definition: SeedMaster.h:387
Provides iterators for std::begin() and std::end()
Policy policyFromName(std::string const &policyName)
Returns the policy with the specified name.
Definition: PolicyNames.cxx:67
An identifier for random engines.
Information for each engine.
Definition: SeedMaster.h:216