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