Belle II Software development
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
19using 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
44void 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
79void 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.
94 s_runRng->setBarrier(s_barrierOffset);
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.
125 s_barrierOffset = s_evtRng->getBarrier();
126}
127
129{
130 gRandom = s_evtRng;
131}
132
133//=====================================================================
134// Python API
135//=====================================================================
136
137namespace {
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(
158Set the random seed. The argument can be any object and will be converted to a
159string using the builtin str() function and will be used to initialize the
160random 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.
static bool parallelProcessingUsed()
Returns true if multiple processes have been spawned, false in single-core mode.
Fast Random number Generator using on xorshift1024* [arXiv:1402.6246].
@ 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.
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.
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.