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