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 
30 
31 #include "CLHEP/Random/engineIDulong.h"
32 #include "CLHEP/Random/JamesRandom.h"
33 #include "CLHEP/Random/RanecuEngine.h"
34 
35 #include <iostream>
36 #include <limits>
37 #include <sstream>
38 #include <unistd.h>
39 
40 namespace edm {
41  namespace service {
42 
43  uint32_t RandomNumberGeneratorService::maxSeedRanecu = 2147483647U;
45  uint32_t RandomNumberGeneratorService::maxSeedTRandom3 = 4294967295U;
46 
48  ActivityRegistry& activityRegistry):
49  saveFileName_(pset.getUntrackedParameter<std::string>("saveFileName")),
50  saveFileNameRecorded_(false),
51  restoreFileName_(pset.getUntrackedParameter<std::string>("restoreFileName")),
52  enableChecking_(pset.getUntrackedParameter<bool>("enableChecking")),
53  firstLumi_(true),
54  childIndex_(0U),
55  eventSeedOffset_(pset.getUntrackedParameter<unsigned>("eventSeedOffset")),
56  failedToFindStatesInLumi_(false) {
57 
58  if(pset.exists("restoreStateTag")) {
59  restoreStateTag_ = pset.getUntrackedParameter<edm::InputTag>("restoreStateTag");
60  if(restoreStateTag_.process() == "") {
62  }
63  } else {
65  }
67 
68  if(!restoreFileName_.empty() && !restoreStateTag_.label().empty()) {
70  << "In the configuration for the RandomNumberGeneratorService both\n"
71  << "restoreFileName and restoreStateLabel were set to nonempty values\n"
72  << "which is illegal. It is impossible to restore the random engine\n"
73  << "states two different ways in the same process.\n";
74  }
75 
76  // The saveFileName must correspond to a file name without any path specification.
77  // Throw if that is not true.
78  if(!saveFileName_.empty() && (saveFileName_.find("/") != std::string::npos)) {
80  << "The saveFileName parameter must be a simple file name with no path\n"
81  << "specification. In the configuration, it was given the value \""
82  << saveFileName_ << "\"\n";
83  }
84 
85  uint32_t initialSeed;
86  VUint32 initialSeedSet;
87  std::string engineName;
88 
90  for(VString::const_iterator it = pSets.begin(), itEnd = pSets.end(); it != itEnd; ++it) {
91 
92  ParameterSet const& modulePSet = pset.getParameterSet(*it);
93  engineName = modulePSet.getUntrackedParameter<std::string>("engineName", std::string("HepJamesRandom"));
94 
95  bool initialSeedExists = modulePSet.exists("initialSeed");
96  bool initialSeedSetExists = modulePSet.exists("initialSeedSet");
97 
98  if(initialSeedExists && initialSeedSetExists) {
100  << "For the module with the label \"" << *it << "\",\n"
101  << "both the parameters \"initialSeed\" and \"initialSeedSet\"\n"
102  << "have been set in the configuration. You must set one or\n"
103  << "the other. It is illegal to set both.\n";
104  } else if(!initialSeedExists && !initialSeedSetExists) {
106  << "For the module with the label \"" << *it << "\",\n"
107  << "neither the parameter \"initialSeed\" nor \"initialSeedSet\"\n"
108  << "has been set in the configuration. You must set one or\n"
109  << "the other.\n";
110  } else if(initialSeedExists) {
111  initialSeed = modulePSet.getUntrackedParameter<uint32_t>("initialSeed");
112  initialSeedSet.clear();
113  initialSeedSet.push_back(initialSeed);
114  } else if(initialSeedSetExists) {
115  initialSeedSet = modulePSet.getUntrackedParameter<VUint32>("initialSeedSet");
116  }
117  seedMap_[*it] = initialSeedSet;
118  engineNameMap_[*it] = engineName;
119 
120  // For the CLHEP::RanecuEngine case, require a seed set containing exactly two seeds.
121 
122  if(engineName == std::string("RanecuEngine")) {
123  if(initialSeedSet.size() != 2U) {
125  << "Random engines of type \"RanecuEngine\" require 2 seeds\n"
126  << "be specified with the parameter named \"initialSeedSet\".\n"
127  << "Either \"initialSeedSet\" was not in the configuration\n"
128  << "or its size was not 2 for the module with label \"" << *it << "\".\n" ;
129  }
130  boost::shared_ptr<CLHEP::HepRandomEngine> engine(new CLHEP::RanecuEngine());
131  engineMap_[*it] = engine;
132 
133  if(initialSeedSet[0] > maxSeedRanecu ||
134  initialSeedSet[1] > maxSeedRanecu) { // They need to fit in a 31 bit integer
136  << "The RanecuEngine seeds should be in the range 0 to 2147483647.\n"
137  << "The seeds passed to the RandomNumberGenerationService from the\n"
138  "configuration file were " << initialSeedSet[0] << " and " << initialSeedSet[1]
139  << "\nThis was for the module with label \"" << *it << "\".\n";
140  }
141  long int seedL[2];
142  seedL[0] = static_cast<long int>(initialSeedSet[0]);
143  seedL[1] = static_cast<long int>(initialSeedSet[1]);
144  engine->setSeeds(seedL, 0);
145  }
146  // For the other engines, one seed is required
147  else {
148  if(initialSeedSet.size() != 1U) {
150  << "Random engines of type \"HepJamesRandom\" and \"TRandom3\n"
151  << "require exactly 1 seed be specified in the configuration.\n"
152  << "There were " << initialSeedSet.size() << " seeds set for the\n"
153  << "module with label \"" << *it << "\".\n" ;
154  }
155  long int seedL = static_cast<long int>(initialSeedSet[0]);
156 
157  if(engineName == "HepJamesRandom") {
158  if(initialSeedSet[0] > maxSeedHepJames) {
160  << "The CLHEP::HepJamesRandom engine seed should be in the range 0 to 900000000.\n"
161  << "The seed passed to the RandomNumberGenerationService from the\n"
162  "configuration file was " << initialSeedSet[0] << ". This was for \n"
163  << "the module with label " << *it << ".\n";
164  }
165  boost::shared_ptr<CLHEP::HepRandomEngine> engine(new CLHEP::HepJamesRandom(seedL));
166  engineMap_[*it] = engine;
167  } else if(engineName == "TRandom3") {
168 
169  // There is a dangerous conversion from uint32_t to long
170  // that occurs above. In the next 2 lines we check the
171  // behavior is what we need for the service to work
172  // properly. This conversion is forced on us by the
173  // CLHEP and ROOT interfaces. If the assert ever starts
174  // to fail we will have to come up with a way to deal
175  // with this.
176  uint32_t seedu32 = static_cast<uint32_t>(seedL);
177  assert(initialSeedSet[0] == seedu32);
178 
179  boost::shared_ptr<CLHEP::HepRandomEngine> engine(new TRandomAdaptor(seedL));
180  engineMap_[*it] = engine;
181  } else {
183  << "The random engine name, \"" << engineName
184  << "\", does not correspond to a supported engine.\n"
185  << "This engine was configured for the module with label \"" << *it << "\"";
186  }
187  }
188  }
189 
191 
194 
197 
200 
203 
206 
209 
212 
215 
217 
218  // the default for the stack is to point to the 'end' of our map which is used to define not set
219  engineStack_.push_back(engineMap_.end());
220  currentEngine_ = engineMap_.end();
221 
222  labelStack_.push_back(std::string());
224  }
225 
227  }
228 
229  CLHEP::HepRandomEngine&
231 
232  if(currentEngine_ == engineMap_.end()) {
233  if(currentLabel_ != std::string()) {
235  << "The module with label \""
236  << currentLabel_
237  << "\" requested a random number engine from the \n"
238  "RandomNumberGeneratorService, but that module was not configured\n"
239  "for random numbers. An engine is created only if a seed(s) is provided\n"
240  "in the configuration file. Please add the following PSet to the\n"
241  "configuration file for the RandomNumberGeneratorService:\n\n"
242  " " << currentLabel_ << " = cms.PSet(\n"
243  " initialSeed = cms.untracked.uint32(your_seed),\n"
244  " engineName = cms.untracked.string('TRandom3')\n"
245  " )\n"
246  "where you replace \"your_seed\" with a number and add a comma if necessary\n"
247  "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
248  } else {
250  << "Requested a random number engine from the RandomNumberGeneratorService\n"
251  "when no module was active. This is not supposed to be possible.\n"
252  "Please inform the edm developers about this. It would be helpful to\n"
253  "know the stack. If a source was requesting a random engine this could\n"
254  "happen. Sources are not supposed to be doing that anymore.\n";
255  }
256  }
257  return *(currentEngine_->second);
258  }
259 
260  uint32_t
262 
263  std::map<std::string, VUint32>::const_iterator iter;
264  iter = seedMap_.find(currentLabel_);
265 
266  if(iter == seedMap_.end()) {
267  if(currentLabel_ != std::string()) {
269  << "The module with label \""
270  << currentLabel_
271  << "\" requested a random number seed from the \n"
272  "RandomNumberGeneratorService, but that module was not configured\n"
273  "for random numbers. An engine is created only if a seed(s) is provided\n"
274  "in the configuration file. Please add the following PSet to the\n"
275  "configuration file for the RandomNumberGeneratorService:\n\n"
276  " " << currentLabel_ << " = cms.PSet(\n"
277  " initialSeed = cms.untracked.uint32(your_seed),\n"
278  " engineName = cms.untracked.string('TRandom3')\n"
279  " )\n"
280  "where you replace \"your_seed\" with a number and add a comma if necessary\n"
281  "The \"engineName\" parameter is optional. If absent the default is \"HepJamesRandom\".\n";
282  } else {
284  << "Requested a random number seed from the RandomNumberGeneratorService\n"
285  "when no module was active. This is not supposed to be possible.\n"
286  "Please inform the edm developers about this. It would be helpful to\n"
287  "know the stack. If a source was requesting a random engine this could\n"
288  "happen. Sources are not supposed to be doing that anymore.\n";
289  }
290  }
291  return iter->second[0];
292  }
293 
294  void
297 
299  edm::InputTag emptyInputTag("", "", "");
300 
301  desc.addNode( edm::ParameterDescription<edm::InputTag>("restoreStateTag", emptyInputTag, false) xor
302  edm::ParameterDescription<std::string>("restoreStateLabel", emptyString, false) );
303 
304  desc.addUntracked<std::string>("saveFileName", emptyString);
305  desc.addUntracked<std::string>("restoreFileName", emptyString);
306  desc.addUntracked<bool>("enableChecking", false);
307  desc.addUntracked<unsigned>("eventSeedOffset", 0U);
308 
310  val.addOptionalUntracked<uint32_t>("initialSeed");
311  val.addOptionalUntracked<std::vector<uint32_t> >("initialSeedSet");
312  val.addOptionalUntracked<std::string>("engineName");
313 
315  wnode.setComment("The name of each ParameterSet will be the associated module label.");
316  desc.addNode(wnode);
317 
318  descriptions.add("RandomNumberGeneratorService", desc);
319  }
320 
321  void
322  RandomNumberGeneratorService::postForkReacquireResources(unsigned childIndex, unsigned /*kMaxChildren*/) {
323  childIndex_ = childIndex;
324 
325  if(!saveFileName_.empty()) {
326  std::ostringstream suffix;
327  suffix << "_" << childIndex;
328  saveFileName_ += suffix.str();
329  }
330  }
331 
332  // The next three functions contain the complex logic
333  // such that things occur in the proper sequence to be
334  // able to save and restore the states.
335 
336  void
338 
339  if(firstLumi_) {
340  // copy state from engines to lumi cache
342 
343  if(!restoreFileName_.empty()) {
344  // copy state from text file to lumi cache
346  }
347  } else {
349  }
350 
351  // copy state from LuminosityBlock to lumi cache
352  if(!restoreStateTag_.label().empty()) {
354  }
355 
356  if(!firstLumi_ || !restoreFileName_.empty() || !restoreStateTag_.label().empty()) {
357  // copy state from lumi cache to engines
359  }
360  }
361 
362  // During the beginLumi processing the producer will copy the
363  // the lumi cache to a product if the producer was scheduled
364  // in a path in the configuration
365 
366  void
368 
369  if(firstLumi_) {
370  // reset state with new seeds based on child index
372  if(!restoreFileName_.empty()) {
374  // copy state from text file to event cache
376  }
377  }
378  if(!firstLumi_ || !restoreFileName_.empty()) {
379  // copy state from event cache to engines
381  }
382  firstLumi_ = false;
383  }
384 
385  void
387  // copy from Event to event cache
388  if(!restoreStateTag_.label().empty()) {
390  readFromEvent(event);
391 
392  // copy from event cache to engines
394  } else {
395  // copy from engines to event cache
397  }
398  // if requested write text file from both caches
399  if(!saveFileName_.empty()) {
401  if(!saveFileNameRecorded_) {
403  Service<JobReport> reportSvc;
404  reportSvc->reportRandomStateFile(fullName);
405  saveFileNameRecorded_ = true;
406  }
407  }
408  }
409 
410  // During the event processing the producer will copy the
411  // the event cache to a product if the producer was scheduled
412  // in a path in the configuration
413 
414  void
416  push(description.moduleLabel());
417  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
418  engineStateStack_.push_back(currentEngine_->second->put());
419  }
420  }
421 
422  void
424  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
425  if(engineStateStack_.back() != currentEngine_->second->put()) {
427  << "It is illegal to generate random numbers during module construction because \n"
428  "that makes it very difficult to reproduce the processing of individual\n"
429  "events. Random numbers were generated during module construction for the module with\n"
430  "class name \"" << description.moduleName() << "\"\n"
431  "and module label \"" << description.moduleLabel() << "\"\n";
432  }
433  engineStateStack_.pop_back();
434  }
435  pop();
436  }
437 
438  void
440  push(description.moduleLabel());
441  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
442  engineStateStack_.push_back(currentEngine_->second->put());
443  }
444  }
445 
446  void
448  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
449  if(engineStateStack_.back() != currentEngine_->second->put()) {
451  << "It is illegal to generate random numbers during beginJob because \n"
452  "that makes it very difficult to reproduce the processing of individual\n"
453  "events. Random numbers were generated during beginJob for the module with\n"
454  "class name \"" << description.moduleName() << "\"\n"
455  "and module label \"" << description.moduleLabel() << "\"\n";
456  }
457  engineStateStack_.pop_back();
458  }
459  pop();
460  }
461 
462  void
464  push(description.moduleLabel());
465  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
466  engineStateStack_.push_back(currentEngine_->second->put());
467  }
468  }
469 
470  void
472  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
473  if(engineStateStack_.back() != currentEngine_->second->put()) {
475  << "It is illegal to generate random numbers during beginRun because \n"
476  "that makes it very difficult to reproduce the processing of individual\n"
477  "events. Random numbers were generated during beginRun for the module with\n"
478  "class name \"" << description.moduleName() << "\"\n"
479  "and module label \"" << description.moduleLabel() << "\"\n";
480  }
481  engineStateStack_.pop_back();
482  }
483  pop();
484  }
485 
486  void
488  push(description.moduleLabel());
489  }
490 
491  void
493  pop();
494  }
495 
496  void
498  push(description.moduleLabel());
499  }
500 
501  void
503  pop();
504  }
505 
506  void
508  push(description.moduleLabel());
509  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
510  engineStateStack_.push_back(currentEngine_->second->put());
511  }
512  }
513 
514  void
516  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
517  if(engineStateStack_.back() != currentEngine_->second->put()) {
519  << "It is illegal to generate random numbers during endLumi because \n"
520  "that makes it very difficult to reproduce the processing of individual\n"
521  "events. Random numbers were generated during endLumi for the module with\n"
522  "class name \"" << description.moduleName() << "\"\n"
523  "and module label \"" << description.moduleLabel() << "\"\n";
524  }
525  engineStateStack_.pop_back();
526  }
527  pop();
528  }
529 
530  void
532  push(description.moduleLabel());
533  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
534  engineStateStack_.push_back(currentEngine_->second->put());
535  }
536  }
537 
538  void
540  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
541  if(engineStateStack_.back() != currentEngine_->second->put()) {
543  << "It is illegal to generate random numbers during endRun because \n"
544  "that makes it very difficult to reproduce the processing of individual\n"
545  "events. Random numbers were generated during endRun for the module with\n"
546  "class name \"" << description.moduleName() << "\"\n"
547  "and module label \"" << description.moduleLabel() << "\"\n";
548  }
549  engineStateStack_.pop_back();
550  }
551  pop();
552  }
553 
554  void
556  push(description.moduleLabel());
557  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
558  engineStateStack_.push_back(currentEngine_->second->put());
559  }
560  }
561 
562  void
564  if(enableChecking_ && currentEngine_ != engineMap_.end()) {
565  if(engineStateStack_.back() != currentEngine_->second->put()) {
567  << "It is illegal to generate random numbers during endJob because \n"
568  "that makes it very difficult to reproduce the processing of individual\n"
569  "events. Random numbers were generated during endJob for the module with\n"
570  "class name \"" << description.moduleName() << "\"\n"
571  "and module label \"" << description.moduleLabel() << "\"\n";
572  }
573  engineStateStack_.pop_back();
574  }
575  pop();
576  }
577 
578  std::vector<RandomEngineState> const&
580  return lumiCache_;
581  }
582 
583  std::vector<RandomEngineState> const&
585  return eventCache_;
586  }
587 
588  void
590  std::cout << "\n\nRandomNumberGeneratorService dump\n\n";
591 
592  std::cout << " Contents of seedMap\n";
593  for(std::map<std::string, std::vector<uint32_t> >::const_iterator iter = seedMap_.begin();
594  iter != seedMap_.end();
595  ++iter) {
596  std::cout << " " << iter->first;
597  std::vector<uint32_t> seeds = iter->second;
598  for(std::vector<uint32_t>::const_iterator vIter = seeds.begin();
599  vIter != seeds.end();
600  ++vIter) {
601  std::cout << " " << *vIter;
602  }
603  std::cout << "\n";
604  }
605  std::cout << "\n Contents of engineNameMap\n";
606  for(std::map<std::string, std::string>::const_iterator iter = engineNameMap_.begin();
607  iter != engineNameMap_.end();
608  ++iter) {
609  std::cout << " " << iter->first << " " << iter->second << "\n";
610  }
611  std::cout << "\n Contents of engineMap\n";
612  for(EngineMap::const_iterator iter = engineMap_.begin();
613  iter != engineMap_.end();
614  ++iter) {
615  std::cout << " " << iter->first
616  << " " << iter->second->name() << " ";
617  if(iter->second->name() == std::string("HepJamesRandom")) {
618  std::cout << iter->second->getSeed();
619  } else {
620  std::cout << "Engine does not know original seed";
621  }
622  std::cout << "\n";
623  }
624  std::cout << "\n";
625  std::cout << " currentLabel_ = " << currentLabel_ << "\n";
626  std::cout << " labelStack_ size = " << labelStack_.size() << "\n";
627  int i = 0;
628  for(VString::const_iterator iter = labelStack_.begin();
629  iter != labelStack_.end();
630  ++iter, ++i) {
631  std::cout << " " << i << " " << *iter << "\n";
632  }
633  if(currentEngine_ == engineMap_.end()) {
634  std::cout << " currentEngine points to end\n";
635  } else {
636  std::cout << " currentEngine_ = " << currentEngine_->first
637  << " " << currentEngine_->second->name()
638  << " " << currentEngine_->second->getSeed() << "\n";
639  }
640 
641  std::cout << " engineStack_ size = " << engineStack_.size() << "\n";
642  i = 0;
643  for(std::vector<EngineMap::const_iterator>::const_iterator iter = engineStack_.begin();
644  iter != engineStack_.end();
645  ++iter, ++i) {
646  if(*iter == engineMap_.end()) {
647  std::cout << " " << i << " Points to end of engine map\n";
648  } else {
649  std::cout << " " << i << " " << (*iter)->first
650  << " " << (*iter)->second->name() << " " << (*iter)->second->getSeed() << "\n";
651  }
652  }
653 
654  std::cout << " restoreStateTag_ = " << restoreStateTag_ << "\n";
655  std::cout << " saveFileName_ = " << saveFileName_ << "\n";
656  std::cout << " restoreFileName_ = " << restoreFileName_ << "\n";
657  }
658 
659  void
661  currentEngine_ = engineMap_.find(iLabel);
662  engineStack_.push_back(currentEngine_);
663 
664  labelStack_.push_back(iLabel);
665  currentLabel_ = iLabel;
666  }
667 
668  void
670  engineStack_.pop_back();
671  //NOTE: algorithm is such that we always have at least one item in the stacks
672  currentEngine_ = engineStack_.back();
673  labelStack_.pop_back();
674  currentLabel_ = labelStack_.back();
675  }
676 
677  void
679 
681  if(tns.isAvailable()) {
682  if(tns->getProcessName() == restoreStateTag_.process()) {
684  << "In the configuration for the RandomNumberGeneratorService the\n"
685  << "restoreStateTag contains the current process which is illegal.\n"
686  << "The process name in the replay process should have been changed\n"
687  << "to be different than the original process name and the restoreStateTag\n"
688  << "should contain either the original process name or an empty process name.\n";
689  }
690  }
691 
694 
695  if(!states.isValid()) {
697  return;
698  }
700  states->getRandomEngineStates(lumiCache_);
701  }
702 
703  void
705 
707 
708  event.getByLabel(restoreStateTag_, states);
709 
710  if(!states.isValid()) {
712  return;
713  } else {
715  << "The RandomNumberGeneratorService is trying to restore\n"
716  << "the state of the random engines by reading a product from\n"
717  << "the Event with input tag \"" << restoreStateTag_ << "\". It\n"
718  << "fails to find one. The label used in the request for the product\n"
719  << "is set in the configuration. It is probably set to the wrong value\n"
720  << "in the configuration file. It must match the module label\n"
721  << "of the RandomEngineStateProducer that created the product in\n"
722  << "a previous process\n";
723  }
724  }
727  << "The RandomNumberGeneratorService is trying to restore\n"
728  << "the state of the random engines by reading a product from\n"
729  << "the Event and LuminosityBlock with input tag \"" << restoreStateTag_ << "\".\n"
730  << "It found the product in the Event but not the one in the LuminosityBlock.\n"
731  << "Either the product in the LuminosityBlock was dropped or\n"
732  << "there is a bug somewhere\n";
733  }
734  states->getRandomEngineStates(eventCache_);
735  }
736 
737  bool
739 
741 
742  event.getByLabel(restoreStateTag_, states);
743  if(!states.isValid()) {
744  return false;
745  }
746  for(std::vector<RandomEngineState>::const_iterator state = states->begin(),
747  iEnd = states->end();
748  state != iEnd; ++state) {
749 
750  std::vector<RandomEngineState>::iterator cachedState =
751  std::lower_bound(eventCache_.begin(), eventCache_.end(), *state);
752 
753 
754  if(cachedState != eventCache_.end() && cachedState->getLabel() == state->getLabel()) {
755  if(cachedState->getSeed().size() != state->getSeed().size() ||
756  cachedState->getState().size() != state->getState().size()) {
758  << "In function RandomNumberGeneratorService::backwardCompatibilityRead.\n"
759  << "When attempting to replay processing with the RandomNumberGeneratorService,\n"
760  << "the engine type for each module must be the same in the replay configuration\n"
761  << "and the original configuration. If this is not the problem, then the data\n"
762  << "is somehow corrupted or there is a bug because the vector in the data containing\n"
763  << "the seeds or engine state is the incorrect size for the type of random engine.\n";
764  }
765  cachedState->setSeed(state->getSeed());
766  cachedState->setState(state->getState());
767  }
768  }
769  return true;
770  }
771 
772  void
773  RandomNumberGeneratorService::snapShot(std::vector<RandomEngineState>& cache) {
774  cache.resize(engineMap_.size());
775  std::vector<RandomEngineState>::iterator state = cache.begin();
776 
777  for(EngineMap::const_iterator iter = engineMap_.begin();
778  iter != engineMap_.end();
779  ++iter, ++state) {
780 
781  state->setLabel(iter->first);
782  state->setSeed(seedMap_[iter->first]);
783 
784  std::vector<unsigned long> stateL = iter->second->put();
785  state->clearStateVector();
786  state->reserveStateVector(stateL.size());
787  for(std::vector<unsigned long>::const_iterator vIter = stateL.begin();
788  vIter != stateL.end();
789  ++vIter) {
790  state->push_back_stateVector(static_cast<uint32_t>(*vIter));
791  }
792  }
793  }
794 
795  void
796  RandomNumberGeneratorService::restoreFromCache(std::vector<RandomEngineState> const& cache) {
797  for(std::vector<RandomEngineState>::const_iterator iter = cache.begin(),
798  iEnd = cache.end();
799  iter != iEnd; ++iter) {
800 
801  std::string const& engineLabel = iter->getLabel();
802 
803  std::vector<uint32_t> const& engineState = iter->getState();
804  std::vector<unsigned long> engineStateL;
805  for(std::vector<uint32_t>::const_iterator iVal = engineState.begin(),
806  theEnd = engineState.end();
807  iVal != theEnd; ++iVal) {
808  engineStateL.push_back(static_cast<unsigned long>(*iVal));
809  }
810 
811  std::vector<uint32_t> const& engineSeeds = iter->getSeed();
812  std::vector<long> engineSeedsL;
813  for(std::vector<uint32_t>::const_iterator iVal = engineSeeds.begin(),
814  theEnd = engineSeeds.end();
815  iVal != theEnd;
816  ++iVal) {
817  long seedL = static_cast<long>(*iVal);
818  engineSeedsL.push_back(seedL);
819 
820  // There is a dangerous conversion from uint32_t to long
821  // that occurs above. In the next 2 lines we check the
822  // behavior is what we need for the service to work
823  // properly. This conversion is forced on us by the
824  // CLHEP and ROOT interfaces. If the assert ever starts
825  // to fail we will have to come up with a way to deal
826  // with this.
827  uint32_t seedu32 = static_cast<uint32_t>(seedL);
828  assert(*iVal == seedu32);
829  }
830 
831  EngineMap::iterator engine = engineMap_.find(engineLabel);
832 
833  if(engine != engineMap_.end()) {
834 
835  seedMap_[engineLabel] = engineSeeds;
836 
837  // We need to handle each type of engine differently because each
838  // has different requirements on the seed or seeds.
839  if(engineStateL[0] == CLHEP::engineIDulong<CLHEP::HepJamesRandom>()) {
840 
841  checkEngineType(engine->second->name(), std::string("HepJamesRandom"), engineLabel);
842 
843  // These two lines actually restore the seed and engine state.
844  engine->second->setSeed(engineSeedsL[0], 0);
845  engine->second->get(engineStateL);
846  } else if(engineStateL[0] == CLHEP::engineIDulong<CLHEP::RanecuEngine>()) {
847 
848  checkEngineType(engine->second->name(), std::string("RanecuEngine"), engineLabel);
849 
850  // This line actually restores the engine state.
851  engine->second->get(engineStateL);
852  } else if(engineStateL[0] == CLHEP::engineIDulong<TRandomAdaptor>()) {
853 
854  checkEngineType(engine->second->name(), std::string("TRandom3"), engineLabel);
855 
856  // This line actually restores the engine state.
857  engine->second->setSeed(engineSeedsL[0], 0);
858  engine->second->get(engineStateL);
859  } else {
860  // This should not be possible because this code should be able to restore
861  // any kind of engine whose state can be saved.
863  << "The RandomNumberGeneratorService is trying to restore the state\n"
864  "of the random engines. The state in the event indicates an engine\n"
865  "of an unknown type. This should not be possible unless you are\n"
866  "running with an old code release on a new file that was created\n"
867  "with a newer release which had new engine types added. In this case\n"
868  "the only solution is to use a newer release. In any other case, notify\n"
869  "the EDM developers because this should not be possible\n";
870  }
871  }
872  }
873  }
874 
875  void
877  std::string const& typeFromEvent,
878  std::string const& engineLabel) {
879  if(typeFromConfig != typeFromEvent) {
881  << "The RandomNumberGeneratorService is trying to restore\n"
882  << "the state of the random engine for the module \""
883  << engineLabel << "\". An\n"
884  << "error was detected because the type of the engine in the\n"
885  << "input file and the configuration file do not match.\n"
886  << "In the configuration file the type is \"" << typeFromConfig
887  << "\".\nIn the input file the type is \"" << typeFromEvent << "\". If\n"
888  << "you are not generating any random numbers in this module, then\n"
889  << "remove the line in the configuration file that gives it\n"
890  << "a seed and the error will go away. Otherwise, you must give\n"
891  << "this module the same engine type in the configuration file or\n"
892  << "stop trying to restore the random engine state.\n";
893  }
894  }
895 
896  void
898  if(!outFile_.is_open()) {
899  outFile_.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
900  }
901  if(!outFile_) {
903  << "Unable to open the file \""
904  << fileName << "\" to save the state of the random engines.\n";
905  }
906  outFile_.seekp(0, std::ios_base::beg);
907  outFile_ << "<RandomEngineStates>\n";
908 
909  outFile_ << "<Event>\n";
911  outFile_ << "</Event>\n" ;
912 
913  outFile_ << "<Lumi>\n";
915  outFile_ << "</Lumi>\n" ;
916 
917  outFile_ << "</RandomEngineStates>\n" ;
918  outFile_.flush();
919  }
920 
921  void
922  RandomNumberGeneratorService::writeStates(std::vector<RandomEngineState> const& v,
923  std::ofstream& outFile) {
924  for(std::vector<RandomEngineState>::const_iterator iter = v.begin(),
925  iEnd = v.end();
926  iter != iEnd; ++iter) {
927 
928  std::vector<uint32_t> const& seedVector = iter->getSeed();
929  std::vector<uint32_t>::size_type seedVectorLength = seedVector.size();
930 
931  std::vector<uint32_t> const& stateVector = iter->getState();
932  std::vector<uint32_t>::size_type stateVectorLength = stateVector.size();
933 
934  outFile << "<ModuleLabel>\n" << iter->getLabel() << "\n</ModuleLabel>\n";
935 
936  outFile << "<SeedLength>\n" << seedVectorLength << "\n</SeedLength>\n" ;
937  outFile << "<InitialSeeds>\n";
938  writeVector(seedVector, outFile);
939  outFile << "</InitialSeeds>\n";
940  outFile << "<FullStateLength>\n" << stateVectorLength << "\n</FullStateLength>\n";
941  outFile << "<FullState>\n";
942  writeVector(stateVector, outFile);
943  outFile << "</FullState>\n";
944  }
945  }
946 
947  void
949  std::ofstream& outFile) {
950  if(v.empty()) return;
951  size_t numItems = v.size();
952  for(size_t i = 0; i < numItems; ++i) {
953  if(i != 0 && i % 10 == 0) outFile << "\n";
954  outFile << std::setw(13) << v[i];
955  }
956  outFile << "\n";
957  }
958 
960  char directory[1500];
961  std::string fullName(getcwd(directory, sizeof(directory)) ? directory : "/PathIsTooBig");
962  fullName += "/" + saveFileName_;
963  return fullName;
964  }
965 
966  void
968  std::string whichStates("<Event>");
969  readStatesFromFile(fileName, eventCache_, whichStates);
970  }
971 
972  void
974  std::string whichStates("<Lumi>");
975  readStatesFromFile(fileName, lumiCache_, whichStates);
976  }
977 
978 
979  void
981  std::vector<RandomEngineState>& cache,
982  std::string const& whichStates) {
983  std::ifstream inFile;
984  inFile.open(fileName.c_str(), std::ifstream::in);
985  if(!inFile) {
987  << "Unable to open the file \""
988  << fileName << "\" to restore the random engine states.\n";
989  }
990 
992  inFile >> text;
993  if(!inFile.good() || text != std::string("<RandomEngineStates>")) {
995  << "Attempting to read file with random number engine states.\n"
996  << "File \"" << restoreFileName_
997  << "\" is ill-structured or otherwise corrupted.\n"
998  << "Cannot read the file header word.\n";
999  }
1000  bool saveToCache = false;
1001  while(readEngineState(inFile, cache, whichStates, saveToCache)) {}
1002  }
1003 
1005  std::vector<RandomEngineState>& cache,
1006  std::string const& whichStates,
1007  bool& saveToCache) {
1008  std::string leading;
1009  std::string trailing;
1010  std::string moduleLabel;
1011  std::vector<uint32_t>::size_type seedVectorSize;
1012  std::vector<uint32_t> seedVector;
1013  std::vector<uint32_t>::size_type stateVectorSize;
1014  std::vector<uint32_t> stateVector;
1015 
1016  // First we need to look for the special strings
1017  // that mark the end of the file and beginning and
1018  // and end of the data for different sections.
1019 
1020  is >> leading;
1021  if(!is.good()) {
1023  << "File \"" << restoreFileName_
1024  << "\" is ill-structured or otherwise corrupted.\n"
1025  << "Cannot read next field and did not hit the end yet.\n";
1026  }
1027 
1028  // This marks the end of the file. We are done.
1029  if(leading == std::string("</RandomEngineStates>")) return false;
1030 
1031  // This marks the end of a section of the data
1032  if(leading == std::string("</Event>") ||
1033  leading == std::string("</Lumi>")) {
1034  saveToCache = false;
1035  return true;
1036  }
1037 
1038  // This marks the beginning of a section
1039  if(leading == std::string("<Event>") ||
1040  leading == std::string("<Lumi>")) {
1041  saveToCache = (leading == whichStates);
1042  return true;
1043  }
1044 
1045  // Process the next engine state
1046 
1047  is >> moduleLabel >> trailing;
1048  if(!is.good() ||
1049  leading != std::string("<ModuleLabel>") ||
1050  trailing != std::string("</ModuleLabel>")) {
1052  << "File \"" << restoreFileName_
1053  << "\" is ill-structured or otherwise corrupted.\n"
1054  << "Cannot read a module label when restoring random engine states.\n";
1055  }
1056 
1057  is >> leading >> seedVectorSize >> trailing;
1058  if(!is.good() ||
1059  leading != std::string("<SeedLength>") ||
1060  trailing != std::string("</SeedLength>")) {
1062  << "File \"" << restoreFileName_
1063  << "\" is ill-structured or otherwise corrupted.\n"
1064  << "Cannot read seed vector length when restoring random engine states.\n";
1065  }
1066 
1067  is >> leading;
1068  if(!is.good() ||
1069  leading != std::string("<InitialSeeds>")) {
1071  << "File \"" << restoreFileName_
1072  << "\" is ill-structured or otherwise corrupted.\n"
1073  << "Cannot read beginning of InitialSeeds when restoring random engine states.\n";
1074  }
1075 
1076  if(seedVectorSize > maxSeeds) {
1078  << "File \"" << restoreFileName_
1079  << "\" is ill-structured or otherwise corrupted.\n"
1080  << "The number of seeds exceeds 64K.\n";
1081  }
1082 
1083  readVector(is, seedVectorSize, seedVector);
1084 
1085  is >> trailing;
1086  if(!is.good() ||
1087  trailing != std::string("</InitialSeeds>")) {
1089  << "File \"" << restoreFileName_
1090  << "\" is ill-structured or otherwise corrupted.\n"
1091  << "Cannot read end of InitialSeeds when restoring random engine states.\n";
1092  }
1093 
1094  is >> leading >> stateVectorSize >> trailing;
1095  if(!is.good() ||
1096  leading != std::string("<FullStateLength>") ||
1097  trailing != std::string("</FullStateLength>")) {
1099  << "File \"" << restoreFileName_
1100  << "\" is ill-structured or otherwise corrupted.\n"
1101  << "Cannot read state vector length when restoring random engine states.\n";
1102  }
1103 
1104  is >> leading;
1105  if(!is.good() ||
1106  leading != std::string("<FullState>")) {
1108  << "File \"" << restoreFileName_
1109  << "\" is ill-structured or otherwise corrupted.\n"
1110  << "Cannot read beginning of FullState when restoring random engine states.\n";
1111  }
1112 
1113  if(stateVectorSize > maxStates) {
1115  << "File \"" << restoreFileName_
1116  << "\" is ill-structured or otherwise corrupted.\n"
1117  << "The number of states exceeds 64K.\n";
1118  }
1119 
1120  readVector(is, stateVectorSize, stateVector);
1121 
1122  is >> trailing;
1123  if(!is.good() ||
1124  trailing != std::string("</FullState>")) {
1126  << "File \"" << restoreFileName_
1127  << "\" is ill-structured or otherwise corrupted.\n"
1128  << "Cannot read end of FullState when restoring random engine states.\n";
1129  }
1130 
1131  if(saveToCache) {
1132  RandomEngineState randomEngineState;
1133  randomEngineState.setLabel(moduleLabel);
1134  std::vector<RandomEngineState>::iterator state =
1135  std::lower_bound(cache.begin(), cache.end(), randomEngineState);
1136 
1137  if(state != cache.end() && moduleLabel == state->getLabel()) {
1138  if(seedVector.size() != state->getSeed().size() ||
1139  stateVector.size() != state->getState().size()) {
1141  << "File \"" << restoreFileName_
1142  << "\" is ill-structured or otherwise corrupted.\n"
1143  << "Vectors containing engine state are the incorrect size for the type of random engine.\n";
1144  }
1145  state->setSeed(seedVector);
1146  state->setState(stateVector);
1147  }
1148  }
1149  return true;
1150  }
1151 
1152  void
1153  RandomNumberGeneratorService::readVector(std::istream& is, unsigned numItems, std::vector<uint32_t>& v) {
1154  v.clear();
1155  v.reserve(numItems);
1156  uint32_t data;
1157  for(unsigned i = 0; i < numItems; ++i) {
1158  is >> data;
1159  if(!is.good()) {
1161  << "File \"" << restoreFileName_
1162  << "\" is ill-structured or otherwise corrupted.\n"
1163  << "Cannot read vector when restoring random engine states.\n";
1164  }
1165  v.push_back(data);
1166  }
1167  }
1168 
1169  void
1171 
1172  if(childIndex_ == 0U && eventSeedOffset_ == 0U) return;
1173 
1174  for(EngineMap::const_iterator iter = engineMap_.begin();
1175  iter != engineMap_.end();
1176  ++iter) {
1177 
1178  uint32_t offset1 = childIndex_;
1179  uint32_t offset2 = eventSeedOffset_;
1180 
1181  std::string const& moduleLabel = iter->first;
1182  std::string const& engineName = engineNameMap_[moduleLabel];
1183  VUint32& seeds = seedMap_[moduleLabel];
1184 
1185  if(engineName == std::string("RanecuEngine")) {
1186  assert(seeds.size() == 2U);
1187  // Wrap around if the offsets push the seed over the maximum allowed value
1188  uint32_t mod = maxSeedRanecu + 1U;
1189  offset1 = offset1 % mod;
1190  offset2 = offset2 % mod;
1191  seeds[0] = (seeds[0] + offset1) % mod;
1192  seeds[0] = (seeds[0] + offset2) % mod;
1193  long int seedL[2];
1194  seedL[0] = static_cast<long int>(seeds[0]);
1195  seedL[1] = static_cast<long int>(seeds[1]);
1196  iter->second->setSeeds(seedL,0);
1197  } else {
1198  assert(seeds.size() == 1U);
1199 
1200  if(engineName == "HepJamesRandom") {
1201  // Wrap around if the offsets push the seed over the maximum allowed value
1202  uint32_t mod = maxSeedHepJames + 1U;
1203  offset1 = offset1 % mod;
1204  offset2 = offset2 % mod;
1205  seeds[0] = (seeds[0] + offset1) % mod;
1206  seeds[0] = (seeds[0] + offset2) % mod;
1207 
1208  long int seedL = static_cast<long int>(seeds[0]);
1209  iter->second->setSeed(seedL, 0);
1210  } else {
1211  assert(engineName == "TRandom3");
1212  // Wrap around if the offsets push the seed over the maximum allowed value
1213  // We have to be extra careful with this one because it may also go beyond
1214  // the values 32 bits can hold
1215  uint32_t max32 = maxSeedTRandom3;
1216  if((max32 - seeds[0]) >= offset1) {
1217  seeds[0] = seeds[0] + offset1;
1218  } else {
1219  seeds[0] = offset1 - (max32 - seeds[0]) - 1U;
1220  }
1221  if((max32 - seeds[0]) >= offset2) {
1222  seeds[0] = seeds[0] + offset2;
1223  } else {
1224  seeds[0] = offset2 - (max32 - seeds[0]) - 1U;
1225  }
1226  long seedL = static_cast<long>(seeds[0]);
1227 
1228  // There is a dangerous conversion from uint32_t to long
1229  // that occurs above. In the next 2 lines we check the
1230  // behavior is what we need for the service to work
1231  // properly. This conversion is forced on us by the
1232  // CLHEP and ROOT interfaces. If the assert ever starts
1233  // to fail we will have to come up with a way to deal
1234  // with this.
1235  uint32_t seedu32 = static_cast<uint32_t>(seedL);
1236  assert(seeds[0] == seedu32);
1237 
1238  iter->second->setSeed(seedL, 0);
1239  }
1240  }
1241  }
1242  }
1243  }
1244 }
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)
void preModuleBeginLumi(ModuleDescription const &description)
std::vector< std::string > getParameterNamesForType(bool trackiness=true) const
Definition: ParameterSet.h:192
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.
static const std::string kSkipCurrentProcess
Definition: InputTag.h:56
void watchPostModuleEndRun(PostModuleEndRun::slot_type const &iSlot)
bool isAvailable() const
Definition: Service.h:46
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)
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)
volatile std::atomic< bool > shutdown_flag false
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)