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