30 #include "CLHEP/Random/DRand48Engine.h" 31 #include "CLHEP/Random/DualRand.h" 32 #include "CLHEP/Random/Hurd160Engine.h" 33 #include "CLHEP/Random/Hurd288Engine.h" 34 #include "CLHEP/Random/JamesRandom.h" 35 #include "CLHEP/Random/MTwistEngine.h" 36 #include "CLHEP/Random/NonRandomEngine.h" 37 #include "CLHEP/Random/Random.h" 38 #include "CLHEP/Random/RanecuEngine.h" 39 #include "CLHEP/Random/Ranlux64Engine.h" 40 #include "CLHEP/Random/RanluxEngine.h" 41 #include "CLHEP/Random/RanshiEngine.h" 42 #include "CLHEP/Random/TripleRand.h" 49 #include "cetlib/assert_only_one_thread.h" 50 #include "cetlib/container_algorithms.h" 51 #include "cetlib/no_delete.h" 52 #include "cetlib_except/exception.h" 75 using eptr_t = RNGservice::eptr_t;
76 using label_t = RNGservice::label_t;
77 using seed_t = RNGservice::seed_t;
78 using base_engine_t = RNGservice::base_engine_t;
80 string const DEFAULT_ENGINE_KIND{
"HepJamesRandom"};
81 seed_t constexpr MAXIMUM_CLHEP_SEED{900000000};
82 seed_t constexpr USE_DEFAULT_SEED{-1};
89 throw_if_invalid_seed(seed_t
const seed)
91 if (seed == USE_DEFAULT_SEED)
93 if (seed > MAXIMUM_CLHEP_SEED)
95 <<
"RNGservice::throw_if_invalid_seed():\n" 97 << seed <<
" exceeds permitted maximum " << MAXIMUM_CLHEP_SEED <<
".\n";
100 <<
"RNGservice::throw_if_invalid_seed():\n" 102 << seed <<
" is not permitted to be negative.\n";
106 qualify_engine_label(ScheduleID::size_type
const schedule_id,
107 label_t
const& engine_label)
114 label += engine_label;
118 template <
class DesiredEngineType>
120 manufacture_an_engine(seed_t
const seed)
122 return eptr_t{seed == USE_DEFAULT_SEED ?
new DesiredEngineType :
123 new DesiredEngineType(seed)};
127 inline eptr_t manufacture_an_engine<CLHEP::NonRandomEngine>(
131 return std::make_shared<CLHEP::NonRandomEngine>();
136 manufacture_an_engine<G4Engine>(seed_t
const seed)
138 if (seed != USE_DEFAULT_SEED)
139 CLHEP::HepRandom::setTheSeed(seed);
141 return eptr_t{CLHEP::HepRandom::getTheEngine(), cet::no_delete{}};
145 engine_factory(
string const& kind_of_engine_to_make, seed_t
const seed)
147 #define MANUFACTURE_EXPLICIT(KIND, TYPE) \ 148 if (kind_of_engine_to_make == string{KIND}) \ 149 return manufacture_an_engine<TYPE>(seed); 151 #define MANUFACTURE_IMPLICIT(ENGINE) \ 152 MANUFACTURE_EXPLICIT(#ENGINE, CLHEP::ENGINE) 165 #undef MANUFACTURE_IMPLICIT 166 #undef MANUFACTURE_EXPLICIT 169 <<
"engine_factory():\n" 170 "Attempt to create engine of unknown kind \"" 171 << kind_of_engine_to_make <<
"\".\n";
175 expand_if_abbrev_kind(
string& requested_engine_kind)
177 if (requested_engine_kind.empty() ||
178 requested_engine_kind ==
"DefaultEngine" ||
179 requested_engine_kind ==
"JamesRandom") {
180 requested_engine_kind = DEFAULT_ENGINE_KIND;
188 RNGservice::RandomNumberGenerator(Parameters
const& config,
190 : restoreStateLabel_{config().restoreStateLabel()}
194 ,
debug_{config().debug()}
197 reg.
sPostEndJob.watch(
this, &RNGservice::postEndJob);
201 unsigned const nSchedules{1u};
202 data_.resize(nSchedules);
208 RNGservice::getEngine()
const 214 RNGservice::getEngine(
label_t const& engine_label)
const 218 return getEngine(schedule_id, engine_label);
222 RNGservice::getEngine(
ScheduleID const schedule_id,
223 label_t const& engine_label)
const 226 auto const sid = schedule_id.
id();
227 label_t const&
label = qualify_engine_label(sid, engine_label);
229 auto d =
data_[sid].dict_.find(label);
230 if (
d ==
data_[sid].dict_.end()) {
232 "The requested engine \"" 233 << label <<
"\" has not been established.\n";
235 assert(
d->second &&
"RNGservice::getEngine()");
245 auto const&
d =
data_[schedule_id];
246 return d.dict_.size() ==
d.tracker_.size() &&
247 d.dict_.size() ==
d.kind_.size();
255 return createEngine(schedule_id, seed, DEFAULT_ENGINE_KIND);
259 RNGservice::createEngine(
ScheduleID const schedule_id,
261 string const& requested_engine_kind)
267 RNGservice::createEngine(
ScheduleID const schedule_id,
269 string requested_engine_kind,
274 CET_ASSERT_ONLY_ONE_THREAD();
276 auto const sid = schedule_id.
id();
277 assert(sid <
data_.size());
279 label_t const& label = qualify_engine_label(sid, engine_label);
283 "Attempt to create engine \"" 284 << label <<
"\" is too late.\n";
288 if (
d.tracker_.find(label) !=
d.tracker_.cend()) {
291 << label <<
"\" has already been created.\n";
294 throw_if_invalid_seed(seed);
295 expand_if_abbrev_kind(requested_engine_kind);
296 eptr_t eptr{engine_factory(requested_engine_kind, seed)};
297 assert(eptr &&
"RNGservice::createEngine()");
300 d.kind_[
label] = requested_engine_kind;
303 log <<
"Instantiated " << requested_engine_kind <<
" engine \"" << label
305 if (seed == USE_DEFAULT_SEED)
306 log <<
"default seed " <<
seed;
308 log <<
"seed " <<
seed;
324 RNGservice::print_()
const 326 CET_ASSERT_ONLY_ONE_THREAD();
328 static unsigned ncalls{};
333 auto print_per_stream = [](std::size_t
const i,
auto const&
d) {
335 if (
d.snapshot_.empty()) {
336 log <<
"No snapshot has yet been made.\n";
340 log <<
"Snapshot information:";
341 for (
auto const&
ss :
d.snapshot_) {
342 log <<
"\nEngine: " <<
ss.label() <<
" Kind: " <<
ss.ekind()
343 <<
" Schedule ID: " << i <<
" State size: " <<
ss.state().size();
348 cet::for_all_with_index(
data_, print_per_stream);
354 RNGservice::takeSnapshot_(
ScheduleID const schedule_id)
357 log <<
"RNGservice::takeSnapshot_() of the following engine labels:\n";
361 for (
auto const& pr :
d.dict_) {
362 label_t const& label = pr.first;
363 eptr_t const& eptr = pr.second;
364 assert(eptr &&
"RNGservice::takeSnapshot_()");
366 d.snapshot_.emplace_back(
d.kind_[label], label, eptr->put());
367 log <<
" | " <<
label;
375 RNGservice::restoreSnapshot_(
ScheduleID const schedule_id,
382 using saved_t = std::vector<RNGsnapshot>;
388 for (
auto const& snapshot : saved) {
389 label_t const& label = snapshot.label();
391 log <<
"RNGservice::restoreSnapshot_(): label \"" << label <<
"\"";
393 auto t = d.tracker_.find(label);
394 if (t == d.tracker_.end()) {
395 log <<
" could not be restored;\n" 396 "no established engine bears this label.\n";
402 <<
"RNGservice::restoreSnapshot_():\n" 403 "The state of engine \"" 405 <<
"\" has been previously read from a file;\n" 406 "it is therefore not restorable from a snapshot product.\n";
410 assert(ep &&
"RNGservice::restoreSnapshot_()");
413 auto const& est = snapshot.restoreState();
415 log <<
" successfully restored.\n";
418 <<
"RNGservice::restoreSnapshot_():\n" 419 "Failed during restore of state of engine for \"" 425 "RNGsnapshot::restoreSnapshot_()");
430 RNGservice::saveToFile_()
435 CET_ASSERT_ONLY_ONE_THREAD();
444 for (
auto const& d :
data_) {
445 for (
auto const& pr : d.dict_) {
446 outfile << pr.first <<
'\n';
447 auto const& eptr = pr.second;
448 assert(eptr &&
"RNGservice::saveToFile_()");
453 <<
"This module's engine has not been saved;\n" 462 RNGservice::restoreFromFile_()
467 CET_ASSERT_ONLY_ONE_THREAD();
473 <<
"RNGservice::restoreFromFile_():\n" 480 assert(std::count(label.cbegin(), label.cend(),
':') == 2u);
481 auto const p1 = label.find_first_of(
':');
482 auto const p2 = label.find_last_of(
':');
483 ScheduleID const schedule_id(std::stoul(label.substr(p1 + 1, p2)));
484 auto& data = data_[schedule_id.
id()];
486 auto d = data.dict_.find(label);
487 if (d == data.dict_.end()) {
489 <<
"Attempt to restore an engine with label " << label
490 <<
" not configured in this job.\n";
493 assert(data.tracker_.find(label) != data.tracker_.cend() &&
494 "RNGservice::restoreFromFile_()");
497 auto& eptr = d->second;
498 assert(eptr &&
"RNGservice::restoreFromFile_()");
499 if (!eptr->get(infile)) {
501 <<
"RNGservice::restoreFromFile_():\n" 502 <<
"Failed during restore of state of engine for label " << label
508 <<
"Engine state file contains two engine states with the " 509 <<
"same label: " << label <<
"\n.";
512 <<
"Internal error: attempt to restore an engine state " << label
513 <<
" from file\nwhich was originally initialized via an " 514 <<
" unknown or impossible method.\n";
517 "RNGservice::restoreFromFile_()");
523 void RNGservice::postBeginJob()
538 RNGservice::postEndJob()
#define MANUFACTURE_IMPLICIT(ENGINE)
GlobalSignal< detail::SignalResponseType::FIFO, void()> sPostBeginJob
std::shared_ptr< base_engine_t > eptr_t
#define MANUFACTURE_EXPLICIT(KIND, TYPE)
#define DEFINE_ART_SERVICE(svc)
GlobalSignal< detail::SignalResponseType::LIFO, void()> sPostEndJob
std::string const restoreFromFilename_
void restoreSnapshot_(ScheduleID scheduleID, art::Event const &)
bool invariant_holds_(ScheduleID::size_type scheduleID)
constexpr id_type id() const
static ScheduleID first()
base_engine_t & getEngine() const
base_engine_t & createEngine(ScheduleID schedule_id, seed_t seed)
std::vector< ScheduleData > data_
std::string const saveToFilename_
CLHEP::HepRandomEngine base_engine_t
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
label_t const restoreStateLabel_
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
GlobalSignal< detail::SignalResponseType::FIFO, void(Event const &)> sPreProcessEvent
bool engine_creation_is_okay_
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
RNGsnapshot::label_t label_t
void takeSnapshot_(ScheduleID scheduleID)
cet::coded_exception< error, detail::translate > exception
Event finding and building.