Geant4-11
RandPoisson.cc
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// -----------------------------------------------------------------------
4// HEP Random
5// --- RandPoisson ---
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 not static Shoot() method: 17th May 1996
13// - Algorithm now operates on doubles: 31st Oct 1996
14// - Added methods to shoot arrays: 28th July 1997
15// - Added check in case xm=-1: 4th February 1998
16// J.Marraffino - Added default mean as attribute and
17// operator() with mean: 16th Feb 1998
18// Gabriele Cosmo - Relocated static data from HepRandom: 5th Jan 1999
19// M Fischler - put and get to/from streams 12/15/04
20// M Fischler - put/get to/from streams uses pairs of ulongs when
21// + storing doubles avoid problems with precision
22// 4/14/05
23// Mark Fischler - Repaired BUG - when mean > 2 billion, was returning
24// mean instead of the proper value. 01/13/06
25// =======================================================================
26
30#include <cmath> // for std::floor()
31#include <iostream>
32#include <string>
33#include <vector>
34
35namespace CLHEP {
36
37std::string RandPoisson::name() const {return "RandPoisson";}
39
40// Initialisation of static data
41CLHEP_THREAD_LOCAL double RandPoisson::status_st[3] = {0., 0., 0.};
43const double RandPoisson::meanMax_st = 2.0E9;
44
46}
47
49 return double(fire( defaultMean ));
50}
51
52double RandPoisson::operator()( double mean ) {
53 return double(fire( mean ));
54}
55
56double gammln(double xx) {
57
58// Returns the value ln(Gamma(xx) for xx > 0. Full accuracy is obtained for
59// xx > 1. For 0 < xx < 1. the reflection formula (6.1.4) can be used first.
60// (Adapted from Numerical Recipes in C)
61
62 static const double cof[6] = {76.18009172947146,-86.50532032941677,
63 24.01409824083091, -1.231739572450155,
64 0.1208650973866179e-2, -0.5395239384953e-5};
65 int j;
66 double x = xx - 1.0;
67 double tmp = x + 5.5;
68 tmp -= (x + 0.5) * std::log(tmp);
69 double ser = 1.000000000190015;
70
71 for ( j = 0; j <= 5; j++ ) {
72 x += 1.0;
73 ser += cof[j]/x;
74 }
75 return -tmp + std::log(2.5066282746310005*ser);
76}
77
78static
79double normal (HepRandomEngine* eptr) // mf 1/13/06
80{
81 double r;
82 double v1,v2,fac;
83 do {
84 v1 = 2.0 * eptr->flat() - 1.0;
85 v2 = 2.0 * eptr->flat() - 1.0;
86 r = v1*v1 + v2*v2;
87 } while ( r > 1.0 );
88
89 fac = std::sqrt(-2.0*std::log(r)/r);
90 return v2*fac;
91}
92
93long RandPoisson::shoot(double xm) {
94
95// Returns as a floating-point number an integer value that is a random
96// deviation drawn from a Poisson distribution of mean xm, using flat()
97// as a source of uniform random numbers.
98// (Adapted from Numerical Recipes in C)
99
100 double em, t, y;
101 double sq, alxm, g1;
102 double om = getOldMean();
104
105 double* pstatus = getPStatus();
106 sq = pstatus[0];
107 alxm = pstatus[1];
108 g1 = pstatus[2];
109
110 if( xm == -1 ) return 0;
111 if( xm < 12.0 ) {
112 if( xm != om ) {
113 setOldMean(xm);
114 g1 = std::exp(-xm);
115 }
116 em = -1;
117 t = 1.0;
118 do {
119 em += 1.0;
120 t *= anEngine->flat();
121 } while( t > g1 );
122 }
123 else if ( xm < getMaxMean() ) {
124 if ( xm != om ) {
125 setOldMean(xm);
126 sq = std::sqrt(2.0*xm);
127 alxm = std::log(xm);
128 g1 = xm*alxm - gammln(xm + 1.0);
129 }
130 do {
131 do {
132 y = std::tan(CLHEP::pi*anEngine->flat());
133 em = sq*y + xm;
134 } while( em < 0.0 );
135 em = std::floor(em);
136 t = 0.9*(1.0 + y*y)* std::exp(em*alxm - gammln(em + 1.0) - g1);
137 } while( anEngine->flat() > t );
138 }
139 else {
140 em = xm + std::sqrt(xm) * normal (anEngine); // mf 1/13/06
141 if ( static_cast<long>(em) < 0 )
142 em = static_cast<long>(xm) >= 0 ? xm : getMaxMean();
143 }
144 setPStatus(sq,alxm,g1);
145 return long(em);
146}
147
148void RandPoisson::shootArray(const int size, long* vect, double m1)
149{
150 for( long* v = vect; v != vect + size; ++v )
151 *v = shoot(m1);
152}
153
154long RandPoisson::shoot(HepRandomEngine* anEngine, double xm) {
155
156// Returns as a floating-point number an integer value that is a random
157// deviation drawn from a Poisson distribution of mean xm, using flat()
158// of a given Random Engine as a source of uniform random numbers.
159// (Adapted from Numerical Recipes in C)
160
161 double em, t, y;
162 double sq, alxm, g1;
163 double om = getOldMean();
164
165 double* pstatus = getPStatus();
166 sq = pstatus[0];
167 alxm = pstatus[1];
168 g1 = pstatus[2];
169
170 if( xm == -1 ) return 0;
171 if( xm < 12.0 ) {
172 if( xm != om ) {
173 setOldMean(xm);
174 g1 = std::exp(-xm);
175 }
176 em = -1;
177 t = 1.0;
178 do {
179 em += 1.0;
180 t *= anEngine->flat();
181 } while( t > g1 );
182 }
183 else if ( xm < getMaxMean() ) {
184 if ( xm != om ) {
185 setOldMean(xm);
186 sq = std::sqrt(2.0*xm);
187 alxm = std::log(xm);
188 g1 = xm*alxm - gammln(xm + 1.0);
189 }
190 do {
191 do {
192 y = std::tan(CLHEP::pi*anEngine->flat());
193 em = sq*y + xm;
194 } while( em < 0.0 );
195 em = std::floor(em);
196 t = 0.9*(1.0 + y*y)* std::exp(em*alxm - gammln(em + 1.0) - g1);
197 } while( anEngine->flat() > t );
198 }
199 else {
200 em = xm + std::sqrt(xm) * normal (anEngine); // mf 1/13/06
201 if ( static_cast<long>(em) < 0 )
202 em = static_cast<long>(xm) >= 0 ? xm : getMaxMean();
203 }
204 setPStatus(sq,alxm,g1);
205 return long(em);
206}
207
208void RandPoisson::shootArray(HepRandomEngine* anEngine, const int size,
209 long* vect, double m1)
210{
211 for( long* v = vect; v != vect + size; ++v )
212 *v = shoot(anEngine,m1);
213}
214
216 return long(fire( defaultMean ));
217}
218
219long RandPoisson::fire(double xm) {
220
221// Returns as a floating-point number an integer value that is a random
222// deviation drawn from a Poisson distribution of mean xm, using flat()
223// as a source of uniform random numbers.
224// (Adapted from Numerical Recipes in C)
225
226 double em, t, y;
227 double sq, alxm, g1;
228
229 sq = status[0];
230 alxm = status[1];
231 g1 = status[2];
232
233 if( xm == -1 ) return 0;
234 if( xm < 12.0 ) {
235 if( xm != oldm ) {
236 oldm = xm;
237 g1 = std::exp(-xm);
238 }
239 em = -1;
240 t = 1.0;
241 do {
242 em += 1.0;
243 t *= localEngine->flat();
244 } while( t > g1 );
245 }
246 else if ( xm < meanMax ) {
247 if ( xm != oldm ) {
248 oldm = xm;
249 sq = std::sqrt(2.0*xm);
250 alxm = std::log(xm);
251 g1 = xm*alxm - gammln(xm + 1.0);
252 }
253 do {
254 do {
255 y = std::tan(CLHEP::pi*localEngine->flat());
256 em = sq*y + xm;
257 } while( em < 0.0 );
258 em = std::floor(em);
259 t = 0.9*(1.0 + y*y)* std::exp(em*alxm - gammln(em + 1.0) - g1);
260 } while( localEngine->flat() > t );
261 }
262 else {
263 em = xm + std::sqrt(xm) * normal (localEngine.get()); // mf 1/13/06
264 if ( static_cast<long>(em) < 0 )
265 em = static_cast<long>(xm) >= 0 ? xm : getMaxMean();
266 }
267 status[0] = sq; status[1] = alxm; status[2] = g1;
268 return long(em);
269}
270
271void RandPoisson::fireArray(const int size, long* vect )
272{
273 for( long* v = vect; v != vect + size; ++v )
274 *v = fire( defaultMean );
275}
276
277void RandPoisson::fireArray(const int size, long* vect, double m1)
278{
279 for( long* v = vect; v != vect + size; ++v )
280 *v = fire( m1 );
281}
282
283std::ostream & RandPoisson::put ( std::ostream & os ) const {
284 int pr=os.precision(20);
285 std::vector<unsigned long> t(2);
286 os << " " << name() << "\n";
287 os << "Uvec" << "\n";
289 os << meanMax << " " << t[0] << " " << t[1] << "\n";
291 os << defaultMean << " " << t[0] << " " << t[1] << "\n";
293 os << status[0] << " " << t[0] << " " << t[1] << "\n";
295 os << status[1] << " " << t[0] << " " << t[1] << "\n";
297 os << status[2] << " " << t[0] << " " << t[1] << "\n";
299 os << oldm << " " << t[0] << " " << t[1] << "\n";
300 os.precision(pr);
301 return os;
302}
303
304std::istream & RandPoisson::get ( std::istream & is ) {
305 std::string inName;
306 is >> inName;
307 if (inName != name()) {
308 is.clear(std::ios::badbit | is.rdstate());
309 std::cerr << "Mismatch when expecting to read state of a "
310 << name() << " distribution\n"
311 << "Name found was " << inName
312 << "\nistream is left in the badbit state\n";
313 return is;
314 }
315 if (possibleKeywordInput(is, "Uvec", meanMax)) {
316 std::vector<unsigned long> t(2);
317 is >> meanMax >> t[0] >> t[1]; meanMax = DoubConv::longs2double(t);
318 is >> defaultMean >> t[0] >> t[1]; defaultMean = DoubConv::longs2double(t);
319 is >> status[0] >> t[0] >> t[1]; status[0] = DoubConv::longs2double(t);
320 is >> status[1] >> t[0] >> t[1]; status[1] = DoubConv::longs2double(t);
321 is >> status[2] >> t[0] >> t[1]; status[2] = DoubConv::longs2double(t);
322 is >> oldm >> t[0] >> t[1]; oldm = DoubConv::longs2double(t);
323 return is;
324 }
325 // is >> meanMax encompassed by possibleKeywordInput
326 is >> defaultMean >> status[0] >> status[1] >> status[2];
327 return is;
328}
329
330} // namespace CLHEP
331
static const G4double fac
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:268
std::string name() const
Definition: RandPoisson.cc:37
std::shared_ptr< HepRandomEngine > localEngine
Definition: RandPoisson.h:117
std::ostream & put(std::ostream &os) const
Definition: RandPoisson.cc:283
static void shootArray(const int size, long *vect, double mean=1.0)
Definition: RandPoisson.cc:148
static long shoot(double mean=1.0)
Definition: RandPoisson.cc:93
static double getOldMean()
Definition: RandPoisson.h:101
virtual ~RandPoisson()
Definition: RandPoisson.cc:45
static double getMaxMean()
Definition: RandPoisson.h:103
static void setOldMean(double val)
Definition: RandPoisson.h:105
static void setPStatus(double sq, double alxm, double g1)
Definition: RandPoisson.h:109
static const double meanMax_st
Definition: RandPoisson.h:123
void fireArray(const int size, long *vect)
Definition: RandPoisson.cc:271
static CLHEP_THREAD_LOCAL double oldm_st
Definition: RandPoisson.h:122
static CLHEP_THREAD_LOCAL double status_st[3]
Definition: RandPoisson.h:121
static double * getPStatus()
Definition: RandPoisson.h:107
std::istream & get(std::istream &is)
Definition: RandPoisson.cc:304
HepRandomEngine & engine()
Definition: RandPoisson.cc:38
Definition: DoubConv.h:17
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:166
double gammln(double xx)
Definition: RandPoisson.cc:56
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:79
static constexpr double pi
Definition: SystemOfUnits.h:55
#define CLHEP_THREAD_LOCAL
Definition: thread_local.h:13