Belle II Software development
RandomGenerator.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 "framework/core/RandomGenerator.h"
10#include "framework/utilities/sha3hash/Hash.h"
11#include "framework/logging/Logger.h"
12#include "framework/datastore/StoreObjPtr.h"
13#include "framework/dataobjects/EventMetaData.h"
14#include <sstream>
15#include <iomanip>
16#include <algorithm>
17
18using namespace Belle2;
19
20namespace {
25 template<class T> void addValueToBuffer(std::vector<unsigned char>& buffer, const T& value)
26 {
27 static_assert(std::is_integral<T>::value, "integral type required");
28 constexpr int bytes = sizeof(T);
29 for (int i = bytes - 1; i >= 0; --i) {
30 buffer.push_back((value >> (i * 8)) & 0xFF);
31 }
32 }
33};
34
35RandomGenerator::RandomGenerator(const std::string& name): TRandom(), m_state{0}, m_index(0), m_barrier(0),
36 m_mode(c_independent)
37{
38 SetName(name.c_str());
39 SetTitle("Belle2 Random Generator");
40}
41
42void RandomGenerator::setSeed(const unsigned char* seed, unsigned int n)
43{
44 //Copy the seed information and set the seed length
45 m_seed.resize(n);
46 std::copy_n(seed, n, m_seed.data());
47 //reinit the state but ignore missing EventMetaInfo
48 setState(0);
49}
50
52{
53 //Reset the internal state position
54 m_index = 0;
55 //Set the barrier to the requested value
57 //Create a SHA-3 hash structrure
58 ShakeHash hash(ShakeHash::c_SHAKE256);
59 //If we have a seed info, add it to the hash
60 if (m_seed.size() > 0) hash.update(m_seed.size(), m_seed.data());
61 //Create a byte buffer to store event dependent data to feed to the hash
62 std::vector<unsigned char> buffer;
63 //estimated size of event dependent info in bytes. vector will make sure it
64 //works even if this changes but we like to avoid unnecessary relocations
65 buffer.reserve(28);
66 //add the barrier to the buffer
67 addValueToBuffer(buffer, m_barrier);
68 //do we want to use EventMetaData at all?
69 if (m_mode != c_independent) {
70 //check if we have event data
72 if (!evt) {
73 //no event data, this should not be
74 B2ERROR("No EventMetaData, cannot set state of RandomGenerator from event data");
75 } else {
76 //ok, add event data to buffer
77 addValueToBuffer(buffer, evt->getExperiment());
78 addValueToBuffer(buffer, evt->getRun());
79 // and if we are in run dependent mode add also event number to the hash
80 if (m_mode == c_eventDependent) {
81 addValueToBuffer(buffer, evt->getEvent());
82 }
83 }
84 }
85
86 hash.update(buffer.size(), buffer.data());
87 //Extract 1024bit hash from the hash structure and write it into the
88 //internal state
89 hash.getHash(sizeof(m_state), (unsigned char*) m_state);
90
91 //Only prepare debugoutput if we actually want to show it. This is almost
92 //equivalent to B2DEBUG(200, ...); but we need to loop over states for
93 //printing so we could not put it in a normal B2DEBUG statement easily.
94#ifndef LOG_NO_B2DEBUG
95 if (Belle2::LogSystem::Instance().isLevelEnabled(Belle2::LogConfig::c_Debug, 200, PACKAGENAME())) {
96 std::stringstream info;
97 info << "Random Generator '" << GetName() << "' State info:\n";
98 info << " seed (" << std::dec << m_seed.size() << "):\n ";
99 for (auto c : m_seed) { info << std::setw(2) << std::setfill('0') << std::hex << (int)c << " "; }
100 info << "\n event info (mode=" << m_mode << "): \n";
101 info << " barrier:" << std::dec << m_barrier;
102 if (m_mode != c_independent) {
104 info << " EXP:" << evt->getExperiment() << " RUN:" << evt->getRun();
105 if (m_mode == c_eventDependent) {
106 info << " EVT:" << evt->getEvent();
107 }
108 }
109 info << "\n event bytes (" << std::dec << buffer.size() << "):\n ";
110 for (auto c : buffer) { info << std::setw(2) << std::setfill('0') << std::hex << (int)c << " "; }
111 info << "\n state (index=" << m_index << "): ";
112 for (int i = 0; i < 16; ++i) {
113 info << ((i % 4 == 0) ? "\n " : " ") << std::setw(16) << std::setfill('0') << std::hex << m_state[i];
114 }
115 _B2LOGMESSAGE(Belle2::LogConfig::c_Debug, 200, info.str(), PACKAGENAME(), FUNCTIONNAME(), __FILE__, __LINE__);
116 }
117#endif
118}
119
120void RandomGenerator::RndmArray(Int_t n, unsigned char* array)
121{
122 //First we fill the array using 64bit blocks
123 RndmArray(n / sizeof(ULong64_t), (ULong64_t*)array);
124 const Int_t remainder = n % sizeof(ULong64_t);
125 //If the size is not divisible by 8 we fill the remainder from one additional
126 //random value
127 if (remainder) {
128 const ULong64_t r = random64();
129 std::copy_n((unsigned char*)&r, remainder, array + (n - remainder - 1));
130 }
131}
@ c_Debug
Debug: for code development.
Definition: LogConfig.h:26
static LogSystem & Instance()
Static method to get a reference to the LogSystem instance.
Definition: LogSystem.cc:31
void setState(int barrier)
Set the state of the random number generator.
@ c_eventDependent
Use experiment, run and event number to generate state.
@ c_independent
Don't use event info to generate state.
uint64_t m_state[16]
Internal state of the random number generator.
unsigned int m_index
currently active index in the internal state
int m_barrier
current barrier index.
EGeneratorMode m_mode
Current generator mode.
void setSeed(const unsigned char *seed, unsigned int n)
Set the seed information.
std::vector< unsigned char > m_seed
seed information
RandomGenerator(const std::string &name="Belle2 Random Generator")
Default constructor, does not initialize the generator.
void barrier()
increase the barrier index.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
uint64_t random64()
Generate one 64bit unsigned integer between 0 and UINT64_MAX (both inclusive).
void RndmArray(Int_t n, Float_t *array)
Fill an array of floats with random values in (0,1), both limits excluded.
Abstract base class for different kinds of events.