File indexing completed on 2024-04-06 12:19:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include "RandomNumberGeneratorService.h"
0014
0015 #include "DataFormats/Common/interface/Handle.h"
0016 #include "DataFormats/Provenance/interface/ModuleDescription.h"
0017 #include "FWCore/Framework/interface/ConsumesCollector.h"
0018 #include "FWCore/Framework/interface/Event.h"
0019 #include "FWCore/Framework/interface/LuminosityBlock.h"
0020 #include "FWCore/Framework/interface/TriggerNamesService.h"
0021 #include "FWCore/MessageLogger/interface/JobReport.h"
0022 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0023 #include "FWCore/ParameterSet/interface/ParameterDescription.h"
0024 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0025 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0026 #include "FWCore/ParameterSet/interface/ParameterWildcard.h"
0027 #include "FWCore/ServiceRegistry/interface/CurrentModuleOnThread.h"
0028 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
0029 #include "FWCore/ServiceRegistry/interface/ModuleCallingContext.h"
0030 #include "FWCore/ServiceRegistry/interface/Service.h"
0031 #include "FWCore/ServiceRegistry/interface/StreamContext.h"
0032 #include "FWCore/ServiceRegistry/interface/SystemBounds.h"
0033 #include "FWCore/Utilities/interface/EDMException.h"
0034 #include "FWCore/Utilities/interface/Exception.h"
0035 #include "FWCore/Utilities/interface/LuminosityBlockIndex.h"
0036 #include "FWCore/Utilities/interface/StreamID.h"
0037 #include "IOMC/RandomEngine/interface/TRandomAdaptor.h"
0038 #include "IOMC/RandomEngine/interface/cloneEngine.h"
0039 #include "SimDataFormats/RandomEngine/interface/RandomEngineState.h"
0040 #include "SimDataFormats/RandomEngine/interface/RandomEngineStates.h"
0041
0042 #include "CLHEP/Random/engineIDulong.h"
0043 #include "CLHEP/Random/JamesRandom.h"
0044 #include "CLHEP/Random/RanecuEngine.h"
0045 #include "CLHEP/Random/MixMaxRng.h"
0046
0047 #include <algorithm>
0048 #include <cassert>
0049 #include <ostream>
0050 #include <sstream>
0051 #include <unistd.h>
0052
0053 namespace edm {
0054 namespace service {
0055
0056 const std::vector<std::uint32_t>::size_type RandomNumberGeneratorService::maxSeeds = 65536U;
0057 const std::vector<std::uint32_t>::size_type RandomNumberGeneratorService::maxStates = 65536U;
0058 const std::uint32_t RandomNumberGeneratorService::maxSeedRanecu = 2147483647U;
0059 const std::uint32_t RandomNumberGeneratorService::maxSeedHepJames = 900000000U;
0060 const std::uint32_t RandomNumberGeneratorService::maxSeedTRandom3 = 4294967295U;
0061
0062 RandomNumberGeneratorService::RandomNumberGeneratorService(ParameterSet const& pset,
0063 ActivityRegistry& activityRegistry)
0064 : nStreams_(0),
0065 saveFileName_(pset.getUntrackedParameter<std::string>("saveFileName")),
0066 saveFileNameRecorded_(false),
0067 restoreFileName_(pset.getUntrackedParameter<std::string>("restoreFileName")),
0068 enableChecking_(pset.getUntrackedParameter<bool>("enableChecking")),
0069 eventSeedOffset_(pset.getUntrackedParameter<unsigned>("eventSeedOffset")),
0070 verbose_(pset.getUntrackedParameter<bool>("verbose")) {
0071 if (pset.exists("restoreStateTag")) {
0072 restoreStateTag_ = pset.getUntrackedParameter<edm::InputTag>("restoreStateTag");
0073 if (restoreStateTag_.process().empty()) {
0074 restoreStateTag_ = edm::InputTag(restoreStateTag_.label(), "", edm::InputTag::kSkipCurrentProcess);
0075 }
0076 } else {
0077 restoreStateTag_ = edm::InputTag(
0078 pset.getUntrackedParameter<std::string>("restoreStateLabel"), "", edm::InputTag::kSkipCurrentProcess);
0079 }
0080 restoreStateBeginLumiTag_ = edm::InputTag(restoreStateTag_.label(), "beginLumi", restoreStateTag_.process());
0081
0082 if (!restoreFileName_.empty() && !restoreStateTag_.label().empty()) {
0083 throw Exception(errors::Configuration) << "In the configuration for the RandomNumberGeneratorService both\n"
0084 << "restoreFileName and restoreStateLabel were set to nonempty values\n"
0085 << "which is illegal. It is impossible to restore the random engine\n"
0086 << "states two different ways in the same process.\n";
0087 }
0088
0089
0090
0091 if (!saveFileName_.empty() && (saveFileName_.find('/') != std::string::npos)) {
0092 throw Exception(errors::Configuration)
0093 << "The saveFileName parameter must be a simple file name with no path\n"
0094 << "specification. In the configuration, it was given the value \"" << saveFileName_ << "\"\n";
0095 }
0096
0097 std::uint32_t initialSeed;
0098 VUint32 initialSeedSet;
0099 std::string engineName;
0100
0101 std::vector<std::string> pSets = pset.getParameterNamesForType<ParameterSet>();
0102 for (auto const& label : pSets) {
0103 ParameterSet const& modulePSet = pset.getParameterSet(label);
0104 engineName = modulePSet.getUntrackedParameter<std::string>("engineName", std::string("HepJamesRandom"));
0105
0106 bool initialSeedExists = modulePSet.exists("initialSeed");
0107 bool initialSeedSetExists = modulePSet.exists("initialSeedSet");
0108
0109 if (initialSeedExists && initialSeedSetExists) {
0110 throw Exception(errors::Configuration) << "For the module with the label \"" << label << "\",\n"
0111 << "both the parameters \"initialSeed\" and \"initialSeedSet\"\n"
0112 << "have been set in the configuration. You must set one or\n"
0113 << "the other. It is illegal to set both.\n";
0114 } else if (!initialSeedExists && !initialSeedSetExists) {
0115 throw Exception(errors::Configuration) << "For the module with the label \"" << label << "\",\n"
0116 << "neither the parameter \"initialSeed\" nor \"initialSeedSet\"\n"
0117 << "has been set in the configuration. You must set one or\n"
0118 << "the other.\n";
0119 } else if (initialSeedExists) {
0120 initialSeed = modulePSet.getUntrackedParameter<std::uint32_t>("initialSeed");
0121 initialSeedSet.clear();
0122 initialSeedSet.push_back(initialSeed);
0123 } else if (initialSeedSetExists) {
0124 initialSeedSet = modulePSet.getUntrackedParameter<VUint32>("initialSeedSet");
0125 }
0126 seedsAndNameMap_.insert(std::pair<std::string, SeedsAndName>(label, SeedsAndName(initialSeedSet, engineName)));
0127
0128
0129 if (engineName == std::string("RanecuEngine")) {
0130 if (initialSeedSet.size() != 2U) {
0131 throw Exception(errors::Configuration)
0132 << "Random engines of type \"RanecuEngine\" require 2 seeds\n"
0133 << "be specified with the parameter named \"initialSeedSet\".\n"
0134 << "Either \"initialSeedSet\" was not in the configuration\n"
0135 << "or its size was not 2 for the module with label \"" << label << "\".\n";
0136 }
0137 if (initialSeedSet[0] > maxSeedRanecu ||
0138 initialSeedSet[1] > maxSeedRanecu) {
0139 throw Exception(errors::Configuration)
0140 << "The RanecuEngine seeds should be in the range 0 to " << maxSeedRanecu << ".\n"
0141 << "The seeds passed to the RandomNumberGenerationService from the\n"
0142 "configuration file were "
0143 << initialSeedSet[0] << " and " << initialSeedSet[1] << "\nThis was for the module with label \""
0144 << label << "\".\n";
0145 }
0146 }
0147
0148 else {
0149 if (initialSeedSet.size() != 1U) {
0150 throw Exception(errors::Configuration)
0151 << "Random engines of type \"HepJamesRandom\", \"TRandom3\" and \"MixMaxRng\" \n"
0152 << "require exactly 1 seed be specified in the configuration.\n"
0153 << "There were " << initialSeedSet.size() << " seeds set for the\n"
0154 << "module with label \"" << label << "\".\n";
0155 }
0156 if (engineName == "HepJamesRandom") {
0157 if (initialSeedSet[0] > maxSeedHepJames) {
0158 throw Exception(errors::Configuration)
0159 << "The CLHEP::HepJamesRandom engine seed should be in the range 0 to " << maxSeedHepJames << ".\n"
0160 << "The seed passed to the RandomNumberGenerationService from the\n"
0161 "configuration file was "
0162 << initialSeedSet[0] << ". This was for \n"
0163 << "the module with label " << label << ".\n";
0164 }
0165 } else if (engineName == "MixMaxRng") {
0166 if (initialSeedSet[0] > maxSeedTRandom3) {
0167 throw Exception(errors::Configuration)
0168 << "The CLHEP::MixMaxRng engine seed should be in the range 0 to " << maxSeedTRandom3 << ".\n"
0169 << "The seed passed to the RandomNumberGenerationService from the\n"
0170 "configuration file was "
0171 << initialSeedSet[0] << ". This was for \n"
0172 << "the module with label " << label << ".\n";
0173 }
0174 } else if (engineName == "TRandom3") {
0175 if (initialSeedSet[0] > maxSeedTRandom3) {
0176 throw Exception(errors::Configuration)
0177 << "The CLHEP::MixMaxRng engine seed should be in the range 0 to " << maxSeedTRandom3 << ".\n"
0178 << "The seed passed to the RandomNumberGenerationService from the\n"
0179 "configuration file was "
0180 << initialSeedSet[0] << ". This was for \n"
0181 << "the module with label " << label << ".\n";
0182 }
0183 } else {
0184 throw Exception(errors::Configuration)
0185 << "The random engine name, \"" << engineName << "\", does not correspond to a supported engine.\n"
0186 << "This engine was configured for the module with label \"" << label << "\"";
0187 }
0188 }
0189 }
0190 activityRegistry.watchPreModuleConstruction(this, &RandomNumberGeneratorService::preModuleConstruction);
0191 activityRegistry.watchPreModuleDestruction(this, &RandomNumberGeneratorService::preModuleDestruction);
0192
0193 activityRegistry.watchPreallocate(this, &RandomNumberGeneratorService::preallocate);
0194
0195 if (enableChecking_) {
0196 activityRegistry.watchPreModuleBeginStream(this, &RandomNumberGeneratorService::preModuleBeginStream);
0197 activityRegistry.watchPostModuleBeginStream(this, &RandomNumberGeneratorService::postModuleBeginStream);
0198
0199 activityRegistry.watchPreModuleEndStream(this, &RandomNumberGeneratorService::preModuleEndStream);
0200 activityRegistry.watchPostModuleEndStream(this, &RandomNumberGeneratorService::postModuleEndStream);
0201
0202 activityRegistry.watchPreModuleStreamBeginRun(this, &RandomNumberGeneratorService::preModuleStreamBeginRun);
0203 activityRegistry.watchPostModuleStreamBeginRun(this, &RandomNumberGeneratorService::postModuleStreamBeginRun);
0204
0205 activityRegistry.watchPreModuleStreamEndRun(this, &RandomNumberGeneratorService::preModuleStreamEndRun);
0206 activityRegistry.watchPostModuleStreamEndRun(this, &RandomNumberGeneratorService::postModuleStreamEndRun);
0207
0208 activityRegistry.watchPreModuleStreamBeginLumi(this, &RandomNumberGeneratorService::preModuleStreamBeginLumi);
0209 activityRegistry.watchPostModuleStreamBeginLumi(this, &RandomNumberGeneratorService::postModuleStreamBeginLumi);
0210
0211 activityRegistry.watchPreModuleStreamEndLumi(this, &RandomNumberGeneratorService::preModuleStreamEndLumi);
0212 activityRegistry.watchPostModuleStreamEndLumi(this, &RandomNumberGeneratorService::postModuleStreamEndLumi);
0213 }
0214 }
0215
0216 RandomNumberGeneratorService::~RandomNumberGeneratorService() {}
0217
0218 void RandomNumberGeneratorService::consumes(ConsumesCollector&& iC) const {
0219 iC.consumes<RandomEngineStates, InLumi>(restoreStateBeginLumiTag_);
0220 iC.consumes<RandomEngineStates>(restoreStateTag_);
0221 }
0222
0223 CLHEP::HepRandomEngine& RandomNumberGeneratorService::getEngine(StreamID const& streamID) {
0224 ModuleCallingContext const* mcc = CurrentModuleOnThread::getCurrentModuleOnThread();
0225 if (mcc == nullptr) {
0226 throw Exception(errors::LogicError)
0227 << "RandomNumberGeneratorService::getEngine\n"
0228 "Requested a random number engine from the RandomNumberGeneratorService\n"
0229 "when no module was active. ModuleCallingContext is null\n";
0230 }
0231 unsigned int moduleID = mcc->moduleDescription()->id();
0232
0233 std::vector<ModuleIDToEngine>& moduleIDVector = streamModuleIDToEngine_.at(streamID.value());
0234 ModuleIDToEngine target(nullptr, moduleID);
0235 std::vector<ModuleIDToEngine>::iterator iter =
0236 std::lower_bound(moduleIDVector.begin(), moduleIDVector.end(), target);
0237 if (iter == moduleIDVector.end() || iter->moduleID() != moduleID) {
0238 throw Exception(errors::Configuration)
0239 << "The module with label \"" << mcc->moduleDescription()->moduleLabel()
0240 << "\" requested a random number engine from the \n"
0241 "RandomNumberGeneratorService, but that module was not configured\n"
0242 "for random numbers. An engine is created only if a seed(s) is provided\n"
0243 "in the configuration file. Please add the following PSet to the\n"
0244 "configuration file for the RandomNumberGeneratorService:\n\n"
0245 " "
0246 << mcc->moduleDescription()->moduleLabel()
0247 << " = cms.PSet(\n"
0248 " initialSeed = cms.untracked.uint32(your_seed),\n"
0249 " engineName = cms.untracked.string('TRandom3')\n"
0250 " )\n"
0251 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
0252 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
0253 }
0254 return *iter->labelAndEngine()->engine();
0255 }
0256
0257 CLHEP::HepRandomEngine& RandomNumberGeneratorService::getEngine(LuminosityBlockIndex const& lumiIndex) {
0258 ModuleCallingContext const* mcc = CurrentModuleOnThread::getCurrentModuleOnThread();
0259 if (mcc == nullptr) {
0260 throw Exception(errors::LogicError)
0261 << "RandomNumberGeneratorService::getEngine\n"
0262 "Requested a random number engine from the RandomNumberGeneratorService\n"
0263 "when no module was active. ModuleCallingContext is null\n";
0264 }
0265 unsigned int moduleID = mcc->moduleDescription()->id();
0266
0267 std::vector<ModuleIDToEngine>& moduleIDVector = lumiModuleIDToEngine_.at(lumiIndex.value());
0268 ModuleIDToEngine target(nullptr, moduleID);
0269 std::vector<ModuleIDToEngine>::iterator iter =
0270 std::lower_bound(moduleIDVector.begin(), moduleIDVector.end(), target);
0271 if (iter == moduleIDVector.end() || iter->moduleID() != moduleID) {
0272 throw Exception(errors::Configuration)
0273 << "The module with label \"" << mcc->moduleDescription()->moduleLabel()
0274 << "\" requested a random number engine from the \n"
0275 "RandomNumberGeneratorService, but that module was not configured\n"
0276 "for random numbers. An engine is created only if a seed(s) is provided\n"
0277 "in the configuration file. Please add the following PSet to the\n"
0278 "configuration file for the RandomNumberGeneratorService:\n\n"
0279 " "
0280 << mcc->moduleDescription()->moduleLabel()
0281 << " = cms.PSet(\n"
0282 " initialSeed = cms.untracked.uint32(your_seed),\n"
0283 " engineName = cms.untracked.string('TRandom3')\n"
0284 " )\n"
0285 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
0286 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
0287 }
0288 return *iter->labelAndEngine()->engine();
0289 }
0290
0291 std::unique_ptr<CLHEP::HepRandomEngine> RandomNumberGeneratorService::cloneEngine(
0292 LuminosityBlockIndex const& lumiIndex) {
0293 return edm::cloneEngine(getEngine(lumiIndex));
0294 }
0295
0296
0297
0298
0299
0300
0301
0302 std::uint32_t RandomNumberGeneratorService::mySeed() const {
0303 std::string label;
0304 ModuleCallingContext const* mcc = CurrentModuleOnThread::getCurrentModuleOnThread();
0305 if (mcc == nullptr) {
0306 throw Exception(errors::LogicError)
0307 << "RandomNumberGeneratorService::getEngine()\n"
0308 "Requested a random number engine from the RandomNumberGeneratorService\n"
0309 "from an unallowed transition. ModuleCallingContext is null\n";
0310 } else {
0311 label = mcc->moduleDescription()->moduleLabel();
0312 }
0313
0314 std::map<std::string, SeedsAndName>::const_iterator iter = seedsAndNameMap_.find(label);
0315 if (iter == seedsAndNameMap_.end()) {
0316 throw Exception(errors::Configuration)
0317 << "The module with label \"" << label
0318 << "\" requested a random number seed from the \n"
0319 "RandomNumberGeneratorService, but that module was not configured\n"
0320 "for random numbers. An engine is created only if a seed(s) is provided\n"
0321 "in the configuration file. Please add the following PSet to the\n"
0322 "configuration file for the RandomNumberGeneratorService:\n\n"
0323 " "
0324 << label
0325 << " = cms.PSet(\n"
0326 " initialSeed = cms.untracked.uint32(your_seed),\n"
0327 " engineName = cms.untracked.string('TRandom3')\n"
0328 " )\n"
0329 "where you replace \"your_seed\" with a number and add a comma if necessary\n"
0330 "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
0331 }
0332 return iter->second.seeds()[0];
0333 }
0334
0335 void RandomNumberGeneratorService::fillDescriptions(ConfigurationDescriptions& descriptions) {
0336 ParameterSetDescription desc;
0337
0338 std::string emptyString;
0339 edm::InputTag emptyInputTag("", "", "");
0340
0341 desc.addNode(edm::ParameterDescription<edm::InputTag>("restoreStateTag", emptyInputTag, false) xor
0342 edm::ParameterDescription<std::string>("restoreStateLabel", emptyString, false));
0343
0344 desc.addUntracked<std::string>("saveFileName", emptyString);
0345 desc.addUntracked<std::string>("restoreFileName", emptyString);
0346 desc.addUntracked<bool>("enableChecking", false);
0347 desc.addUntracked<unsigned>("eventSeedOffset", 0U);
0348 desc.addUntracked<bool>("verbose", false);
0349
0350 ParameterSetDescription val;
0351 val.addOptionalUntracked<std::uint32_t>("initialSeed");
0352 val.addOptionalUntracked<std::vector<std::uint32_t> >("initialSeedSet");
0353 val.addOptionalUntracked<std::string>("engineName");
0354
0355 ParameterWildcard<ParameterSetDescription> wnode("*", RequireZeroOrMore, true, val);
0356 wnode.setComment("The name of each ParameterSet will be the associated module label.");
0357 desc.addNode(wnode);
0358
0359 descriptions.add("RandomNumberGeneratorService", desc);
0360 }
0361
0362 void RandomNumberGeneratorService::preModuleConstruction(ModuleDescription const& description) {
0363 std::map<std::string, SeedsAndName>::iterator iter = seedsAndNameMap_.find(description.moduleLabel());
0364 if (iter != seedsAndNameMap_.end()) {
0365 iter->second.setModuleID(description.id());
0366 }
0367 }
0368
0369 void RandomNumberGeneratorService::preModuleDestruction(ModuleDescription const& description) {
0370 std::map<std::string, SeedsAndName>::iterator iter = seedsAndNameMap_.find(description.moduleLabel());
0371 if (iter != seedsAndNameMap_.end()) {
0372 iter->second.setModuleID(SeedsAndName::kInvalid);
0373 }
0374 }
0375
0376 void RandomNumberGeneratorService::preallocate(SystemBounds const& sb) {
0377 nStreams_ = sb.maxNumberOfStreams();
0378 assert(nStreams_ >= 1);
0379 if (!restoreFileName_.empty() && nStreams_ != 1) {
0380 throw Exception(errors::Configuration)
0381 << "Configuration is illegal. The RandomNumberGeneratorService is configured\n"
0382 << "to run replay using a text file to input the random engine states and\n"
0383 << "the number of streams is greater than 1. Either set the\n"
0384 << "parameter named \"restoreFileName\" in the RandomNumberGeneratorService\n"
0385 << "to the empty string or set the parameter \"numberOfStreams\" in the top\n"
0386 << "level options parameter set to 1. (Probably these are the default values\n"
0387 << "and just not setting the parameters will also work)\n";
0388 }
0389 unsigned int nConcurrentLumis = sb.maxNumberOfConcurrentLuminosityBlocks();
0390
0391 streamModuleIDToEngine_.resize(nStreams_);
0392 lumiModuleIDToEngine_.resize(nConcurrentLumis);
0393 streamEngines_.resize(nStreams_);
0394 lumiEngines_.resize(nConcurrentLumis);
0395 eventCache_.resize(nStreams_);
0396 lumiCache_.resize(nConcurrentLumis);
0397 outFiles_.resize(nStreams_);
0398
0399 for (unsigned int iStream = 0; iStream < nStreams_; ++iStream) {
0400 unsigned int seedOffset = iStream;
0401 createEnginesInVector(streamEngines_[iStream], seedOffset, eventSeedOffset_, streamModuleIDToEngine_[iStream]);
0402 if (!saveFileName_.empty()) {
0403 outFiles_[iStream] = std::make_shared<std::ofstream>();
0404 }
0405 }
0406 for (unsigned int iLumi = 0; iLumi < nConcurrentLumis; ++iLumi) {
0407 unsigned int seedOffset = nStreams_;
0408 createEnginesInVector(lumiEngines_[iLumi], seedOffset, 0, lumiModuleIDToEngine_[iLumi]);
0409 snapShot(lumiEngines_[iLumi], lumiCache_[iLumi]);
0410 if (!restoreFileName_.empty()) {
0411 readLumiStatesFromTextFile(restoreFileName_, lumiCache_[iLumi]);
0412 }
0413 }
0414
0415 if (!restoreFileName_.empty()) {
0416
0417 snapShot(streamEngines_[0], eventCache_[0]);
0418 readEventStatesFromTextFile(restoreFileName_, eventCache_[0]);
0419 restoreFromCache(eventCache_[0], streamEngines_[0]);
0420 }
0421 if (verbose_) {
0422 print(std::cout);
0423 }
0424 }
0425
0426 void RandomNumberGeneratorService::preBeginLumi(LuminosityBlock const& lumi) {
0427 if (!restoreStateTag_.label().empty()) {
0428
0429 readFromLuminosityBlock(lumi);
0430 }
0431
0432 restoreFromCache(lumiCache_[lumi.index()], lumiEngines_[lumi.index()]);
0433 }
0434
0435 void RandomNumberGeneratorService::postEventRead(Event const& event) {
0436 if (!restoreStateTag_.label().empty()) {
0437
0438 snapShot(streamEngines_[event.streamID()], eventCache_[event.streamID()]);
0439
0440
0441 readFromEvent(event);
0442
0443
0444 restoreFromCache(eventCache_[event.streamID()], streamEngines_[event.streamID()]);
0445
0446 } else {
0447
0448 snapShot(streamEngines_[event.streamID()], eventCache_[event.streamID()]);
0449 }
0450
0451
0452 if (!saveFileName_.empty()) {
0453 saveStatesToFile(saveFileName_, event.streamID(), event.getLuminosityBlock().index());
0454 bool expected = false;
0455 if (saveFileNameRecorded_.compare_exchange_strong(expected, true)) {
0456 std::string fullName = constructSaveFileName();
0457 Service<JobReport> reportSvc;
0458 reportSvc->reportRandomStateFile(fullName);
0459 }
0460 }
0461 }
0462
0463 void RandomNumberGeneratorService::setLumiCache(LuminosityBlockIndex iLumi,
0464 std::vector<RandomEngineState> const& iStates) {
0465 lumiCache_[iLumi] = iStates;
0466
0467 restoreFromCache(lumiCache_[iLumi], lumiEngines_[iLumi]);
0468 }
0469 void RandomNumberGeneratorService::setEventCache(StreamID iStream, std::vector<RandomEngineState> const& iStates) {
0470 eventCache_[iStream] = iStates;
0471
0472 restoreFromCache(eventCache_[iStream], streamEngines_[iStream]);
0473 }
0474
0475 void RandomNumberGeneratorService::preModuleBeginStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0476 preModuleStreamCheck(sc, mcc);
0477 }
0478
0479 void RandomNumberGeneratorService::postModuleBeginStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0480 postModuleStreamCheck(sc, mcc);
0481 }
0482
0483 void RandomNumberGeneratorService::preModuleEndStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0484 preModuleStreamCheck(sc, mcc);
0485 }
0486
0487 void RandomNumberGeneratorService::postModuleEndStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0488 postModuleStreamCheck(sc, mcc);
0489 }
0490
0491 void RandomNumberGeneratorService::preModuleStreamBeginRun(StreamContext const& sc,
0492 ModuleCallingContext const& mcc) {
0493 preModuleStreamCheck(sc, mcc);
0494 }
0495
0496 void RandomNumberGeneratorService::postModuleStreamBeginRun(StreamContext const& sc,
0497 ModuleCallingContext const& mcc) {
0498 postModuleStreamCheck(sc, mcc);
0499 }
0500
0501 void RandomNumberGeneratorService::preModuleStreamEndRun(StreamContext const& sc, ModuleCallingContext const& mcc) {
0502 preModuleStreamCheck(sc, mcc);
0503 }
0504
0505 void RandomNumberGeneratorService::postModuleStreamEndRun(StreamContext const& sc,
0506 ModuleCallingContext const& mcc) {
0507 postModuleStreamCheck(sc, mcc);
0508 }
0509
0510 void RandomNumberGeneratorService::preModuleStreamBeginLumi(StreamContext const& sc,
0511 ModuleCallingContext const& mcc) {
0512 preModuleStreamCheck(sc, mcc);
0513 }
0514
0515 void RandomNumberGeneratorService::postModuleStreamBeginLumi(StreamContext const& sc,
0516 ModuleCallingContext const& mcc) {
0517 postModuleStreamCheck(sc, mcc);
0518 }
0519
0520 void RandomNumberGeneratorService::preModuleStreamEndLumi(StreamContext const& sc,
0521 ModuleCallingContext const& mcc) {
0522 preModuleStreamCheck(sc, mcc);
0523 }
0524
0525 void RandomNumberGeneratorService::postModuleStreamEndLumi(StreamContext const& sc,
0526 ModuleCallingContext const& mcc) {
0527 postModuleStreamCheck(sc, mcc);
0528 }
0529
0530 std::vector<RandomEngineState> const& RandomNumberGeneratorService::getLumiCache(
0531 LuminosityBlockIndex const& lumiIndex) const {
0532 return lumiCache_.at(lumiIndex.value());
0533 }
0534
0535 std::vector<RandomEngineState> const& RandomNumberGeneratorService::getEventCache(StreamID const& streamID) const {
0536 return eventCache_.at(streamID.value());
0537 }
0538
0539 void RandomNumberGeneratorService::print(std::ostream& os) const {
0540 os << "\n\nRandomNumberGeneratorService dump\n\n";
0541
0542 os << " Contents of seedsAndNameMap (label moduleID engineType seeds)\n";
0543 for (auto const& entry : seedsAndNameMap_) {
0544 os << " " << entry.first << " " << entry.second.moduleID() << " " << entry.second.engineName();
0545 for (auto val : entry.second.seeds()) {
0546 os << " " << val;
0547 }
0548 os << "\n";
0549 }
0550 os << " nStreams_ = " << nStreams_ << "\n";
0551 os << " saveFileName_ = " << saveFileName_ << "\n";
0552 os << " saveFileNameRecorded_ = " << saveFileNameRecorded_ << "\n";
0553 os << " restoreFileName_ = " << restoreFileName_ << "\n";
0554 os << " enableChecking_ = " << enableChecking_ << "\n";
0555 os << " eventSeedOffset_ = " << eventSeedOffset_ << "\n";
0556 os << " verbose_ = " << verbose_ << "\n";
0557 os << " restoreStateTag_ = " << restoreStateTag_ << "\n";
0558 os << " restoreStateBeginLumiTag_ = " << restoreStateBeginLumiTag_ << "\n";
0559
0560 os << "\n streamEngines_\n";
0561 unsigned int iStream = 0;
0562 for (auto const& k : streamEngines_) {
0563 os << " Stream " << iStream << "\n";
0564 for (auto const& i : k) {
0565 os << " " << i.label();
0566 for (auto const& j : i.seeds()) {
0567 os << " " << j;
0568 }
0569 os << " " << i.engine()->name();
0570 if (i.engine()->name() == std::string("HepJamesRandom")) {
0571 os << " " << i.engine()->getSeed();
0572 } else if (i.engine()->name() == std::string("MixMaxRng")) {
0573 os << " " << i.engine()->getSeed();
0574 } else {
0575 os << " engine does not know seeds";
0576 }
0577 os << "\n";
0578 }
0579 ++iStream;
0580 }
0581 os << "\n lumiEngines_\n";
0582 unsigned int iLumi = 0;
0583 for (auto const& k : lumiEngines_) {
0584 os << " lumiIndex " << iLumi << "\n";
0585 for (auto const& i : k) {
0586 os << " " << i.label();
0587 for (auto const& j : i.seeds()) {
0588 os << " " << j;
0589 }
0590 os << " " << i.engine()->name();
0591 if (i.engine()->name() == std::string("HepJamesRandom")) {
0592 os << " " << i.engine()->getSeed();
0593 } else if (i.engine()->name() == std::string("MixMaxRng")) {
0594 os << " " << i.engine()->getSeed();
0595 } else {
0596 os << " engine does not know seeds";
0597 }
0598 os << "\n";
0599 }
0600 ++iLumi;
0601 }
0602 }
0603
0604 void RandomNumberGeneratorService::preModuleStreamCheck(StreamContext const& sc, ModuleCallingContext const& mcc) {
0605 if (enableChecking_) {
0606 unsigned int moduleID = mcc.moduleDescription()->id();
0607 std::vector<ModuleIDToEngine>& moduleIDVector = streamModuleIDToEngine_.at(sc.streamID().value());
0608 ModuleIDToEngine target(nullptr, moduleID);
0609 std::vector<ModuleIDToEngine>::iterator iter =
0610 std::lower_bound(moduleIDVector.begin(), moduleIDVector.end(), target);
0611 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
0612 LabelAndEngine* labelAndEngine = iter->labelAndEngine();
0613 iter->setEngineState(labelAndEngine->engine()->put());
0614 }
0615 }
0616 }
0617
0618 void RandomNumberGeneratorService::postModuleStreamCheck(StreamContext const& sc, ModuleCallingContext const& mcc) {
0619 if (enableChecking_) {
0620 unsigned int moduleID = mcc.moduleDescription()->id();
0621 std::vector<ModuleIDToEngine>& moduleIDVector = streamModuleIDToEngine_.at(sc.streamID().value());
0622 ModuleIDToEngine target(nullptr, moduleID);
0623 std::vector<ModuleIDToEngine>::iterator iter =
0624 std::lower_bound(moduleIDVector.begin(), moduleIDVector.end(), target);
0625 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
0626 LabelAndEngine* labelAndEngine = iter->labelAndEngine();
0627 if (iter->engineState() != labelAndEngine->engine()->put()) {
0628 throw Exception(errors::LogicError)
0629 << "It is illegal to generate random numbers during beginStream, endStream,\n"
0630 "beginRun, endRun, beginLumi, endLumi because that makes it very difficult\n"
0631 "to replay the processing of individual events. Random numbers were\n"
0632 "generated during one of these methods for the module with class name\n\""
0633 << mcc.moduleDescription()->moduleName()
0634 << "\" "
0635 "and module label \""
0636 << mcc.moduleDescription()->moduleLabel() << "\"\n";
0637 }
0638 }
0639 }
0640 }
0641
0642 void RandomNumberGeneratorService::readFromLuminosityBlock(LuminosityBlock const& lumi) {
0643 Service<TriggerNamesService> tns;
0644 if (tns.isAvailable()) {
0645 if (tns->getProcessName() == restoreStateTag_.process()) {
0646 throw Exception(errors::Configuration)
0647 << "In the configuration for the RandomNumberGeneratorService the\n"
0648 << "restoreStateTag contains the current process which is illegal.\n"
0649 << "The process name in the replay process should have been changed\n"
0650 << "to be different than the original process name and the restoreStateTag\n"
0651 << "should contain either the original process name or an empty process name.\n";
0652 }
0653 }
0654
0655 Handle<RandomEngineStates> states;
0656 lumi.getByLabel(restoreStateBeginLumiTag_, states);
0657
0658 if (!states.isValid()) {
0659 throw Exception(errors::ProductNotFound)
0660 << "The RandomNumberGeneratorService is trying to restore\n"
0661 << "the state of the random engines by reading a product from\n"
0662 << "the LuminosityBlock with input tag \"" << restoreStateBeginLumiTag_ << "\".\n"
0663 << "It could not find the product.\n"
0664 << "Either the product in the LuminosityBlock was dropped or\n"
0665 << "not produced or the configured input tag is incorrect or there is a bug somewhere\n";
0666 return;
0667 }
0668 states->getRandomEngineStates(lumiCache_.at(lumi.index()));
0669 }
0670
0671 void RandomNumberGeneratorService::readFromEvent(Event const& event) {
0672 Handle<RandomEngineStates> states;
0673
0674 event.getByLabel(restoreStateTag_, states);
0675
0676 if (!states.isValid()) {
0677 throw Exception(errors::ProductNotFound)
0678 << "The RandomNumberGeneratorService is trying to restore\n"
0679 << "the state of the random engines by reading a product from\n"
0680 << "the Event with input tag \"" << restoreStateTag_ << "\".\n"
0681 << "It could not find the product.\n"
0682 << "Either the product in the Event was dropped or\n"
0683 << "not produced or the configured input tag is incorrect or there is a bug somewhere\n";
0684 return;
0685 }
0686 states->getRandomEngineStates(eventCache_.at(event.streamID()));
0687 }
0688
0689 void RandomNumberGeneratorService::snapShot(std::vector<LabelAndEngine> const& engines,
0690 std::vector<RandomEngineState>& cache) {
0691 cache.resize(engines.size());
0692 std::vector<RandomEngineState>::iterator state = cache.begin();
0693
0694 for (std::vector<LabelAndEngine>::const_iterator iter = engines.begin(); iter != engines.end(); ++iter, ++state) {
0695 std::string const& label = iter->label();
0696 state->setLabel(label);
0697 state->setSeed(iter->seeds());
0698
0699 std::vector<unsigned long> stateL = iter->engine()->put();
0700 state->clearStateVector();
0701 state->reserveStateVector(stateL.size());
0702 for (auto element : stateL) {
0703 state->push_back_stateVector(static_cast<std::uint32_t>(element));
0704 }
0705 }
0706 }
0707
0708 void RandomNumberGeneratorService::restoreFromCache(std::vector<RandomEngineState> const& cache,
0709 std::vector<LabelAndEngine>& engines) {
0710 std::vector<LabelAndEngine>::iterator labelAndEngine = engines.begin();
0711 for (auto const& cachedState : cache) {
0712 std::string const& engineLabel = cachedState.getLabel();
0713
0714 std::vector<std::uint32_t> const& engineState = cachedState.getState();
0715 std::vector<unsigned long> engineStateL;
0716 engineStateL.reserve(engineState.size());
0717 for (auto const& value : engineState) {
0718 engineStateL.push_back(static_cast<unsigned long>(value));
0719 }
0720
0721 std::vector<std::uint32_t> const& engineSeeds = cachedState.getSeed();
0722 std::vector<long> engineSeedsL;
0723 engineSeedsL.reserve(engineSeeds.size());
0724 for (auto const& val : engineSeeds) {
0725 long seedL = static_cast<long>(val);
0726 engineSeedsL.push_back(seedL);
0727
0728
0729
0730
0731
0732
0733
0734
0735 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
0736 assert(val == seedu32);
0737 }
0738
0739 assert(labelAndEngine != engines.end() && engineLabel == labelAndEngine->label());
0740 std::shared_ptr<CLHEP::HepRandomEngine> const& engine = labelAndEngine->engine();
0741
0742
0743
0744 if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
0745 checkEngineType(engine->name(), std::string("HepJamesRandom"), engineLabel);
0746
0747
0748 engine->setSeed(engineSeedsL[0], 0);
0749 engine->get(engineStateL);
0750
0751 labelAndEngine->setSeed(engineSeeds[0], 0);
0752 } else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
0753 checkEngineType(engine->name(), std::string("RanecuEngine"), engineLabel);
0754
0755
0756 engine->get(engineStateL);
0757
0758 labelAndEngine->setSeed(engineSeeds[0], 0);
0759 labelAndEngine->setSeed(engineSeeds[1], 1);
0760 } else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::MixMaxRng>()) {
0761 checkEngineType(engine->name(), std::string("MixMaxRng"), engineLabel);
0762
0763
0764 engine->setSeed(engineSeedsL[0], 0);
0765 engine->get(engineStateL);
0766
0767 labelAndEngine->setSeed(engineSeeds[0], 0);
0768 } else if (engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
0769 checkEngineType(engine->name(), std::string("TRandom3"), engineLabel);
0770
0771
0772 engine->setSeed(engineSeedsL[0], 0);
0773 engine->get(engineStateL);
0774
0775 labelAndEngine->setSeed(engineSeeds[0], 0);
0776 } else {
0777
0778
0779 throw Exception(errors::Unknown)
0780 << "The RandomNumberGeneratorService is trying to restore the state\n"
0781 "of the random engines. The state in the event indicates an engine\n"
0782 "of an unknown type. This should not be possible unless you are\n"
0783 "running with an old code release on a new file that was created\n"
0784 "with a newer release which had new engine types added. In this case\n"
0785 "the only solution is to use a newer release. In any other case, notify\n"
0786 "the EDM developers because this should not be possible\n";
0787 }
0788 ++labelAndEngine;
0789 }
0790 }
0791
0792 void RandomNumberGeneratorService::checkEngineType(std::string const& typeFromConfig,
0793 std::string const& typeFromEvent,
0794 std::string const& engineLabel) const {
0795 if (typeFromConfig != typeFromEvent) {
0796 throw Exception(errors::Configuration)
0797 << "The RandomNumberGeneratorService is trying to restore\n"
0798 << "the state of the random engine for the module \"" << engineLabel << "\". An\n"
0799 << "error was detected because the type of the engine in the\n"
0800 << "input file and the configuration file do not match.\n"
0801 << "In the configuration file the type is \"" << typeFromConfig << "\".\nIn the input file the type is \""
0802 << typeFromEvent << "\". If\n"
0803 << "you are not generating any random numbers in this module, then\n"
0804 << "remove the line in the configuration file that gives it\n"
0805 << "a seed and the error will go away. Otherwise, you must give\n"
0806 << "this module the same engine type in the configuration file or\n"
0807 << "stop trying to restore the random engine state.\n";
0808 }
0809 }
0810
0811 void RandomNumberGeneratorService::saveStatesToFile(std::string const& fileName,
0812 StreamID const& streamID,
0813 LuminosityBlockIndex const& lumiIndex) {
0814 std::ofstream& outFile = *outFiles_.at(streamID);
0815
0816 if (!outFile.is_open()) {
0817 std::stringstream file;
0818 file << fileName;
0819 if (nStreams_ > 1) {
0820 file << "_" << streamID.value();
0821 }
0822
0823 outFile.open(file.str().c_str(), std::ofstream::out | std::ofstream::trunc);
0824
0825 if (!outFile) {
0826 throw Exception(errors::Configuration)
0827 << "Unable to open the file \"" << file.str() << "\" to save the state of the random engines.\n";
0828 }
0829 }
0830
0831 outFile.seekp(0, std::ios_base::beg);
0832 outFile << "<RandomEngineStates>\n";
0833
0834 outFile << "<Event>\n";
0835 writeStates(eventCache_.at(streamID), outFile);
0836 outFile << "</Event>\n";
0837
0838 outFile << "<Lumi>\n";
0839 writeStates(lumiCache_.at(lumiIndex), outFile);
0840 outFile << "</Lumi>\n";
0841
0842 outFile << "</RandomEngineStates>\n";
0843 outFile.flush();
0844 }
0845
0846 void RandomNumberGeneratorService::writeStates(std::vector<RandomEngineState> const& v, std::ofstream& outFile) {
0847 for (auto& state : v) {
0848 std::vector<std::uint32_t> const& seedVector = state.getSeed();
0849 std::vector<std::uint32_t>::size_type seedVectorLength = seedVector.size();
0850
0851 std::vector<std::uint32_t> const& stateVector = state.getState();
0852 std::vector<std::uint32_t>::size_type stateVectorLength = stateVector.size();
0853
0854 outFile << "<ModuleLabel>\n" << state.getLabel() << "\n</ModuleLabel>\n";
0855
0856 outFile << "<SeedLength>\n" << seedVectorLength << "\n</SeedLength>\n";
0857 outFile << "<InitialSeeds>\n";
0858 writeVector(seedVector, outFile);
0859 outFile << "</InitialSeeds>\n";
0860 outFile << "<FullStateLength>\n" << stateVectorLength << "\n</FullStateLength>\n";
0861 outFile << "<FullState>\n";
0862 writeVector(stateVector, outFile);
0863 outFile << "</FullState>\n";
0864 }
0865 }
0866
0867 void RandomNumberGeneratorService::writeVector(VUint32 const& v, std::ofstream& outFile) {
0868 if (v.empty())
0869 return;
0870 size_t numItems = v.size();
0871 for (size_t i = 0; i < numItems; ++i) {
0872 if (i != 0 && i % 10 == 0)
0873 outFile << "\n";
0874 outFile << std::setw(13) << v[i];
0875 }
0876 outFile << "\n";
0877 }
0878
0879 std::string RandomNumberGeneratorService::constructSaveFileName() const {
0880 char directory[1500];
0881 std::string fullName(getcwd(directory, sizeof(directory)) ? directory : "/PathIsTooBig");
0882 fullName += "/" + saveFileName_;
0883 return fullName;
0884 }
0885
0886 void RandomNumberGeneratorService::readEventStatesFromTextFile(std::string const& fileName,
0887 std::vector<RandomEngineState>& cache) {
0888 std::string whichStates("<Event>");
0889 readStatesFromFile(fileName, cache, whichStates);
0890 }
0891
0892 void RandomNumberGeneratorService::readLumiStatesFromTextFile(std::string const& fileName,
0893 std::vector<RandomEngineState>& cache) {
0894 std::string whichStates("<Lumi>");
0895 readStatesFromFile(fileName, cache, whichStates);
0896 }
0897
0898 void RandomNumberGeneratorService::readStatesFromFile(std::string const& fileName,
0899 std::vector<RandomEngineState>& cache,
0900 std::string const& whichStates) {
0901 std::ifstream inFile;
0902 inFile.open(fileName.c_str(), std::ifstream::in);
0903 if (!inFile) {
0904 throw Exception(errors::Configuration)
0905 << "Unable to open the file \"" << fileName << "\" to restore the random engine states.\n";
0906 }
0907
0908 std::string text;
0909 inFile >> text;
0910 if (!inFile.good() || text != std::string("<RandomEngineStates>")) {
0911 throw Exception(errors::Configuration)
0912 << "Attempting to read file with random number engine states.\n"
0913 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0914 << "Cannot read the file header word.\n";
0915 }
0916 bool saveToCache = false;
0917 while (readEngineState(inFile, cache, whichStates, saveToCache)) {
0918 }
0919 }
0920
0921 bool RandomNumberGeneratorService::readEngineState(std::istream& is,
0922 std::vector<RandomEngineState>& cache,
0923 std::string const& whichStates,
0924 bool& saveToCache) {
0925 std::string leading;
0926 std::string trailing;
0927 std::string moduleLabel;
0928 std::vector<std::uint32_t>::size_type seedVectorSize;
0929 std::vector<std::uint32_t> seedVector;
0930 std::vector<std::uint32_t>::size_type stateVectorSize;
0931 std::vector<std::uint32_t> stateVector;
0932
0933
0934
0935
0936
0937 is >> leading;
0938 if (!is.good()) {
0939 throw Exception(errors::Configuration)
0940 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0941 << "Cannot read next field and did not hit the end yet.\n";
0942 }
0943
0944
0945 if (leading == std::string("</RandomEngineStates>"))
0946 return false;
0947
0948
0949 if (leading == std::string("</Event>") || leading == std::string("</Lumi>")) {
0950 saveToCache = false;
0951 return true;
0952 }
0953
0954
0955 if (leading == std::string("<Event>") || leading == std::string("<Lumi>")) {
0956 saveToCache = (leading == whichStates);
0957 return true;
0958 }
0959
0960
0961
0962 is >> moduleLabel >> trailing;
0963 if (!is.good() || leading != std::string("<ModuleLabel>") || trailing != std::string("</ModuleLabel>")) {
0964 throw Exception(errors::Configuration)
0965 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0966 << "Cannot read a module label when restoring random engine states.\n";
0967 }
0968
0969 is >> leading >> seedVectorSize >> trailing;
0970 if (!is.good() || leading != std::string("<SeedLength>") || trailing != std::string("</SeedLength>")) {
0971 throw Exception(errors::Configuration)
0972 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0973 << "Cannot read seed vector length when restoring random engine states.\n";
0974 }
0975
0976 is >> leading;
0977 if (!is.good() || leading != std::string("<InitialSeeds>")) {
0978 throw Exception(errors::Configuration)
0979 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0980 << "Cannot read beginning of InitialSeeds when restoring random engine states.\n";
0981 }
0982
0983 if (seedVectorSize > maxSeeds) {
0984 throw Exception(errors::Configuration)
0985 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0986 << "The number of seeds exceeds 64K.\n";
0987 }
0988
0989 readVector(is, seedVectorSize, seedVector);
0990
0991 is >> trailing;
0992 if (!is.good() || trailing != std::string("</InitialSeeds>")) {
0993 throw Exception(errors::Configuration)
0994 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0995 << "Cannot read end of InitialSeeds when restoring random engine states.\n";
0996 }
0997
0998 is >> leading >> stateVectorSize >> trailing;
0999 if (!is.good() || leading != std::string("<FullStateLength>") || trailing != std::string("</FullStateLength>")) {
1000 throw Exception(errors::Configuration)
1001 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1002 << "Cannot read state vector length when restoring random engine states.\n";
1003 }
1004
1005 is >> leading;
1006 if (!is.good() || leading != std::string("<FullState>")) {
1007 throw Exception(errors::Configuration)
1008 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1009 << "Cannot read beginning of FullState when restoring random engine states.\n";
1010 }
1011
1012 if (stateVectorSize > maxStates) {
1013 throw Exception(errors::Configuration)
1014 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1015 << "The number of states exceeds 64K.\n";
1016 }
1017
1018 readVector(is, stateVectorSize, stateVector);
1019
1020 is >> trailing;
1021 if (!is.good() || trailing != std::string("</FullState>")) {
1022 throw Exception(errors::Configuration)
1023 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1024 << "Cannot read end of FullState when restoring random engine states.\n";
1025 }
1026
1027 if (saveToCache) {
1028 RandomEngineState randomEngineState;
1029 randomEngineState.setLabel(moduleLabel);
1030 std::vector<RandomEngineState>::iterator state =
1031 std::lower_bound(cache.begin(), cache.end(), randomEngineState);
1032
1033 if (state != cache.end() && moduleLabel == state->getLabel()) {
1034 if (seedVector.size() != state->getSeed().size() || stateVector.size() != state->getState().size()) {
1035 throw Exception(errors::Configuration)
1036 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1037 << "Vectors containing engine state are the incorrect size for the type of random engine.\n";
1038 }
1039 state->setSeed(seedVector);
1040 state->setState(stateVector);
1041 }
1042 }
1043 return true;
1044 }
1045
1046 void RandomNumberGeneratorService::readVector(std::istream& is, unsigned numItems, std::vector<std::uint32_t>& v) {
1047 v.clear();
1048 v.reserve(numItems);
1049 std::uint32_t data;
1050 for (unsigned i = 0; i < numItems; ++i) {
1051 is >> data;
1052 if (!is.good()) {
1053 throw Exception(errors::Configuration)
1054 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1055 << "Cannot read vector when restoring random engine states.\n";
1056 }
1057 v.push_back(data);
1058 }
1059 }
1060
1061 void RandomNumberGeneratorService::createEnginesInVector(std::vector<LabelAndEngine>& engines,
1062 unsigned int seedOffset,
1063 unsigned int eventSeedOffset,
1064 std::vector<ModuleIDToEngine>& moduleIDVector) {
1065
1066
1067 engines.reserve(seedsAndNameMap_.size());
1068 moduleIDVector.reserve(seedsAndNameMap_.size());
1069
1070 for (auto const& i : seedsAndNameMap_) {
1071 unsigned int moduleID = i.second.moduleID();
1072 if (moduleID != std::numeric_limits<unsigned int>::max()) {
1073 std::string const& label = i.first;
1074 std::string const& name = i.second.engineName();
1075 VUint32 const& seeds = i.second.seeds();
1076
1077 if (name == "RanecuEngine") {
1078 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::RanecuEngine>();
1079 engines.emplace_back(label, seeds, engine);
1080 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1081 }
1082
1083 else {
1084 long int seedL = static_cast<long int>(seeds[0]);
1085
1086 if (name == "HepJamesRandom") {
1087 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::HepJamesRandom>(seedL);
1088 engines.emplace_back(label, seeds, engine);
1089 if (seedOffset != 0 || eventSeedOffset != 0) {
1090 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1091 }
1092 } else if (name == "MixMaxRng") {
1093 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::MixMaxRng>(seedL);
1094 engines.emplace_back(label, seeds, engine);
1095 if (seedOffset != 0 || eventSeedOffset != 0) {
1096 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1097 }
1098 } else {
1099
1100
1101
1102
1103
1104
1105
1106
1107 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1108 assert(seeds[0] == seedu32);
1109
1110 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<TRandomAdaptor>(seedL);
1111 engines.emplace_back(label, seeds, engine);
1112 if (seedOffset != 0 || eventSeedOffset != 0) {
1113 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1114 }
1115 }
1116 }
1117 moduleIDVector.emplace_back(&engines.back(), moduleID);
1118 }
1119 }
1120 std::sort(moduleIDVector.begin(), moduleIDVector.end());
1121 }
1122
1123 void RandomNumberGeneratorService::resetEngineSeeds(LabelAndEngine& labelAndEngine,
1124 std::string const& engineName,
1125 VUint32 const& seeds,
1126 std::uint32_t offset1,
1127 std::uint32_t offset2) {
1128 if (engineName == "RanecuEngine") {
1129 assert(seeds.size() == 2U);
1130
1131 std::uint32_t mod = maxSeedRanecu + 1U;
1132 offset1 %= mod;
1133 offset2 %= mod;
1134 std::uint32_t seed0 = (seeds[0] + offset1) % mod;
1135 seed0 = (seed0 + offset2) % mod;
1136 labelAndEngine.setSeed(seed0, 0);
1137 labelAndEngine.setSeed(seeds[1], 1);
1138 long int seedL[2];
1139 seedL[0] = static_cast<long int>(seed0);
1140 seedL[1] = static_cast<long int>(seeds[1]);
1141 labelAndEngine.engine()->setSeeds(seedL, 0);
1142 } else {
1143 assert(seeds.size() == 1U);
1144
1145 if (engineName == "HepJamesRandom" || engineName == "MixMaxRng") {
1146
1147 std::uint32_t mod = maxSeedHepJames + 1U;
1148 offset1 %= mod;
1149 offset2 %= mod;
1150 std::uint32_t seed0 = (seeds[0] + offset1) % mod;
1151 seed0 = (seed0 + offset2) % mod;
1152 labelAndEngine.setSeed(seed0, 0);
1153
1154 long int seedL = static_cast<long int>(seed0);
1155 labelAndEngine.engine()->setSeed(seedL, 0);
1156 } else {
1157 assert(engineName == "TRandom3");
1158
1159
1160
1161 std::uint32_t max32 = maxSeedTRandom3;
1162 std::uint32_t seed0 = seeds[0];
1163 if ((max32 - seed0) >= offset1) {
1164 seed0 += offset1;
1165 } else {
1166 seed0 = offset1 - (max32 - seed0) - 1U;
1167 }
1168 if ((max32 - seed0) >= offset2) {
1169 seed0 += offset2;
1170 } else {
1171 seed0 = offset2 - (max32 - seed0) - 1U;
1172 }
1173 labelAndEngine.setSeed(seed0, 0);
1174
1175 long seedL = static_cast<long>(seed0);
1176
1177
1178
1179
1180
1181
1182
1183
1184 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1185 assert(seed0 == seedu32);
1186
1187 labelAndEngine.engine()->setSeed(seedL, 0);
1188 }
1189 }
1190 }
1191 }
1192 }