File indexing completed on 2025-04-13 22:50: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 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(ProcessContext const&) { beginJobEndJobActive_ = true; }
0432
0433 void RandomNumberGeneratorService::postBeginJob() { beginJobEndJobActive_ = false; }
0434
0435 void RandomNumberGeneratorService::preEndJob() { beginJobEndJobActive_ = true; }
0436
0437 void RandomNumberGeneratorService::postEndJob() { beginJobEndJobActive_ = false; }
0438
0439 void RandomNumberGeneratorService::preBeginLumi(LuminosityBlock const& lumi) {
0440 if (!restoreStateTag_.label().empty()) {
0441
0442 readFromLuminosityBlock(lumi);
0443 }
0444
0445 restoreFromCache(lumiCache_[lumi.index()], lumiEngines_[lumi.index()]);
0446 }
0447
0448 void RandomNumberGeneratorService::postEventRead(Event const& event) {
0449 if (!restoreStateTag_.label().empty()) {
0450
0451 snapShot(streamEngines_[event.streamID()], eventCache_[event.streamID()]);
0452
0453
0454 readFromEvent(event);
0455
0456
0457 restoreFromCache(eventCache_[event.streamID()], streamEngines_[event.streamID()]);
0458
0459 } else {
0460
0461 snapShot(streamEngines_[event.streamID()], eventCache_[event.streamID()]);
0462 }
0463
0464
0465 if (!saveFileName_.empty()) {
0466 saveStatesToFile(saveFileName_, event.streamID(), event.getLuminosityBlock().index());
0467 bool expected = false;
0468 if (saveFileNameRecorded_.compare_exchange_strong(expected, true)) {
0469 std::string fullName = constructSaveFileName();
0470 Service<JobReport> reportSvc;
0471 reportSvc->reportRandomStateFile(fullName);
0472 }
0473 }
0474 }
0475
0476 void RandomNumberGeneratorService::setLumiCache(LuminosityBlockIndex iLumi,
0477 std::vector<RandomEngineState> const& iStates) {
0478 lumiCache_[iLumi] = iStates;
0479
0480 restoreFromCache(lumiCache_[iLumi], lumiEngines_[iLumi]);
0481 }
0482 void RandomNumberGeneratorService::setEventCache(StreamID iStream, std::vector<RandomEngineState> const& iStates) {
0483 eventCache_[iStream] = iStates;
0484
0485 restoreFromCache(eventCache_[iStream], streamEngines_[iStream]);
0486 }
0487
0488 void RandomNumberGeneratorService::preModuleBeginStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0489 preModuleStreamCheck(sc, mcc);
0490 }
0491
0492 void RandomNumberGeneratorService::postModuleBeginStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0493 postModuleStreamCheck(sc, mcc);
0494 }
0495
0496 void RandomNumberGeneratorService::preModuleEndStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0497 preModuleStreamCheck(sc, mcc);
0498 }
0499
0500 void RandomNumberGeneratorService::postModuleEndStream(StreamContext const& sc, ModuleCallingContext const& mcc) {
0501 postModuleStreamCheck(sc, mcc);
0502 }
0503
0504 void RandomNumberGeneratorService::preModuleStreamBeginRun(StreamContext const& sc,
0505 ModuleCallingContext const& mcc) {
0506 preModuleStreamCheck(sc, mcc);
0507 }
0508
0509 void RandomNumberGeneratorService::postModuleStreamBeginRun(StreamContext const& sc,
0510 ModuleCallingContext const& mcc) {
0511 postModuleStreamCheck(sc, mcc);
0512 }
0513
0514 void RandomNumberGeneratorService::preModuleStreamEndRun(StreamContext const& sc, ModuleCallingContext const& mcc) {
0515 preModuleStreamCheck(sc, mcc);
0516 }
0517
0518 void RandomNumberGeneratorService::postModuleStreamEndRun(StreamContext const& sc,
0519 ModuleCallingContext const& mcc) {
0520 postModuleStreamCheck(sc, mcc);
0521 }
0522
0523 void RandomNumberGeneratorService::preModuleStreamBeginLumi(StreamContext const& sc,
0524 ModuleCallingContext const& mcc) {
0525 preModuleStreamCheck(sc, mcc);
0526 }
0527
0528 void RandomNumberGeneratorService::postModuleStreamBeginLumi(StreamContext const& sc,
0529 ModuleCallingContext const& mcc) {
0530 postModuleStreamCheck(sc, mcc);
0531 }
0532
0533 void RandomNumberGeneratorService::preModuleStreamEndLumi(StreamContext const& sc,
0534 ModuleCallingContext const& mcc) {
0535 preModuleStreamCheck(sc, mcc);
0536 }
0537
0538 void RandomNumberGeneratorService::postModuleStreamEndLumi(StreamContext const& sc,
0539 ModuleCallingContext const& mcc) {
0540 postModuleStreamCheck(sc, mcc);
0541 }
0542
0543 std::vector<RandomEngineState> const& RandomNumberGeneratorService::getLumiCache(
0544 LuminosityBlockIndex const& lumiIndex) const {
0545 return lumiCache_.at(lumiIndex.value());
0546 }
0547
0548 std::vector<RandomEngineState> const& RandomNumberGeneratorService::getEventCache(StreamID const& streamID) const {
0549 return eventCache_.at(streamID.value());
0550 }
0551
0552 void RandomNumberGeneratorService::print(std::ostream& os) const {
0553 os << "\n\nRandomNumberGeneratorService dump\n\n";
0554
0555 os << " Contents of seedsAndNameMap (label moduleID engineType seeds)\n";
0556 for (auto const& entry : seedsAndNameMap_) {
0557 os << " " << entry.first << " " << entry.second.moduleID() << " " << entry.second.engineName();
0558 for (auto val : entry.second.seeds()) {
0559 os << " " << val;
0560 }
0561 os << "\n";
0562 }
0563 os << " nStreams_ = " << nStreams_ << "\n";
0564 os << " saveFileName_ = " << saveFileName_ << "\n";
0565 os << " saveFileNameRecorded_ = " << saveFileNameRecorded_ << "\n";
0566 os << " restoreFileName_ = " << restoreFileName_ << "\n";
0567 os << " enableChecking_ = " << enableChecking_ << "\n";
0568 os << " eventSeedOffset_ = " << eventSeedOffset_ << "\n";
0569 os << " verbose_ = " << verbose_ << "\n";
0570 os << " restoreStateTag_ = " << restoreStateTag_ << "\n";
0571 os << " restoreStateBeginLumiTag_ = " << restoreStateBeginLumiTag_ << "\n";
0572
0573 os << "\n streamEngines_\n";
0574 unsigned int iStream = 0;
0575 for (auto const& k : streamEngines_) {
0576 os << " Stream " << iStream << "\n";
0577 for (auto const& i : k) {
0578 os << " " << i.label();
0579 for (auto const& j : i.seeds()) {
0580 os << " " << j;
0581 }
0582 os << " " << i.engine()->name();
0583 if (i.engine()->name() == std::string("HepJamesRandom")) {
0584 os << " " << i.engine()->getSeed();
0585 } else if (i.engine()->name() == std::string("MixMaxRng")) {
0586 os << " " << i.engine()->getSeed();
0587 } else {
0588 os << " engine does not know seeds";
0589 }
0590 os << "\n";
0591 }
0592 ++iStream;
0593 }
0594 os << "\n lumiEngines_\n";
0595 unsigned int iLumi = 0;
0596 for (auto const& k : lumiEngines_) {
0597 os << " lumiIndex " << iLumi << "\n";
0598 for (auto const& i : k) {
0599 os << " " << i.label();
0600 for (auto const& j : i.seeds()) {
0601 os << " " << j;
0602 }
0603 os << " " << i.engine()->name();
0604 if (i.engine()->name() == std::string("HepJamesRandom")) {
0605 os << " " << i.engine()->getSeed();
0606 } else if (i.engine()->name() == std::string("MixMaxRng")) {
0607 os << " " << i.engine()->getSeed();
0608 } else {
0609 os << " engine does not know seeds";
0610 }
0611 os << "\n";
0612 }
0613 ++iLumi;
0614 }
0615 }
0616
0617 void RandomNumberGeneratorService::preModuleStreamCheck(StreamContext const& sc, ModuleCallingContext const& mcc) {
0618 if (enableChecking_) {
0619 unsigned int moduleID = mcc.moduleDescription()->id();
0620 std::vector<ModuleIDToEngine>& moduleIDVector = streamModuleIDToEngine_.at(sc.streamID().value());
0621 ModuleIDToEngine target(nullptr, moduleID);
0622 std::vector<ModuleIDToEngine>::iterator iter =
0623 std::lower_bound(moduleIDVector.begin(), moduleIDVector.end(), target);
0624 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
0625 LabelAndEngine* labelAndEngine = iter->labelAndEngine();
0626 iter->setEngineState(labelAndEngine->engine()->put());
0627 }
0628 }
0629 }
0630
0631 void RandomNumberGeneratorService::postModuleStreamCheck(StreamContext const& sc, ModuleCallingContext const& mcc) {
0632 if (enableChecking_) {
0633 unsigned int moduleID = mcc.moduleDescription()->id();
0634 std::vector<ModuleIDToEngine>& moduleIDVector = streamModuleIDToEngine_.at(sc.streamID().value());
0635 ModuleIDToEngine target(nullptr, moduleID);
0636 std::vector<ModuleIDToEngine>::iterator iter =
0637 std::lower_bound(moduleIDVector.begin(), moduleIDVector.end(), target);
0638 if (iter != moduleIDVector.end() && iter->moduleID() == moduleID) {
0639 LabelAndEngine* labelAndEngine = iter->labelAndEngine();
0640 if (iter->engineState() != labelAndEngine->engine()->put()) {
0641 throw Exception(errors::LogicError)
0642 << "It is illegal to generate random numbers during beginStream, endStream,\n"
0643 "beginRun, endRun, beginLumi, endLumi because that makes it very difficult\n"
0644 "to replay the processing of individual events. Random numbers were\n"
0645 "generated during one of these methods for the module with class name\n\""
0646 << mcc.moduleDescription()->moduleName()
0647 << "\" "
0648 "and module label \""
0649 << mcc.moduleDescription()->moduleLabel() << "\"\n";
0650 }
0651 }
0652 }
0653 }
0654
0655 void RandomNumberGeneratorService::readFromLuminosityBlock(LuminosityBlock const& lumi) {
0656 Service<TriggerNamesService> tns;
0657 if (tns.isAvailable()) {
0658 if (tns->getProcessName() == restoreStateTag_.process()) {
0659 throw Exception(errors::Configuration)
0660 << "In the configuration for the RandomNumberGeneratorService the\n"
0661 << "restoreStateTag contains the current process which is illegal.\n"
0662 << "The process name in the replay process should have been changed\n"
0663 << "to be different than the original process name and the restoreStateTag\n"
0664 << "should contain either the original process name or an empty process name.\n";
0665 }
0666 }
0667
0668 Handle<RandomEngineStates> states;
0669 lumi.getByLabel(restoreStateBeginLumiTag_, states);
0670
0671 if (!states.isValid()) {
0672 throw Exception(errors::ProductNotFound)
0673 << "The RandomNumberGeneratorService is trying to restore\n"
0674 << "the state of the random engines by reading a product from\n"
0675 << "the LuminosityBlock with input tag \"" << restoreStateBeginLumiTag_ << "\".\n"
0676 << "It could not find the product.\n"
0677 << "Either the product in the LuminosityBlock was dropped or\n"
0678 << "not produced or the configured input tag is incorrect or there is a bug somewhere\n";
0679 return;
0680 }
0681 states->getRandomEngineStates(lumiCache_.at(lumi.index()));
0682 }
0683
0684 void RandomNumberGeneratorService::readFromEvent(Event const& event) {
0685 Handle<RandomEngineStates> states;
0686
0687 event.getByLabel(restoreStateTag_, states);
0688
0689 if (!states.isValid()) {
0690 throw Exception(errors::ProductNotFound)
0691 << "The RandomNumberGeneratorService is trying to restore\n"
0692 << "the state of the random engines by reading a product from\n"
0693 << "the Event with input tag \"" << restoreStateTag_ << "\".\n"
0694 << "It could not find the product.\n"
0695 << "Either the product in the Event was dropped or\n"
0696 << "not produced or the configured input tag is incorrect or there is a bug somewhere\n";
0697 return;
0698 }
0699 states->getRandomEngineStates(eventCache_.at(event.streamID()));
0700 }
0701
0702 void RandomNumberGeneratorService::snapShot(std::vector<LabelAndEngine> const& engines,
0703 std::vector<RandomEngineState>& cache) {
0704 cache.resize(engines.size());
0705 std::vector<RandomEngineState>::iterator state = cache.begin();
0706
0707 for (std::vector<LabelAndEngine>::const_iterator iter = engines.begin(); iter != engines.end(); ++iter, ++state) {
0708 std::string const& label = iter->label();
0709 state->setLabel(label);
0710 state->setSeed(iter->seeds());
0711
0712 std::vector<unsigned long> stateL = iter->engine()->put();
0713 state->clearStateVector();
0714 state->reserveStateVector(stateL.size());
0715 for (auto element : stateL) {
0716 state->push_back_stateVector(static_cast<std::uint32_t>(element));
0717 }
0718 }
0719 }
0720
0721 void RandomNumberGeneratorService::restoreFromCache(std::vector<RandomEngineState> const& cache,
0722 std::vector<LabelAndEngine>& engines) {
0723 std::vector<LabelAndEngine>::iterator labelAndEngine = engines.begin();
0724 for (auto const& cachedState : cache) {
0725 std::string const& engineLabel = cachedState.getLabel();
0726
0727 std::vector<std::uint32_t> const& engineState = cachedState.getState();
0728 std::vector<unsigned long> engineStateL;
0729 engineStateL.reserve(engineState.size());
0730 for (auto const& value : engineState) {
0731 engineStateL.push_back(static_cast<unsigned long>(value));
0732 }
0733
0734 std::vector<std::uint32_t> const& engineSeeds = cachedState.getSeed();
0735 std::vector<long> engineSeedsL;
0736 engineSeedsL.reserve(engineSeeds.size());
0737 for (auto const& val : engineSeeds) {
0738 long seedL = static_cast<long>(val);
0739 engineSeedsL.push_back(seedL);
0740
0741
0742
0743
0744
0745
0746
0747
0748 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
0749 assert(val == seedu32);
0750 }
0751
0752 assert(labelAndEngine != engines.end() && engineLabel == labelAndEngine->label());
0753 std::shared_ptr<CLHEP::HepRandomEngine> const& engine = labelAndEngine->engine();
0754
0755
0756
0757 if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
0758 checkEngineType(engine->name(), std::string("HepJamesRandom"), engineLabel);
0759
0760
0761 engine->setSeed(engineSeedsL[0], 0);
0762 engine->get(engineStateL);
0763
0764 labelAndEngine->setSeed(engineSeeds[0], 0);
0765 } else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
0766 checkEngineType(engine->name(), std::string("RanecuEngine"), engineLabel);
0767
0768
0769 engine->get(engineStateL);
0770
0771 labelAndEngine->setSeed(engineSeeds[0], 0);
0772 labelAndEngine->setSeed(engineSeeds[1], 1);
0773 } else if (engineStateL[0] == CLHEP::engineIDulong<CLHEP::MixMaxRng>()) {
0774 checkEngineType(engine->name(), std::string("MixMaxRng"), engineLabel);
0775
0776
0777 engine->setSeed(engineSeedsL[0], 0);
0778 engine->get(engineStateL);
0779
0780 labelAndEngine->setSeed(engineSeeds[0], 0);
0781 } else if (engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
0782 checkEngineType(engine->name(), std::string("TRandom3"), engineLabel);
0783
0784
0785 engine->setSeed(engineSeedsL[0], 0);
0786 engine->get(engineStateL);
0787
0788 labelAndEngine->setSeed(engineSeeds[0], 0);
0789 } else {
0790
0791
0792 throw Exception(errors::Unknown)
0793 << "The RandomNumberGeneratorService is trying to restore the state\n"
0794 "of the random engines. The state in the event indicates an engine\n"
0795 "of an unknown type. This should not be possible unless you are\n"
0796 "running with an old code release on a new file that was created\n"
0797 "with a newer release which had new engine types added. In this case\n"
0798 "the only solution is to use a newer release. In any other case, notify\n"
0799 "the EDM developers because this should not be possible\n";
0800 }
0801 ++labelAndEngine;
0802 }
0803 }
0804
0805 void RandomNumberGeneratorService::checkEngineType(std::string const& typeFromConfig,
0806 std::string const& typeFromEvent,
0807 std::string const& engineLabel) const {
0808 if (typeFromConfig != typeFromEvent) {
0809 throw Exception(errors::Configuration)
0810 << "The RandomNumberGeneratorService is trying to restore\n"
0811 << "the state of the random engine for the module \"" << engineLabel << "\". An\n"
0812 << "error was detected because the type of the engine in the\n"
0813 << "input file and the configuration file do not match.\n"
0814 << "In the configuration file the type is \"" << typeFromConfig << "\".\nIn the input file the type is \""
0815 << typeFromEvent << "\". If\n"
0816 << "you are not generating any random numbers in this module, then\n"
0817 << "remove the line in the configuration file that gives it\n"
0818 << "a seed and the error will go away. Otherwise, you must give\n"
0819 << "this module the same engine type in the configuration file or\n"
0820 << "stop trying to restore the random engine state.\n";
0821 }
0822 }
0823
0824 void RandomNumberGeneratorService::saveStatesToFile(std::string const& fileName,
0825 StreamID const& streamID,
0826 LuminosityBlockIndex const& lumiIndex) {
0827 std::ofstream& outFile = *outFiles_.at(streamID);
0828
0829 if (!outFile.is_open()) {
0830 std::stringstream file;
0831 file << fileName;
0832 if (nStreams_ > 1) {
0833 file << "_" << streamID.value();
0834 }
0835
0836 outFile.open(file.str().c_str(), std::ofstream::out | std::ofstream::trunc);
0837
0838 if (!outFile) {
0839 throw Exception(errors::Configuration)
0840 << "Unable to open the file \"" << file.str() << "\" to save the state of the random engines.\n";
0841 }
0842 }
0843
0844 outFile.seekp(0, std::ios_base::beg);
0845 outFile << "<RandomEngineStates>\n";
0846
0847 outFile << "<Event>\n";
0848 writeStates(eventCache_.at(streamID), outFile);
0849 outFile << "</Event>\n";
0850
0851 outFile << "<Lumi>\n";
0852 writeStates(lumiCache_.at(lumiIndex), outFile);
0853 outFile << "</Lumi>\n";
0854
0855 outFile << "</RandomEngineStates>\n";
0856 outFile.flush();
0857 }
0858
0859 void RandomNumberGeneratorService::writeStates(std::vector<RandomEngineState> const& v, std::ofstream& outFile) {
0860 for (auto& state : v) {
0861 std::vector<std::uint32_t> const& seedVector = state.getSeed();
0862 std::vector<std::uint32_t>::size_type seedVectorLength = seedVector.size();
0863
0864 std::vector<std::uint32_t> const& stateVector = state.getState();
0865 std::vector<std::uint32_t>::size_type stateVectorLength = stateVector.size();
0866
0867 outFile << "<ModuleLabel>\n" << state.getLabel() << "\n</ModuleLabel>\n";
0868
0869 outFile << "<SeedLength>\n" << seedVectorLength << "\n</SeedLength>\n";
0870 outFile << "<InitialSeeds>\n";
0871 writeVector(seedVector, outFile);
0872 outFile << "</InitialSeeds>\n";
0873 outFile << "<FullStateLength>\n" << stateVectorLength << "\n</FullStateLength>\n";
0874 outFile << "<FullState>\n";
0875 writeVector(stateVector, outFile);
0876 outFile << "</FullState>\n";
0877 }
0878 }
0879
0880 void RandomNumberGeneratorService::writeVector(VUint32 const& v, std::ofstream& outFile) {
0881 if (v.empty())
0882 return;
0883 size_t numItems = v.size();
0884 for (size_t i = 0; i < numItems; ++i) {
0885 if (i != 0 && i % 10 == 0)
0886 outFile << "\n";
0887 outFile << std::setw(13) << v[i];
0888 }
0889 outFile << "\n";
0890 }
0891
0892 std::string RandomNumberGeneratorService::constructSaveFileName() const {
0893 char directory[1500];
0894 std::string fullName(getcwd(directory, sizeof(directory)) ? directory : "/PathIsTooBig");
0895 fullName += "/" + saveFileName_;
0896 return fullName;
0897 }
0898
0899 void RandomNumberGeneratorService::readEventStatesFromTextFile(std::string const& fileName,
0900 std::vector<RandomEngineState>& cache) {
0901 std::string whichStates("<Event>");
0902 readStatesFromFile(fileName, cache, whichStates);
0903 }
0904
0905 void RandomNumberGeneratorService::readLumiStatesFromTextFile(std::string const& fileName,
0906 std::vector<RandomEngineState>& cache) {
0907 std::string whichStates("<Lumi>");
0908 readStatesFromFile(fileName, cache, whichStates);
0909 }
0910
0911 void RandomNumberGeneratorService::readStatesFromFile(std::string const& fileName,
0912 std::vector<RandomEngineState>& cache,
0913 std::string const& whichStates) {
0914 std::ifstream inFile;
0915 inFile.open(fileName.c_str(), std::ifstream::in);
0916 if (!inFile) {
0917 throw Exception(errors::Configuration)
0918 << "Unable to open the file \"" << fileName << "\" to restore the random engine states.\n";
0919 }
0920
0921 std::string text;
0922 inFile >> text;
0923 if (!inFile.good() || text != std::string("<RandomEngineStates>")) {
0924 throw Exception(errors::Configuration)
0925 << "Attempting to read file with random number engine states.\n"
0926 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0927 << "Cannot read the file header word.\n";
0928 }
0929 bool saveToCache = false;
0930 while (readEngineState(inFile, cache, whichStates, saveToCache)) {
0931 }
0932 }
0933
0934 bool RandomNumberGeneratorService::readEngineState(std::istream& is,
0935 std::vector<RandomEngineState>& cache,
0936 std::string const& whichStates,
0937 bool& saveToCache) {
0938 std::string leading;
0939 std::string trailing;
0940 std::string moduleLabel;
0941 std::vector<std::uint32_t>::size_type seedVectorSize;
0942 std::vector<std::uint32_t> seedVector;
0943 std::vector<std::uint32_t>::size_type stateVectorSize;
0944 std::vector<std::uint32_t> stateVector;
0945
0946
0947
0948
0949
0950 is >> leading;
0951 if (!is.good()) {
0952 throw Exception(errors::Configuration)
0953 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0954 << "Cannot read next field and did not hit the end yet.\n";
0955 }
0956
0957
0958 if (leading == std::string("</RandomEngineStates>"))
0959 return false;
0960
0961
0962 if (leading == std::string("</Event>") || leading == std::string("</Lumi>")) {
0963 saveToCache = false;
0964 return true;
0965 }
0966
0967
0968 if (leading == std::string("<Event>") || leading == std::string("<Lumi>")) {
0969 saveToCache = (leading == whichStates);
0970 return true;
0971 }
0972
0973
0974
0975 is >> moduleLabel >> trailing;
0976 if (!is.good() || leading != std::string("<ModuleLabel>") || trailing != std::string("</ModuleLabel>")) {
0977 throw Exception(errors::Configuration)
0978 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0979 << "Cannot read a module label when restoring random engine states.\n";
0980 }
0981
0982 is >> leading >> seedVectorSize >> trailing;
0983 if (!is.good() || leading != std::string("<SeedLength>") || trailing != std::string("</SeedLength>")) {
0984 throw Exception(errors::Configuration)
0985 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0986 << "Cannot read seed vector length when restoring random engine states.\n";
0987 }
0988
0989 is >> leading;
0990 if (!is.good() || leading != std::string("<InitialSeeds>")) {
0991 throw Exception(errors::Configuration)
0992 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0993 << "Cannot read beginning of InitialSeeds when restoring random engine states.\n";
0994 }
0995
0996 if (seedVectorSize > maxSeeds) {
0997 throw Exception(errors::Configuration)
0998 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
0999 << "The number of seeds exceeds 64K.\n";
1000 }
1001
1002 readVector(is, seedVectorSize, seedVector);
1003
1004 is >> trailing;
1005 if (!is.good() || trailing != std::string("</InitialSeeds>")) {
1006 throw Exception(errors::Configuration)
1007 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1008 << "Cannot read end of InitialSeeds when restoring random engine states.\n";
1009 }
1010
1011 is >> leading >> stateVectorSize >> trailing;
1012 if (!is.good() || leading != std::string("<FullStateLength>") || trailing != std::string("</FullStateLength>")) {
1013 throw Exception(errors::Configuration)
1014 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1015 << "Cannot read state vector length when restoring random engine states.\n";
1016 }
1017
1018 is >> leading;
1019 if (!is.good() || leading != std::string("<FullState>")) {
1020 throw Exception(errors::Configuration)
1021 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1022 << "Cannot read beginning of FullState when restoring random engine states.\n";
1023 }
1024
1025 if (stateVectorSize > maxStates) {
1026 throw Exception(errors::Configuration)
1027 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1028 << "The number of states exceeds 64K.\n";
1029 }
1030
1031 readVector(is, stateVectorSize, stateVector);
1032
1033 is >> trailing;
1034 if (!is.good() || trailing != std::string("</FullState>")) {
1035 throw Exception(errors::Configuration)
1036 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1037 << "Cannot read end of FullState when restoring random engine states.\n";
1038 }
1039
1040 if (saveToCache) {
1041 RandomEngineState randomEngineState;
1042 randomEngineState.setLabel(moduleLabel);
1043 std::vector<RandomEngineState>::iterator state =
1044 std::lower_bound(cache.begin(), cache.end(), randomEngineState);
1045
1046 if (state != cache.end() && moduleLabel == state->getLabel()) {
1047 if (seedVector.size() != state->getSeed().size() || stateVector.size() != state->getState().size()) {
1048 throw Exception(errors::Configuration)
1049 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1050 << "Vectors containing engine state are the incorrect size for the type of random engine.\n";
1051 }
1052 state->setSeed(seedVector);
1053 state->setState(stateVector);
1054 }
1055 }
1056 return true;
1057 }
1058
1059 void RandomNumberGeneratorService::readVector(std::istream& is, unsigned numItems, std::vector<std::uint32_t>& v) {
1060 v.clear();
1061 v.reserve(numItems);
1062 std::uint32_t data;
1063 for (unsigned i = 0; i < numItems; ++i) {
1064 is >> data;
1065 if (!is.good()) {
1066 throw Exception(errors::Configuration)
1067 << "File \"" << restoreFileName_ << "\" is ill-structured or otherwise corrupted.\n"
1068 << "Cannot read vector when restoring random engine states.\n";
1069 }
1070 v.push_back(data);
1071 }
1072 }
1073
1074 void RandomNumberGeneratorService::createEnginesInVector(std::vector<LabelAndEngine>& engines,
1075 unsigned int seedOffset,
1076 unsigned int eventSeedOffset,
1077 std::vector<ModuleIDToEngine>& moduleIDVector) {
1078
1079
1080 engines.reserve(seedsAndNameMap_.size());
1081 moduleIDVector.reserve(seedsAndNameMap_.size());
1082
1083 for (auto const& i : seedsAndNameMap_) {
1084 unsigned int moduleID = i.second.moduleID();
1085 if (moduleID != std::numeric_limits<unsigned int>::max()) {
1086 std::string const& label = i.first;
1087 std::string const& name = i.second.engineName();
1088 VUint32 const& seeds = i.second.seeds();
1089
1090 if (name == "RanecuEngine") {
1091 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::RanecuEngine>();
1092 engines.emplace_back(label, seeds, engine);
1093 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1094 }
1095
1096 else {
1097 long int seedL = static_cast<long int>(seeds[0]);
1098
1099 if (name == "HepJamesRandom") {
1100 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::HepJamesRandom>(seedL);
1101 engines.emplace_back(label, seeds, engine);
1102 if (seedOffset != 0 || eventSeedOffset != 0) {
1103 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1104 }
1105 } else if (name == "MixMaxRng") {
1106 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<CLHEP::MixMaxRng>(seedL);
1107 engines.emplace_back(label, seeds, engine);
1108 if (seedOffset != 0 || eventSeedOffset != 0) {
1109 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1110 }
1111 } else {
1112
1113
1114
1115
1116
1117
1118
1119
1120 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1121 assert(seeds[0] == seedu32);
1122
1123 std::shared_ptr<CLHEP::HepRandomEngine> engine = std::make_shared<TRandomAdaptor>(seedL);
1124 engines.emplace_back(label, seeds, engine);
1125 if (seedOffset != 0 || eventSeedOffset != 0) {
1126 resetEngineSeeds(engines.back(), name, seeds, seedOffset, eventSeedOffset);
1127 }
1128 }
1129 }
1130 moduleIDVector.emplace_back(&engines.back(), moduleID);
1131 }
1132 }
1133 std::sort(moduleIDVector.begin(), moduleIDVector.end());
1134 }
1135
1136 void RandomNumberGeneratorService::resetEngineSeeds(LabelAndEngine& labelAndEngine,
1137 std::string const& engineName,
1138 VUint32 const& seeds,
1139 std::uint32_t offset1,
1140 std::uint32_t offset2) {
1141 if (engineName == "RanecuEngine") {
1142 assert(seeds.size() == 2U);
1143
1144 std::uint32_t mod = maxSeedRanecu + 1U;
1145 offset1 %= mod;
1146 offset2 %= mod;
1147 std::uint32_t seed0 = (seeds[0] + offset1) % mod;
1148 seed0 = (seed0 + offset2) % mod;
1149 labelAndEngine.setSeed(seed0, 0);
1150 labelAndEngine.setSeed(seeds[1], 1);
1151 long int seedL[2];
1152 seedL[0] = static_cast<long int>(seed0);
1153 seedL[1] = static_cast<long int>(seeds[1]);
1154 labelAndEngine.engine()->setSeeds(seedL, 0);
1155 } else {
1156 assert(seeds.size() == 1U);
1157
1158 if (engineName == "HepJamesRandom" || engineName == "MixMaxRng") {
1159
1160 std::uint32_t mod = maxSeedHepJames + 1U;
1161 offset1 %= mod;
1162 offset2 %= mod;
1163 std::uint32_t seed0 = (seeds[0] + offset1) % mod;
1164 seed0 = (seed0 + offset2) % mod;
1165 labelAndEngine.setSeed(seed0, 0);
1166
1167 long int seedL = static_cast<long int>(seed0);
1168 labelAndEngine.engine()->setSeed(seedL, 0);
1169 } else {
1170 assert(engineName == "TRandom3");
1171
1172
1173
1174 std::uint32_t max32 = maxSeedTRandom3;
1175 std::uint32_t seed0 = seeds[0];
1176 if ((max32 - seed0) >= offset1) {
1177 seed0 += offset1;
1178 } else {
1179 seed0 = offset1 - (max32 - seed0) - 1U;
1180 }
1181 if ((max32 - seed0) >= offset2) {
1182 seed0 += offset2;
1183 } else {
1184 seed0 = offset2 - (max32 - seed0) - 1U;
1185 }
1186 labelAndEngine.setSeed(seed0, 0);
1187
1188 long seedL = static_cast<long>(seed0);
1189
1190
1191
1192
1193
1194
1195
1196
1197 std::uint32_t seedu32 = static_cast<std::uint32_t>(seedL);
1198 assert(seed0 == seedu32);
1199
1200 labelAndEngine.engine()->setSeed(seedL, 0);
1201 }
1202 }
1203 }
1204 }
1205 }