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