Geant4 Cross Reference |
1 // -*- C++ -*- 1 // -*- C++ -*- 2 // 2 // 3 // ------------------------------------------- 3 // ----------------------------------------------------------------------- 4 // HEP Random 4 // HEP Random 5 // --- RandGamma --- 5 // --- RandGamma --- 6 // class implementation f 6 // class implementation file 7 // ------------------------------------------- 7 // ----------------------------------------------------------------------- 8 8 9 // =========================================== 9 // ======================================================================= 10 // John Marraffino - Created: 12th May 1998 10 // John Marraffino - Created: 12th May 1998 11 // M Fischler - put and get to/from strea 11 // M Fischler - put and get to/from streams 12/13/04 12 // M Fischler - put/get to/from streams 12 // M Fischler - put/get to/from streams uses pairs of ulongs when 13 // + storing doubles avoid problems with 13 // + storing doubles avoid problems with precision 14 // 4/14/05 14 // 4/14/05 15 // =========================================== 15 // ======================================================================= 16 16 17 #include "CLHEP/Random/RandGamma.h" 17 #include "CLHEP/Random/RandGamma.h" 18 #include "CLHEP/Random/DoubConv.h" 18 #include "CLHEP/Random/DoubConv.h" 19 #include "CLHEP/Utility/thread_local.h" 19 #include "CLHEP/Utility/thread_local.h" 20 #include <cmath> // for std::log() 20 #include <cmath> // for std::log() 21 #include <iostream> << 22 #include <string> << 23 #include <vector> << 24 21 25 namespace CLHEP { 22 namespace CLHEP { 26 23 27 std::string RandGamma::name() const {return "R 24 std::string RandGamma::name() const {return "RandGamma";} 28 HepRandomEngine & RandGamma::engine() {return 25 HepRandomEngine & RandGamma::engine() {return *localEngine;} 29 26 30 RandGamma::~RandGamma() { 27 RandGamma::~RandGamma() { 31 } 28 } 32 29 33 double RandGamma::shoot( HepRandomEngine *anEn 30 double RandGamma::shoot( HepRandomEngine *anEngine, double k, 34 31 double lambda ) { 35 return genGamma( anEngine, k, lambda ); 32 return genGamma( anEngine, k, lambda ); 36 } 33 } 37 34 38 double RandGamma::shoot( double k, double lamb 35 double RandGamma::shoot( double k, double lambda ) { 39 HepRandomEngine *anEngine = HepRandom::getTh 36 HepRandomEngine *anEngine = HepRandom::getTheEngine(); 40 return genGamma( anEngine, k, lambda ); 37 return genGamma( anEngine, k, lambda ); 41 } 38 } 42 39 43 double RandGamma::fire( double k, double lambd 40 double RandGamma::fire( double k, double lambda ) { 44 return genGamma( localEngine.get(), k, lambd 41 return genGamma( localEngine.get(), k, lambda ); 45 } 42 } 46 43 47 void RandGamma::shootArray( const int size, do 44 void RandGamma::shootArray( const int size, double* vect, 48 double k, double l 45 double k, double lambda ) 49 { 46 { 50 for( double* v = vect; v != vect + size; ++v 47 for( double* v = vect; v != vect + size; ++v ) 51 *v = shoot(k,lambda); 48 *v = shoot(k,lambda); 52 } 49 } 53 50 54 void RandGamma::shootArray( HepRandomEngine* a 51 void RandGamma::shootArray( HepRandomEngine* anEngine, 55 const int size, do 52 const int size, double* vect, 56 double k, double l 53 double k, double lambda ) 57 { 54 { 58 for( double* v = vect; v != vect + size; ++v 55 for( double* v = vect; v != vect + size; ++v ) 59 *v = shoot(anEngine,k,lambda); 56 *v = shoot(anEngine,k,lambda); 60 } 57 } 61 58 62 void RandGamma::fireArray( const int size, dou 59 void RandGamma::fireArray( const int size, double* vect) 63 { 60 { 64 for( double* v = vect; v != vect + size; ++v 61 for( double* v = vect; v != vect + size; ++v ) 65 *v = fire(defaultK,defaultLambda); 62 *v = fire(defaultK,defaultLambda); 66 } 63 } 67 64 68 void RandGamma::fireArray( const int size, dou 65 void RandGamma::fireArray( const int size, double* vect, 69 double k, double la 66 double k, double lambda ) 70 { 67 { 71 for( double* v = vect; v != vect + size; ++v 68 for( double* v = vect; v != vect + size; ++v ) 72 *v = fire(k,lambda); 69 *v = fire(k,lambda); 73 } 70 } 74 71 75 double RandGamma::genGamma( HepRandomEngine *a 72 double RandGamma::genGamma( HepRandomEngine *anEngine, 76 double a, doubl 73 double a, double lambda ) { 77 /********************************************* 74 /************************************************************************* 78 * Gamma Distribution - Rejection algo 75 * Gamma Distribution - Rejection algorithm gs combined with * 79 * Acceptance com 76 * Acceptance complement method gd * 80 ********************************************* 77 *************************************************************************/ 81 78 82 double aa = -1.0, aaa = -1.0, b{0.}, c{0.}, << 79 static CLHEP_THREAD_LOCAL double aa = -1.0, aaa = -1.0, b, c, d, e, r, s, si, ss, q0; 83 constexpr double q1 = 0.0416666664, q2 = 0. << 80 static const double q1 = 0.0416666664, q2 = 0.0208333723, q3 = 0.0079849875, 84 q4 = 0.0015746717, q5 = -0.0003349403, 81 q4 = 0.0015746717, q5 = -0.0003349403, q6 = 0.0003340332, 85 q7 = 0.0006053049, q8 = -0.0004701849, 82 q7 = 0.0006053049, q8 = -0.0004701849, q9 = 0.0001710320, 86 a1 = 0.333333333, a2 = -0.249999949, 83 a1 = 0.333333333, a2 = -0.249999949, a3 = 0.199999867, 87 a4 =-0.166677482, a5 = 0.142873973, 84 a4 =-0.166677482, a5 = 0.142873973, a6 =-0.124385581, 88 a7 = 0.110368310, a8 = -0.112750886, 85 a7 = 0.110368310, a8 = -0.112750886, a9 = 0.104089866, 89 e1 = 1.000000000, e2 = 0.499999994, 86 e1 = 1.000000000, e2 = 0.499999994, e3 = 0.166666848, 90 e4 = 0.041664508, e5 = 0.008345522, 87 e4 = 0.041664508, e5 = 0.008345522, e6 = 0.001353826, 91 e7 = 0.000247453; 88 e7 = 0.000247453; 92 89 93 double gds{0.},p{0.},q{0.},t{0.},sign_u{0.},u << 90 double gds,p,q,t,sign_u,u,v,w,x; 94 double v1{0.},v2{0.},v12{0.}; << 91 double v1,v2,v12; 95 92 96 // Check for invalid input values 93 // Check for invalid input values 97 94 98 if( a <= 0.0 ) return (-1.0); 95 if( a <= 0.0 ) return (-1.0); 99 if( lambda <= 0.0 ) return (-1.0); 96 if( lambda <= 0.0 ) return (-1.0); 100 97 101 if (a < 1.0) 98 if (a < 1.0) 102 { // CASE A: Acceptance rejection 99 { // CASE A: Acceptance rejection algorithm gs 103 b = 1.0 + 0.36788794412 * a; // Step 100 b = 1.0 + 0.36788794412 * a; // Step 1 104 for(;;) 101 for(;;) 105 { 102 { 106 p = b * anEngine->flat(); 103 p = b * anEngine->flat(); 107 if (p <= 1.0) 104 if (p <= 1.0) 108 { // Step 2. Ca 105 { // Step 2. Case gds <= 1 109 gds = std::exp(std::log(p) / a); 106 gds = std::exp(std::log(p) / a); 110 if (std::log(anEngine->flat()) <= -gds) r 107 if (std::log(anEngine->flat()) <= -gds) return(gds/lambda); 111 } 108 } 112 else 109 else 113 { // Step 3. Ca 110 { // Step 3. Case gds > 1 114 gds = - std::log ((b - p) / a); 111 gds = - std::log ((b - p) / a); 115 if (std::log(anEngine->flat()) <= ((a - 1 112 if (std::log(anEngine->flat()) <= ((a - 1.0) * std::log(gds))) return(gds/lambda); 116 } 113 } 117 } 114 } 118 } 115 } 119 else 116 else 120 { // CASE B: Acceptance complement 117 { // CASE B: Acceptance complement algorithm gd 121 if (a != aa) 118 if (a != aa) 122 { // Step 119 { // Step 1. Preparations 123 aa = a; 120 aa = a; 124 ss = a - 0.5; 121 ss = a - 0.5; 125 s = std::sqrt(ss); 122 s = std::sqrt(ss); 126 d = 5.656854249 - 12.0 * s; 123 d = 5.656854249 - 12.0 * s; 127 } 124 } 128 125 // Step 2. Normal deviate 129 do { 126 do { 130 v1 = 2.0 * anEngine->flat() - 1.0; 127 v1 = 2.0 * anEngine->flat() - 1.0; 131 v2 = 2.0 * anEngine->flat() - 1.0; 128 v2 = 2.0 * anEngine->flat() - 1.0; 132 v12 = v1*v1 + v2*v2; 129 v12 = v1*v1 + v2*v2; 133 } while ( v12 > 1.0 ); 130 } while ( v12 > 1.0 ); 134 t = v1*std::sqrt(-2.0*std::log(v12)/v12); 131 t = v1*std::sqrt(-2.0*std::log(v12)/v12); 135 x = s + 0.5 * t; 132 x = s + 0.5 * t; 136 gds = x * x; 133 gds = x * x; 137 if (t >= 0.0) return(gds/lambda); 134 if (t >= 0.0) return(gds/lambda); // Immediate acceptance 138 135 139 u = anEngine->flat(); // Step 3 136 u = anEngine->flat(); // Step 3. Uniform random number 140 if (d * u <= t * t * t) return(gds/lambda) 137 if (d * u <= t * t * t) return(gds/lambda); // Squeeze acceptance 141 138 142 if (a != aaa) 139 if (a != aaa) 143 { // Step 140 { // Step 4. Set-up for hat case 144 aaa = a; 141 aaa = a; 145 r = 1.0 / a; 142 r = 1.0 / a; 146 q0 = ((((((((q9 * r + q8) * r + q7) * r + q6 143 q0 = ((((((((q9 * r + q8) * r + q7) * r + q6) * r + q5) * r + q4) * 147 r + q3) * r + q2) * r + q1) * r; 144 r + q3) * r + q2) * r + q1) * r; 148 if (a > 3.686) 145 if (a > 3.686) 149 { 146 { 150 if (a > 13.022) 147 if (a > 13.022) 151 { 148 { 152 b = 1.77; 149 b = 1.77; 153 si = 0.75; 150 si = 0.75; 154 c = 0.1515 / s; 151 c = 0.1515 / s; 155 } 152 } 156 else 153 else 157 { 154 { 158 b = 1.654 + 0.0076 * ss; 155 b = 1.654 + 0.0076 * ss; 159 si = 1.68 / s + 0.275; 156 si = 1.68 / s + 0.275; 160 c = 0.062 / s + 0.024; 157 c = 0.062 / s + 0.024; 161 } 158 } 162 } 159 } 163 else 160 else 164 { 161 { 165 b = 0.463 + s - 0.178 * ss; 162 b = 0.463 + s - 0.178 * ss; 166 si = 1.235; 163 si = 1.235; 167 c = 0.195 / s - 0.079 + 0.016 * s; 164 c = 0.195 / s - 0.079 + 0.016 * s; 168 } 165 } 169 } 166 } 170 if (x > 0.0) // Step 167 if (x > 0.0) // Step 5. Calculation of q 171 { 168 { 172 v = t / (s + s); // Step 6. 169 v = t / (s + s); // Step 6. 173 if (std::fabs(v) > 0.25) 170 if (std::fabs(v) > 0.25) 174 { 171 { 175 q = q0 - s * t + 0.25 * t * t + (ss + ss 172 q = q0 - s * t + 0.25 * t * t + (ss + ss) * std::log(1.0 + v); 176 } 173 } 177 else 174 else 178 { 175 { 179 q = q0 + 0.5 * t * t * ((((((((a9 * v + 176 q = q0 + 0.5 * t * t * ((((((((a9 * v + a8) * v + a7) * v + a6) * 180 v + a5) * v + a4) * v + a3) * v + a2 177 v + a5) * v + a4) * v + a3) * v + a2) * v + a1) * v; 181 } // Step 7. Quotient acce 178 } // Step 7. Quotient acceptance 182 if (std::log(1.0 - u) <= q) return(gds/lambd 179 if (std::log(1.0 - u) <= q) return(gds/lambda); 183 } 180 } 184 181 185 for(;;) 182 for(;;) 186 { // Step 8. Double 183 { // Step 8. Double exponential deviate t 187 do 184 do 188 { 185 { 189 e = -std::log(anEngine->flat()); 186 e = -std::log(anEngine->flat()); 190 u = anEngine->flat(); 187 u = anEngine->flat(); 191 u = u + u - 1.0; 188 u = u + u - 1.0; 192 sign_u = (u > 0)? 1.0 : -1.0; 189 sign_u = (u > 0)? 1.0 : -1.0; 193 t = b + (e * si) * sign_u; 190 t = b + (e * si) * sign_u; 194 } 191 } 195 while (t <= -0.71874483771719); // Step 9. 192 while (t <= -0.71874483771719); // Step 9. Rejection of t 196 v = t / (s + s); // Step 10 193 v = t / (s + s); // Step 10. New q(t) 197 if (std::fabs(v) > 0.25) 194 if (std::fabs(v) > 0.25) 198 { 195 { 199 q = q0 - s * t + 0.25 * t * t + (ss + ss 196 q = q0 - s * t + 0.25 * t * t + (ss + ss) * std::log(1.0 + v); 200 } 197 } 201 else 198 else 202 { 199 { 203 q = q0 + 0.5 * t * t * ((((((((a9 * v + 200 q = q0 + 0.5 * t * t * ((((((((a9 * v + a8) * v + a7) * v + a6) * 204 v + a5) * v + a4) * v + a3) * v + a2 201 v + a5) * v + a4) * v + a3) * v + a2) * v + a1) * v; 205 } 202 } 206 if (q <= 0.0) continue; // Step 11 203 if (q <= 0.0) continue; // Step 11. 207 if (q > 0.5) 204 if (q > 0.5) 208 { 205 { 209 w = std::exp(q) - 1.0; 206 w = std::exp(q) - 1.0; 210 } 207 } 211 else 208 else 212 { 209 { 213 w = ((((((e7 * q + e6) * q + e5) * q + e 210 w = ((((((e7 * q + e6) * q + e5) * q + e4) * q + e3) * q + e2) * 214 q + e1) * q; 211 q + e1) * q; 215 } // Step 12. Hat acce 212 } // Step 12. Hat acceptance 216 if ( c * u * sign_u <= w * std::exp(e - 0.5 213 if ( c * u * sign_u <= w * std::exp(e - 0.5 * t * t)) 217 { 214 { 218 x = s + 0.5 * t; 215 x = s + 0.5 * t; 219 return(x*x/lambda); 216 return(x*x/lambda); 220 } 217 } 221 } 218 } 222 } 219 } 223 } 220 } 224 221 225 std::ostream & RandGamma::put ( std::ostream & 222 std::ostream & RandGamma::put ( std::ostream & os ) const { 226 long pr=os.precision(20); << 223 int pr=os.precision(20); 227 std::vector<unsigned long> t(2); 224 std::vector<unsigned long> t(2); 228 os << " " << name() << "\n"; 225 os << " " << name() << "\n"; 229 os << "Uvec" << "\n"; 226 os << "Uvec" << "\n"; 230 t = DoubConv::dto2longs(defaultK); 227 t = DoubConv::dto2longs(defaultK); 231 os << defaultK << " " << t[0] << " " << t[1] 228 os << defaultK << " " << t[0] << " " << t[1] << "\n"; 232 t = DoubConv::dto2longs(defaultLambda); 229 t = DoubConv::dto2longs(defaultLambda); 233 os << defaultLambda << " " << t[0] << " " << 230 os << defaultLambda << " " << t[0] << " " << t[1] << "\n"; 234 os.precision(pr); 231 os.precision(pr); 235 return os; 232 return os; 236 } 233 } 237 234 238 std::istream & RandGamma::get ( std::istream & 235 std::istream & RandGamma::get ( std::istream & is ) { 239 std::string inName; 236 std::string inName; 240 is >> inName; 237 is >> inName; 241 if (inName != name()) { 238 if (inName != name()) { 242 is.clear(std::ios::badbit | is.rdstate()); 239 is.clear(std::ios::badbit | is.rdstate()); 243 std::cerr << "Mismatch when expecting to r 240 std::cerr << "Mismatch when expecting to read state of a " 244 << name() << " distribution\n" 241 << name() << " distribution\n" 245 << "Name found was " << inName 242 << "Name found was " << inName 246 << "\nistream is left in the badbit st 243 << "\nistream is left in the badbit state\n"; 247 return is; 244 return is; 248 } 245 } 249 if (possibleKeywordInput(is, "Uvec", default 246 if (possibleKeywordInput(is, "Uvec", defaultK)) { 250 std::vector<unsigned long> t(2); 247 std::vector<unsigned long> t(2); 251 is >> defaultK >> t[0] >> t[1]; defaultK = 248 is >> defaultK >> t[0] >> t[1]; defaultK = DoubConv::longs2double(t); 252 is >> defaultLambda>>t[0]>>t[1]; defaultLa 249 is >> defaultLambda>>t[0]>>t[1]; defaultLambda = DoubConv::longs2double(t); 253 return is; 250 return is; 254 } 251 } 255 // is >> defaultK encompassed by possibleKey 252 // is >> defaultK encompassed by possibleKeywordInput 256 is >> defaultLambda; 253 is >> defaultLambda; 257 return is; 254 return is; 258 } 255 } 259 256 260 } // namespace CLHEP 257 } // namespace CLHEP 261 258 262 259