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 <<
"\"";
223 if (mcc ==
nullptr) {
225 <<
"RandomNumberGeneratorService::getEngine\n"
226 "Requested a random number engine from the RandomNumberGeneratorService\n"
227 "when no module was active. ModuleCallingContext is null\n";
233 std::vector<ModuleIDToEngine>::iterator iter =
235 if (iter == moduleIDVector.end() || iter->moduleID() != moduleID) {
238 <<
"\" requested a random number engine from the \n"
239 "RandomNumberGeneratorService, but that module was not configured\n"
240 "for random numbers. An engine is created only if a seed(s) is provided\n"
241 "in the configuration file. Please add the following PSet to the\n"
242 "configuration file for the RandomNumberGeneratorService:\n\n"
246 " initialSeed = cms.untracked.uint32(your_seed),\n"
247 " engineName = cms.untracked.string('TRandom3')\n"
249 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
250 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
252 return *iter->labelAndEngine()->engine();
257 if (mcc ==
nullptr) {
259 <<
"RandomNumberGeneratorService::getEngine\n"
260 "Requested a random number engine from the RandomNumberGeneratorService\n"
261 "when no module was active. ModuleCallingContext is null\n";
267 std::vector<ModuleIDToEngine>::iterator iter =
269 if (iter == moduleIDVector.end() || iter->moduleID() != moduleID) {
272 <<
"\" requested a random number engine from the \n"
273 "RandomNumberGeneratorService, but that module was not configured\n"
274 "for random numbers. An engine is created only if a seed(s) is provided\n"
275 "in the configuration file. Please add the following PSet to the\n"
276 "configuration file for the RandomNumberGeneratorService:\n\n"
280 " initialSeed = cms.untracked.uint32(your_seed),\n"
281 " engineName = cms.untracked.string('TRandom3')\n"
283 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
284 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
286 return *iter->labelAndEngine()->engine();
293 std::vector<unsigned long> stateL = existingEngine.put();
294 long seedL = existingEngine.getSeed();
295 std::unique_ptr<CLHEP::HepRandomEngine> newEngine;
296 if (stateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
297 newEngine = std::make_unique<CLHEP::HepJamesRandom>(seedL);
298 }
else if (stateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
299 newEngine = std::make_unique<CLHEP::RanecuEngine>();
300 }
else if (stateL[0] == CLHEP::engineIDulong<CLHEP::MixMaxRng>()) {
301 newEngine = std::make_unique<CLHEP::MixMaxRng>(seedL);
302 }
else if (stateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
303 newEngine = std::make_unique<TRandomAdaptor>(seedL);
308 newEngine->get(stateL);
321 if (mcc ==
nullptr) {
323 <<
"RandomNumberGeneratorService::getEngine()\n"
324 "Requested a random number engine from the RandomNumberGeneratorService\n"
325 "from an unallowed transition. ModuleCallingContext is null\n";
333 <<
"The module with label \"" <<
label
334 <<
"\" requested a random number seed from the \n"
335 "RandomNumberGeneratorService, but that module was not configured\n"
336 "for random numbers. An engine is created only if a seed(s) is provided\n"
337 "in the configuration file. Please add the following PSet to the\n"
338 "configuration file for the RandomNumberGeneratorService:\n\n"
342 " initialSeed = cms.untracked.uint32(your_seed),\n"
343 " engineName = cms.untracked.string('TRandom3')\n"
345 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
346 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
348 return iter->second.seeds()[0];
362 desc.addUntracked<
bool>(
"enableChecking",
false);
363 desc.addUntracked<
unsigned>(
"eventSeedOffset", 0
U);
364 desc.addUntracked<
bool>(
"verbose",
false);
367 val.addOptionalUntracked<std::uint32_t>(
"initialSeed");
368 val.addOptionalUntracked<std::vector<std::uint32_t> >(
"initialSeedSet");
372 wnode.setComment(
"The name of each ParameterSet will be the associated module label.");
375 descriptions.
add(
"RandomNumberGeneratorService",
desc);
390 <<
"Configuration is illegal. The RandomNumberGeneratorService is configured\n"
391 <<
"to run replay using a text file to input the random engine states and\n"
392 <<
"the number of streams is greater than 1. Either set the\n"
393 <<
"parameter named \"restoreFileName\" in the RandomNumberGeneratorService\n"
394 <<
"to the empty string or set the parameter \"numberOfStreams\" in the top\n"
395 <<
"level options parameter set to 1. (Probably these are the default values\n"
396 <<
"and just not setting the parameters will also work)\n";
408 for (
unsigned int iStream = 0; iStream <
nStreams_; ++iStream) {
409 unsigned int seedOffset = iStream;
412 outFiles_[iStream] = std::make_shared<std::ofstream>();
415 for (
unsigned int iLumi = 0; iLumi < nConcurrentLumis; ++iLumi) {
463 bool expected =
false;
467 reportSvc->reportRandomStateFile(
fullName);
473 std::vector<RandomEngineState>
const& iStates) {
549 os <<
"\n\nRandomNumberGeneratorService dump\n\n";
551 os <<
" Contents of seedsAndNameMap (label moduleID engineType seeds)\n";
553 os <<
" " <<
entry.first <<
" " <<
entry.second.moduleID() <<
" " <<
entry.second.engineName();
554 for (
auto val :
entry.second.seeds()) {
559 os <<
" nStreams_ = " <<
nStreams_ <<
"\n";
565 os <<
" verbose_ = " <<
verbose_ <<
"\n";
569 os <<
"\n streamEngines_\n";
570 unsigned int iStream = 0;
572 os <<
" Stream " << iStream <<
"\n";
573 for (
auto const&
i :
k) {
574 os <<
" " <<
i.label();
575 for (
auto const&
j :
i.seeds()) {
578 os <<
" " <<
i.engine()->name();
579 if (
i.engine()->name() ==
std::string(
"HepJamesRandom")) {
580 os <<
" " <<
i.engine()->getSeed();
581 }
else if (
i.engine()->name() ==
std::string(
"MixMaxRng")) {
582 os <<
" " <<
i.engine()->getSeed();
584 os <<
" engine does not know seeds";
590 os <<
"\n lumiEngines_\n";
591 unsigned int iLumi = 0;
593 os <<
" lumiIndex " << iLumi <<
"\n";
594 for (
auto const&
i :
k) {
595 os <<
" " <<
i.label();
596 for (
auto const&
j :
i.seeds()) {
599 os <<
" " <<
i.engine()->name();
600 if (
i.engine()->name() ==
std::string(
"HepJamesRandom")) {
601 os <<
" " <<
i.engine()->getSeed();
602 }
else if (
i.engine()->name() ==
std::string(
"MixMaxRng")) {
603 os <<
" " <<
i.engine()->getSeed();
605 os <<
" engine does not know seeds";
618 std::vector<ModuleIDToEngine>::iterator iter =
620 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
622 iter->setEngineState(labelAndEngine->
engine()->put());
632 std::vector<ModuleIDToEngine>::iterator iter =
634 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
636 if (iter->engineState() != labelAndEngine->
engine()->put()) {
638 <<
"It is illegal to generate random numbers during beginStream, endStream,\n"
639 "beginRun, endRun, beginLumi, endLumi because that makes it very difficult\n"
640 "to replay the processing of individual events. Random numbers were\n"
641 "generated during one of these methods for the module with class name\n\""
644 "and module label \""
656 <<
"In the configuration for the RandomNumberGeneratorService the\n"
657 <<
"restoreStateTag contains the current process which is illegal.\n"
658 <<
"The process name in the replay process should have been changed\n"
659 <<
"to be different than the original process name and the restoreStateTag\n"
660 <<
"should contain either the original process name or an empty process name.\n";
669 <<
"The RandomNumberGeneratorService is trying to restore\n"
670 <<
"the state of the random engines by reading a product from\n"
672 <<
"It could not find the product.\n"
673 <<
"Either the product in the LuminosityBlock was dropped or\n"
674 <<
"not produced or the configured input tag is incorrect or there is a bug somewhere\n";
687 <<
"The RandomNumberGeneratorService is trying to restore\n"
688 <<
"the state of the random engines by reading a product from\n"
690 <<
"It could not find the product.\n"
691 <<
"Either the product in the Event was dropped or\n"
692 <<
"not produced or the configured input tag is incorrect or there is a bug somewhere\n";
699 std::vector<RandomEngineState>&
cache) {
700 cache.resize(engines.size());
701 std::vector<RandomEngineState>::iterator
state =
cache.begin();
703 for (std::vector<LabelAndEngine>::const_iterator iter = engines.begin(); iter != engines.end(); ++iter, ++
state) {
706 state->setSeed(iter->seeds());
708 std::vector<unsigned long> stateL = iter->engine()->put();
709 state->clearStateVector();
710 state->reserveStateVector(stateL.size());
711 for (
auto element : stateL) {
712 state->push_back_stateVector(static_cast<std::uint32_t>(element));
718 std::vector<LabelAndEngine>& engines) {
719 std::vector<LabelAndEngine>::iterator labelAndEngine = engines.begin();
720 for (
auto const& cachedState :
cache) {
721 std::string const& engineLabel = cachedState.getLabel();
723 std::vector<std::uint32_t>
const& engineState = cachedState.getState();
724 std::vector<unsigned long> engineStateL;
725 engineStateL.reserve(engineState.size());
726 for (
auto const&
value : engineState) {
727 engineStateL.push_back(static_cast<unsigned long>(
value));
730 std::vector<std::uint32_t>
const& engineSeeds = cachedState.getSeed();
731 std::vector<long> engineSeedsL;
732 engineSeedsL.reserve(engineSeeds.size());
733 for (
auto const&
val : engineSeeds) {
734 long seedL = static_cast<long>(
val);
735 engineSeedsL.push_back(seedL);
744 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
748 assert(labelAndEngine != engines.end() && engineLabel == labelAndEngine->label());
749 std::shared_ptr<CLHEP::HepRandomEngine>
const& engine = labelAndEngine->engine();
753 if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
757 engine->setSeed(engineSeedsL[0], 0);
758 engine->get(engineStateL);
760 labelAndEngine->setSeed(engineSeeds[0], 0);
761 }
else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
765 engine->get(engineStateL);
767 labelAndEngine->setSeed(engineSeeds[0], 0);
768 labelAndEngine->setSeed(engineSeeds[1], 1);
769 }
else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::MixMaxRng>()) {
773 engine->setSeed(engineSeedsL[0], 0);
774 engine->get(engineStateL);
776 labelAndEngine->setSeed(engineSeeds[0], 0);
777 }
else if (engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
781 engine->setSeed(engineSeedsL[0], 0);
782 engine->get(engineStateL);
784 labelAndEngine->setSeed(engineSeeds[0], 0);
789 <<
"The RandomNumberGeneratorService is trying to restore the state\n"
790 "of the random engines. The state in the event indicates an engine\n"
791 "of an unknown type. This should not be possible unless you are\n"
792 "running with an old code release on a new file that was created\n"
793 "with a newer release which had new engine types added. In this case\n"
794 "the only solution is to use a newer release. In any other case, notify\n"
795 "the EDM developers because this should not be possible\n";
804 if (typeFromConfig != typeFromEvent) {
806 <<
"The RandomNumberGeneratorService is trying to restore\n"
807 <<
"the state of the random engine for the module \"" << engineLabel <<
"\". An\n"
808 <<
"error was detected because the type of the engine in the\n"
809 <<
"input file and the configuration file do not match.\n"
810 <<
"In the configuration file the type is \"" << typeFromConfig <<
"\".\nIn the input file the type is \""
811 << typeFromEvent <<
"\". If\n"
812 <<
"you are not generating any random numbers in this module, then\n"
813 <<
"remove the line in the configuration file that gives it\n"
814 <<
"a seed and the error will go away. Otherwise, you must give\n"
815 <<
"this module the same engine type in the configuration file or\n"
816 <<
"stop trying to restore the random engine state.\n";
826 std::stringstream
file;
836 <<
"Unable to open the file \"" <<
file.str() <<
"\" to save the state of the random engines.\n";
840 outFile.seekp(0, std::ios_base::beg);
841 outFile <<
"<RandomEngineStates>\n";
851 outFile <<
"</RandomEngineStates>\n";
857 std::vector<std::uint32_t>
const& seedVector =
state.getSeed();
860 std::vector<std::uint32_t>
const& stateVector =
state.getState();
863 outFile <<
"<ModuleLabel>\n" <<
state.getLabel() <<
"\n</ModuleLabel>\n";
865 outFile <<
"<SeedLength>\n" << seedVectorLength <<
"\n</SeedLength>\n";
868 outFile <<
"</InitialSeeds>\n";
869 outFile <<
"<FullStateLength>\n" << stateVectorLength <<
"\n</FullStateLength>\n";
879 size_t numItems =
v.size();
880 for (
size_t i = 0;
i < numItems; ++
i) {
881 if (
i != 0 &&
i % 10 == 0)
896 std::vector<RandomEngineState>&
cache) {
902 std::vector<RandomEngineState>&
cache) {
908 std::vector<RandomEngineState>&
cache,
910 std::ifstream inFile;
914 <<
"Unable to open the file \"" <<
fileName <<
"\" to restore the random engine states.\n";
921 <<
"Attempting to read file with random number engine states.\n"
922 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
923 <<
"Cannot read the file header word.\n";
925 bool saveToCache =
false;
931 std::vector<RandomEngineState>&
cache,
938 std::vector<std::uint32_t> seedVector;
940 std::vector<std::uint32_t> stateVector;
949 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
950 <<
"Cannot read next field and did not hit the end yet.\n";
954 if (leading ==
std::string(
"</RandomEngineStates>"))
965 saveToCache = (leading == whichStates);
974 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
975 <<
"Cannot read a module label when restoring random engine states.\n";
978 is >> leading >> seedVectorSize >> trailing;
981 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
982 <<
"Cannot read seed vector length when restoring random engine states.\n";
986 if (!is.good() || leading !=
std::string(
"<InitialSeeds>")) {
988 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
989 <<
"Cannot read beginning of InitialSeeds when restoring random engine states.\n";
994 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
995 <<
"The number of seeds exceeds 64K.\n";
1001 if (!is.good() || trailing !=
std::string(
"</InitialSeeds>")) {
1003 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1004 <<
"Cannot read end of InitialSeeds when restoring random engine states.\n";
1007 is >> leading >> stateVectorSize >> trailing;
1008 if (!is.good() || leading !=
std::string(
"<FullStateLength>") || trailing !=
std::string(
"</FullStateLength>")) {
1010 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1011 <<
"Cannot read state vector length when restoring random engine states.\n";
1015 if (!is.good() || leading !=
std::string(
"<FullState>")) {
1017 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1018 <<
"Cannot read beginning of FullState when restoring random engine states.\n";
1023 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1024 <<
"The number of states exceeds 64K.\n";
1027 readVector(is, stateVectorSize, stateVector);
1030 if (!is.good() || trailing !=
std::string(
"</FullState>")) {
1032 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1033 <<
"Cannot read end of FullState when restoring random engine states.\n";
1039 std::vector<RandomEngineState>::iterator
state =
1043 if (seedVector.size() !=
state->getSeed().size() || stateVector.size() !=
state->getState().size()) {
1045 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1046 <<
"Vectors containing engine state are the incorrect size for the type of random engine.\n";
1048 state->setSeed(seedVector);
1049 state->setState(stateVector);
1057 v.reserve(numItems);
1059 for (
unsigned i = 0;
i < numItems; ++
i) {
1063 <<
"File \"" <<
restoreFileName_ <<
"\" is ill-structured or otherwise corrupted.\n"
1064 <<
"Cannot read vector when restoring random engine states.\n";
1071 unsigned int seedOffset,
1072 unsigned int eventSeedOffset,
1073 std::vector<ModuleIDToEngine>& moduleIDVector) {
1080 unsigned int moduleID =
i.second.moduleID();
1086 if (
name ==
"RanecuEngine") {
1087 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::RanecuEngine>();
1093 long int seedL = static_cast<long int>(
seeds[0]);
1095 if (
name ==
"HepJamesRandom") {
1096 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::HepJamesRandom>(seedL);
1098 if (seedOffset != 0 || eventSeedOffset != 0) {
1101 }
else if (
name ==
"MixMaxRng") {
1102 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::MixMaxRng>(seedL);
1104 if (seedOffset != 0 || eventSeedOffset != 0) {
1116 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1119 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<TRandomAdaptor>(seedL);
1121 if (seedOffset != 0 || eventSeedOffset != 0) {
1126 moduleIDVector.emplace_back(&engines.back(), moduleID);
1129 std::sort(moduleIDVector.begin(), moduleIDVector.end());
1135 std::uint32_t offset1,
1136 std::uint32_t offset2) {
1143 std::uint32_t seed0 = (
seeds[0] + offset1) %
mod;
1144 seed0 = (seed0 + offset2) %
mod;
1145 labelAndEngine.
setSeed(seed0, 0);
1148 seedL[0] = static_cast<long int>(seed0);
1149 seedL[1] = static_cast<long int>(
seeds[1]);
1150 labelAndEngine.
engine()->setSeeds(seedL, 0);
1159 std::uint32_t seed0 = (
seeds[0] + offset1) %
mod;
1160 seed0 = (seed0 + offset2) %
mod;
1161 labelAndEngine.
setSeed(seed0, 0);
1163 long int seedL = static_cast<long int>(seed0);
1164 labelAndEngine.
engine()->setSeed(seedL, 0);
1171 std::uint32_t seed0 =
seeds[0];
1172 if ((max32 - seed0) >= offset1) {
1175 seed0 = offset1 - (max32 - seed0) - 1
U;
1177 if ((max32 - seed0) >= offset2) {
1180 seed0 = offset2 - (max32 - seed0) - 1
U;
1182 labelAndEngine.
setSeed(seed0, 0);
1184 long seedL = static_cast<long>(seed0);
1193 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1194 assert(seed0 == seedu32);
1196 labelAndEngine.
engine()->setSeed(seedL, 0);