LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SeedMaster.h
Go to the documentation of this file.
1 
9 #ifndef NUTOOLS_RANDOMUTILS_PROVIDERS_SEEDMASTER_H
10 #define NUTOOLS_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
28 
29 // more headers included in the implementation section below
30 
31 
32 // The master list of all the policies
33 #define SEED_SERVICE_POLICIES \
34  SEED_SERVICE_POLICY(unDefined) \
35  SEED_SERVICE_POLICY(autoIncrement) \
36  SEED_SERVICE_POLICY(linearMapping) \
37  SEED_SERVICE_POLICY(preDefinedOffset) \
38  SEED_SERVICE_POLICY(preDefinedSeed) \
39  SEED_SERVICE_POLICY(random) \
40  SEED_SERVICE_POLICY(perEvent) \
41 
42 
43 
44 namespace rndm {
45 
207  template <typename SEED>
208  class SeedMaster {
209  public:
210  using seed_t = SEED;
212 
214 
216  using Seeder_t = std::function<void(EngineId const&, seed_t)>;
217 
218  private:
221 
223  using map_type = std::map<EngineId, seed_t>;
224 
226  struct EngineInfo_t {
227  public:
228  bool hasSeeder() const { return bool(seeder); }
229  bool isFrozen() const { return !autoseed; }
230 
231  void freeze(bool doFreeze = true) { autoseed = !doFreeze; }
232  void setSeeder(Seeder_t new_seeder) { seeder = new_seeder; }
233 
235  template <typename... Args>
236  void applySeed(Args... args) const
237  { if (hasSeeder()) seeder(std::forward<Args>(args)...); }
238 
240  template <typename... Args>
241  void autoApplySeed(Args... args) const
242  { if (!isFrozen()) applySeed(std::forward<Args>(args)...); }
243 
244  private:
246  bool autoseed = true;
247 
248  }; // EngineInfo_t
249 
251  using EngineData_t = std::map<EngineId, EngineInfo_t>;
252 
253  public:
256 
259 
260  enum Policy {
261 #define SEED_SERVICE_POLICY(x) x,
263 #undef SEED_SERVICE_POLICY
264  };
265 
266  static const std::vector<std::string>& policyNames();
267 
271 
273 
274  // Accept compiler written c'tors, assignments and d'tor.
275 
277  bool hasEngine(EngineId const& id) const
278  { return engineData.count(id) > 0; }
279 
281  bool hasSeeder(EngineId const& id) const
282  {
283  auto iEngineInfo = engineData.find(id);
284  return
285  (iEngineInfo != engineData.end()) && iEngineInfo->second.hasSeeder();
286  }
287 
289  seed_t getSeed(std::string moduleLabel);
290 
292  seed_t getSeed(std::string moduleLabel, std::string instanceName);
293 
295  seed_t getSeed(EngineId const&);
296 
300  (EventData_t const& data, std::string instanceName);
301  seed_t getEventSeed(EventData_t const& data, EngineId const& id);
303 
305  seed_t getCurrentSeed(EngineId const& id) const
306  { return getSeedFromMap(currentSeeds, id); }
307 
308 
319  void registerSeeder(EngineId const& id, Seeder_t seeder);
320 
321 
333  void registerNewSeeder(EngineId const& id, Seeder_t seeder);
334 
335 
337  void freezeSeed(EngineId const& id, seed_t seed);
338 
339 
348  seed_t reseed(EngineId const& id);
349 
359  seed_t reseedEvent(EngineId const& id, EventData_t const& data);
360 
362  template<typename Stream> void print(Stream&&) const;
363 
366 
368  void onNewEvent();
369 
371  void print() const { print(mf::LogVerbatim("SEEDS")); }
372 
373  private:
376 
379 
382 
385 
388 
390 
392  void setPolicy(std::string policyName);
393 
398  void ensureUnique
399  (EngineId const& id, seed_t seed, map_type const& map) const;
400  void ensureUnique(EngineId const& id, seed_t seed) const
401  { return ensureUnique(id, seed, configuredSeeds); }
403 
405  std::unique_ptr<PolicyImpl_t> policy_impl;
406 
407 
409  static seed_t getSeedFromMap(map_type const& seeds, EngineId const& id)
410  {
411  auto iSeed = seeds.find(id);
412  return (iSeed == seeds.end())? InvalidSeed: iSeed->second;
413  }
414 
415  }; // class SeedMaster
416 
417 } // namespace rndm
418 
419 
420 //==============================================================================
421 //=== Template implementation
422 //===
423 
424 
425 // C++ include files
426 #include <ostream>
427 #include <iomanip> // std::setw()
428 #include <ostream> // std::endl
429 #include <algorithm> // std::find(), std::copy()
430 #include <iterator> // std::ostream_iterator<>, std::distance()
431 
432 // Supporting library include files
434 
435 // Art include files
437 
438 
439 //----------------------------------------------------------------------------
440 template <typename SEED>
441 std::vector<std::string> const& rndm::SeedMaster<SEED>::policyNames() {
442  static std::vector<std::string> names;
443  if(names.empty()) {
444  const char *cnames[] = {
445 #define SEED_SERVICE_POLICY(x) #x,
447 #undef SEED_SERVICE_POLICY
448  };
449  names = std::vector<std::string>
450  (cnames, cnames + sizeof(cnames)/sizeof(cnames[0]));
451  }
452 
453  return names;
454 } // SeedMaster<SEED>::policyNames()
455 
456 
457 
458 //----------------------------------------------------------------------------
459 template <typename SEED>
461  verbosity(pSet.get<int>("verbosity",0)),
462  policy(unDefined),
463  configuredSeeds(),
464  knownEventSeeds(),
465  currentSeeds(),
466  engineData()
467 {
468 
469  // Throw if policy is not recognized.
470  const std::string strPolicy = pSet.get<std::string>("policy");
471  setPolicy(strPolicy);
472 
473  // Finish parsing the parameter set, as required by the selected policy
474  switch(policy) {
475  case autoIncrement:
477  break;
478  case linearMapping:
480  break;
481  case preDefinedOffset:
483  break;
484  case preDefinedSeed:
486  break;
487  case random:
489  break;
490  case perEvent:
492  break;
493  default:
495  << "SeedMaster(): Internal error: unknown policy_ value";
496  } // switch
497 
498  if ( verbosity > 0 )
499  print(mf::LogVerbatim("SeedMaster"));
500 
501 } // SeedMaster<SEED>::SeedMaster()
502 
503 
504 
505 //----------------------------------------------------------------------------
506 template <typename SEED>
507 inline typename rndm::SeedMaster<SEED>::seed_t
509  (std::string moduleLabel)
510 {
511  return getSeed(EngineId(moduleLabel));
512 } // SeedMaster<SEED>::getSeed(string)
513 
514 
515 //----------------------------------------------------------------------------
516 template <typename SEED>
518  (std::string moduleLabel, std::string instanceName)
519 {
520  return getSeed(EngineId(moduleLabel,instanceName));
521 } // SeedMaster<SEED>::getSeed(string, string)
522 
523 
524 //----------------------------------------------------------------------------
525 template <typename SEED>
527  (EngineId const& id, Seeder_t seeder)
528 {
529  engineData[id].setSeeder(seeder); // creates anew and sets
530 } // SeedMaster<SEED>::registerSeeder()
531 
532 
533 //----------------------------------------------------------------------------
534 template <typename SEED>
536  (EngineId const& id, Seeder_t seeder)
537 {
538  if (hasEngine(id)) {
540  << "SeedMaster(): Engine with ID='" << id << "' already registered";
541  }
542  registerSeeder(id, seeder);
543 } // SeedMaster<SEED>::registerNewSeeder()
544 
545 
546 //----------------------------------------------------------------------------
547 template <typename SEED>
549  engineData.at(id).freeze();
550  configuredSeeds[id] = seed;
551  currentSeeds[id] = seed;
552 } // SeedMaster<>::freezeSeed()
553 
554 
555 //----------------------------------------------------------------------------
556 template <typename SEED>
558  (EngineId const& id)
559 {
560  auto const& engineInfo = engineData.at(id);
561  if (engineInfo.isFrozen()) return InvalidSeed;
562  seed_t seed = getSeed(id);
563  if (seed != InvalidSeed) { // reseed
564  engineInfo.applySeed(id, seed);
565  }
566  return seed;
567 } // SeedMaster<SEED>::reseed()
568 
569 
570 template <typename SEED>
572  (EngineId const& id, EventData_t const& data)
573 {
574  auto const& engineInfo = engineData.at(id);
575  if (engineInfo.isFrozen()) return InvalidSeed;
576  seed_t seed = getEventSeed(data, id);
577  if (seed != InvalidSeed) { // reseed
578  engineInfo.autoApplySeed(id, seed);
579  }
580  return seed;
581 } // SeedMaster<SEED>::reseedEvent()
582 
583 
584 
585 //----------------------------------------------------------------------------
586 template <typename SEED> template <typename Stream>
587 void rndm::SeedMaster<SEED>::print(Stream&& log) const {
588  log << "\nSummary of seeds computed by the NuRandomService";
589 
590  // allow the policy implementation to print whatever it feels to
591  std::ostringstream sstr;
592  policy_impl->print(sstr);
593  if (!sstr.str().empty()) log << '\n' << sstr.str();
594 
595  if ( !currentSeeds.empty() ) {
596 
597  constexpr unsigned int ConfSeedWidth = 18;
598  constexpr unsigned int SepWidth1 = 2;
599  constexpr unsigned int LastSeedWidth = 18;
600  constexpr unsigned int SepWidth2 = SepWidth1 + 1;
601 
602  log << "\n "
603  << std::setw(ConfSeedWidth) << "Configured value"
604  << std::setw(SepWidth1) << ""
605  << std::setw(LastSeedWidth) << "Last value"
606  << std::setw(SepWidth2) << ""
607  << "ModuleLabel.InstanceName";
608 
609  for (auto const& p: currentSeeds) {
610  EngineId const& ID = p.first;
611  seed_t configuredSeed = getSeedFromMap(configuredSeeds, ID);
612  seed_t currentSeed = p.second;
613 
614  if (configuredSeed == InvalidSeed) {
615  if (currentSeed == InvalidSeed) {
616  log << "\n "
617  << std::setw(ConfSeedWidth) << "INVALID!!!"
618  << std::setw(SepWidth1) << ""
619  << std::setw(LastSeedWidth) << ""
620  << std::setw(SepWidth2) << ""
621  << ID;
622  }
623  else { // if seed was configured, it should be that one all the way!!
624  log << "\n "
625  << std::setw(ConfSeedWidth) << "(per event)"
626  << std::setw(SepWidth1) << ""
627  << std::setw(LastSeedWidth) << currentSeed
628  << std::setw(SepWidth2) << ""
629  << ID;
630  }
631  }
632  else {
633  if (configuredSeed == currentSeed) {
634  log << "\n "
635  << std::setw(ConfSeedWidth) << configuredSeed
636  << std::setw(SepWidth1) << ""
637  << std::setw(LastSeedWidth) << "(same)"
638  << std::setw(SepWidth2) << ""
639  << ID;
640  }
641  else { // if seed was configured, it should be that one all the way!!
642  log << "\n "
643  << std::setw(ConfSeedWidth) << configuredSeed
644  << std::setw(SepWidth1) << ""
645  << std::setw(LastSeedWidth) << currentSeed
646  << std::setw(SepWidth2) << ""
647  << ID << " [[ERROR!!!]]";
648  }
649  } // if per job
650  if (ID.isGlobal()) log << " (global)";
651  if (hasEngine(ID) && engineData.at(ID).isFrozen()) log << " [overridden]";
652  } // for all seeds
653  } // if any seed
654  log << '\n' << std::endl;
655 } // SeedMaster<SEED>::print(Stream)
656 
657 
658 //----------------------------------------------------------------------------
659 template <typename SEED>
661  (EngineId const& id)
662 {
663  // Check for an already computed seed.
664  typename map_type::const_iterator iSeed = configuredSeeds.find(id);
666  if (iSeed != configuredSeeds.end()) return iSeed->second;
667 
668  // Compute the seed.
669  seed = policy_impl->getSeed(id);
670  if (policy_impl->yieldsUniqueSeeds()) ensureUnique(id, seed);
671 
672  // Save the result.
673  configuredSeeds[id] = seed;
674 
675  // for per-event policies, configured seed is invalid;
676  // in that case we don't expect to change the seed,
677  // and we should not record it as current; this should not matter anyway
678  // we still store it if there is nothing (emplace does not overwrite)
679  if (seed != InvalidSeed) currentSeeds[id] = seed;
680  else currentSeeds.emplace(id, seed);
681 
682  return seed;
683 } // SeedMaster<SEED>::getSeed()
684 
685 
686 //----------------------------------------------------------------------------
687 template <typename SEED>
689  (EventData_t const& data, EngineId const& id)
690 {
691  // Check for an already computed seed.
692  typename map_type::iterator iSeed = knownEventSeeds.find(id);
694  if (iSeed != knownEventSeeds.end()) return iSeed->second;
695 
696  // Compute the seed.
697  seed = policy_impl->getEventSeed(id, data);
698  if ((seed != InvalidSeed) && policy_impl->yieldsUniqueSeeds())
699  ensureUnique(id, seed, knownEventSeeds);
700 
701  // Save the result.
702  knownEventSeeds[id] = seed;
703 
704  // for configured-seed policies, per-event seed is invalid;
705  // in that case we don't expect to change the seed,
706  // and we should not record it as current
707  // we still store it if there is nothing (emplace does not overwrite)
708  if (seed != InvalidSeed) currentSeeds[id] = seed;
709  else currentSeeds.emplace(id, seed);
710 
711  return seed;
712 } // SeedMaster<SEED>::getEventSeed(EngineId)
713 
714 
715 template <typename SEED>
717  (EventData_t const& data, std::string instanceName)
718 {
719  return getEventSeed(data, EngineId(data.moduleLabel, instanceName));
720 } // SeedMaster<SEED>::getEventSeed(string)
721 
722 
723 
724 //----------------------------------------------------------------------------
725 template <typename SEED>
727  // forget all we know about the current event
728  knownEventSeeds.clear();
729 } // SeedMaster<SEED>::onNewEvent()
730 
731 
732 //----------------------------------------------------------------------------
733 template <typename SEED>
734 void rndm::SeedMaster<SEED>::setPolicy(std::string policyName) {
735 
737  = std::find(policyNames().begin(), policyNames().end(), policyName);
738  if (iter != policyNames().end()) {
739  policy = Policy(std::distance(policyNames().begin(), iter));
740  }
741 
742  if (policy == unDefined) {
743  std::ostringstream os;
744  os<< "NuRandomService::setPolicy(): Unrecognized policy: "
745  << policyName
746  << "\n Known policies are: ";
747 
748  std::copy(policyNames().begin(), policyNames().end(),
749  std::ostream_iterator<std::string>(os, ", "));
750 
751  throw art::Exception(art::errors::Configuration) << os.str();
752  }
753 } // SeedMaster<SEED>::setPolicy()
754 
755 
756 //----------------------------------------------------------------------------
757 template <typename SEED>
759  (EngineId const& id, seed_t seed, map_type const& seeds) const
760 {
761 
762  for (auto const& p: seeds) {
763 
764  // Do not compare to self
765  if ( p.first == id ) continue;
766 
767  if ( p.second == seed ){
769  << "NuRandomService::ensureUnique() seed: "<<seed
770  << " already used by module.instance: " << p.first << "\n"
771  << "May not be reused by module.instance: " << id;
772  }
773  } // for
774 } // SeedMaster<SEED>::ensureUnique()
775 
776 
777 #endif // NUTOOLS_RANDOMUTILS_PROVIDERS_SEEDMASTER_H
void setPolicy(std::string policyName)
Helper function to parse the policy name.
Definition: SeedMaster.h:734
A class to assist in the distribution of guaranteed unique seeds to all engine IDs.
Definition: SeedMaster.h:208
void applySeed(Args...args) const
Execute the seeder (whatever arguments it has...)
Definition: SeedMaster.h:236
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:246
std::map< EngineId, EngineInfo_t > EngineData_t
type of map of seeders associated with the engines
Definition: SeedMaster.h:251
void print() const
Prints to the framework Info logger.
Definition: SeedMaster.h:371
intermediate_table::iterator iterator
bool hasSeeder(EngineId const &id) const
Returns whether the specified engine has a valid seeder.
Definition: SeedMaster.h:281
map_type knownEventSeeds
List of event seeds already computed.
Definition: SeedMaster.h:384
int verbosity
Control the level of information messages.
Definition: SeedMaster.h:375
static constexpr seed_t InvalidSeed
An invalid seed.
Definition: SeedMaster.h:258
std::map< EngineId, seed_t > map_type
Type for seed data base.
Definition: SeedMaster.h:223
Implementation of the "preDefinedOffset" policy.
Definition: BasePolicies.h:693
seed_t getEventSeed(EventData_t const &data, std::string instanceName)
Returns the seed value for the event with specified data.
Definition: SeedMaster.h:717
map_type currentSeeds
List of seeds already computed.
Definition: SeedMaster.h:387
bool hasEngine(EngineId const &id) const
Returns whether the specified engine is already registered.
Definition: SeedMaster.h:277
Implementation of the "random" policy.
Definition: BasePolicies.h:781
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:409
seed_t seed_t
type of served seeds
Definition: SeedMaster.h:210
intermediate_table::const_iterator const_iterator
SeedMasterHelper::EngineId EngineId
type of engine ID
Definition: SeedMaster.h:213
void registerNewSeeder(EngineId const &id, Seeder_t seeder)
Register the specified function to reseed the engine id.
Definition: SeedMaster.h:536
Interface for a policy implementation.
Definition: BasePolicies.h:43
long seed
Definition: chem4.cc:68
std::function< void(EngineId const &, seed_t)> Seeder_t
type of a function setting a seed
Definition: SeedMaster.h:216
Implementation of the "autoIncrement" policy.
Definition: BasePolicies.h:343
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:255
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
void freezeSeed(EngineId const &id, seed_t seed)
Forces SeedMaster not to change the seed of a registered engine.
Definition: SeedMaster.h:548
Implementation of the "preDefinedSeed" policy.
Definition: BasePolicies.h:625
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:441
void freeze(bool doFreeze=true)
Definition: SeedMaster.h:231
Provides a key iterator from a map-type object.
Implementation of the "linearMapping" policy.
Definition: BasePolicies.h:415
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
Policy policy
Which of the supported policies to use?
Definition: SeedMaster.h:378
SeedMaster(const fhicl::ParameterSet &)
Definition: SeedMaster.h:460
Implementation of the "perEvent" policy.
seed_t reseedEvent(EngineId const &id, EventData_t const &data)
Reseeds the specified engine with an event seed (if any)
Definition: SeedMaster.h:572
seed_t getSeed(std::string moduleLabel)
Returns the seed value for this module label.
Definition: SeedMaster.h:509
void onNewEvent()
Prepares for a new event.
Definition: SeedMaster.h:726
Definition: G4Helper.h:37
void ensureUnique(EngineId const &id, seed_t seed, map_type const &map) const
Throws if the seed has already been used.
Definition: SeedMaster.h:759
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:245
map_type configuredSeeds
List of seeds computed from configuration information.
Definition: SeedMaster.h:381
void setSeeder(Seeder_t new_seeder)
Definition: SeedMaster.h:232
std::unique_ptr< PolicyImpl_t > policy_impl
the instance of the random policy
Definition: SeedMaster.h:405
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
EngineInfoIteratorBox engineIDsRange() const
Returns an object to iterate in range-for through configured engine IDs.
Definition: SeedMaster.h:365
EngineData_t engineData
list of all engine information
Definition: SeedMaster.h:389
void registerSeeder(EngineId const &id, Seeder_t seeder)
Register the specified function to reseed the engine id.
Definition: SeedMaster.h:527
seed_t reseed(EngineId const &id)
Reseeds the specified engine with a global seed (if any)
Definition: SeedMaster.h:558
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:305
void autoApplySeed(Args...args) const
Applies the seed unless frozen.
Definition: SeedMaster.h:241
void ensureUnique(EngineId const &id, seed_t seed) const
Throws if the seed has already been used.
Definition: SeedMaster.h:400
Provides iterators for std::begin() and std::end()
An identifier for random engines.
Information for each engine.
Definition: SeedMaster.h:226