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