Geant4 Cross Reference |
1 // -*- C++ -*- 2 // 3 // ----------------------------------------------------------------------- 4 // HEP Random 5 // --- RandGauss --- 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 // - Added methods to shoot arrays: 28th July 1997 13 // J.Marraffino - Added default arguments as attributes and 14 // operator() with arguments. Introduced method normal() 15 // for computation in fire(): 16th Feb 1998 16 // Gabriele Cosmo - Relocated static data from HepRandom: 5th Jan 1999 17 // M Fischler - Copy constructor should supply right engine to HepRandom: 18 // 1/26/00. 19 // M Fischler - Workaround for problem of non-reproducing saveEngineStatus 20 // by saving cached gaussian. March 2000. 21 // M Fischler - Avoiding hang when file not found in restoreEngineStatus 22 // 12/3/04 23 // M Fischler - put and get to/from streams 12/8/04 24 // M Fischler - save and restore dist to streams 12/20/04 25 // M Fischler - put/get to/from streams uses pairs of ulongs when 26 // storing doubles avoid problems with precision. 27 // Similarly for saveEngineStatus and RestoreEngineStatus 28 // and for save/restore distState 29 // Care was taken that old-form output can still be read back. 30 // 4/14/05 31 // 32 // ======================================================================= 33 34 #include "CLHEP/Random/RandGauss.h" 35 #include "CLHEP/Random/DoubConv.h" 36 #include <cmath> // for std::log() 37 #include <iostream> 38 #include <string.h> // for strcmp 39 #include <string> 40 #include <vector> 41 42 namespace CLHEP { 43 44 std::string RandGauss::name() const {return "RandGauss";} 45 HepRandomEngine & RandGauss::engine() {return *localEngine;} 46 47 // Initialisation of static data 48 CLHEP_THREAD_LOCAL bool RandGauss::set_st = false; 49 CLHEP_THREAD_LOCAL double RandGauss::nextGauss_st = 0.0; 50 51 RandGauss::~RandGauss() { 52 } 53 54 double RandGauss::operator()() { 55 return fire( defaultMean, defaultStdDev ); 56 } 57 58 double RandGauss::operator()( double mean, double stdDev ) { 59 return fire( mean, stdDev ); 60 } 61 62 double RandGauss::shoot() 63 { 64 // Gaussian random numbers are generated two at the time, so every other 65 // time this is called we just return a number generated the time before. 66 67 if ( getFlag() ) { 68 setFlag(false); 69 double x = getVal(); 70 return x; 71 // return getVal(); 72 } 73 74 double r; 75 double v1,v2,fac,val; 76 HepRandomEngine* anEngine = HepRandom::getTheEngine(); 77 78 do { 79 v1 = 2.0 * anEngine->flat() - 1.0; 80 v2 = 2.0 * anEngine->flat() - 1.0; 81 r = v1*v1 + v2*v2; 82 } while ( r > 1.0 ); 83 84 fac = std::sqrt(-2.0*std::log(r)/r); 85 val = v1*fac; 86 setVal(val); 87 setFlag(true); 88 return v2*fac; 89 } 90 91 void RandGauss::shootArray( const int size, double* vect, 92 double mean, double stdDev ) 93 { 94 for( double* v = vect; v != vect + size; ++v ) 95 *v = shoot(mean,stdDev); 96 } 97 98 double RandGauss::shoot( HepRandomEngine* anEngine ) 99 { 100 // Gaussian random numbers are generated two at the time, so every other 101 // time this is called we just return a number generated the time before. 102 103 if ( getFlag() ) { 104 setFlag(false); 105 return getVal(); 106 } 107 108 double r; 109 double v1,v2,fac,val; 110 111 do { 112 v1 = 2.0 * anEngine->flat() - 1.0; 113 v2 = 2.0 * anEngine->flat() - 1.0; 114 r = v1*v1 + v2*v2; 115 } while ( r > 1.0 ); 116 117 fac = std::sqrt( -2.0*std::log(r)/r); 118 val = v1*fac; 119 setVal(val); 120 setFlag(true); 121 return v2*fac; 122 } 123 124 void RandGauss::shootArray( HepRandomEngine* anEngine, 125 const int size, double* vect, 126 double mean, double stdDev ) 127 { 128 for( double* v = vect; v != vect + size; ++v ) 129 *v = shoot(anEngine,mean,stdDev); 130 } 131 132 double RandGauss::normal() 133 { 134 // Gaussian random numbers are generated two at the time, so every other 135 // time this is called we just return a number generated the time before. 136 137 if ( set ) { 138 set = false; 139 return nextGauss; 140 } 141 142 double r; 143 double v1,v2,fac,val; 144 145 do { 146 v1 = 2.0 * localEngine->flat() - 1.0; 147 v2 = 2.0 * localEngine->flat() - 1.0; 148 r = v1*v1 + v2*v2; 149 } while ( r > 1.0 ); 150 151 fac = std::sqrt(-2.0*std::log(r)/r); 152 val = v1*fac; 153 nextGauss = val; 154 set = true; 155 return v2*fac; 156 } 157 158 void RandGauss::fireArray( const int size, double* vect) 159 { 160 for( double* v = vect; v != vect + size; ++v ) 161 *v = fire( defaultMean, defaultStdDev ); 162 } 163 164 void RandGauss::fireArray( const int size, double* vect, 165 double mean, double stdDev ) 166 { 167 for( double* v = vect; v != vect + size; ++v ) 168 *v = fire( mean, stdDev ); 169 } 170 171 bool RandGauss::getFlag() 172 { 173 return set_st; 174 } 175 176 void RandGauss::setFlag( bool val ) 177 { 178 set_st = val; 179 } 180 181 double RandGauss::getVal() 182 { 183 return nextGauss_st; 184 } 185 186 void RandGauss::setVal( double nextVal ) 187 { 188 nextGauss_st = nextVal; 189 } 190 191 void RandGauss::saveEngineStatus ( const char filename[] ) { 192 193 // First save the engine status just like the base class would do: 194 getTheEngine()->saveStatus( filename ); 195 196 // Now append the cached variate, if any: 197 198 std::ofstream outfile ( filename, std::ios::app ); 199 200 if ( getFlag() ) { 201 std::vector<unsigned long> t(2); 202 t = DoubConv::dto2longs(getVal()); 203 outfile << "RANDGAUSS CACHED_GAUSSIAN: Uvec " 204 << getVal() << " " << t[0] << " " << t[1] << "\n"; 205 } else { 206 outfile << "RANDGAUSS NO_CACHED_GAUSSIAN: 0 \n" ; 207 } 208 209 } // saveEngineStatus 210 211 void RandGauss::restoreEngineStatus( const char filename[] ) { 212 213 // First restore the engine status just like the base class would do: 214 getTheEngine()->restoreStatus( filename ); 215 216 // Now find the line describing the cached variate: 217 218 std::ifstream infile ( filename, std::ios::in ); 219 if (!infile) return; 220 221 char inputword[] = "NO_KEYWORD "; // leaves room for 14 characters plus \0 222 while (true) { 223 infile.width(13); 224 infile >> inputword; 225 if (strcmp(inputword,"RANDGAUSS")==0) break; 226 if (infile.eof()) break; 227 // If the file ends without the RANDGAUSS line, that means this 228 // was a file produced by an earlier version of RandGauss. We will 229 // replicated the old behavior in that case: set_st is cleared. 230 } 231 232 // Then read and use the caching info: 233 234 if (strcmp(inputword,"RANDGAUSS")==0) { 235 char setword[40]; // the longest, staticFirstUnusedBit: has length 21 236 infile.width(39); 237 infile >> setword; // setword should be CACHED_GAUSSIAN: 238 if (strcmp(setword,"CACHED_GAUSSIAN:") ==0) { 239 if (possibleKeywordInput(infile, "Uvec", nextGauss_st)) { 240 std::vector<unsigned long> t(2); 241 infile >> nextGauss_st >> t[0] >> t[1]; 242 nextGauss_st = DoubConv::longs2double(t); 243 } 244 // is >> nextGauss_st encompassed by possibleKeywordInput 245 setFlag(true); 246 } else { 247 setFlag(false); 248 infile >> nextGauss_st; // because a 0 will have been output 249 } 250 } else { 251 setFlag(false); 252 } 253 254 } // restoreEngineStatus 255 256 // Save and restore to/from streams 257 258 std::ostream & RandGauss::put ( std::ostream & os ) const { 259 os << name() << "\n"; 260 long prec = os.precision(20); 261 std::vector<unsigned long> t(2); 262 os << "Uvec\n"; 263 t = DoubConv::dto2longs(defaultMean); 264 os << defaultMean << " " << t[0] << " " << t[1] << "\n"; 265 t = DoubConv::dto2longs(defaultStdDev); 266 os << defaultStdDev << " " << t[0] << " " << t[1] << "\n"; 267 if ( set ) { 268 t = DoubConv::dto2longs(nextGauss); 269 os << "nextGauss " << nextGauss << " " << t[0] << " " << t[1] << "\n"; 270 } else { 271 os << "no_cached_nextGauss \n"; 272 } 273 os.precision(prec); 274 return os; 275 } // put 276 277 std::istream & RandGauss::get ( std::istream & is ) { 278 std::string inName; 279 is >> inName; 280 if (inName != name()) { 281 is.clear(std::ios::badbit | is.rdstate()); 282 std::cerr << "Mismatch when expecting to read state of a " 283 << name() << " distribution\n" 284 << "Name found was " << inName 285 << "\nistream is left in the badbit state\n"; 286 return is; 287 } 288 std::string c1; 289 std::string c2; 290 if (possibleKeywordInput(is, "Uvec", c1)) { 291 std::vector<unsigned long> t(2); 292 is >> defaultMean >> t[0] >> t[1]; defaultMean = DoubConv::longs2double(t); 293 is >> defaultStdDev>>t[0]>>t[1]; defaultStdDev = DoubConv::longs2double(t); 294 std::string ng; 295 is >> ng; 296 set = false; 297 if (ng == "nextGauss") { 298 is >> nextGauss >> t[0] >> t[1]; nextGauss = DoubConv::longs2double(t); 299 set = true; 300 } 301 return is; 302 } 303 // is >> c1 encompassed by possibleKeywordInput 304 is >> defaultMean >> c2 >> defaultStdDev; 305 if ( (!is) || (c1 != "Mean:") || (c2 != "Sigma:") ) { 306 std::cerr << "i/o problem while expecting to read state of a " 307 << name() << " distribution\n" 308 << "default mean and/or sigma could not be read\n"; 309 return is; 310 } 311 is >> c1 >> c2 >> nextGauss; 312 if ( (!is) || (c1 != "RANDGAUSS") ) { 313 is.clear(std::ios::badbit | is.rdstate()); 314 std::cerr << "Failure when reading caching state of RandGauss\n"; 315 return is; 316 } 317 if (c2 == "CACHED_GAUSSIAN:") { 318 set = true; 319 } else if (c2 == "NO_CACHED_GAUSSIAN:") { 320 set = false; 321 } else { 322 is.clear(std::ios::badbit | is.rdstate()); 323 std::cerr << "Unexpected caching state keyword of RandGauss:" << c2 324 << "\nistream is left in the badbit state\n"; 325 } 326 return is; 327 } // get 328 329 // Static save and restore to/from streams 330 331 std::ostream & RandGauss::saveDistState ( std::ostream & os ) { 332 long prec = os.precision(20); 333 std::vector<unsigned long> t(2); 334 os << distributionName() << "\n"; 335 os << "Uvec\n"; 336 if ( getFlag() ) { 337 t = DoubConv::dto2longs(getVal()); 338 os << "nextGauss_st " << getVal() << " " << t[0] << " " << t[1] << "\n"; 339 } else { 340 os << "no_cached_nextGauss_st \n"; 341 } 342 os.precision(prec); 343 return os; 344 } 345 346 std::istream & RandGauss::restoreDistState ( std::istream & is ) { 347 std::string inName; 348 is >> inName; 349 if (inName != distributionName()) { 350 is.clear(std::ios::badbit | is.rdstate()); 351 std::cerr << "Mismatch when expecting to read static state of a " 352 << distributionName() << " distribution\n" 353 << "Name found was " << inName 354 << "\nistream is left in the badbit state\n"; 355 return is; 356 } 357 std::string c1; 358 std::string c2; 359 if (possibleKeywordInput(is, "Uvec", c1)) { 360 std::vector<unsigned long> t(2); 361 std::string ng; 362 is >> ng; 363 setFlag (false); 364 if (ng == "nextGauss_st") { 365 is >> nextGauss_st >> t[0] >> t[1]; 366 nextGauss_st = DoubConv::longs2double(t); 367 setFlag (true); 368 } 369 return is; 370 } 371 // is >> c1 encompassed by possibleKeywordInput 372 is >> c2 >> nextGauss_st; 373 if ( (!is) || (c1 != "RANDGAUSS") ) { 374 is.clear(std::ios::badbit | is.rdstate()); 375 std::cerr << "Failure when reading caching state of static RandGauss\n"; 376 return is; 377 } 378 if (c2 == "CACHED_GAUSSIAN:") { 379 setFlag(true); 380 } else if (c2 == "NO_CACHED_GAUSSIAN:") { 381 setFlag(false); 382 } else { 383 is.clear(std::ios::badbit | is.rdstate()); 384 std::cerr << "Unexpected caching state keyword of static RandGauss:" << c2 385 << "\nistream is left in the badbit state\n"; 386 } 387 return is; 388 } 389 390 std::ostream & RandGauss::saveFullState ( std::ostream & os ) { 391 HepRandom::saveFullState(os); 392 saveDistState(os); 393 return os; 394 } 395 396 std::istream & RandGauss::restoreFullState ( std::istream & is ) { 397 HepRandom::restoreFullState(is); 398 restoreDistState(is); 399 return is; 400 } 401 402 } // namespace CLHEP 403 404