CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/IOMC/RandomEngine/src/RandomNumberGeneratorService.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     RandomEngine
00004 // Class  :     RandomNumberGeneratorService
00005 //
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Chris Jones, W. David Dagenhart
00010 //   Created:  Tue Mar  7 09:43:46 EST 2006 (originally in FWCore/Services)
00011 //
00012 
00013 #include "IOMC/RandomEngine/src/RandomNumberGeneratorService.h"
00014 
00015 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00016 #include "FWCore/Framework/interface/Event.h"
00017 #include "FWCore/Framework/interface/LuminosityBlock.h"
00018 #include "FWCore/MessageLogger/interface/JobReport.h"
00019 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00020 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00021 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00022 #include "FWCore/ParameterSet/interface/ParameterWildcard.h"
00023 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
00024 #include "FWCore/ServiceRegistry/interface/Service.h"
00025 #include "FWCore/Utilities/interface/EDMException.h"
00026 #include "IOMC/RandomEngine/src/TRandomAdaptor.h"
00027 #include "SimDataFormats/RandomEngine/interface/RandomEngineState.h"
00028 #include "SimDataFormats/RandomEngine/interface/RandomEngineStates.h"
00029 
00030 #include "CLHEP/Random/engineIDulong.h"
00031 #include "CLHEP/Random/JamesRandom.h"
00032 #include "CLHEP/Random/RanecuEngine.h"
00033 
00034 #include <iostream>
00035 #include <limits>
00036 #include <sstream>
00037 #include <unistd.h>
00038 
00039 namespace edm {
00040   namespace service {
00041 
00042     uint32_t RandomNumberGeneratorService::maxSeedRanecu =   2147483647U;
00043     uint32_t RandomNumberGeneratorService::maxSeedHepJames =  900000000U;
00044     uint32_t RandomNumberGeneratorService::maxSeedTRandom3 = 4294967295U;
00045 
00046     RandomNumberGeneratorService::RandomNumberGeneratorService(ParameterSet const& pset,
00047                                                                ActivityRegistry& activityRegistry):
00048       saveFileName_(pset.getUntrackedParameter<std::string>("saveFileName")),
00049       saveFileNameRecorded_(false),
00050       restoreFileName_(pset.getUntrackedParameter<std::string>("restoreFileName")),
00051       enableChecking_(pset.getUntrackedParameter<bool>("enableChecking")),
00052       firstLumi_(true),
00053       childIndex_(0U),
00054       eventSeedOffset_(pset.getUntrackedParameter<unsigned>("eventSeedOffset")),
00055       failedToFindStatesInLumi_(false) {
00056 
00057       if(pset.exists("restoreStateTag")) {
00058         restoreStateTag_ = pset.getUntrackedParameter<edm::InputTag>("restoreStateTag");
00059       } else {
00060         restoreStateTag_ = edm::InputTag(pset.getUntrackedParameter<std::string>("restoreStateLabel"), "", "");
00061       }
00062       restoreStateBeginLumiTag_ = edm::InputTag(restoreStateTag_.label(), "beginLumi", restoreStateTag_.process()); 
00063 
00064       if(!restoreFileName_.empty() && !restoreStateTag_.label().empty()) {
00065         throw Exception(errors::Configuration)
00066           << "In the configuration for the RandomNumberGeneratorService both\n"
00067           << "restoreFileName and restoreStateLabel were set to nonempty values\n"
00068           << "which is illegal.  It is impossible to restore the random engine\n"
00069           << "states two different ways in the same process.\n";
00070       }
00071 
00072       // The saveFileName must correspond to a file name without any path specification.
00073       // Throw if that is not true.
00074       if(!saveFileName_.empty() && (saveFileName_.find("/") != std::string::npos)) {
00075         throw Exception(errors::Configuration)
00076           << "The saveFileName parameter must be a simple file name with no path\n"
00077           << "specification. In the configuration, it was given the value \""
00078           << saveFileName_ << "\"\n";
00079       }
00080 
00081       uint32_t initialSeed;
00082       VUint32 initialSeedSet;
00083       std::string engineName;
00084 
00085       VString pSets = pset.getParameterNamesForType<ParameterSet>();
00086       for(VString::const_iterator it = pSets.begin(), itEnd = pSets.end(); it != itEnd; ++it) {
00087 
00088         ParameterSet const& modulePSet = pset.getParameterSet(*it);
00089         engineName = modulePSet.getUntrackedParameter<std::string>("engineName", std::string("HepJamesRandom"));
00090 
00091         bool initialSeedExists = modulePSet.exists("initialSeed");
00092         bool initialSeedSetExists = modulePSet.exists("initialSeedSet");
00093 
00094         if(initialSeedExists && initialSeedSetExists) {
00095           throw Exception(errors::Configuration)
00096             << "For the module with the label \"" << *it << "\",\n"
00097             << "both the parameters \"initialSeed\" and \"initialSeedSet\"\n"
00098             << "have been set in the configuration. You must set one or\n"
00099             << "the other.  It is illegal to set both.\n";
00100         } else if(!initialSeedExists && !initialSeedSetExists) {
00101           throw Exception(errors::Configuration)
00102             << "For the module with the label \"" << *it << "\",\n"
00103             << "neither the parameter \"initialSeed\" nor \"initialSeedSet\"\n"
00104             << "has been set in the configuration. You must set one or\n"
00105             << "the other.\n";
00106         } else if(initialSeedExists) {
00107           initialSeed = modulePSet.getUntrackedParameter<uint32_t>("initialSeed");
00108           initialSeedSet.clear();
00109           initialSeedSet.push_back(initialSeed);
00110         } else if(initialSeedSetExists) {
00111           initialSeedSet = modulePSet.getUntrackedParameter<VUint32>("initialSeedSet");
00112         }
00113         seedMap_[*it] = initialSeedSet;
00114         engineNameMap_[*it] = engineName;
00115 
00116         // For the CLHEP::RanecuEngine case, require a seed set containing exactly two seeds.
00117 
00118         if(engineName == std::string("RanecuEngine")) {
00119           if(initialSeedSet.size() != 2U) {
00120             throw Exception(errors::Configuration)
00121               << "Random engines of type \"RanecuEngine\" require 2 seeds\n"
00122               << "be specified with the parameter named \"initialSeedSet\".\n"
00123               << "Either \"initialSeedSet\" was not in the configuration\n"
00124               << "or its size was not 2 for the module with label \"" << *it << "\".\n" ;
00125           }
00126           boost::shared_ptr<CLHEP::HepRandomEngine> engine(new CLHEP::RanecuEngine());
00127           engineMap_[*it] = engine;
00128 
00129           if(initialSeedSet[0] > maxSeedRanecu ||
00130               initialSeedSet[1] > maxSeedRanecu) {  // They need to fit in a 31 bit integer
00131             throw Exception(errors::Configuration)
00132               << "The RanecuEngine seeds should be in the range 0 to 2147483647.\n"
00133               << "The seeds passed to the RandomNumberGenerationService from the\n"
00134                  "configuration file were " << initialSeedSet[0] << " and " << initialSeedSet[1]
00135               << "\nThis was for the module with label \"" << *it << "\".\n";
00136           }
00137           long int seedL[2];
00138           seedL[0] = static_cast<long int>(initialSeedSet[0]);
00139           seedL[1] = static_cast<long int>(initialSeedSet[1]);
00140           engine->setSeeds(seedL, 0);
00141         }
00142         // For the other engines, one seed is required
00143         else {
00144           if(initialSeedSet.size() != 1U) {
00145             throw Exception(errors::Configuration)
00146               << "Random engines of type \"HepJamesRandom\" and \"TRandom3\n"
00147               << "require exactly 1 seed be specified in the configuration.\n"
00148               << "There were " << initialSeedSet.size() << " seeds set for the\n"
00149               << "module with label \"" << *it << "\".\n" ;
00150           }
00151           long int seedL = static_cast<long int>(initialSeedSet[0]);
00152 
00153           if(engineName == "HepJamesRandom") {
00154             if(initialSeedSet[0] > maxSeedHepJames) {
00155               throw Exception(errors::Configuration)
00156                 << "The CLHEP::HepJamesRandom engine seed should be in the range 0 to 900000000.\n"
00157                 << "The seed passed to the RandomNumberGenerationService from the\n"
00158                    "configuration file was " << initialSeedSet[0] << ".  This was for \n"
00159                 << "the module with label " << *it << ".\n";
00160             }
00161             boost::shared_ptr<CLHEP::HepRandomEngine> engine(new CLHEP::HepJamesRandom(seedL));
00162             engineMap_[*it] = engine;
00163           } else if(engineName == "TRandom3") {
00164 
00165             // There is a dangerous conversion from uint32_t to long
00166             // that occurs above. In the next 2 lines we check the
00167             // behavior is what we need for the service to work
00168             // properly.  This conversion is forced on us by the
00169             // CLHEP and ROOT interfaces. If the assert ever starts
00170             // to fail we will have to come up with a way to deal
00171             // with this.
00172             uint32_t seedu32 = static_cast<uint32_t>(seedL);
00173             assert(initialSeedSet[0] == seedu32);
00174 
00175             boost::shared_ptr<CLHEP::HepRandomEngine> engine(new TRandomAdaptor(seedL));
00176             engineMap_[*it] = engine;
00177           } else {
00178             throw Exception(errors::Configuration)
00179               << "The random engine name, \"" << engineName
00180               << "\", does not correspond to a supported engine.\n"
00181               << "This engine was configured for the module with label \"" << *it << "\"";
00182           }
00183         }
00184       }
00185 
00186       activityRegistry.watchPostBeginLumi(this, &RandomNumberGeneratorService::postBeginLumi);
00187 
00188       activityRegistry.watchPreModuleConstruction(this, &RandomNumberGeneratorService::preModuleConstruction);
00189       activityRegistry.watchPostModuleConstruction(this, &RandomNumberGeneratorService::postModuleConstruction);
00190 
00191       activityRegistry.watchPreModuleBeginJob(this, &RandomNumberGeneratorService::preModuleBeginJob);
00192       activityRegistry.watchPostModuleBeginJob(this, &RandomNumberGeneratorService::postModuleBeginJob);
00193 
00194       activityRegistry.watchPreModuleBeginRun(this, &RandomNumberGeneratorService::preModuleBeginRun);
00195       activityRegistry.watchPostModuleBeginRun(this, &RandomNumberGeneratorService::postModuleBeginRun);
00196 
00197       activityRegistry.watchPreModuleBeginLumi(this, &RandomNumberGeneratorService::preModuleBeginLumi);
00198       activityRegistry.watchPostModuleBeginLumi(this, &RandomNumberGeneratorService::postModuleBeginLumi);
00199 
00200       activityRegistry.watchPreModule(this, &RandomNumberGeneratorService::preModule);
00201       activityRegistry.watchPostModule(this, &RandomNumberGeneratorService::postModule);
00202 
00203       activityRegistry.watchPreModuleEndLumi(this, &RandomNumberGeneratorService::preModuleEndLumi);
00204       activityRegistry.watchPostModuleEndLumi(this, &RandomNumberGeneratorService::postModuleEndLumi);
00205 
00206       activityRegistry.watchPreModuleEndRun(this, &RandomNumberGeneratorService::preModuleEndRun);
00207       activityRegistry.watchPostModuleEndRun(this, &RandomNumberGeneratorService::postModuleEndRun);
00208 
00209       activityRegistry.watchPreModuleEndJob(this, &RandomNumberGeneratorService::preModuleEndJob);
00210       activityRegistry.watchPostModuleEndJob(this, &RandomNumberGeneratorService::postModuleEndJob);
00211 
00212       activityRegistry.watchPostForkReacquireResources(this, &RandomNumberGeneratorService::postForkReacquireResources);
00213 
00214       // the default for the stack is to point to the 'end' of our map which is used to define not set
00215       engineStack_.push_back(engineMap_.end());
00216       currentEngine_ = engineMap_.end();
00217 
00218       labelStack_.push_back(std::string());
00219       currentLabel_ = std::string();
00220     }
00221 
00222     RandomNumberGeneratorService::~RandomNumberGeneratorService() {
00223     }
00224 
00225     CLHEP::HepRandomEngine&
00226     RandomNumberGeneratorService::getEngine() const {
00227 
00228       if(currentEngine_ == engineMap_.end()) {
00229         if(currentLabel_ != std::string()) {
00230           throw Exception(errors::Configuration)
00231             << "The module with label \""
00232             << currentLabel_
00233             << "\" requested a random number engine from the \n"
00234                "RandomNumberGeneratorService, but that module was not configured\n"
00235                "for random numbers.  An engine is created only if a seed(s) is provided\n"
00236                "in the configuration file.  Please add the following PSet to the\n"
00237                "configuration file for the RandomNumberGeneratorService:\n\n"
00238                "  " << currentLabel_ << " = cms.PSet(\n"
00239                "    initialSeed = cms.untracked.uint32(your_seed),\n"
00240                "    engineName = cms.untracked.string('TRandom3')\n"
00241                "  )\n"
00242                "where you replace \"your_seed\" with a number and add a comma if necessary\n"
00243               "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
00244         } else {
00245           throw Exception(errors::Unknown)
00246              << "Requested a random number engine from the RandomNumberGeneratorService\n"
00247                 "when no module was active.  This is not supposed to be possible.\n"
00248                 "Please inform the edm developers about this. It would be helpful to\n"
00249                 "know the stack. If a source was requesting a random engine this could\n"
00250                 "happen. Sources are not supposed to be doing that anymore.\n";
00251         }
00252       }
00253       return *(currentEngine_->second);
00254     }
00255 
00256     uint32_t
00257     RandomNumberGeneratorService::mySeed() const {
00258 
00259       std::map<std::string, VUint32>::const_iterator iter;
00260       iter = seedMap_.find(currentLabel_);
00261 
00262       if(iter == seedMap_.end()) {
00263         if(currentLabel_ != std::string()) {
00264           throw Exception(errors::Configuration)
00265             << "The module with label \""
00266             << currentLabel_
00267             << "\" requested a random number seed from the \n"
00268                "RandomNumberGeneratorService, but that module was not configured\n"
00269                "for random numbers.  An engine is created only if a seed(s) is provided\n"
00270                "in the configuration file.  Please add the following PSet to the\n"
00271                "configuration file for the RandomNumberGeneratorService:\n\n"
00272                "  " << currentLabel_ << " = cms.PSet(\n"
00273                "    initialSeed = cms.untracked.uint32(your_seed),\n"
00274                "    engineName = cms.untracked.string('TRandom3')\n"
00275                "  )\n"
00276                "where you replace \"your_seed\" with a number and add a comma if necessary\n"
00277               "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
00278         } else {
00279           throw Exception(errors::Unknown)
00280              << "Requested a random number seed from the RandomNumberGeneratorService\n"
00281                 "when no module was active.  This is not supposed to be possible.\n"
00282                 "Please inform the edm developers about this. It would be helpful to\n"
00283                 "know the stack. If a source was requesting a random engine this could\n"
00284                 "happen. Sources are not supposed to be doing that anymore.\n";
00285         }
00286       }
00287       return iter->second[0];
00288     }
00289 
00290     void
00291     RandomNumberGeneratorService::fillDescriptions(ConfigurationDescriptions& descriptions) {
00292       ParameterSetDescription desc;
00293 
00294       std::string emptyString;
00295       edm::InputTag emptyInputTag("", "", "");
00296 
00297       desc.addNode( edm::ParameterDescription<edm::InputTag>("restoreStateTag", emptyInputTag, false) xor
00298                     edm::ParameterDescription<std::string>("restoreStateLabel", emptyString, false) );
00299 
00300       desc.addUntracked<std::string>("saveFileName", emptyString);
00301       desc.addUntracked<std::string>("restoreFileName", emptyString);
00302       desc.addUntracked<bool>("enableChecking", false);
00303       desc.addUntracked<unsigned>("eventSeedOffset", 0U);
00304 
00305       ParameterSetDescription val;
00306       val.addOptionalUntracked<uint32_t>("initialSeed");
00307       val.addOptionalUntracked<std::vector<uint32_t> >("initialSeedSet");
00308       val.addOptionalUntracked<std::string>("engineName");
00309 
00310       ParameterWildcard<ParameterSetDescription> wnode("*", RequireZeroOrMore, true, val);
00311       wnode.setComment("The name of each ParameterSet will be the associated module label.");
00312       desc.addNode(wnode);
00313 
00314       descriptions.add("RandomNumberGeneratorService", desc);
00315     }
00316 
00317     void
00318     RandomNumberGeneratorService::postForkReacquireResources(unsigned childIndex, unsigned /*kMaxChildren*/) {
00319       childIndex_ = childIndex;
00320 
00321       if(!saveFileName_.empty()) {
00322         std::ostringstream suffix;
00323         suffix << "_" << childIndex;
00324         saveFileName_ += suffix.str();
00325       }
00326     }
00327 
00328     // The next three functions contain the complex logic
00329     // such that things occur in the proper sequence to be
00330     // able to save and restore the states.
00331 
00332     void
00333     RandomNumberGeneratorService::preBeginLumi(LuminosityBlock const& lumi) {
00334 
00335       if(firstLumi_) {
00336         // copy state from engines to lumi cache
00337         snapShot(lumiCache_);
00338 
00339         if(!restoreFileName_.empty()) {
00340           // copy state from text file to lumi cache
00341           readLumiStatesFromTextFile(restoreFileName_);
00342         }
00343       } else {
00344         snapShot(eventCache_);
00345       }
00346 
00347       // copy state from LuminosityBlock to lumi cache
00348       if(!restoreStateTag_.label().empty()) {
00349         readFromLuminosityBlock(lumi);
00350       }
00351 
00352       if(!firstLumi_ || !restoreFileName_.empty() || !restoreStateTag_.label().empty()) {
00353         // copy state from lumi cache to engines
00354         restoreFromCache(lumiCache_);
00355       }
00356     }
00357 
00358     // During the beginLumi processing the producer will copy the
00359     // the lumi cache to a product if the producer was scheduled
00360     // in a path in the configuration
00361 
00362     void
00363     RandomNumberGeneratorService::postBeginLumi(LuminosityBlock const&, EventSetup const&) {
00364 
00365       if(firstLumi_) {
00366         // reset state with new seeds based on child index
00367         startNewSequencesForEvents();
00368         if(!restoreFileName_.empty()) {
00369           snapShot(eventCache_);
00370           // copy state from text file to event cache
00371           readEventStatesFromTextFile(restoreFileName_);
00372         }
00373       }
00374       if(!firstLumi_ || !restoreFileName_.empty()) {
00375         // copy state from event cache to engines
00376         restoreFromCache(eventCache_);
00377       }
00378       firstLumi_ = false;
00379     }
00380 
00381     void
00382     RandomNumberGeneratorService::postEventRead(Event const& event) {
00383       // copy from Event to event cache
00384       if(!restoreStateTag_.label().empty()) {
00385         snapShot(eventCache_);
00386         readFromEvent(event);
00387 
00388         // copy from event cache to engines
00389         restoreFromCache(eventCache_);
00390       } else {
00391         // copy from engines to event cache
00392         snapShot(eventCache_);
00393       }
00394       // if requested write text file from both caches
00395       if(!saveFileName_.empty())  {
00396         saveStatesToFile(saveFileName_);
00397         if(!saveFileNameRecorded_) {
00398           std::string fullName = constructSaveFileName();
00399           Service<JobReport> reportSvc;
00400           reportSvc->reportRandomStateFile(fullName);
00401           saveFileNameRecorded_ = true;
00402         }
00403       }
00404     }
00405 
00406     // During the event processing the producer will copy the
00407     // the event cache to a product if the producer was scheduled
00408     // in a path in the configuration
00409 
00410     void
00411     RandomNumberGeneratorService::preModuleConstruction(ModuleDescription const& description) {
00412       push(description.moduleLabel());
00413       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00414         engineStateStack_.push_back(currentEngine_->second->put());
00415       }
00416     }
00417 
00418     void
00419     RandomNumberGeneratorService::postModuleConstruction(ModuleDescription const& description) {
00420       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00421         if(engineStateStack_.back() != currentEngine_->second->put()) {
00422           throw Exception(errors::LogicError)
00423             << "It is illegal to generate random numbers during module construction because \n"
00424                "that makes it very difficult to reproduce the processing of individual\n"
00425                "events.  Random numbers were generated during module construction for the module with\n"
00426                "class name \"" << description.moduleName() << "\"\n"
00427                "and module label \"" << description.moduleLabel() << "\"\n";
00428         }
00429         engineStateStack_.pop_back();
00430       }
00431       pop();
00432     }
00433 
00434     void
00435     RandomNumberGeneratorService::preModuleBeginJob(ModuleDescription const& description) {
00436       push(description.moduleLabel());
00437       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00438         engineStateStack_.push_back(currentEngine_->second->put());
00439       }
00440     }
00441 
00442     void
00443     RandomNumberGeneratorService::postModuleBeginJob(ModuleDescription const& description) {
00444       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00445         if(engineStateStack_.back() != currentEngine_->second->put()) {
00446           throw Exception(errors::LogicError)
00447             << "It is illegal to generate random numbers during beginJob because \n"
00448                "that makes it very difficult to reproduce the processing of individual\n"
00449                "events.  Random numbers were generated during beginJob for the module with\n"
00450                "class name \"" << description.moduleName() << "\"\n"
00451                "and module label \"" << description.moduleLabel() << "\"\n";
00452         }
00453         engineStateStack_.pop_back();
00454       }
00455       pop();
00456     }
00457 
00458     void
00459     RandomNumberGeneratorService::preModuleBeginRun(ModuleDescription const& description) {
00460       push(description.moduleLabel());
00461       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00462         engineStateStack_.push_back(currentEngine_->second->put());
00463       }
00464     }
00465 
00466     void
00467     RandomNumberGeneratorService::postModuleBeginRun(ModuleDescription const& description) {
00468       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00469         if(engineStateStack_.back() != currentEngine_->second->put()) {
00470           throw Exception(errors::LogicError)
00471             << "It is illegal to generate random numbers during beginRun because \n"
00472                "that makes it very difficult to reproduce the processing of individual\n"
00473                "events.  Random numbers were generated during beginRun for the module with\n"
00474                "class name \"" << description.moduleName() << "\"\n"
00475                "and module label \"" << description.moduleLabel() << "\"\n";
00476         }
00477         engineStateStack_.pop_back();
00478       }
00479       pop();
00480     }
00481 
00482     void
00483     RandomNumberGeneratorService::preModuleBeginLumi(ModuleDescription const& description) {
00484       push(description.moduleLabel());
00485     }
00486 
00487     void
00488     RandomNumberGeneratorService::postModuleBeginLumi(ModuleDescription const&) {
00489       pop();
00490     }
00491 
00492     void
00493     RandomNumberGeneratorService::preModule(ModuleDescription const& description) {
00494       push(description.moduleLabel());
00495     }
00496 
00497     void
00498     RandomNumberGeneratorService::postModule(ModuleDescription const&) {
00499       pop();
00500     }
00501 
00502     void
00503     RandomNumberGeneratorService::preModuleEndLumi(ModuleDescription const& description) {
00504       push(description.moduleLabel());
00505       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00506         engineStateStack_.push_back(currentEngine_->second->put());
00507       }
00508     }
00509 
00510     void
00511     RandomNumberGeneratorService::postModuleEndLumi(ModuleDescription const& description) {
00512       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00513         if(engineStateStack_.back() != currentEngine_->second->put()) {
00514           throw Exception(errors::LogicError)
00515             << "It is illegal to generate random numbers during endLumi because \n"
00516                "that makes it very difficult to reproduce the processing of individual\n"
00517                "events.  Random numbers were generated during endLumi for the module with\n"
00518                "class name \"" << description.moduleName() << "\"\n"
00519                "and module label \"" << description.moduleLabel() << "\"\n";
00520         }
00521         engineStateStack_.pop_back();
00522       }
00523       pop();
00524     }
00525 
00526     void
00527     RandomNumberGeneratorService::preModuleEndRun(ModuleDescription const& description) {
00528       push(description.moduleLabel());
00529       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00530         engineStateStack_.push_back(currentEngine_->second->put());
00531       }
00532     }
00533 
00534     void
00535     RandomNumberGeneratorService::postModuleEndRun(ModuleDescription const& description) {
00536       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00537         if(engineStateStack_.back() != currentEngine_->second->put()) {
00538           throw Exception(errors::LogicError)
00539             << "It is illegal to generate random numbers during endRun because \n"
00540                "that makes it very difficult to reproduce the processing of individual\n"
00541                "events.  Random numbers were generated during endRun for the module with\n"
00542                "class name \"" << description.moduleName() << "\"\n"
00543                "and module label \"" << description.moduleLabel() << "\"\n";
00544         }
00545         engineStateStack_.pop_back();
00546       }
00547       pop();
00548     }
00549 
00550     void
00551     RandomNumberGeneratorService::preModuleEndJob(ModuleDescription const& description) {
00552       push(description.moduleLabel());
00553       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00554         engineStateStack_.push_back(currentEngine_->second->put());
00555       }
00556     }
00557 
00558     void
00559     RandomNumberGeneratorService::postModuleEndJob(ModuleDescription const& description) {
00560       if(enableChecking_ && currentEngine_ != engineMap_.end()) {
00561         if(engineStateStack_.back() != currentEngine_->second->put()) {
00562           throw Exception(errors::LogicError)
00563             << "It is illegal to generate random numbers during endJob because \n"
00564                "that makes it very difficult to reproduce the processing of individual\n"
00565                "events.  Random numbers were generated during endJob for the module with\n"
00566                "class name \"" << description.moduleName() << "\"\n"
00567                "and module label \"" << description.moduleLabel() << "\"\n";
00568         }
00569         engineStateStack_.pop_back();
00570       }
00571       pop();
00572     }
00573 
00574     std::vector<RandomEngineState> const&
00575     RandomNumberGeneratorService::getLumiCache() const {
00576       return lumiCache_;
00577     }
00578 
00579     std::vector<RandomEngineState> const&
00580     RandomNumberGeneratorService::getEventCache() const {
00581       return eventCache_;
00582     }
00583 
00584     void
00585     RandomNumberGeneratorService::print() {
00586       std::cout << "\n\nRandomNumberGeneratorService dump\n\n";
00587 
00588       std::cout << "    Contents of seedMap\n";
00589       for(std::map<std::string, std::vector<uint32_t> >::const_iterator iter = seedMap_.begin();
00590            iter != seedMap_.end();
00591            ++iter) {
00592         std::cout << "        " << iter->first;
00593         std::vector<uint32_t> seeds = iter->second;
00594         for(std::vector<uint32_t>::const_iterator vIter = seeds.begin();
00595              vIter != seeds.end();
00596              ++vIter) {
00597           std::cout << "   "  << *vIter;
00598         }
00599         std::cout << "\n";
00600       }
00601       std::cout << "\n    Contents of engineNameMap\n";
00602       for(std::map<std::string, std::string>::const_iterator iter = engineNameMap_.begin();
00603            iter != engineNameMap_.end();
00604            ++iter) {
00605         std::cout << "        " << iter->first << "   " << iter->second << "\n";
00606       }
00607       std::cout << "\n    Contents of engineMap\n";
00608       for(EngineMap::const_iterator iter = engineMap_.begin();
00609            iter != engineMap_.end();
00610            ++iter) {
00611         std::cout << "        " << iter->first
00612                   << "   " << iter->second->name() << "   ";
00613         if(iter->second->name() == std::string("HepJamesRandom")) {
00614           std::cout << iter->second->getSeed();
00615         } else {
00616           std::cout << "Engine does not know original seed";
00617         }
00618         std::cout << "\n";
00619       }
00620       std::cout << "\n";
00621       std::cout << "    currentLabel_ = " << currentLabel_ << "\n";
00622       std::cout << "    labelStack_ size = " << labelStack_.size() << "\n";
00623       int i = 0;
00624       for(VString::const_iterator iter = labelStack_.begin();
00625            iter != labelStack_.end();
00626            ++iter, ++i) {
00627         std::cout << "                 " << i << "  " << *iter << "\n";
00628       }
00629       if(currentEngine_ == engineMap_.end()) {
00630         std::cout << "    currentEngine points to end\n";
00631       } else {
00632         std::cout << "    currentEngine_ = " << currentEngine_->first
00633                   << "  " << currentEngine_->second->name()
00634                   << "  " << currentEngine_->second->getSeed() << "\n";
00635       }
00636 
00637       std::cout << "    engineStack_ size = " << engineStack_.size() << "\n";
00638       i = 0;
00639       for(std::vector<EngineMap::const_iterator>::const_iterator iter = engineStack_.begin();
00640            iter != engineStack_.end();
00641            ++iter, ++i) {
00642         if(*iter == engineMap_.end()) {
00643           std::cout << "                 " << i << "  Points to end of engine map\n";
00644         } else {
00645           std::cout << "                 " << i << "  " << (*iter)->first
00646                     << "  " << (*iter)->second->name() << "  " << (*iter)->second->getSeed() << "\n";
00647         }
00648       }
00649 
00650       std::cout << "    restoreStateTag_ = " << restoreStateTag_ << "\n";
00651       std::cout << "    saveFileName_ = " << saveFileName_ << "\n";
00652       std::cout << "    restoreFileName_ = " << restoreFileName_ << "\n";
00653     }
00654 
00655     void
00656     RandomNumberGeneratorService::push(std::string const& iLabel) {
00657       currentEngine_ = engineMap_.find(iLabel);
00658       engineStack_.push_back(currentEngine_);
00659 
00660       labelStack_.push_back(iLabel);
00661       currentLabel_ = iLabel;
00662     }
00663 
00664     void
00665     RandomNumberGeneratorService::pop() {
00666       engineStack_.pop_back();
00667       //NOTE: algorithm is such that we always have at least one item in the stacks
00668       currentEngine_ = engineStack_.back();
00669       labelStack_.pop_back();
00670       currentLabel_ = labelStack_.back();
00671     }
00672 
00673     void
00674     RandomNumberGeneratorService::readFromLuminosityBlock(LuminosityBlock const& lumi) {
00675 
00676       Handle<RandomEngineStates> states;
00677       lumi.getByLabel(restoreStateBeginLumiTag_, states);
00678 
00679       if(!states.isValid()) {
00680         failedToFindStatesInLumi_ = true;
00681         return;
00682       }
00683       failedToFindStatesInLumi_ = false;
00684       states->getRandomEngineStates(lumiCache_);
00685     }
00686 
00687     void
00688     RandomNumberGeneratorService::readFromEvent(Event const& event) {
00689 
00690       Handle<RandomEngineStates> states;
00691 
00692       event.getByLabel(restoreStateTag_, states);
00693 
00694       if(!states.isValid()) {
00695         if(failedToFindStatesInLumi_ && backwardCompatibilityRead(event)) {
00696           return;
00697         } else {
00698           throw Exception(errors::ProductNotFound)
00699             << "The RandomNumberGeneratorService is trying to restore\n"
00700             << "the state of the random engines by reading a product from\n"
00701             << "the Event with input tag \"" << restoreStateTag_ << "\".  It\n"
00702             << "fails to find one.  The label used in the request for the product\n"
00703             << "is set in the configuration. It is probably set to the wrong value\n"
00704             << "in the configuration file.  It must match the module label\n"
00705             << "of the RandomEngineStateProducer that created the product in\n"
00706             << "a previous process\n";
00707         }
00708       }
00709       if(failedToFindStatesInLumi_) {
00710         throw Exception(errors::ProductNotFound)
00711           << "The RandomNumberGeneratorService is trying to restore\n"
00712           << "the state of the random engines by reading a product from\n"
00713           << "the Event and LuminosityBlock with input tag \"" << restoreStateTag_ << "\".\n"
00714           << "It found the product in the Event but not the one in the LuminosityBlock.\n"
00715           << "Either the product in the LuminosityBlock was dropped or\n"
00716           << "there is a bug somewhere\n";
00717       }
00718       states->getRandomEngineStates(eventCache_);
00719     }
00720 
00721     bool
00722     RandomNumberGeneratorService::backwardCompatibilityRead(Event const& event) {
00723 
00724       Handle<std::vector<RandomEngineState> > states;
00725 
00726       event.getByLabel(restoreStateTag_, states);
00727       if(!states.isValid()) {
00728         return false;
00729       }
00730       for(std::vector<RandomEngineState>::const_iterator state = states->begin(),
00731                                                           iEnd = states->end();
00732            state != iEnd; ++state) {
00733 
00734         std::vector<RandomEngineState>::iterator cachedState =
00735           std::lower_bound(eventCache_.begin(), eventCache_.end(), *state);
00736 
00737 
00738         if(cachedState != eventCache_.end() && cachedState->getLabel() == state->getLabel()) {
00739           if(cachedState->getSeed().size() != state->getSeed().size() ||
00740               cachedState->getState().size() != state->getState().size()) {
00741             throw Exception(errors::Configuration)
00742               << "In function RandomNumberGeneratorService::backwardCompatibilityRead.\n"
00743               << "When attempting to replay processing with the RandomNumberGeneratorService,\n"
00744               << "the engine type for each module must be the same in the replay configuration\n"
00745               << "and the original configuration.  If this is not the problem, then the data\n"
00746               << "is somehow corrupted or there is a bug because the vector in the data containing\n"
00747               << "the seeds or engine state is the incorrect size for the type of random engine.\n";
00748           }
00749           cachedState->setSeed(state->getSeed());
00750           cachedState->setState(state->getState());
00751         }
00752       }
00753       return true;
00754     }
00755 
00756     void
00757     RandomNumberGeneratorService::snapShot(std::vector<RandomEngineState>& cache) {
00758       cache.resize(engineMap_.size());
00759       std::vector<RandomEngineState>::iterator state = cache.begin();
00760 
00761       for(EngineMap::const_iterator iter = engineMap_.begin();
00762            iter != engineMap_.end();
00763            ++iter, ++state) {
00764 
00765         state->setLabel(iter->first);
00766         state->setSeed(seedMap_[iter->first]);
00767 
00768         std::vector<unsigned long> stateL = iter->second->put();
00769         state->clearStateVector();
00770         state->reserveStateVector(stateL.size());
00771         for(std::vector<unsigned long>::const_iterator vIter = stateL.begin();
00772              vIter != stateL.end();
00773              ++vIter) {
00774           state->push_back_stateVector(static_cast<uint32_t>(*vIter));
00775         }
00776       }
00777     }
00778 
00779     void
00780     RandomNumberGeneratorService::restoreFromCache(std::vector<RandomEngineState> const& cache) {
00781       for(std::vector<RandomEngineState>::const_iterator iter = cache.begin(),
00782                                                           iEnd = cache.end();
00783            iter != iEnd; ++iter) {
00784 
00785         std::string const& engineLabel = iter->getLabel();
00786 
00787         std::vector<uint32_t> const& engineState = iter->getState();
00788         std::vector<unsigned long> engineStateL;
00789         for(std::vector<uint32_t>::const_iterator iVal = engineState.begin(),
00790                                                  theEnd = engineState.end();
00791              iVal != theEnd; ++iVal) {
00792           engineStateL.push_back(static_cast<unsigned long>(*iVal));
00793         }
00794 
00795         std::vector<uint32_t> const& engineSeeds = iter->getSeed();
00796         std::vector<long> engineSeedsL;
00797         for(std::vector<uint32_t>::const_iterator iVal = engineSeeds.begin(),
00798                                                  theEnd = engineSeeds.end();
00799           iVal != theEnd;
00800           ++iVal) {
00801           long seedL = static_cast<long>(*iVal);
00802           engineSeedsL.push_back(seedL);
00803 
00804           // There is a dangerous conversion from uint32_t to long
00805           // that occurs above. In the next 2 lines we check the
00806           // behavior is what we need for the service to work
00807           // properly.  This conversion is forced on us by the
00808           // CLHEP and ROOT interfaces. If the assert ever starts
00809           // to fail we will have to come up with a way to deal
00810           // with this.
00811           uint32_t seedu32 = static_cast<uint32_t>(seedL);
00812           assert(*iVal == seedu32);
00813         }
00814 
00815         EngineMap::iterator engine = engineMap_.find(engineLabel);
00816 
00817         if(engine != engineMap_.end()) {
00818 
00819           seedMap_[engineLabel] = engineSeeds;
00820 
00821           // We need to handle each type of engine differently because each
00822           // has different requirements on the seed or seeds.
00823           if(engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
00824 
00825             checkEngineType(engine->second->name(), std::string("HepJamesRandom"), engineLabel);
00826 
00827             // These two lines actually restore the seed and engine state.
00828             engine->second->setSeed(engineSeedsL[0], 0);
00829             engine->second->get(engineStateL);
00830           } else if(engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
00831 
00832             checkEngineType(engine->second->name(), std::string("RanecuEngine"), engineLabel);
00833 
00834             // This line actually restores the engine state.
00835             engine->second->get(engineStateL);
00836           } else if(engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
00837 
00838             checkEngineType(engine->second->name(), std::string("TRandom3"), engineLabel);
00839 
00840             // This line actually restores the engine state.
00841             engine->second->setSeed(engineSeedsL[0], 0);
00842             engine->second->get(engineStateL);
00843           } else {
00844             // This should not be possible because this code should be able to restore
00845             // any kind of engine whose state can be saved.
00846             throw Exception(errors::Unknown)
00847               << "The RandomNumberGeneratorService is trying to restore the state\n"
00848                  "of the random engines.  The state in the event indicates an engine\n"
00849                  "of an unknown type.  This should not be possible unless you are\n"
00850                  "running with an old code release on a new file that was created\n"
00851                  "with a newer release which had new engine types added.  In this case\n"
00852                  "the only solution is to use a newer release.  In any other case, notify\n"
00853                  "the EDM developers because this should not be possible\n";
00854           }
00855         }
00856       }
00857     }
00858 
00859     void
00860     RandomNumberGeneratorService::checkEngineType(std::string const& typeFromConfig,
00861                                                   std::string const& typeFromEvent,
00862                                                   std::string const& engineLabel) {
00863       if(typeFromConfig != typeFromEvent) {
00864         throw Exception(errors::Configuration)
00865           << "The RandomNumberGeneratorService is trying to restore\n"
00866           << "the state of the random engine for the module \""
00867           << engineLabel << "\".  An\n"
00868           << "error was detected because the type of the engine in the\n"
00869           << "input file and the configuration file do not match.\n"
00870           << "In the configuration file the type is \"" << typeFromConfig
00871           << "\".\nIn the input file the type is \"" << typeFromEvent << "\".  If\n"
00872           << "you are not generating any random numbers in this module, then\n"
00873           << "remove the line in the configuration file that gives it\n"
00874           << "a seed and the error will go away.  Otherwise, you must give\n"
00875           << "this module the same engine type in the configuration file or\n"
00876           << "stop trying to restore the random engine state.\n";
00877       }
00878     }
00879 
00880     void
00881     RandomNumberGeneratorService::saveStatesToFile(std::string const& fileName) {
00882       if(!outFile_.is_open()) {
00883         outFile_.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
00884       }
00885       if(!outFile_) {
00886         throw Exception(errors::Configuration)
00887           << "Unable to open the file \""
00888           << fileName << "\" to save the state of the random engines.\n";
00889       }
00890       outFile_.seekp(0, std::ios_base::beg);
00891       outFile_ << "<RandomEngineStates>\n";
00892 
00893       outFile_ << "<Event>\n";
00894       writeStates(eventCache_, outFile_);
00895       outFile_ << "</Event>\n" ;
00896 
00897       outFile_ << "<Lumi>\n";
00898       writeStates(lumiCache_, outFile_);
00899       outFile_ << "</Lumi>\n" ;
00900 
00901       outFile_ << "</RandomEngineStates>\n" ;
00902       outFile_.flush();
00903     }
00904 
00905     void
00906     RandomNumberGeneratorService::writeStates(std::vector<RandomEngineState> const& v,
00907                                               std::ofstream& outFile) {
00908       for(std::vector<RandomEngineState>::const_iterator iter = v.begin(),
00909                                                           iEnd = v.end();
00910         iter != iEnd; ++iter) {
00911 
00912         std::vector<uint32_t> const& seedVector = iter->getSeed();
00913         std::vector<uint32_t>::size_type seedVectorLength = seedVector.size();
00914 
00915         std::vector<uint32_t> const& stateVector = iter->getState();
00916         std::vector<uint32_t>::size_type stateVectorLength = stateVector.size();
00917 
00918         outFile << "<ModuleLabel>\n" << iter->getLabel() << "\n</ModuleLabel>\n";
00919 
00920         outFile << "<SeedLength>\n" << seedVectorLength << "\n</SeedLength>\n" ;
00921         outFile << "<InitialSeeds>\n";
00922         writeVector(seedVector, outFile);
00923         outFile << "</InitialSeeds>\n";
00924         outFile << "<FullStateLength>\n" << stateVectorLength << "\n</FullStateLength>\n";
00925         outFile << "<FullState>\n";
00926         writeVector(stateVector, outFile);
00927         outFile   << "</FullState>\n";
00928       }
00929     }
00930 
00931     void
00932     RandomNumberGeneratorService::writeVector(VUint32 const& v,
00933                                               std::ofstream& outFile) {
00934       if(v.empty()) return;
00935       size_t numItems = v.size();
00936       for(size_t i = 0; i < numItems; ++i)  {
00937         if(i != 0 && i % 10 == 0) outFile << "\n";
00938         outFile << std::setw(13) << v[i];
00939       }
00940       outFile << "\n";
00941     }
00942 
00943     std::string RandomNumberGeneratorService::constructSaveFileName() {
00944       char directory[1500];
00945       std::string fullName(getcwd(directory, sizeof(directory)) ? directory : "/PathIsTooBig");
00946       fullName += "/" + saveFileName_;
00947       return fullName;
00948     }
00949 
00950     void
00951     RandomNumberGeneratorService::readEventStatesFromTextFile(std::string const& fileName) {
00952       std::string whichStates("<Event>");
00953       readStatesFromFile(fileName, eventCache_, whichStates);
00954     }
00955 
00956     void
00957     RandomNumberGeneratorService::readLumiStatesFromTextFile(std::string const& fileName) {
00958       std::string whichStates("<Lumi>");
00959       readStatesFromFile(fileName, lumiCache_, whichStates);
00960     }
00961 
00962 
00963     void
00964     RandomNumberGeneratorService::readStatesFromFile(std::string const& fileName,
00965                                                      std::vector<RandomEngineState>& cache,
00966                                                      std::string const& whichStates) {
00967       std::ifstream inFile;
00968       inFile.open(fileName.c_str(), std::ifstream::in);
00969       if(!inFile) {
00970         throw Exception(errors::Configuration)
00971           << "Unable to open the file \""
00972           << fileName << "\" to restore the random engine states.\n";
00973       }
00974 
00975       std::string text;
00976       inFile >> text;
00977       if(!inFile.good() || text != std::string("<RandomEngineStates>")) {
00978         throw Exception(errors::Configuration)
00979           << "Attempting to read file with random number engine states.\n"
00980           << "File \"" << restoreFileName_
00981           << "\" is ill-structured or otherwise corrupted.\n"
00982           << "Cannot read the file header word.\n";
00983       }
00984       bool saveToCache = false;
00985       while(readEngineState(inFile, cache, whichStates, saveToCache)) {}
00986     }
00987 
00988     bool RandomNumberGeneratorService::readEngineState(std::istream& is,
00989                                                        std::vector<RandomEngineState>& cache,
00990                                                        std::string const& whichStates,
00991                                                        bool& saveToCache) {
00992       std::string leading;
00993       std::string trailing;
00994       std::string moduleLabel;
00995       std::vector<uint32_t>::size_type seedVectorSize;
00996       std::vector<uint32_t> seedVector;
00997       std::vector<uint32_t>::size_type stateVectorSize;
00998       std::vector<uint32_t> stateVector;
00999 
01000       // First we need to look for the special strings
01001       // that mark the end of the file and beginning and
01002       // and end of the data for different sections.
01003 
01004       is >> leading;
01005       if(!is.good()) {
01006         throw Exception(errors::Configuration)
01007           << "File \"" << restoreFileName_
01008           << "\" is ill-structured or otherwise corrupted.\n"
01009           << "Cannot read next field and did not hit the end yet.\n";
01010       }
01011 
01012       // This marks the end of the file. We are done.
01013       if(leading == std::string("</RandomEngineStates>")) return false;
01014 
01015       // This marks the end of a section of the data
01016       if(leading == std::string("</Event>") ||
01017           leading == std::string("</Lumi>")) {
01018         saveToCache = false;
01019         return true;
01020       }
01021 
01022       // This marks the beginning of a section
01023       if(leading == std::string("<Event>") ||
01024           leading == std::string("<Lumi>")) {
01025         saveToCache = (leading == whichStates);
01026         return true;
01027       }
01028 
01029       // Process the next engine state
01030 
01031       is >> moduleLabel >> trailing;
01032       if(!is.good() ||
01033           leading != std::string("<ModuleLabel>") ||
01034           trailing != std::string("</ModuleLabel>")) {
01035         throw Exception(errors::Configuration)
01036           << "File \"" << restoreFileName_
01037           << "\" is ill-structured or otherwise corrupted.\n"
01038           << "Cannot read a module label when restoring random engine states.\n";
01039       }
01040 
01041       is >> leading >> seedVectorSize >> trailing;
01042       if(!is.good() ||
01043           leading != std::string("<SeedLength>") ||
01044           trailing != std::string("</SeedLength>")) {
01045         throw Exception(errors::Configuration)
01046           << "File \"" << restoreFileName_
01047           << "\" is ill-structured or otherwise corrupted.\n"
01048           << "Cannot read seed vector length when restoring random engine states.\n";
01049       }
01050 
01051       is >> leading;
01052       if(!is.good() ||
01053           leading != std::string("<InitialSeeds>")) {
01054         throw Exception(errors::Configuration)
01055           << "File \"" << restoreFileName_
01056           << "\" is ill-structured or otherwise corrupted.\n"
01057           << "Cannot read beginning of InitialSeeds when restoring random engine states.\n";
01058       }
01059 
01060       if(seedVectorSize > maxSeeds) {
01061         throw Exception(errors::Configuration)
01062           << "File \"" << restoreFileName_
01063           << "\" is ill-structured or otherwise corrupted.\n"
01064           << "The number of seeds exceeds 64K.\n";
01065       }
01066 
01067       readVector(is, seedVectorSize, seedVector);
01068 
01069       is >> trailing;
01070       if(!is.good() ||
01071           trailing != std::string("</InitialSeeds>")) {
01072         throw Exception(errors::Configuration)
01073           << "File \"" << restoreFileName_
01074           << "\" is ill-structured or otherwise corrupted.\n"
01075           << "Cannot read end of InitialSeeds when restoring random engine states.\n";
01076       }
01077 
01078       is >> leading >> stateVectorSize >> trailing;
01079       if(!is.good() ||
01080           leading != std::string("<FullStateLength>") ||
01081           trailing != std::string("</FullStateLength>")) {
01082         throw Exception(errors::Configuration)
01083           << "File \"" << restoreFileName_
01084           << "\" is ill-structured or otherwise corrupted.\n"
01085           << "Cannot read state vector length when restoring random engine states.\n";
01086       }
01087 
01088       is >> leading;
01089       if(!is.good() ||
01090           leading != std::string("<FullState>")) {
01091         throw Exception(errors::Configuration)
01092           << "File \"" << restoreFileName_
01093           << "\" is ill-structured or otherwise corrupted.\n"
01094           << "Cannot read beginning of FullState when restoring random engine states.\n";
01095       }
01096 
01097       if(stateVectorSize > maxStates) {
01098         throw Exception(errors::Configuration)
01099           << "File \"" << restoreFileName_
01100           << "\" is ill-structured or otherwise corrupted.\n"
01101           << "The number of states exceeds 64K.\n";
01102       }
01103 
01104       readVector(is, stateVectorSize, stateVector);
01105 
01106       is >> trailing;
01107       if(!is.good() ||
01108           trailing != std::string("</FullState>")) {
01109         throw Exception(errors::Configuration)
01110           << "File \"" << restoreFileName_
01111           << "\" is ill-structured or otherwise corrupted.\n"
01112           << "Cannot read end of FullState when restoring random engine states.\n";
01113       }
01114 
01115       if(saveToCache) {
01116         RandomEngineState randomEngineState;
01117         randomEngineState.setLabel(moduleLabel);
01118         std::vector<RandomEngineState>::iterator state =
01119           std::lower_bound(cache.begin(), cache.end(), randomEngineState);
01120 
01121         if(state != cache.end() && moduleLabel == state->getLabel()) {
01122           if(seedVector.size() != state->getSeed().size() ||
01123               stateVector.size() != state->getState().size()) {
01124             throw Exception(errors::Configuration)
01125               << "File \"" << restoreFileName_
01126               << "\" is ill-structured or otherwise corrupted.\n"
01127               << "Vectors containing engine state are the incorrect size for the type of random engine.\n";
01128           }
01129           state->setSeed(seedVector);
01130           state->setState(stateVector);
01131         }
01132       }
01133       return true;
01134     }
01135 
01136     void
01137     RandomNumberGeneratorService::readVector(std::istream& is, unsigned numItems, std::vector<uint32_t>& v) {
01138       v.clear();
01139       v.reserve(numItems);
01140       uint32_t data;
01141       for(unsigned i = 0; i < numItems; ++i) {
01142         is >> data;
01143         if(!is.good()) {
01144           throw Exception(errors::Configuration)
01145             << "File \"" << restoreFileName_
01146             << "\" is ill-structured or otherwise corrupted.\n"
01147             << "Cannot read vector when restoring random engine states.\n";
01148         }
01149         v.push_back(data);
01150       }
01151     }
01152 
01153     void
01154     RandomNumberGeneratorService::startNewSequencesForEvents() {
01155 
01156       if(childIndex_ == 0U && eventSeedOffset_ == 0U) return;
01157 
01158       for(EngineMap::const_iterator iter = engineMap_.begin();
01159            iter != engineMap_.end();
01160            ++iter) {
01161 
01162         uint32_t offset1 = childIndex_;
01163         uint32_t offset2 = eventSeedOffset_;
01164 
01165         std::string const& moduleLabel = iter->first;
01166         std::string const& engineName = engineNameMap_[moduleLabel];
01167         VUint32& seeds = seedMap_[moduleLabel];
01168 
01169        if(engineName == std::string("RanecuEngine")) {
01170           assert(seeds.size() == 2U);
01171           // Wrap around if the offsets push the seed over the maximum allowed value
01172           uint32_t mod = maxSeedRanecu + 1U;
01173           offset1 = offset1 % mod;
01174           offset2 = offset2 % mod;
01175           seeds[0] = (seeds[0] + offset1) % mod;
01176           seeds[0] = (seeds[0] + offset2) % mod;
01177           long int seedL[2];
01178           seedL[0] = static_cast<long int>(seeds[0]);
01179           seedL[1] = static_cast<long int>(seeds[1]);
01180           iter->second->setSeeds(seedL,0);
01181         } else {
01182           assert(seeds.size() == 1U);
01183 
01184           if(engineName == "HepJamesRandom") {
01185             // Wrap around if the offsets push the seed over the maximum allowed value
01186             uint32_t mod = maxSeedHepJames + 1U;
01187             offset1 = offset1 % mod;
01188             offset2 = offset2 % mod;
01189             seeds[0] = (seeds[0] + offset1) % mod;
01190             seeds[0] = (seeds[0] + offset2) % mod;
01191 
01192             long int seedL = static_cast<long int>(seeds[0]);
01193             iter->second->setSeed(seedL, 0);
01194           } else {
01195             assert(engineName == "TRandom3");
01196             // Wrap around if the offsets push the seed over the maximum allowed value
01197             // We have to be extra careful with this one because it may also go beyond
01198             // the values 32 bits can hold
01199             uint32_t max32 = maxSeedTRandom3;
01200             if((max32 - seeds[0]) >= offset1) {
01201               seeds[0] = seeds[0] + offset1;
01202             } else {
01203               seeds[0] = offset1 - (max32 - seeds[0]) - 1U;
01204             }
01205             if((max32 - seeds[0]) >= offset2) {
01206               seeds[0] = seeds[0] + offset2;
01207             } else {
01208               seeds[0] = offset2 - (max32 - seeds[0]) - 1U;
01209             }
01210             long seedL = static_cast<long>(seeds[0]);
01211 
01212             // There is a dangerous conversion from uint32_t to long
01213             // that occurs above. In the next 2 lines we check the
01214             // behavior is what we need for the service to work
01215             // properly.  This conversion is forced on us by the
01216             // CLHEP and ROOT interfaces. If the assert ever starts
01217             // to fail we will have to come up with a way to deal
01218             // with this.
01219             uint32_t seedu32 = static_cast<uint32_t>(seedL);
01220             assert(seeds[0] == seedu32);
01221 
01222             iter->second->setSeed(seedL, 0);
01223           }
01224         }
01225       }
01226     }
01227   }
01228 }