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