Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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";}
38HepRandomEngine & RandPoisson::engine() {return *localEngine;}
39
40// Initialisation of static data
41CLHEP_THREAD_LOCAL double RandPoisson::status_st[3] = {0., 0., 0.};
42CLHEP_THREAD_LOCAL double RandPoisson::oldm_st = -1.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";
292 t = DoubConv::dto2longs(status[0]);
293 os << status[0] << " " << t[0] << " " << t[1] << "\n";
294 t = DoubConv::dto2longs(status[1]);
295 os << status[1] << " " << t[0] << " " << t[1] << "\n";
296 t = DoubConv::dto2longs(status[2]);
297 os << status[2] << " " << t[0] << " " << t[1] << "\n";
298 t = DoubConv::dto2longs(oldm);
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 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::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
void fireArray(const int size, long *vect)
Definition: RandPoisson.cc:271
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
#define CLHEP_THREAD_LOCAL
Definition: thread_local.h:13