CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
RandomNumberGeneratorService.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: RandomEngine
4 // Class : RandomNumberGeneratorService
5 //
6 // Implementation:
7 // <Notes on implementation>
8 //
9 // Original Author: Chris Jones, W. David Dagenhart
10 // Created: Tue Mar 7 09:43:46 EST 2006 (originally in FWCore/Services)
11 //
12 
14 
29 
30 #include "CLHEP/Random/engineIDulong.h"
31 #include "CLHEP/Random/JamesRandom.h"
32 #include "CLHEP/Random/RanecuEngine.h"
33 
34 #include <iostream>
35 #include <limits>
36 #include <sstream>
37 #include <unistd.h>
38 
39 namespace edm {
40  namespace service {
41 
42  uint32_t RandomNumberGeneratorService::maxSeedRanecu = 2147483647U;
44  uint32_t RandomNumberGeneratorService::maxSeedTRandom3 = 4294967295U;
45 
47  ActivityRegistry& activityRegistry):
48  saveFileName_(pset.getUntrackedParameter<std::string>("saveFileName")),
49  saveFileNameRecorded_(false),
50  restoreFileName_(pset.getUntrackedParameter<std::string>("restoreFileName")),
51  enableChecking_(pset.getUntrackedParameter<bool>("enableChecking")),
52  firstLumi_(true),
53  childIndex_(0U),
54  eventSeedOffset_(pset.getUntrackedParameter<unsigned>("eventSeedOffset")),
55  failedToFindStatesInLumi_(false) {
56 
57  if(pset.exists("restoreStateTag")) {
58  restoreStateTag_ = pset.getUntrackedParameter<edm::InputTag>("restoreStateTag");
59  } else {
60  restoreStateTag_ = edm::InputTag(pset.getUntrackedParameter<std::string>("restoreStateLabel"), "", "");
61  }
63 
64  if(!restoreFileName_.empty() && !restoreStateTag_.label().empty()) {
66  << "In the configuration for the RandomNumberGeneratorService both\n"
67  << "restoreFileName and restoreStateLabel were set to nonempty values\n"
68  << "which is illegal. It is impossible to restore the random engine\n"
69  << "states two different ways in the same process.\n";
70  }
71 
72  // The saveFileName must correspond to a file name without any path specification.
73  // Throw if that is not true.
74  if(!saveFileName_.empty() && (saveFileName_.find("/") != std::string::npos)) {
76  << "The saveFileName parameter must be a simple file name with no path\n"
77  << "specification. In the configuration, it was given the value \""
78  << saveFileName_ << "\"\n";
79  }
80 
81  uint32_t initialSeed;
82  VUint32 initialSeedSet;
83  std::string engineName;
84 
86  for(VString::const_iterator it = pSets.begin(), itEnd = pSets.end(); it != itEnd; ++it) {
87 
88  ParameterSet const& modulePSet = pset.getParameterSet(*it);
89  engineName = modulePSet.getUntrackedParameter<std::string>("engineName", std::string("HepJamesRandom"));
90 
91  bool initialSeedExists = modulePSet.exists("initialSeed");
92  bool initialSeedSetExists = modulePSet.exists("initialSeedSet");
93 
94  if(initialSeedExists && initialSeedSetExists) {
96  << "For the module with the label \"" << *it << "\",\n"
97  << "both the parameters \"initialSeed\" and \"initialSeedSet\"\n"
98  << "have been set in the configuration. You must set one or\n"
99  << "the other. It is illegal to set both.\n";
100  } else if(!initialSeedExists && !initialSeedSetExists) {
102  << "For the module with the label \"" << *it << "\",\n"
103  << "neither the parameter \"initialSeed\" nor \"initialSeedSet\"\n"
104  << "has been set in the configuration. You must set one or\n"
105  << "the other.\n";
106  } else if(initialSeedExists) {
107  initialSeed = modulePSet.getUntrackedParameter<uint32_t>("initialSeed");
108  initialSeedSet.clear();
109  initialSeedSet.push_back(initialSeed);
110  } else if(initialSeedSetExists) {
111  initialSeedSet = modulePSet.getUntrackedParameter<VUint32>("initialSeedSet");
112  }
113  seedMap_[*it] = initialSeedSet;
114  engineNameMap_[*it] = engineName;
115 
116  // For the CLHEP::RanecuEngine case, require a seed set containing exactly two seeds.
117 
118  if(engineName == std::string("RanecuEngine")) {
119  if(initialSeedSet.size() != 2U) {
121  << "Random engines of type \"RanecuEngine\" require 2 seeds\n"
122  << "be specified with the parameter named \"initialSeedSet\".\n"
123  << "Either \"initialSeedSet\" was not in the configuration\n"
124  << "or its size was not 2 for the module with label \"" << *it << "\".\n" ;
125  }
126  boost::shared_ptr<CLHEP::HepRandomEngine> engine(new CLHEP::RanecuEngine());
127  engineMap_[*it] = engine;
128 
129  if(initialSeedSet[0] > maxSeedRanecu ||
130  initialSeedSet[1] > maxSeedRanecu) { // They need to fit in a 31 bit integer
132  << "The RanecuEngine seeds should be in the range 0 to 2147483647.\n"
133  << "The seeds passed to the RandomNumberGenerationService from the\n"
134  "configuration file were " << initialSeedSet[0] << " and " << initialSeedSet[1]
135  << "\nThis was for the module with label \"" << *it << "\".\n";
136  }
137  long int seedL[2];
138  seedL[0] = static_cast<long int>(initialSeedSet[0]);
139  seedL[1] = static_cast<long int>(initialSeedSet[1]);
140  engine->setSeeds(seedL, 0);
141  }
142  // For the other engines, one seed is required
143  else {
144  if(initialSeedSet.size() != 1U) {
146  << "Random engines of type \"HepJamesRandom\" and \"TRandom3\n"
147  << "require exactly 1 seed be specified in the configuration.\n"
148  << "There were " << initialSeedSet.size() << " seeds set for the\n"
149  << "module with label \"" << *it << "\".\n" ;
150  }
151  long int seedL = static_cast<long int>(initialSeedSet[0]);
152 
153  if(engineName == "HepJamesRandom") {
154  if(initialSeedSet[0] > maxSeedHepJames) {
156  << "The CLHEP::HepJamesRandom engine seed should be in the range 0 to 900000000.\n"
157  << "The seed passed to the RandomNumberGenerationService from the\n"
158  "configuration file was " << initialSeedSet[0] << ". This was for \n"
159  << "the module with label " << *it << ".\n";
160  }
161  boost::shared_ptr<CLHEP::HepRandomEngine> engine(new CLHEP::HepJamesRandom(seedL));
162  engineMap_[*it] = engine;
163  } else if(engineName == "TRandom3") {
164 
165  // There is a dangerous conversion from uint32_t to long
166  // that occurs above. In the next 2 lines we check the
167  // behavior is what we need for the service to work
168  // properly. This conversion is forced on us by the
169  // CLHEP and ROOT interfaces. If the assert ever starts
170  // to fail we will have to come up with a way to deal
171  // with this.
172  uint32_t seedu32 = static_cast<uint32_t>(seedL);
173  assert(initialSeedSet[0] == seedu32);
174 
175  boost::shared_ptr<CLHEP::HepRandomEngine> engine(new TRandomAdaptor(seedL));
176  engineMap_[*it] = engine;
177  } else {
179  << "The random engine name, \"" << engineName
180  << "\", does not correspond to a supported engine.\n"
181  << "This engine was configured for the module with label \"" << *it << "\"";
182  }
183  }
184  }
185 
187 
190 
193 
196 
199 
202 
205 
208 
211 
213 
214  // the default for the stack is to point to the 'end' of our map which is used to define not set
215  engineStack_.push_back(engineMap_.end());
216  currentEngine_ = engineMap_.end();
217 
218  labelStack_.push_back(std::string());
220  }
221 
223  }
224 
225  CLHEP::HepRandomEngine&
227 
228  if(currentEngine_ == engineMap_.end()) {
229  if(currentLabel_ != std::string()) {
231  << "The module with label \""
232  << currentLabel_
233  << "\" requested a random number engine from the \n"
234  "RandomNumberGeneratorService, but that module was not configured\n"
235  "for random numbers. An engine is created only if a seed(s) is provided\n"
236  "in the configuration file. Please add the following PSet to the\n"
237  "configuration file for the RandomNumberGeneratorService:\n\n"
238  " " << currentLabel_ << " = cms.PSet(\n"
239  " initialSeed = cms.untracked.uint32(your_seed),\n"
240  " engineName = cms.untracked.string('TRandom3')\n"
241  " )\n"
242  "where you replace \"your_seed\" with a number and add a comma if necessary\n"
243  "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
244  } else {
246  << "Requested a random number engine from the RandomNumberGeneratorService\n"
247  "when no module was active. This is not supposed to be possible.\n"
248  "Please inform the edm developers about this. It would be helpful to\n"
249  "know the stack. If a source was requesting a random engine this could\n"
250  "happen. Sources are not supposed to be doing that anymore.\n";
251  }
252  }
253  return *(currentEngine_->second);
254  }
255 
256  uint32_t
258 
259  std::map<std::string, VUint32>::const_iterator iter;
260  iter = seedMap_.find(currentLabel_);
261 
262  if(iter == seedMap_.end()) {
263  if(currentLabel_ != std::string()) {
265  << "The module with label \""
266  << currentLabel_
267  << "\" requested a random number seed from the \n"
268  "RandomNumberGeneratorService, but that module was not configured\n"
269  "for random numbers. An engine is created only if a seed(s) is provided\n"
270  "in the configuration file. Please add the following PSet to the\n"
271  "configuration file for the RandomNumberGeneratorService:\n\n"
272  " " << currentLabel_ << " = cms.PSet(\n"
273  " initialSeed = cms.untracked.uint32(your_seed),\n"
274  " engineName = cms.untracked.string('TRandom3')\n"
275  " )\n"
276  "where you replace \"your_seed\" with a number and add a comma if necessary\n"
277  "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
278  } else {
280  << "Requested a random number seed from the RandomNumberGeneratorService\n"
281  "when no module was active. This is not supposed to be possible.\n"
282  "Please inform the edm developers about this. It would be helpful to\n"
283  "know the stack. If a source was requesting a random engine this could\n"
284  "happen. Sources are not supposed to be doing that anymore.\n";
285  }
286  }
287  return iter->second[0];
288  }
289 
290  void
293 
295  edm::InputTag emptyInputTag("", "", "");
296 
297  desc.addNode( edm::ParameterDescription<edm::InputTag>("restoreStateTag", emptyInputTag, false) xor
298  edm::ParameterDescription<std::string>("restoreStateLabel", emptyString, false) );
299 
300  desc.addUntracked<std::string>("saveFileName", emptyString);
301  desc.addUntracked<std::string>("restoreFileName", emptyString);
302  desc.addUntracked<bool>("enableChecking", false);
303  desc.addUntracked<unsigned>("eventSeedOffset", 0U);
304 
306  val.addOptionalUntracked<uint32_t>("initialSeed");
307  val.addOptionalUntracked<std::vector<uint32_t> >("initialSeedSet");
308  val.addOptionalUntracked<std::string>("engineName");
309 
311  wnode.setComment("The name of each ParameterSet will be the associated module label.");
312  desc.addNode(wnode);
313 
314  descriptions.add("RandomNumberGeneratorService", desc);
315  }
316 
317  void
318  RandomNumberGeneratorService::postForkReacquireResources(unsigned childIndex, unsigned /*kMaxChildren*/) {
319  childIndex_ = childIndex;
320 
321  if(!saveFileName_.empty()) {
322  std::ostringstream suffix;
323  suffix << "_" << childIndex;
324  saveFileName_ += suffix.str();
325  }
326  }
327 
328  // The next three functions contain the complex logic
329  // such that things occur in the proper sequence to be
330  // able to save and restore the states.
331 
332  void
334 
335  if(firstLumi_) {
336  // copy state from engines to lumi cache
338 
339  if(!restoreFileName_.empty()) {
340  // copy state from text file to lumi cache
342  }
343  } else {
345  }
346 
347  // copy state from LuminosityBlock to lumi cache
348  if(!restoreStateTag_.label().empty()) {
350  }
351 
352  if(!firstLumi_ || !restoreFileName_.empty() || !restoreStateTag_.label().empty()) {
353  // copy state from lumi cache to engines
355  }
356  }
357 
358  // During the beginLumi processing the producer will copy the
359  // the lumi cache to a product if the producer was scheduled
360  // in a path in the configuration
361 
362  void
364 
365  if(firstLumi_) {
366  // reset state with new seeds based on child index
368  if(!restoreFileName_.empty()) {
370  // copy state from text file to event cache
372  }
373  }
374  if(!firstLumi_ || !restoreFileName_.empty()) {
375  // copy state from event cache to engines
377  }
378  firstLumi_ = false;
379  }
380 
381  void
383  // copy from Event to event cache
384  if(!restoreStateTag_.label().empty()) {
386  readFromEvent(event);
387 
388  // copy from event cache to engines
390  } else {
391  // copy from engines to event cache
393  }
394  // if requested write text file from both caches
395  if(!saveFileName_.empty()) {
397  if(!saveFileNameRecorded_) {
399  Service<JobReport> reportSvc;
400  reportSvc->reportRandomStateFile(fullName);
401  saveFileNameRecorded_ = true;
402  }
403  }
404  }
405 
406  // During the event processing the producer will copy the
407  // the event cache to a product if the producer was scheduled
408  // in a path in the configuration
409 
410  void
412  push(description.moduleLabel());
413  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
414  engineStateStack_.push_back(currentEngine_->second->put());
415  }
416  }
417 
418  void
420  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
421  if(engineStateStack_.back() != currentEngine_->second->put()) {
423  << "It is illegal to generate random numbers during module construction because \n"
424  "that makes it very difficult to reproduce the processing of individual\n"
425  "events. Random numbers were generated during module construction for the module with\n"
426  "class name \"" << description.moduleName() << "\"\n"
427  "and module label \"" << description.moduleLabel() << "\"\n";
428  }
429  engineStateStack_.pop_back();
430  }
431  pop();
432  }
433 
434  void
436  push(description.moduleLabel());
437  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
438  engineStateStack_.push_back(currentEngine_->second->put());
439  }
440  }
441 
442  void
444  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
445  if(engineStateStack_.back() != currentEngine_->second->put()) {
447  << "It is illegal to generate random numbers during beginJob because \n"
448  "that makes it very difficult to reproduce the processing of individual\n"
449  "events. Random numbers were generated during beginJob for the module with\n"
450  "class name \"" << description.moduleName() << "\"\n"
451  "and module label \"" << description.moduleLabel() << "\"\n";
452  }
453  engineStateStack_.pop_back();
454  }
455  pop();
456  }
457 
458  void
460  push(description.moduleLabel());
461  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
462  engineStateStack_.push_back(currentEngine_->second->put());
463  }
464  }
465 
466  void
468  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
469  if(engineStateStack_.back() != currentEngine_->second->put()) {
471  << "It is illegal to generate random numbers during beginRun because \n"
472  "that makes it very difficult to reproduce the processing of individual\n"
473  "events. Random numbers were generated during beginRun for the module with\n"
474  "class name \"" << description.moduleName() << "\"\n"
475  "and module label \"" << description.moduleLabel() << "\"\n";
476  }
477  engineStateStack_.pop_back();
478  }
479  pop();
480  }
481 
482  void
484  push(description.moduleLabel());
485  }
486 
487  void
489  pop();
490  }
491 
492  void
494  push(description.moduleLabel());
495  }
496 
497  void
499  pop();
500  }
501 
502  void
504  push(description.moduleLabel());
505  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
506  engineStateStack_.push_back(currentEngine_->second->put());
507  }
508  }
509 
510  void
512  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
513  if(engineStateStack_.back() != currentEngine_->second->put()) {
515  << "It is illegal to generate random numbers during endLumi because \n"
516  "that makes it very difficult to reproduce the processing of individual\n"
517  "events. Random numbers were generated during endLumi for the module with\n"
518  "class name \"" << description.moduleName() << "\"\n"
519  "and module label \"" << description.moduleLabel() << "\"\n";
520  }
521  engineStateStack_.pop_back();
522  }
523  pop();
524  }
525 
526  void
528  push(description.moduleLabel());
529  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
530  engineStateStack_.push_back(currentEngine_->second->put());
531  }
532  }
533 
534  void
536  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
537  if(engineStateStack_.back() != currentEngine_->second->put()) {
539  << "It is illegal to generate random numbers during endRun because \n"
540  "that makes it very difficult to reproduce the processing of individual\n"
541  "events. Random numbers were generated during endRun for the module with\n"
542  "class name \"" << description.moduleName() << "\"\n"
543  "and module label \"" << description.moduleLabel() << "\"\n";
544  }
545  engineStateStack_.pop_back();
546  }
547  pop();
548  }
549 
550  void
552  push(description.moduleLabel());
553  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
554  engineStateStack_.push_back(currentEngine_->second->put());
555  }
556  }
557 
558  void
560  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
561  if(engineStateStack_.back() != currentEngine_->second->put()) {
563  << "It is illegal to generate random numbers during endJob because \n"
564  "that makes it very difficult to reproduce the processing of individual\n"
565  "events. Random numbers were generated during endJob for the module with\n"
566  "class name \"" << description.moduleName() << "\"\n"
567  "and module label \"" << description.moduleLabel() << "\"\n";
568  }
569  engineStateStack_.pop_back();
570  }
571  pop();
572  }
573 
574  std::vector<RandomEngineState> const&
576  return lumiCache_;
577  }
578 
579  std::vector<RandomEngineState> const&
581  return eventCache_;
582  }
583 
584  void
586  std::cout << "\n\nRandomNumberGeneratorService dump\n\n";
587 
588  std::cout << " Contents of seedMap\n";
589  for(std::map<std::string, std::vector<uint32_t> >::const_iterator iter = seedMap_.begin();
590  iter != seedMap_.end();
591  ++iter) {
592  std::cout << " " << iter->first;
593  std::vector<uint32_t> seeds = iter->second;
594  for(std::vector<uint32_t>::const_iterator vIter = seeds.begin();
595  vIter != seeds.end();
596  ++vIter) {
597  std::cout << " " << *vIter;
598  }
599  std::cout << "\n";
600  }
601  std::cout << "\n Contents of engineNameMap\n";
602  for(std::map<std::string, std::string>::const_iterator iter = engineNameMap_.begin();
603  iter != engineNameMap_.end();
604  ++iter) {
605  std::cout << " " << iter->first << " " << iter->second << "\n";
606  }
607  std::cout << "\n Contents of engineMap\n";
608  for(EngineMap::const_iterator iter = engineMap_.begin();
609  iter != engineMap_.end();
610  ++iter) {
611  std::cout << " " << iter->first
612  << " " << iter->second->name() << " ";
613  if(iter->second->name() == std::string("HepJamesRandom")) {
614  std::cout << iter->second->getSeed();
615  } else {
616  std::cout << "Engine does not know original seed";
617  }
618  std::cout << "\n";
619  }
620  std::cout << "\n";
621  std::cout << " currentLabel_ = " << currentLabel_ << "\n";
622  std::cout << " labelStack_ size = " << labelStack_.size() << "\n";
623  int i = 0;
624  for(VString::const_iterator iter = labelStack_.begin();
625  iter != labelStack_.end();
626  ++iter, ++i) {
627  std::cout << " " << i << " " << *iter << "\n";
628  }
629  if(currentEngine_ == engineMap_.end()) {
630  std::cout << " currentEngine points to end\n";
631  } else {
632  std::cout << " currentEngine_ = " << currentEngine_->first
633  << " " << currentEngine_->second->name()
634  << " " << currentEngine_->second->getSeed() << "\n";
635  }
636 
637  std::cout << " engineStack_ size = " << engineStack_.size() << "\n";
638  i = 0;
639  for(std::vector<EngineMap::const_iterator>::const_iterator iter = engineStack_.begin();
640  iter != engineStack_.end();
641  ++iter, ++i) {
642  if(*iter == engineMap_.end()) {
643  std::cout << " " << i << " Points to end of engine map\n";
644  } else {
645  std::cout << " " << i << " " << (*iter)->first
646  << " " << (*iter)->second->name() << " " << (*iter)->second->getSeed() << "\n";
647  }
648  }
649 
650  std::cout << " restoreStateTag_ = " << restoreStateTag_ << "\n";
651  std::cout << " saveFileName_ = " << saveFileName_ << "\n";
652  std::cout << " restoreFileName_ = " << restoreFileName_ << "\n";
653  }
654 
655  void
657  currentEngine_ = engineMap_.find(iLabel);
658  engineStack_.push_back(currentEngine_);
659 
660  labelStack_.push_back(iLabel);
661  currentLabel_ = iLabel;
662  }
663 
664  void
666  engineStack_.pop_back();
667  //NOTE: algorithm is such that we always have at least one item in the stacks
668  currentEngine_ = engineStack_.back();
669  labelStack_.pop_back();
670  currentLabel_ = labelStack_.back();
671  }
672 
673  void
675 
678 
679  if(!states.isValid()) {
681  return;
682  }
684  states->getRandomEngineStates(lumiCache_);
685  }
686 
687  void
689 
691 
692  event.getByLabel(restoreStateTag_, states);
693 
694  if(!states.isValid()) {
696  return;
697  } else {
699  << "The RandomNumberGeneratorService is trying to restore\n"
700  << "the state of the random engines by reading a product from\n"
701  << "the Event with input tag \"" << restoreStateTag_ << "\". It\n"
702  << "fails to find one. The label used in the request for the product\n"
703  << "is set in the configuration. It is probably set to the wrong value\n"
704  << "in the configuration file. It must match the module label\n"
705  << "of the RandomEngineStateProducer that created the product in\n"
706  << "a previous process\n";
707  }
708  }
711  << "The RandomNumberGeneratorService is trying to restore\n"
712  << "the state of the random engines by reading a product from\n"
713  << "the Event and LuminosityBlock with input tag \"" << restoreStateTag_ << "\".\n"
714  << "It found the product in the Event but not the one in the LuminosityBlock.\n"
715  << "Either the product in the LuminosityBlock was dropped or\n"
716  << "there is a bug somewhere\n";
717  }
718  states->getRandomEngineStates(eventCache_);
719  }
720 
721  bool
723 
725 
726  event.getByLabel(restoreStateTag_, states);
727  if(!states.isValid()) {
728  return false;
729  }
730  for(std::vector<RandomEngineState>::const_iterator state = states->begin(),
731  iEnd = states->end();
732  state != iEnd; ++state) {
733 
734  std::vector<RandomEngineState>::iterator cachedState =
735  std::lower_bound(eventCache_.begin(), eventCache_.end(), *state);
736 
737 
738  if(cachedState != eventCache_.end() && cachedState->getLabel() == state->getLabel()) {
739  if(cachedState->getSeed().size() != state->getSeed().size() ||
740  cachedState->getState().size() != state->getState().size()) {
742  << "In function RandomNumberGeneratorService::backwardCompatibilityRead.\n"
743  << "When attempting to replay processing with the RandomNumberGeneratorService,\n"
744  << "the engine type for each module must be the same in the replay configuration\n"
745  << "and the original configuration. If this is not the problem, then the data\n"
746  << "is somehow corrupted or there is a bug because the vector in the data containing\n"
747  << "the seeds or engine state is the incorrect size for the type of random engine.\n";
748  }
749  cachedState->setSeed(state->getSeed());
750  cachedState->setState(state->getState());
751  }
752  }
753  return true;
754  }
755 
756  void
757  RandomNumberGeneratorService::snapShot(std::vector<RandomEngineState>& cache) {
758  cache.resize(engineMap_.size());
759  std::vector<RandomEngineState>::iterator state = cache.begin();
760 
761  for(EngineMap::const_iterator iter = engineMap_.begin();
762  iter != engineMap_.end();
763  ++iter, ++state) {
764 
765  state->setLabel(iter->first);
766  state->setSeed(seedMap_[iter->first]);
767 
768  std::vector<unsigned long> stateL = iter->second->put();
769  state->clearStateVector();
770  state->reserveStateVector(stateL.size());
771  for(std::vector<unsigned long>::const_iterator vIter = stateL.begin();
772  vIter != stateL.end();
773  ++vIter) {
774  state->push_back_stateVector(static_cast<uint32_t>(*vIter));
775  }
776  }
777  }
778 
779  void
780  RandomNumberGeneratorService::restoreFromCache(std::vector<RandomEngineState> const& cache) {
781  for(std::vector<RandomEngineState>::const_iterator iter = cache.begin(),
782  iEnd = cache.end();
783  iter != iEnd; ++iter) {
784 
785  std::string const& engineLabel = iter->getLabel();
786 
787  std::vector<uint32_t> const& engineState = iter->getState();
788  std::vector<unsigned long> engineStateL;
789  for(std::vector<uint32_t>::const_iterator iVal = engineState.begin(),
790  theEnd = engineState.end();
791  iVal != theEnd; ++iVal) {
792  engineStateL.push_back(static_cast<unsigned long>(*iVal));
793  }
794 
795  std::vector<uint32_t> const& engineSeeds = iter->getSeed();
796  std::vector<long> engineSeedsL;
797  for(std::vector<uint32_t>::const_iterator iVal = engineSeeds.begin(),
798  theEnd = engineSeeds.end();
799  iVal != theEnd;
800  ++iVal) {
801  long seedL = static_cast<long>(*iVal);
802  engineSeedsL.push_back(seedL);
803 
804  // There is a dangerous conversion from uint32_t to long
805  // that occurs above. In the next 2 lines we check the
806  // behavior is what we need for the service to work
807  // properly. This conversion is forced on us by the
808  // CLHEP and ROOT interfaces. If the assert ever starts
809  // to fail we will have to come up with a way to deal
810  // with this.
811  uint32_t seedu32 = static_cast<uint32_t>(seedL);
812  assert(*iVal == seedu32);
813  }
814 
815  EngineMap::iterator engine = engineMap_.find(engineLabel);
816 
817  if(engine != engineMap_.end()) {
818 
819  seedMap_[engineLabel] = engineSeeds;
820 
821  // We need to handle each type of engine differently because each
822  // has different requirements on the seed or seeds.
823  if(engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
824 
825  checkEngineType(engine->second->name(), std::string("HepJamesRandom"), engineLabel);
826 
827  // These two lines actually restore the seed and engine state.
828  engine->second->setSeed(engineSeedsL[0], 0);
829  engine->second->get(engineStateL);
830  } else if(engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
831 
832  checkEngineType(engine->second->name(), std::string("RanecuEngine"), engineLabel);
833 
834  // This line actually restores the engine state.
835  engine->second->get(engineStateL);
836  } else if(engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
837 
838  checkEngineType(engine->second->name(), std::string("TRandom3"), engineLabel);
839 
840  // This line actually restores the engine state.
841  engine->second->setSeed(engineSeedsL[0], 0);
842  engine->second->get(engineStateL);
843  } else {
844  // This should not be possible because this code should be able to restore
845  // any kind of engine whose state can be saved.
847  << "The RandomNumberGeneratorService is trying to restore the state\n"
848  "of the random engines. The state in the event indicates an engine\n"
849  "of an unknown type. This should not be possible unless you are\n"
850  "running with an old code release on a new file that was created\n"
851  "with a newer release which had new engine types added. In this case\n"
852  "the only solution is to use a newer release. In any other case, notify\n"
853  "the EDM developers because this should not be possible\n";
854  }
855  }
856  }
857  }
858 
859  void
861  std::string const& typeFromEvent,
862  std::string const& engineLabel) {
863  if(typeFromConfig != typeFromEvent) {
865  << "The RandomNumberGeneratorService is trying to restore\n"
866  << "the state of the random engine for the module \""
867  << engineLabel << "\". An\n"
868  << "error was detected because the type of the engine in the\n"
869  << "input file and the configuration file do not match.\n"
870  << "In the configuration file the type is \"" << typeFromConfig
871  << "\".\nIn the input file the type is \"" << typeFromEvent << "\". If\n"
872  << "you are not generating any random numbers in this module, then\n"
873  << "remove the line in the configuration file that gives it\n"
874  << "a seed and the error will go away. Otherwise, you must give\n"
875  << "this module the same engine type in the configuration file or\n"
876  << "stop trying to restore the random engine state.\n";
877  }
878  }
879 
880  void
882  if(!outFile_.is_open()) {
883  outFile_.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
884  }
885  if(!outFile_) {
887  << "Unable to open the file \""
888  << fileName << "\" to save the state of the random engines.\n";
889  }
890  outFile_.seekp(0, std::ios_base::beg);
891  outFile_ << "<RandomEngineStates>\n";
892 
893  outFile_ << "<Event>\n";
895  outFile_ << "</Event>\n" ;
896 
897  outFile_ << "<Lumi>\n";
899  outFile_ << "</Lumi>\n" ;
900 
901  outFile_ << "</RandomEngineStates>\n" ;
902  outFile_.flush();
903  }
904 
905  void
906  RandomNumberGeneratorService::writeStates(std::vector<RandomEngineState> const& v,
907  std::ofstream& outFile) {
908  for(std::vector<RandomEngineState>::const_iterator iter = v.begin(),
909  iEnd = v.end();
910  iter != iEnd; ++iter) {
911 
912  std::vector<uint32_t> const& seedVector = iter->getSeed();
913  std::vector<uint32_t>::size_type seedVectorLength = seedVector.size();
914 
915  std::vector<uint32_t> const& stateVector = iter->getState();
916  std::vector<uint32_t>::size_type stateVectorLength = stateVector.size();
917 
918  outFile << "<ModuleLabel>\n" << iter->getLabel() << "\n</ModuleLabel>\n";
919 
920  outFile << "<SeedLength>\n" << seedVectorLength << "\n</SeedLength>\n" ;
921  outFile << "<InitialSeeds>\n";
922  writeVector(seedVector, outFile);
923  outFile << "</InitialSeeds>\n";
924  outFile << "<FullStateLength>\n" << stateVectorLength << "\n</FullStateLength>\n";
925  outFile << "<FullState>\n";
926  writeVector(stateVector, outFile);
927  outFile << "</FullState>\n";
928  }
929  }
930 
931  void
933  std::ofstream& outFile) {
934  if(v.empty()) return;
935  size_t numItems = v.size();
936  for(size_t i = 0; i < numItems; ++i) {
937  if(i != 0 && i % 10 == 0) outFile << "\n";
938  outFile << std::setw(13) << v[i];
939  }
940  outFile << "\n";
941  }
942 
944  char directory[1500];
945  std::string fullName(getcwd(directory, sizeof(directory)) ? directory : "/PathIsTooBig");
946  fullName += "/" + saveFileName_;
947  return fullName;
948  }
949 
950  void
952  std::string whichStates("<Event>");
953  readStatesFromFile(fileName, eventCache_, whichStates);
954  }
955 
956  void
958  std::string whichStates("<Lumi>");
959  readStatesFromFile(fileName, lumiCache_, whichStates);
960  }
961 
962 
963  void
965  std::vector<RandomEngineState>& cache,
966  std::string const& whichStates) {
967  std::ifstream inFile;
968  inFile.open(fileName.c_str(), std::ifstream::in);
969  if(!inFile) {
971  << "Unable to open the file \""
972  << fileName << "\" to restore the random engine states.\n";
973  }
974 
976  inFile >> text;
977  if(!inFile.good() || text != std::string("<RandomEngineStates>")) {
979  << "Attempting to read file with random number engine states.\n"
980  << "File \"" << restoreFileName_
981  << "\" is ill-structured or otherwise corrupted.\n"
982  << "Cannot read the file header word.\n";
983  }
984  bool saveToCache = false;
985  while(readEngineState(inFile, cache, whichStates, saveToCache)) {}
986  }
987 
989  std::vector<RandomEngineState>& cache,
990  std::string const& whichStates,
991  bool& saveToCache) {
992  std::string leading;
993  std::string trailing;
994  std::string moduleLabel;
995  std::vector<uint32_t>::size_type seedVectorSize;
996  std::vector<uint32_t> seedVector;
997  std::vector<uint32_t>::size_type stateVectorSize;
998  std::vector<uint32_t> stateVector;
999 
1000  // First we need to look for the special strings
1001  // that mark the end of the file and beginning and
1002  // and end of the data for different sections.
1003 
1004  is >> leading;
1005  if(!is.good()) {
1007  << "File \"" << restoreFileName_
1008  << "\" is ill-structured or otherwise corrupted.\n"
1009  << "Cannot read next field and did not hit the end yet.\n";
1010  }
1011 
1012  // This marks the end of the file. We are done.
1013  if(leading == std::string("</RandomEngineStates>")) return false;
1014 
1015  // This marks the end of a section of the data
1016  if(leading == std::string("</Event>") ||
1017  leading == std::string("</Lumi>")) {
1018  saveToCache = false;
1019  return true;
1020  }
1021 
1022  // This marks the beginning of a section
1023  if(leading == std::string("<Event>") ||
1024  leading == std::string("<Lumi>")) {
1025  saveToCache = (leading == whichStates);
1026  return true;
1027  }
1028 
1029  // Process the next engine state
1030 
1031  is >> moduleLabel >> trailing;
1032  if(!is.good() ||
1033  leading != std::string("<ModuleLabel>") ||
1034  trailing != std::string("</ModuleLabel>")) {
1036  << "File \"" << restoreFileName_
1037  << "\" is ill-structured or otherwise corrupted.\n"
1038  << "Cannot read a module label when restoring random engine states.\n";
1039  }
1040 
1041  is >> leading >> seedVectorSize >> trailing;
1042  if(!is.good() ||
1043  leading != std::string("<SeedLength>") ||
1044  trailing != std::string("</SeedLength>")) {
1046  << "File \"" << restoreFileName_
1047  << "\" is ill-structured or otherwise corrupted.\n"
1048  << "Cannot read seed vector length when restoring random engine states.\n";
1049  }
1050 
1051  is >> leading;
1052  if(!is.good() ||
1053  leading != std::string("<InitialSeeds>")) {
1055  << "File \"" << restoreFileName_
1056  << "\" is ill-structured or otherwise corrupted.\n"
1057  << "Cannot read beginning of InitialSeeds when restoring random engine states.\n";
1058  }
1059 
1060  if(seedVectorSize > maxSeeds) {
1062  << "File \"" << restoreFileName_
1063  << "\" is ill-structured or otherwise corrupted.\n"
1064  << "The number of seeds exceeds 64K.\n";
1065  }
1066 
1067  readVector(is, seedVectorSize, seedVector);
1068 
1069  is >> trailing;
1070  if(!is.good() ||
1071  trailing != std::string("</InitialSeeds>")) {
1073  << "File \"" << restoreFileName_
1074  << "\" is ill-structured or otherwise corrupted.\n"
1075  << "Cannot read end of InitialSeeds when restoring random engine states.\n";
1076  }
1077 
1078  is >> leading >> stateVectorSize >> trailing;
1079  if(!is.good() ||
1080  leading != std::string("<FullStateLength>") ||
1081  trailing != std::string("</FullStateLength>")) {
1083  << "File \"" << restoreFileName_
1084  << "\" is ill-structured or otherwise corrupted.\n"
1085  << "Cannot read state vector length when restoring random engine states.\n";
1086  }
1087 
1088  is >> leading;
1089  if(!is.good() ||
1090  leading != std::string("<FullState>")) {
1092  << "File \"" << restoreFileName_
1093  << "\" is ill-structured or otherwise corrupted.\n"
1094  << "Cannot read beginning of FullState when restoring random engine states.\n";
1095  }
1096 
1097  if(stateVectorSize > maxStates) {
1099  << "File \"" << restoreFileName_
1100  << "\" is ill-structured or otherwise corrupted.\n"
1101  << "The number of states exceeds 64K.\n";
1102  }
1103 
1104  readVector(is, stateVectorSize, stateVector);
1105 
1106  is >> trailing;
1107  if(!is.good() ||
1108  trailing != std::string("</FullState>")) {
1110  << "File \"" << restoreFileName_
1111  << "\" is ill-structured or otherwise corrupted.\n"
1112  << "Cannot read end of FullState when restoring random engine states.\n";
1113  }
1114 
1115  if(saveToCache) {
1116  RandomEngineState randomEngineState;
1117  randomEngineState.setLabel(moduleLabel);
1118  std::vector<RandomEngineState>::iterator state =
1119  std::lower_bound(cache.begin(), cache.end(), randomEngineState);
1120 
1121  if(state != cache.end() && moduleLabel == state->getLabel()) {
1122  if(seedVector.size() != state->getSeed().size() ||
1123  stateVector.size() != state->getState().size()) {
1125  << "File \"" << restoreFileName_
1126  << "\" is ill-structured or otherwise corrupted.\n"
1127  << "Vectors containing engine state are the incorrect size for the type of random engine.\n";
1128  }
1129  state->setSeed(seedVector);
1130  state->setState(stateVector);
1131  }
1132  }
1133  return true;
1134  }
1135 
1136  void
1137  RandomNumberGeneratorService::readVector(std::istream& is, unsigned numItems, std::vector<uint32_t>& v) {
1138  v.clear();
1139  v.reserve(numItems);
1140  uint32_t data;
1141  for(unsigned i = 0; i < numItems; ++i) {
1142  is >> data;
1143  if(!is.good()) {
1145  << "File \"" << restoreFileName_
1146  << "\" is ill-structured or otherwise corrupted.\n"
1147  << "Cannot read vector when restoring random engine states.\n";
1148  }
1149  v.push_back(data);
1150  }
1151  }
1152 
1153  void
1155 
1156  if(childIndex_ == 0U && eventSeedOffset_ == 0U) return;
1157 
1158  for(EngineMap::const_iterator iter = engineMap_.begin();
1159  iter != engineMap_.end();
1160  ++iter) {
1161 
1162  uint32_t offset1 = childIndex_;
1163  uint32_t offset2 = eventSeedOffset_;
1164 
1165  std::string const& moduleLabel = iter->first;
1166  std::string const& engineName = engineNameMap_[moduleLabel];
1167  VUint32& seeds = seedMap_[moduleLabel];
1168 
1169  if(engineName == std::string("RanecuEngine")) {
1170  assert(seeds.size() == 2U);
1171  // Wrap around if the offsets push the seed over the maximum allowed value
1172  uint32_t mod = maxSeedRanecu + 1U;
1173  offset1 = offset1 % mod;
1174  offset2 = offset2 % mod;
1175  seeds[0] = (seeds[0] + offset1) % mod;
1176  seeds[0] = (seeds[0] + offset2) % mod;
1177  long int seedL[2];
1178  seedL[0] = static_cast<long int>(seeds[0]);
1179  seedL[1] = static_cast<long int>(seeds[1]);
1180  iter->second->setSeeds(seedL,0);
1181  } else {
1182  assert(seeds.size() == 1U);
1183 
1184  if(engineName == "HepJamesRandom") {
1185  // Wrap around if the offsets push the seed over the maximum allowed value
1186  uint32_t mod = maxSeedHepJames + 1U;
1187  offset1 = offset1 % mod;
1188  offset2 = offset2 % mod;
1189  seeds[0] = (seeds[0] + offset1) % mod;
1190  seeds[0] = (seeds[0] + offset2) % mod;
1191 
1192  long int seedL = static_cast<long int>(seeds[0]);
1193  iter->second->setSeed(seedL, 0);
1194  } else {
1195  assert(engineName == "TRandom3");
1196  // Wrap around if the offsets push the seed over the maximum allowed value
1197  // We have to be extra careful with this one because it may also go beyond
1198  // the values 32 bits can hold
1199  uint32_t max32 = maxSeedTRandom3;
1200  if((max32 - seeds[0]) >= offset1) {
1201  seeds[0] = seeds[0] + offset1;
1202  } else {
1203  seeds[0] = offset1 - (max32 - seeds[0]) - 1U;
1204  }
1205  if((max32 - seeds[0]) >= offset2) {
1206  seeds[0] = seeds[0] + offset2;
1207  } else {
1208  seeds[0] = offset2 - (max32 - seeds[0]) - 1U;
1209  }
1210  long seedL = static_cast<long>(seeds[0]);
1211 
1212  // There is a dangerous conversion from uint32_t to long
1213  // that occurs above. In the next 2 lines we check the
1214  // behavior is what we need for the service to work
1215  // properly. This conversion is forced on us by the
1216  // CLHEP and ROOT interfaces. If the assert ever starts
1217  // to fail we will have to come up with a way to deal
1218  // with this.
1219  uint32_t seedu32 = static_cast<uint32_t>(seedL);
1220  assert(seeds[0] == seedu32);
1221 
1222  iter->second->setSeed(seedL, 0);
1223  }
1224  }
1225  }
1226  }
1227  }
1228 }
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
void writeStates(std::vector< RandomEngineState > const &v, std::ofstream &outFile)
T getUntrackedParameter(std::string const &, T const &) const
int i
Definition: DBlmapReader.cc:9
void restoreFromCache(std::vector< RandomEngineState > const &cache)
void watchPostModuleBeginLumi(PostModuleBeginLumi::slot_type const &iSlot)
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void postModuleEndJob(ModuleDescription const &description)
void preModuleEndLumi(ModuleDescription const &description)
void watchPreModuleConstruction(PreModuleConstruction::slot_type const &iSlot)
tuple lumi
Definition: fjr2json.py:35
void watchPostModule(PostModule::slot_type const &iSlot)
virtual void print()
For debugging purposes only.
void setLabel(const std::string &value)
std::vector< std::vector< unsigned long > > engineStateStack_
bool exists(std::string const &parameterName) const
checks if a parameter exists
std::string const & moduleName() const
ParameterDescriptionNode * addNode(ParameterDescriptionNode const &node)
void preModuleConstruction(ModuleDescription const &description)
void postModuleEndLumi(ModuleDescription const &description)
void preModule(ModuleDescription const &description)
void postBeginLumi(LuminosityBlock const &lumi, EventSetup const &es)
void postModule(ModuleDescription const &description)
void watchPreModuleEndLumi(PreModuleEndLumi::slot_type const &iSlot)
void preModuleBeginJob(ModuleDescription const &description)
bool getByLabel(std::string const &label, Handle< PROD > &result) const
void readFromLuminosityBlock(LuminosityBlock const &lumi)
void readLumiStatesFromTextFile(std::string const &fileName)
std::map< std::string, std::string > engineNameMap_
std::string const & moduleLabel() const
void checkEngineType(std::string const &typeFromConfig, std::string const &typeFromEvent, std::string const &engineLabel)
uint16_t size_type
void watchPreModule(PreModule::slot_type const &iSlot)
dictionary map
Definition: Association.py:205
void preModuleBeginLumi(ModuleDescription const &description)
std::vector< std::string > getParameterNamesForType(bool trackiness=true) const
Definition: ParameterSet.h:195
void postModuleBeginRun(ModuleDescription const &description)
void watchPreModuleEndRun(PreModuleEndRun::slot_type const &iSlot)
virtual CLHEP::HepRandomEngine & getEngine() const
Use this to get the random number engine, this is the only function most users should call...
RandomNumberGeneratorService(ParameterSet const &pset, ActivityRegistry &activityRegistry)
virtual std::vector< RandomEngineState > const & getEventCache() const
void postModuleEndRun(ModuleDescription const &description)
bool readEngineState(std::istream &is, std::vector< RandomEngineState > &cache, std::string const &whichStates, bool &saveToCache)
virtual uint32_t mySeed() const
Exists for backward compatibility.
void watchPostModuleEndRun(PostModuleEndRun::slot_type const &iSlot)
void readEventStatesFromTextFile(std::string const &fileName)
void watchPreModuleEndJob(PreModuleEndJob::slot_type const &iSlot)
virtual void preBeginLumi(LuminosityBlock const &lumi)
tuple text
Definition: runonSM.py:42
void readStatesFromFile(std::string const &fileName, std::vector< RandomEngineState > &cache, std::string const &whichStates)
void snapShot(std::vector< RandomEngineState > &cache)
static void fillDescriptions(ConfigurationDescriptions &descriptions)
void watchPostBeginLumi(PostBeginLumi::slot_type const &iSlot)
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
bool isValid() const
Definition: HandleBase.h:76
void watchPreModuleBeginJob(PreModuleBeginJob::slot_type const &iSlot)
void postModuleBeginJob(ModuleDescription const &description)
std::vector< EngineMap::const_iterator > engineStack_
void watchPostModuleBeginRun(PostModuleBeginRun::slot_type const &iSlot)
virtual std::vector< RandomEngineState > const & getLumiCache() const
tuple out
Definition: dbtoconf.py:99
void preModuleEndRun(ModuleDescription const &description)
tuple description
Definition: idDealer.py:66
string fullName
ParameterSet const & getParameterSet(std::string const &) const
void postModuleBeginLumi(ModuleDescription const &description)
void preModuleEndJob(ModuleDescription const &description)
void postForkReacquireResources(unsigned childIndex, unsigned kMaxChildren)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void readVector(std::istream &is, unsigned numItems, std::vector< uint32_t > &v)
void postModuleConstruction(ModuleDescription const &description)
char state
Definition: procUtils.cc:75
std::string const & label() const
Definition: InputTag.h:42
static std::string const emptyString("")
std::string const & process() const
Definition: InputTag.h:46
void watchPostForkReacquireResources(PostForkReacquireResources::slot_type const &iSlot)
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
void writeVector(VUint32 const &v, std::ofstream &outFile)
void watchPostModuleBeginJob(PostModuleBeginJob::slot_type const &iSlot)
tuple cout
Definition: gather_cfg.py:121
ParameterDescriptionBase * addOptionalUntracked(U const &iLabel, T const &value)
void watchPreModuleBeginLumi(PreModuleBeginLumi::slot_type const &iSlot)
void preModuleBeginRun(ModuleDescription const &description)
T mod(const T &a, const T &b)
Definition: ecalDccMap.h:4
void watchPostModuleEndJob(PostModuleEndJob::slot_type const &iSlot)
void watchPreModuleBeginRun(PreModuleBeginRun::slot_type const &iSlot)
void watchPostModuleEndLumi(PostModuleEndLumi::slot_type const &iSlot)