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