CMS 3D CMS Logo

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