StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RandPoisson.cc
1 /***************************************************************************
2  *
3  * $Id: RandPoisson.cc,v 1.4 2016/01/22 17:10:50 smirnovd Exp $
4  *
5  * Author:
6  ***************************************************************************
7  *
8  * Description:
9  * RandPoisson.cc,v 1.4 1998/02/04 23:22:00
10  * -----------------------------------------------------------------------
11  * HEP Random
12  * --- RandPoisson ---
13  * class implementation file
14  * -----------------------------------------------------------------------
15  * This file is part of Geant4 (simulation toolkit for HEP).
16  *
17  ***************************************************************************
18  *
19  * $Log: RandPoisson.cc,v $
20  * Revision 1.4 2016/01/22 17:10:50 smirnovd
21  * StarClassLibrary: Removed deprecated storage class specifier 'register'
22  *
23  * This keyword is deprecated since C++11 and serves no purpose
24  *
25  * "
26  * The register specifier is only allowed for objects declared at block scope and
27  * in function parameter lists. It indicates automatic storage duration, which is
28  * the default for these kinds of declarations. Additionally, the presence of this
29  * keyword may be used as a hint for the optimizer to store the value of this
30  * variable in a CPU register.
31  * "
32  *
33  * Revision 1.3 2003/09/02 17:59:34 perev
34  * gcc 3.2 updates + WarnOff
35  *
36  * Revision 1.2 1999/12/07 23:43:04 ullrich
37  * Modified to get rid of warnings on Linux.
38  *
39  * Revision 1.1 1999/01/30 03:59:00 fisyak
40  * Root Version of StarClassLibrary
41  *
42  * Revision 1.1 1999/01/23 00:29:09 ullrich
43  * Initial Revision
44  *
45  **************************************************************************/
46 #include "RandPoisson.h"
47 
48 RandPoisson::~RandPoisson() {
49  if ( deleteEngine ) delete localEngine;
50 }
51 
52 HepDouble RandPoisson::operator()() {
53  return HepDouble(fire());
54 }
55 
56 HepDouble gammln(HepDouble 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 HepDouble cof[6] = {76.18009172947146,-86.50532032941677,
63  24.01409824083091, -1.231739572450155,
64  0.1208650973866179e-2, -0.5395239384953e-5};
65  HepInt j;
66  HepDouble x = xx - 1.0;
67  HepDouble tmp = x + 5.5;
68  tmp -= (x + 0.5) * ::log(tmp);
69  HepDouble ser = 1.000000000190015;
70 
71  for ( j = 0; j <= 5; j++ ) {
72  x += 1.0;
73  ser += cof[j]/x;
74  }
75  return -tmp + ::log(2.5066282746310005*ser);
76 }
77 
78 long RandPoisson::shoot(HepDouble xm) {
79 
80 // Returns as a floating-point number an integer value that is a random
81 // deviation drawn from a Poisson distribution of mean xm, using flat()
82 // as a source of uniform random numbers.
83 // (Adapted from Numerical Recipes in C)
84 
85  HepDouble em;
86  HepDouble t, y;
87  HepDouble sq, alxm, g;
88  HepDouble om = getOldMean();
89 
90  HepDouble* status = getPStatus();
91  sq = status[0];
92  alxm = status[1];
93  g = status[2];
94 
95  if( xm == -1 ) return 0;
96  if( xm < 12.0 ) {
97  if( xm != om ) {
98  setOldMean(xm);
99  g = exp(-xm);
100  }
101  em = -1;
102  t = 1.0;
103  do {
104  em += 1.0;
105  t *= HepRandom::getTheGenerator()->flat();
106  } while( t > g );
107  }
108  else if ( xm < getMaxMean() ) {
109  if ( xm != om ) {
110  setOldMean(xm);
111  sq = ::sqrt(2.0*xm);
112  alxm = ::log(xm);
113  g = xm*alxm - gammln(xm + 1.0);
114  }
115  do {
116  do {
117  y = tan(M_PI*HepRandom::getTheGenerator()->flat());
118  em = sq*y + xm;
119  } while( em < 0.0 );
120  em = floor(em);
121  t = 0.9*(1.0 + y*y)* exp(em*alxm - gammln(em + 1.0) - g);
122  } while( HepRandom::getTheGenerator()->flat() > t );
123  }
124  else {
125  if ( xm != om ) {
126  setOldMean(xm);
127  sq = ::sqrt(2.0*xm);
128  alxm = ::log(xm);
129  g = xm*alxm - gammln(xm + 1.0);
130  }
131  em = xm;
132  }
133  setPStatus(sq,alxm,g);
134  return long(em);
135 }
136 
137 void RandPoisson::shootArray(const HepInt size, long* vect, HepDouble m)
138 {
139  for (int i=0; i<size; ++i)
140  vect[i] = shoot(m);
141 }
142 
143 void
144 #ifndef ST_NO_TEMPLATE_DEF_ARGS
145 RandPoisson::shootArray(vector<long>& vec, HepDouble m)
146 #else
147 RandPoisson::shootArray(vector<long,allocator<long> >& vec, HepDouble m)
148 #endif
149 {
150  for (unsigned int i=0; i<vec.size(); ++i)
151  vec[i] = shoot(m);
152 }
153 
154 long RandPoisson::shoot(HepRandomEngine* anEngine, HepDouble 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  HepDouble em;
162  HepDouble t, y;
163  HepDouble sq, alxm, g;
164  HepDouble om = getOldMean();
165 
166  HepDouble* status = getPStatus();
167  sq = status[0];
168  alxm = status[1];
169  g = status[2];
170 
171  if( xm == -1 ) return 0;
172  if( xm < 12.0 ) {
173  if( xm != om ) {
174  setOldMean(xm);
175  g = exp(-xm);
176  }
177  em = -1;
178  t = 1.0;
179  do {
180  em += 1.0;
181  t *= anEngine->flat();
182  } while( t > g );
183  }
184  else if ( xm < getMaxMean() ) {
185  if ( xm != om ) {
186  setOldMean(xm);
187  sq = ::sqrt(2.0*xm);
188  alxm = ::log(xm);
189  g = xm*alxm - gammln(xm + 1.0);
190  }
191  do {
192  do {
193  y = tan(M_PI*anEngine->flat());
194  em = sq*y + xm;
195  } while( em < 0.0 );
196  em = floor(em);
197  t = 0.9*(1.0 + y*y)* exp(em*alxm - gammln(em + 1.0) - g);
198  } while( anEngine->flat() > t );
199  }
200  else {
201  if ( xm != om ) {
202  setOldMean(xm);
203  sq = ::sqrt(2.0*xm);
204  alxm = ::log(xm);
205  g = xm*alxm - gammln(xm + 1.0);
206  }
207  em = xm;
208  }
209  setPStatus(sq,alxm,g);
210  return long(em);
211 }
212 
213 void RandPoisson::shootArray(HepRandomEngine* anEngine, const HepInt size,
214  long* vect, HepDouble m)
215 {
216  HepInt i;
217 
218  for (i=0; i<size; ++i)
219  vect[i] = shoot(anEngine,m);
220 }
221 void
222 #ifndef ST_NO_TEMPLATE_DEF_ARGS
223 RandPoisson::shootArray(HepRandomEngine* anEngine,
224  vector<long>& vec, HepDouble m)
225 #else
226 RandPoisson::shootArray(HepRandomEngine* anEngine,
227  vector<long,allocator<long> >& vec, HepDouble m)
228 #endif
229 {
230  for (unsigned int i=0; i<vec.size(); ++i)
231  vec[i] = shoot(anEngine,m);
232 }
233 long RandPoisson::fire(HepDouble xm) {
234 
235 // Returns as a floating-point number an integer value that is a random
236 // deviation drawn from a Poisson distribution of mean xm, using flat()
237 // as a source of uniform random numbers.
238 // (Adapted from Numerical Recipes in C)
239 
240  HepDouble em;
241  HepDouble t, y;
242  HepDouble sq, alxm, g;
243 
244  sq = status[0];
245  alxm = status[1];
246  g = status[2];
247 
248  if( xm == -1 ) return 0;
249  if( xm < 12.0 ) {
250  if( xm != oldm ) {
251  oldm = xm;
252  g = exp(-xm);
253  }
254  em = -1;
255  t = 1.0;
256  do {
257  em += 1.0;
258  t *= localEngine->flat();
259  } while( t > g );
260  }
261  else if ( xm < meanMax ) {
262  if ( xm != oldm ) {
263  oldm = xm;
264  sq = ::sqrt(2.0*xm);
265  alxm = ::log(xm);
266  g = xm*alxm - gammln(xm + 1.0);
267  }
268  do {
269  do {
270  y = tan(M_PI*localEngine->flat());
271  em = sq*y + xm;
272  } while( em < 0.0 );
273  em = floor(em);
274  t = 0.9*(1.0 + y*y)* exp(em*alxm - gammln(em + 1.0) - g);
275  } while( localEngine->flat() > t );
276  }
277  else {
278  if ( xm != oldm ) {
279  oldm = xm;
280  sq = ::sqrt(2.0*xm);
281  alxm = ::log(xm);
282  g = xm*alxm - gammln(xm + 1.0);
283  }
284  em = xm;
285  }
286  status[0] = sq; status[1] = alxm; status[2] = g;
287  return long(em);
288 }
289 
290 void RandPoisson::fireArray(const HepInt size, long* vect, HepDouble m)
291 {
292  HepInt i;
293 
294  for (i=0; i<size; ++i)
295  vect[i] = fire(m);
296 }
297 
298 void
299 #ifndef ST_NO_TEMPLATE_DEF_ARGS
300 RandPoisson::fireArray(vector<long>& vec, HepDouble m)
301 #else
302 RandPoisson::fireArray(vector<long,allocator<long> >& vec, HepDouble m)
303 #endif
304 {
305  for (unsigned int i=0; i<vec.size(); ++i)
306  vec[i] = fire(m);
307 }