CMS 3D CMS Logo

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

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