CMS 3D CMS Logo

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