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