Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-12-06 02:04:00

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