Belle II Software  release-08-01-10
RandomNumbers.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <boost/python.hpp>
10 #include <random>
11 #include <sstream>
12 
13 #include <framework/core/RandomNumbers.h>
14 #include <framework/pcore/ProcHandler.h>
15 #include <framework/pcore/ProcHelper.h>
16 #include <framework/logging/Logger.h>
17 
18 
19 using namespace Belle2;
20 
21 
31 
33 {
34  //use std::random_device to get non deterministic initial seed to be used if
35  //user doesn't set one
36  std::random_device random_device;
37  std::stringstream seed;
38  for (int i = 0; i < 8; ++i) {
39  seed << std::hex << random_device();
40  }
41  initialize(seed.str());
42 }
43 
44 void RandomNumbers::initialize(const std::string& seed)
45 {
46  s_initialSeed = seed;
47  if (!s_evtRng) {
48  s_evtRng = new RandomGenerator("event generator");
49  }
50  if (!s_runRng) {
51  s_runRng = new RandomGenerator("independent generator");
52  }
53  auto* gen = dynamic_cast<RandomGenerator*>(gRandom);
54  if (!gen) {
55  delete gRandom;
56  B2DEBUG(100, "Replacing gRandom from " << gRandom << " to " << gen);
57  }
58  gRandom = s_evtRng;
60  s_evtRng->setSeed((const unsigned char*)seed.c_str(), seed.size());
61  s_runRng->setSeed((const unsigned char*)seed.c_str(), seed.size());
62 }
63 
65 {
66  return (s_evtRng != nullptr);
67 }
68 
70 {
71  auto* gen = dynamic_cast<RandomGenerator*>(gRandom);
72  if (!gen) {
73  B2ERROR("Random Generator gRandom is not Belle2::RandomGenerator, cannot increase barrier");
74  } else {
75  gen->barrier();
76  }
77 }
78 
79 void RandomNumbers::setSeed(const std::string& seed)
80 {
81  initialize(seed);
82  B2INFO("The random number seed is set to \"" << seed << '"');
83 }
84 
86 {
87  gRandom = s_runRng;
89  //This might be called in in main or output process. In that case we don't
90  //know how many random barriers came before but we can look at the s_evtRng
91  //as this was passed from the previous process and contains the current
92  //barrier number in the event flow. We save it in intializeEvent so let's use
93  //it now.
95 };
96 
98 {
99  gRandom = s_runRng;
101  //We set the barrier index to it's minimum possible value: usually barrier
102  //index starts at 0 but for endRun we set it to a negative number large
103  //enough that there is no realistic chance that beginRun had the same barrier
104  //index.
105  s_runRng->setBarrier(INT_MIN + s_barrierOffset);
106 }
107 
109 {
111  //we pass the random generator to other processes in multiprocessing so we only
112  //want to initialize it in the input process (or if there is no multi processing)a
113  //However on HLT we do things differently and so we need to initialize on all
114  //worker processes. So the HLT event processor can request initialization in
115  //all cases.
117  // when in event loop we want an error if there is no EventMetaData
119  s_evtRng->initialize();
120  }
121  //Ok, now we either have reset the barrier to 0 if we are an input process or
122  //have decided to keep the state from the previous process. In any case, this
123  //is the start barrier we want to use for begin/end of run processing so we
124  //keep it.
126 }
127 
129 {
130  gRandom = s_evtRng;
131 }
132 
133 //=====================================================================
134 // Python API
135 //=====================================================================
136 
137 namespace {
139  std::string pythonObjectToString(const boost::python::object& obj)
140  {
141  return boost::python::extract<std::string>(obj.attr("__str__")());
142  }
144  void setPythonSeed(const boost::python::object& obj)
145  {
146  RandomNumbers::setSeed(pythonObjectToString(obj));
147  }
148 }
149 
151 {
152  using namespace boost::python;
153 
154  //don't show c++ signature in python doc to keep it simple
155  docstring_options options(true, true, false);
156  //Expose RandomNumbers class
157  def("set_random_seed", &setPythonSeed, args("seed"), R"DOCSTRING(
158 Set the random seed. The argument can be any object and will be converted to a
159 string using the builtin str() function and will be used to initialize the
160 random generator.)DOCSTRING");
161  def("get_random_seed", &RandomNumbers::getSeed, "Return the current random seed");
162 }
static bool isInputProcess()
Return true if the process is an input process.
Definition: ProcHandler.cc:228
static bool parallelProcessingUsed()
Returns true if multiple processes have been spawned, false in single-core mode.
Definition: ProcHandler.cc:226
Fast Random number Generator using on xorshift1024* [arXiv:1402.6246].
void setBarrier(int barrierIndex)
manually set the barrier index to a fixed value
@ c_runDependent
Use experiment and run number to generate state.
@ c_eventDependent
Use experiment, run and event number to generate state.
@ c_independent
Don't use event info to generate state.
void initialize()
set the State from event meta information like experiment, run, and event number.
int getBarrier() const
obtain the currently active barrier id
void setSeed(const unsigned char *seed, unsigned int n)
Set the seed information.
void setMode(EGeneratorMode mode)
Set the generator mode.
static int s_barrierOffset
barrier index offset to be used in begin/endRun.
static void initializeEndRun()
Initialize run independent random generator for end run.
static bool isInitialized()
Truth that the random number generator has been initialized.
static RandomGenerator * s_runRng
event independent random generator to be used for begin/end run processing
static void setSeed(const std::string &seed)
Sets the seed for the random number generator.
static void initializeBeginRun()
Initialize run independent random generator for begin run.
static std::string getSeed()
Get the random number generator seed.
Definition: RandomNumbers.h:92
static void initialize()
Initialize the random number generator with a unique random seed;.
static void useEventDependent()
Set Event dependent Random Generator as current one.
static std::string s_initialSeed
The random number generator seed set by the user.
static void exposePythonAPI()
Exposes methods of the RandomNumbers class to Python.
static RandomGenerator * s_evtRng
event dependent random generator to be used for event processing
static void barrier()
Increase random barrier.
static void initializeEvent(bool force=false)
Initialize event information.
Abstract base class for different kinds of events.