41 #include "CLHEP/Random/engineIDulong.h"
42 #include "CLHEP/Random/JamesRandom.h"
43 #include "CLHEP/Random/RanecuEngine.h"
44 #include "CLHEP/Random/MixMaxRng.h"
64 saveFileName_(
pset.getUntrackedParameter<
std::
string>(
"saveFileName")),
65 saveFileNameRecorded_(
false),
66 restoreFileName_(
pset.getUntrackedParameter<
std::
string>(
"restoreFileName")),
67 enableChecking_(
pset.getUntrackedParameter<
bool>(
"enableChecking")),
68 eventSeedOffset_(
pset.getUntrackedParameter<unsigned>(
"eventSeedOffset")),
69 verbose_(
pset.getUntrackedParameter<
bool>(
"verbose")) {
70 if (
pset.exists(
"restoreStateTag")) {
83 <<
"restoreFileName and restoreStateLabel were set to nonempty values\n"
84 <<
"which is illegal. It is impossible to restore the random engine\n"
85 <<
"states two different ways in the same process.\n";
92 <<
"The saveFileName parameter must be a simple file name with no path\n"
93 <<
"specification. In the configuration, it was given the value \"" <<
saveFileName_ <<
"\"\n";
100 std::vector<std::string> pSets =
pset.getParameterNamesForType<
ParameterSet>();
101 for (
auto const&
label : pSets) {
105 bool initialSeedExists = modulePSet.
exists(
"initialSeed");
106 bool initialSeedSetExists = modulePSet.
exists(
"initialSeedSet");
108 if (initialSeedExists && initialSeedSetExists) {
110 <<
"both the parameters \"initialSeed\" and \"initialSeedSet\"\n"
111 <<
"have been set in the configuration. You must set one or\n"
112 <<
"the other. It is illegal to set both.\n";
113 }
else if (!initialSeedExists && !initialSeedSetExists) {
115 <<
"neither the parameter \"initialSeed\" nor \"initialSeedSet\"\n"
116 <<
"has been set in the configuration. You must set one or\n"
118 }
else if (initialSeedExists) {
122 }
else if (initialSeedSetExists) {
131 <<
"Random engines of type \"RanecuEngine\" require 2 seeds\n"
132 <<
"be specified with the parameter named \"initialSeedSet\".\n"
133 <<
"Either \"initialSeedSet\" was not in the configuration\n"
134 <<
"or its size was not 2 for the module with label \"" <<
label <<
"\".\n";
139 <<
"The RanecuEngine seeds should be in the range 0 to " <<
maxSeedRanecu <<
".\n"
140 <<
"The seeds passed to the RandomNumberGenerationService from the\n"
141 "configuration file were "
150 <<
"Random engines of type \"HepJamesRandom\", \"TRandom3\" and \"MixMaxRng\" \n"
151 <<
"require exactly 1 seed be specified in the configuration.\n"
152 <<
"There were " <<
initialSeedSet.size() <<
" seeds set for the\n"
153 <<
"module with label \"" <<
label <<
"\".\n";
158 <<
"The CLHEP::HepJamesRandom engine seed should be in the range 0 to " <<
maxSeedHepJames <<
".\n"
159 <<
"The seed passed to the RandomNumberGenerationService from the\n"
160 "configuration file was "
162 <<
"the module with label " <<
label <<
".\n";
167 <<
"The CLHEP::MixMaxRng engine seed should be in the range 0 to " <<
maxSeedTRandom3 <<
".\n"
168 <<
"The seed passed to the RandomNumberGenerationService from the\n"
169 "configuration file was "
171 <<
"the module with label " <<
label <<
".\n";
176 <<
"The CLHEP::MixMaxRng engine seed should be in the range 0 to " <<
maxSeedTRandom3 <<
".\n"
177 <<
"The seed passed to the RandomNumberGenerationService from the\n"
178 "configuration file was "
180 <<
"the module with label " <<
label <<
".\n";
184 <<
"The random engine name, \"" <<
engineName <<
"\", does not correspond to a supported engine.\n"
185 <<
"This engine was configured for the module with label \"" <<
label <<
"\"";
224 if (mcc ==
nullptr) {
226 <<
"RandomNumberGeneratorService::getEngine\n"
227 "Requested a random number engine from the RandomNumberGeneratorService\n"
228 "when no module was active. ModuleCallingContext is null\n";
234 std::vector<ModuleIDToEngine>::iterator iter =
236 if (iter == moduleIDVector.end() || iter->moduleID() != moduleID) {
239 <<
"\" requested a random number engine from the \n"
240 "RandomNumberGeneratorService, but that module was not configured\n"
241 "for random numbers. An engine is created only if a seed(s) is provided\n"
242 "in the configuration file. Please add the following PSet to the\n"
243 "configuration file for the RandomNumberGeneratorService:\n\n"
247 " initialSeed = cms.untracked.uint32(your_seed),\n"
248 " engineName = cms.untracked.string('TRandom3')\n"
250 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
251 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
253 return *iter->labelAndEngine()->engine();
258 if (mcc ==
nullptr) {
260 <<
"RandomNumberGeneratorService::getEngine\n"
261 "Requested a random number engine from the RandomNumberGeneratorService\n"
262 "when no module was active. ModuleCallingContext is null\n";
268 std::vector<ModuleIDToEngine>::iterator iter =
270 if (iter == moduleIDVector.end() || iter->moduleID() != moduleID) {
273 <<
"\" requested a random number engine from the \n"
274 "RandomNumberGeneratorService, but that module was not configured\n"
275 "for random numbers. An engine is created only if a seed(s) is provided\n"
276 "in the configuration file. Please add the following PSet to the\n"
277 "configuration file for the RandomNumberGeneratorService:\n\n"
281 " initialSeed = cms.untracked.uint32(your_seed),\n"
282 " engineName = cms.untracked.string('TRandom3')\n"
284 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
285 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
287 return *iter->labelAndEngine()->engine();
294 std::vector<unsigned long> stateL = existingEngine.put();
295 long seedL = existingEngine.getSeed();
296 std::unique_ptr<CLHEP::HepRandomEngine> newEngine;
297 if (stateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
298 newEngine = std::make_unique<CLHEP::HepJamesRandom>(seedL);
299 }
else if (stateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
300 newEngine = std::make_unique<CLHEP::RanecuEngine>();
301 }
else if (stateL[0] == CLHEP::engineIDulong<CLHEP::MixMaxRng>()) {
302 newEngine = std::make_unique<CLHEP::MixMaxRng>(seedL);
303 }
else if (stateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
304 newEngine = std::make_unique<TRandomAdaptor>(seedL);
309 newEngine->get(stateL);
322 if (mcc ==
nullptr) {
324 <<
"RandomNumberGeneratorService::getEngine()\n"
325 "Requested a random number engine from the RandomNumberGeneratorService\n"
326 "from an unallowed transition. ModuleCallingContext is null\n";
334 <<
"The module with label \"" <<
label
335 <<
"\" requested a random number seed from the \n"
336 "RandomNumberGeneratorService, but that module was not configured\n"
337 "for random numbers. An engine is created only if a seed(s) is provided\n"
338 "in the configuration file. Please add the following PSet to the\n"
339 "configuration file for the RandomNumberGeneratorService:\n\n"
343 " initialSeed = cms.untracked.uint32(your_seed),\n"
344 " engineName = cms.untracked.string('TRandom3')\n"
346 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
347 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
349 return iter->second.seeds()[0];
363 desc.addUntracked<
bool>(
"enableChecking",
false);
364 desc.addUntracked<
unsigned>(
"eventSeedOffset", 0
U);
365 desc.addUntracked<
bool>(
"verbose",
false);
368 val.addOptionalUntracked<std::uint32_t>(
"initialSeed");
369 val.addOptionalUntracked<std::vector<std::uint32_t> >(
"initialSeedSet");
373 wnode.setComment(
"The name of each ParameterSet will be the associated module label.");
376 descriptions.
add(
"RandomNumberGeneratorService",
desc);
398 <<
"Configuration is illegal. The RandomNumberGeneratorService is configured\n"
399 <<
"to run replay using a text file to input the random engine states and\n"
400 <<
"the number of streams is greater than 1. Either set the\n"
401 <<
"parameter named \"restoreFileName\" in the RandomNumberGeneratorService\n"
402 <<
"to the empty string or set the parameter \"numberOfStreams\" in the top\n"
403 <<
"level options parameter set to 1. (Probably these are the default values\n"
404 <<
"and just not setting the parameters will also work)\n";
416 for (
unsigned int iStream = 0; iStream <
nStreams_; ++iStream) {
417 unsigned int seedOffset = iStream;
420 outFiles_[iStream] = std::make_shared<std::ofstream>();
423 for (
unsigned int iLumi = 0; iLumi < nConcurrentLumis; ++iLumi) {
471 bool expected =
false;
475 reportSvc->reportRandomStateFile(
fullName);
481 std::vector<RandomEngineState>
const& iStates) {
557 os <<
"\n\nRandomNumberGeneratorService dump\n\n";
559 os <<
" Contents of seedsAndNameMap (label moduleID engineType seeds)\n";
561 os <<
" " <<
entry.first <<
" " <<
entry.second.moduleID() <<
" " <<
entry.second.engineName();
562 for (
auto val :
entry.second.seeds()) {
567 os <<
" nStreams_ = " <<
nStreams_ <<
"\n";
573 os <<
" verbose_ = " <<
verbose_ <<
"\n";
577 os <<
"\n streamEngines_\n";
578 unsigned int iStream = 0;
580 os <<
" Stream " << iStream <<
"\n";
581 for (
auto const&
i :
k) {
582 os <<
" " <<
i.label();
583 for (
auto const&
j :
i.seeds()) {
586 os <<
" " <<
i.engine()->name();
587 if (
i.engine()->name() ==
std::string(
"HepJamesRandom")) {
588 os <<
" " <<
i.engine()->getSeed();
589 }
else if (
i.engine()->name() ==
std::string(
"MixMaxRng")) {
590 os <<
" " <<
i.engine()->getSeed();
592 os <<
" engine does not know seeds";
598 os <<
"\n lumiEngines_\n";
599 unsigned int iLumi = 0;
601 os <<
" lumiIndex " << iLumi <<
"\n";
602 for (
auto const&
i :
k) {
603 os <<
" " <<
i.label();
604 for (
auto const&
j :
i.seeds()) {
607 os <<
" " <<
i.engine()->name();
608 if (
i.engine()->name() ==
std::string(
"HepJamesRandom")) {
609 os <<
" " <<
i.engine()->getSeed();
610 }
else if (
i.engine()->name() ==
std::string(
"MixMaxRng")) {
611 os <<
" " <<
i.engine()->getSeed();
613 os <<
" engine does not know seeds";
626 std::vector<ModuleIDToEngine>::iterator iter =
628 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
630 iter->setEngineState(labelAndEngine->
engine()->put());
640 std::vector<ModuleIDToEngine>::iterator iter =
642 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
644 if (iter->engineState() != labelAndEngine->
engine()->put()) {
646 <<
"It is illegal to generate random numbers during beginStream, endStream,\n"
647 "beginRun, endRun, beginLumi, endLumi because that makes it very difficult\n"
648 "to replay the processing of individual events. Random numbers were\n"
649 "generated during one of these methods for the module with class name\n\""
652 "and module label \""
664 <<
"In the configuration for the RandomNumberGeneratorService the\n"
665 <<
"restoreStateTag contains the current process which is illegal.\n"
666 <<
"The process name in the replay process should have been changed\n"
667 <<
"to be different than the original process name and the restoreStateTag\n"
668 <<
"should contain either the original process name or an empty process name.\n";
677 <<
"The RandomNumberGeneratorService is trying to restore\n"
678 <<
"the state of the random engines by reading a product from\n"
680 <<
"It could not find the product.\n"
681 <<
"Either the product in the LuminosityBlock was dropped or\n"
682 <<
"not produced or the configured input tag is incorrect or there is a bug somewhere\n";
695 <<
"The RandomNumberGeneratorService is trying to restore\n"
696 <<
"the state of the random engines by reading a product from\n"
698 <<
"It could not find the product.\n"
699 <<
"Either the product in the Event was dropped or\n"
700 <<
"not produced or the configured input tag is incorrect or there is a bug somewhere\n";
707 std::vector<RandomEngineState>&
cache) {
708 cache.resize(engines.size());
709 std::vector<RandomEngineState>::iterator
state =
cache.begin();
711 for (std::vector<LabelAndEngine>::const_iterator iter = engines.begin(); iter != engines.end(); ++iter, ++
state) {
714 state->setSeed(iter->seeds());
716 std::vector<unsigned long> stateL = iter->engine()->put();
717 state->clearStateVector();
718 state->reserveStateVector(stateL.size());
719 for (
auto element : stateL) {
720 state->push_back_stateVector(static_cast<std::uint32_t>(element));
726 std::vector<LabelAndEngine>& engines) {
727 std::vector<LabelAndEngine>::iterator labelAndEngine = engines.begin();
728 for (
auto const& cachedState :
cache) {
729 std::string const& engineLabel = cachedState.getLabel();
731 std::vector<std::uint32_t>
const& engineState = cachedState.getState();
732 std::vector<unsigned long> engineStateL;
733 engineStateL.reserve(engineState.size());
734 for (
auto const&
value : engineState) {
735 engineStateL.push_back(static_cast<unsigned long>(
value));
738 std::vector<std::uint32_t>
const& engineSeeds = cachedState.getSeed();
739 std::vector<long> engineSeedsL;
740 engineSeedsL.reserve(engineSeeds.size());
741 for (
auto const&
val : engineSeeds) {
742 long seedL = static_cast<long>(
val);
743 engineSeedsL.push_back(seedL);
752 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
756 assert(labelAndEngine != engines.end() && engineLabel == labelAndEngine->label());
757 std::shared_ptr<CLHEP::HepRandomEngine>
const& engine = labelAndEngine->engine();
761 if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
765 engine->setSeed(engineSeedsL[0], 0);
766 engine->get(engineStateL);
768 labelAndEngine->setSeed(engineSeeds[0], 0);
769 }
else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
773 engine->get(engineStateL);
775 labelAndEngine->setSeed(engineSeeds[0], 0);
776 labelAndEngine->setSeed(engineSeeds[1], 1);
777 }
else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::MixMaxRng>()) {
781 engine->setSeed(engineSeedsL[0], 0);
782 engine->get(engineStateL);
784 labelAndEngine->setSeed(engineSeeds[0], 0);
785 }
else if (engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
789 engine->setSeed(engineSeedsL[0], 0);
790 engine->get(engineStateL);
792 labelAndEngine->setSeed(engineSeeds[0], 0);
797 <<
"The RandomNumberGeneratorService is trying to restore the state\n"
798 "of the random engines. The state in the event indicates an engine\n"
799 "of an unknown type. This should not be possible unless you are\n"
800 "running with an old code release on a new file that was created\n"
801 "with a newer release which had new engine types added. In this case\n"
802 "the only solution is to use a newer release. In any other case, notify\n"
803 "the EDM developers because this should not be possible\n";
812 if (typeFromConfig != typeFromEvent) {
814 <<
"The RandomNumberGeneratorService is trying to restore\n"
815 <<
"the state of the random engine for the module \"" << engineLabel <<
"\". An\n"
816 <<
"error was detected because the type of the engine in the\n"
817 <<
"input file and the configuration file do not match.\n"
818 <<
"In the configuration file the type is \"" << typeFromConfig <<
"\".\nIn the input file the type is \""
819 << typeFromEvent <<
"\". If\n"
820 <<
"you are not generating any random numbers in this module, then\n"
821 <<
"remove the line in the configuration file that gives it\n"
822 <<
"a seed and the error will go away. Otherwise, you must give\n"
823 <<
"this module the same engine type in the configuration file or\n"
824 <<
"stop trying to restore the random engine state.\n";
834 std::stringstream
file;
844 <<
"Unable to open the file \"" <<
file.str() <<
"\" to save the state of the random engines.\n";
848 outFile.seekp(0, std::ios_base::beg);
849 outFile <<
"<RandomEngineStates>\n";
859 outFile <<
"</RandomEngineStates>\n";
865 std::vector<std::uint32_t>
const& seedVector =
state.getSeed();
868 std::vector<std::uint32_t>
const& stateVector =
state.getState();
871 outFile <<
"<ModuleLabel>\n" <<
state.getLabel() <<
"\n</ModuleLabel>\n";
873 outFile <<
"<SeedLength>\n" << seedVectorLength <<
"\n</SeedLength>\n";
876 outFile <<
"</InitialSeeds>\n";
877 outFile <<
"<FullStateLength>\n" << stateVectorLength <<
"\n</FullStateLength>\n";
887 size_t numItems =
v.size();
888 for (
size_t i = 0;
i < numItems; ++
i) {
889 if (
i != 0 &&
i % 10 == 0)
904 std::vector<RandomEngineState>&
cache) {
910 std::vector<RandomEngineState>&
cache) {
916 std::vector<RandomEngineState>&
cache,
918 std::ifstream inFile;
922 <<
"Unable to open the file \"" <<
fileName <<
"\" to restore the random engine states.\n";
929 <<
"Attempting to read file with random number engine states.\n"
930 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
931 <<
"Cannot read the file header word.\n";
933 bool saveToCache =
false;
939 std::vector<RandomEngineState>&
cache,
946 std::vector<std::uint32_t> seedVector;
948 std::vector<std::uint32_t> stateVector;
957 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
958 <<
"Cannot read next field and did not hit the end yet.\n";
962 if (leading ==
std::string(
"</RandomEngineStates>"))
973 saveToCache = (leading == whichStates);
982 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
983 <<
"Cannot read a module label when restoring random engine states.\n";
986 is >> leading >> seedVectorSize >> trailing;
989 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
990 <<
"Cannot read seed vector length when restoring random engine states.\n";
994 if (!is.good() || leading !=
std::string(
"<InitialSeeds>")) {
996 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
997 <<
"Cannot read beginning of InitialSeeds when restoring random engine states.\n";
1002 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1003 <<
"The number of seeds exceeds 64K.\n";
1009 if (!is.good() || trailing !=
std::string(
"</InitialSeeds>")) {
1011 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1012 <<
"Cannot read end of InitialSeeds when restoring random engine states.\n";
1015 is >> leading >> stateVectorSize >> trailing;
1016 if (!is.good() || leading !=
std::string(
"<FullStateLength>") || trailing !=
std::string(
"</FullStateLength>")) {
1018 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1019 <<
"Cannot read state vector length when restoring random engine states.\n";
1023 if (!is.good() || leading !=
std::string(
"<FullState>")) {
1025 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1026 <<
"Cannot read beginning of FullState when restoring random engine states.\n";
1031 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1032 <<
"The number of states exceeds 64K.\n";
1035 readVector(is, stateVectorSize, stateVector);
1038 if (!is.good() || trailing !=
std::string(
"</FullState>")) {
1040 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1041 <<
"Cannot read end of FullState when restoring random engine states.\n";
1047 std::vector<RandomEngineState>::iterator
state =
1051 if (seedVector.size() !=
state->getSeed().size() || stateVector.size() !=
state->getState().size()) {
1053 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1054 <<
"Vectors containing engine state are the incorrect size for the type of random engine.\n";
1056 state->setSeed(seedVector);
1057 state->setState(stateVector);
1065 v.reserve(numItems);
1067 for (
unsigned i = 0;
i < numItems; ++
i) {
1071 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1072 <<
"Cannot read vector when restoring random engine states.\n";
1079 unsigned int seedOffset,
1080 unsigned int eventSeedOffset,
1081 std::vector<ModuleIDToEngine>& moduleIDVector) {
1088 unsigned int moduleID =
i.second.moduleID();
1094 if (
name ==
"RanecuEngine") {
1095 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::RanecuEngine>();
1101 long int seedL = static_cast<long int>(
seeds[0]);
1103 if (
name ==
"HepJamesRandom") {
1104 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::HepJamesRandom>(seedL);
1106 if (seedOffset != 0 || eventSeedOffset != 0) {
1109 }
else if (
name ==
"MixMaxRng") {
1110 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::MixMaxRng>(seedL);
1112 if (seedOffset != 0 || eventSeedOffset != 0) {
1124 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1127 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<TRandomAdaptor>(seedL);
1129 if (seedOffset != 0 || eventSeedOffset != 0) {
1134 moduleIDVector.emplace_back(&engines.back(), moduleID);
1137 std::sort(moduleIDVector.begin(), moduleIDVector.end());
1143 std::uint32_t offset1,
1144 std::uint32_t offset2) {
1151 std::uint32_t seed0 = (
seeds[0] + offset1) %
mod;
1152 seed0 = (seed0 + offset2) %
mod;
1153 labelAndEngine.
setSeed(seed0, 0);
1156 seedL[0] = static_cast<long int>(seed0);
1157 seedL[1] = static_cast<long int>(
seeds[1]);
1158 labelAndEngine.
engine()->setSeeds(seedL, 0);
1167 std::uint32_t seed0 = (
seeds[0] + offset1) %
mod;
1168 seed0 = (seed0 + offset2) %
mod;
1169 labelAndEngine.
setSeed(seed0, 0);
1171 long int seedL = static_cast<long int>(seed0);
1172 labelAndEngine.
engine()->setSeed(seedL, 0);
1179 std::uint32_t seed0 =
seeds[0];
1180 if ((max32 - seed0) >= offset1) {
1183 seed0 = offset1 - (max32 - seed0) - 1
U;
1185 if ((max32 - seed0) >= offset2) {
1188 seed0 = offset2 - (max32 - seed0) - 1
U;
1190 labelAndEngine.
setSeed(seed0, 0);
1192 long seedL = static_cast<long>(seed0);
1201 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1202 assert(seed0 == seedu32);
1204 labelAndEngine.
engine()->setSeed(seedL, 0);