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