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