Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Random.cc
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// -----------------------------------------------------------------------
4// HEP Random
5// --- HepRandom ---
6// class implementation file
7// -----------------------------------------------------------------------
8// This file is part of Geant4 (simulation toolkit for HEP).
9
10// =======================================================================
11// Gabriele Cosmo - Created: 5th September 1995
12// - Minor corrections: 31st October 1996
13// - Added methods for engine status: 19th November 1996
14// - HepRandom defined as singleton, constructors are
15// kept public for backward compatibility: 27th Feb 1998
16// - Relocated Poisson and Gauss data and simplified
17// initialisation of static generator: 5th Jan 1999
18// =======================================================================
19
21#include "CLHEP/Random/Random.h"
26
27// -----------------------------
28// Static members initialisation
29// -----------------------------
30
32
33#include <assert.h>
34#include <iostream>
35#include <type_traits>
36#include <string>
37
38namespace CLHEP {
39
40 namespace {
41
42 struct defaults {
43
44 defaults()
45 : theGenerator( &theDefaultGenerator, do_nothing_deleter() )
46 , theEngine ( &theDefaultEngine, do_nothing_deleter() )
47 { }
48
49 defaults(defaults const& other) = delete;
50 defaults const& operator=(defaults const&) = delete;
51
52 void resetEngine( HepRandomEngine * newEngine ) {
53 theEngine.reset( newEngine );
54 }
55
56 void resetEngine( HepRandomEngine & newEngine ) {
57 theEngine.reset( &newEngine, do_nothing_deleter() );
58 }
59
60 bool ensureInitialized() {
61 assert( theGenerator.get() != 0 && theEngine.get() != 0 );
62 return true;
63 }
64
65 ~defaults()
66 { }
67
68 private:
69
70 HepRandom theDefaultGenerator;
71 MixMaxRng theDefaultEngine;
72
73 public:
74
75 std::shared_ptr<HepRandom > theGenerator;
76 std::shared_ptr<HepRandomEngine> theEngine;
77 }; // defaults
78
79
80#ifdef CLHEP_USE_ATOMIC
81
82 // The ThreadSafeDefaultCache is used only by the function named theDefaults.
83 // It is a singly linked list that is intended to hold one object of
84 // type "defaults" per thread.
85
86 class ThreadSafeDefaultsCache {
87 public:
88
89 ThreadSafeDefaultsCache();
90
91 // The destructor deletes the objects of type "defaults"
92 ~ThreadSafeDefaultsCache();
93
94 // Creates new objects and adds them to the linked list in a thread safe manner.
95 defaults* createNewDefaults();
96
97 // Note that there are no other functions. No erasing or moving or other accessors.
98
99 private:
100
101 class DefaultsNode {
102 public:
103 DefaultsNode(DefaultsNode* iNext);
104 DefaultsNode const* next() const { return next_; }
105 void setNext(DefaultsNode* v) { next_ = v; }
106 defaults* addressOfDefaults() { return &defaults_; }
107 private:
108 DefaultsNode* next_;
109 defaults defaults_;
110 };
111
112 // points to first node in the linked list
113 std::atomic<DefaultsNode*> front_;
114 };
115
116 ThreadSafeDefaultsCache::ThreadSafeDefaultsCache() :
117 front_(nullptr) {
118 }
119
120 defaults* ThreadSafeDefaultsCache::createNewDefaults() {
121 DefaultsNode* expected = front_.load();
122 DefaultsNode* newNode = new DefaultsNode(expected);
123 while (!front_.compare_exchange_strong(expected, newNode)) {
124 // another thread changed front_ before us so try again
125 newNode->setNext(expected);
126 }
127 return newNode->addressOfDefaults();
128 }
129
130 ThreadSafeDefaultsCache::DefaultsNode::DefaultsNode(DefaultsNode* iNext) :
131 next_(iNext),
132 defaults_() {
133 }
134
135 ThreadSafeDefaultsCache::~ThreadSafeDefaultsCache() {
136 DefaultsNode const* node = front_.load();
137 while (node) {
138 DefaultsNode const* next = node->next();
139 delete node;
140 node = next;
141 }
142 }
143
144 defaults & theDefaults() {
145
146 // We need to have different engines on different threads because
147 // the engines are not thread safe. One cannot generate random numbers
148 // using the same engine on different threads simultaneously.
149 // Originally we had the defaults object itself as a thread local,
150 // but that was failing because on Mac OSX there is not full
151 // support for thread locals yet. Objects containing std::shared_ptr
152 // in thread local storage were causing failures. So now we create
153 // a container of them that is a function static (not thread local)
154 // and the thread local contains only a pointer to an object in the
155 // container.
156 static ThreadSafeDefaultsCache defaultsForAllThreads;
157
158 // A pointer for each thread to defaults object built for each thread.
159 static CLHEP_THREAD_LOCAL defaults* theDefaults = defaultsForAllThreads.createNewDefaults();
160
161 return *theDefaults;
162 }
163#else
164
165 // This version is used with old compilers not supporting atomics.
166 // In that case, the code should not be executed in more than one thread.
167 defaults & theDefaults() {
168 static defaults theDefaults;
169 return theDefaults;
170 }
171
172#endif
173
174 } // namespace
175
176//---------------------------- HepRandom ---------------------------------
177
178HepRandom::HepRandom()
179{ }
180
181HepRandom::HepRandom(long seed)
182{
183 setTheSeed(seed);
184}
185
186HepRandom::HepRandom(HepRandomEngine & algorithm)
187{
188 theDefaults().resetEngine( algorithm );
189}
190
191HepRandom::HepRandom(HepRandomEngine * algorithm)
192{
193 theDefaults().resetEngine( algorithm );
194}
195
196HepRandom::~HepRandom()
197{ }
198
199double HepRandom::flat()
200{
201 return theDefaults().theEngine->flat();
202}
203
204void HepRandom::flatArray(const int size, double* vect)
205{
206 theDefaults().theEngine->flatArray(size,vect);
207}
208
209double HepRandom::operator()() {
210 return flat();
211}
212
213std::string HepRandom::name() const {return "HepRandom";}
214HepRandomEngine & HepRandom::engine() {
215 std::cerr << "HepRandom::engine() called -- there is no assigned engine!\n";
216 return *theDefaults().theEngine.get();
217}
218
219std::ostream & operator<< (std::ostream & os, const HepRandom & dist) {
220 return dist.put(os);
221}
222
223std::istream & operator>> (std::istream & is, HepRandom & dist) {
224 return dist.get(is);
225}
226
227std::ostream & HepRandom::put(std::ostream & os) const {return os;}
228std::istream & HepRandom::get(std::istream & is) {return is;}
229
230// --------------------------
231// Static methods definitions
232// --------------------------
233
234void HepRandom::setTheSeed(long seed, int lux)
235{
236 theDefaults().theEngine->setSeed(seed,lux);
237}
238
239long HepRandom::getTheSeed()
240{
241 return theDefaults().theEngine->getSeed();
242}
243
244void HepRandom::setTheSeeds(const long* seeds, int aux)
245{
246 theDefaults().theEngine->setSeeds(seeds,aux);
247}
248
249const long* HepRandom::getTheSeeds ()
250{
251 return theDefaults().theEngine->getSeeds();
252}
253
254void HepRandom::getTheTableSeeds(long* seeds, int index)
255{
256 if ((index >= 0) && (index < 215)) {
257 seeds[0] = seedTable[index][0];
258 seeds[1] = seedTable[index][1];
259 }
260 else seeds = NULL;
261}
262
263HepRandom * HepRandom::getTheGenerator()
264{
265 return theDefaults().theGenerator.get();
266}
267
268HepRandomEngine * HepRandom::getTheEngine()
269{
270 return theDefaults().theEngine.get();
271}
272
273void HepRandom::setTheEngine (HepRandomEngine* theNewEngine)
274{
275 theDefaults().theEngine.reset( theNewEngine, do_nothing_deleter() );
276}
277
278void HepRandom::saveEngineStatus( const char filename[] )
279{
280 theDefaults().theEngine->saveStatus( filename );
281}
282
283void HepRandom::restoreEngineStatus( const char filename[] )
284{
285 theDefaults().theEngine->restoreStatus( filename );
286}
287
288std::ostream& HepRandom::saveFullState ( std::ostream & os ) {
289 os << *getTheEngine();
290 return os;
291}
292
293std::istream& HepRandom::restoreFullState ( std::istream & is ) {
294 is >> *getTheEngine();
295 return is;
296}
297
298std::ostream& HepRandom::saveStaticRandomStates ( std::ostream & os ) {
299 return StaticRandomStates::save(os);
300}
301
302std::istream& HepRandom::restoreStaticRandomStates ( std::istream & is ) {
303 return StaticRandomStates::restore(is);
304}
305
306void HepRandom::showEngineStatus()
307{
308 theDefaults().theEngine->showStatus();
309}
310
311int HepRandom::createInstance()
312{
313 return static_cast<int>( theDefaults().ensureInitialized() );
314}
315
316} // namespace CLHEP
std::istream & operator>>(std::istream &s, G4BetaDecayType &q)
std::ostream & operator<<(std::ostream &out, const G4CellScoreComposer &ps)
std::shared_ptr< HepRandom > theGenerator
Definition: Random.cc:75
std::shared_ptr< HepRandomEngine > theEngine
Definition: Random.cc:76
virtual std::istream & get(std::istream &is)
Definition: RandomEngine.cc:63
virtual std::istream & get(std::istream &is)
Definition: Random.cc:228
virtual std::ostream & put(std::ostream &os) const
Definition: Random.cc:227
Definition: DoubConv.h:17
yystype & operator=(const yystype &right)
Definition: G4UItokenNum.hh:78
#define CLHEP_THREAD_LOCAL
Definition: thread_local.h:13