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