RandPoisson.cc

Go to the documentation of this file.
00001 // $Id:$
00002 // -*- C++ -*-
00003 //
00004 // -----------------------------------------------------------------------
00005 //                             HEP Random
00006 //                         --- RandPoisson ---
00007 //                      class implementation file
00008 // -----------------------------------------------------------------------
00009 // This file is part of Geant4 (simulation toolkit for HEP).
00010 
00011 // =======================================================================
00012 // Gabriele Cosmo - Created: 5th September 1995
00013 //                - Added not static Shoot() method: 17th May 1996
00014 //                - Algorithm now operates on doubles: 31st Oct 1996
00015 //                - Added methods to shoot arrays: 28th July 1997
00016 //                - Added check in case xm=-1: 4th February 1998
00017 // J.Marraffino   - Added default mean as attribute and
00018 //                  operator() with mean: 16th Feb 1998
00019 // Gabriele Cosmo - Relocated static data from HepRandom: 5th Jan 1999
00020 // M Fischler     - put and get to/from streams 12/15/04
00021 // M Fischler         - put/get to/from streams uses pairs of ulongs when
00022 //                      + storing doubles avoid problems with precision 
00023 //                      4/14/05
00024 // Mark Fischler  - Repaired BUG - when mean > 2 billion, was returning
00025 //                  mean instead of the proper value.  01/13/06
00026 // =======================================================================
00027 
00028 #include "CLHEP/Random/RandPoisson.h"
00029 #include "CLHEP/Units/PhysicalConstants.h"
00030 #include "CLHEP/Random/DoubConv.h"
00031 #include <cmath>        // for std::floor()
00032 
00033 namespace CLHEP {
00034 
00035 std::string RandPoisson::name() const {return "RandPoisson";}
00036 HepRandomEngine & RandPoisson::engine() {return *localEngine;}
00037 
00038 // Initialisation of static data
00039 double RandPoisson::status_st[3] = {0., 0., 0.};
00040 double RandPoisson::oldm_st = -1.0;
00041 const double RandPoisson::meanMax_st = 2.0E9;
00042 
00043 RandPoisson::~RandPoisson() {
00044 }
00045 
00046 double RandPoisson::operator()() {
00047   return double(fire( defaultMean ));
00048 }
00049 
00050 double RandPoisson::operator()( double mean ) {
00051   return double(fire( mean ));
00052 }
00053 
00054 double gammln(double xx) {
00055 
00056 // Returns the value ln(Gamma(xx) for xx > 0.  Full accuracy is obtained for 
00057 // xx > 1. For 0 < xx < 1. the reflection formula (6.1.4) can be used first.
00058 // (Adapted from Numerical Recipes in C)
00059 
00060   static double cof[6] = {76.18009172947146,-86.50532032941677,
00061                              24.01409824083091, -1.231739572450155,
00062                              0.1208650973866179e-2, -0.5395239384953e-5};
00063   int j;
00064   double x = xx - 1.0;
00065   double tmp = x + 5.5;
00066   tmp -= (x + 0.5) * std::log(tmp);
00067   double ser = 1.000000000190015;
00068 
00069   for ( j = 0; j <= 5; j++ ) {
00070     x += 1.0;
00071     ser += cof[j]/x;
00072   }
00073   return -tmp + std::log(2.5066282746310005*ser);
00074 }
00075 
00076 static
00077 double normal (HepRandomEngine* eptr)           // mf 1/13/06
00078 {
00079   double r;
00080   double v1,v2,fac;
00081   do {
00082     v1 = 2.0 * eptr->flat() - 1.0;
00083     v2 = 2.0 * eptr->flat() - 1.0;
00084     r = v1*v1 + v2*v2;
00085   } while ( r > 1.0 );
00086 
00087   fac = std::sqrt(-2.0*std::log(r)/r);
00088   return v2*fac;
00089 }
00090 
00091 long RandPoisson::shoot(double xm) {
00092 
00093 // Returns as a floating-point number an integer value that is a random
00094 // deviation drawn from a Poisson distribution of mean xm, using flat()
00095 // as a source of uniform random numbers.
00096 // (Adapted from Numerical Recipes in C)
00097 
00098   double em, t, y;
00099   double sq, alxm, g1;
00100   double om = getOldMean();
00101   HepRandomEngine* anEngine = HepRandom::getTheEngine();
00102 
00103   double* status = getPStatus();
00104   sq = status[0];
00105   alxm = status[1];
00106   g1 = status[2];
00107 
00108   if( xm == -1 ) return 0;
00109   if( xm < 12.0 ) {
00110     if( xm != om ) {
00111       setOldMean(xm);
00112       g1 = std::exp(-xm);
00113     }
00114     em = -1;
00115     t = 1.0;
00116     do {
00117       em += 1.0;
00118       t *= anEngine->flat();
00119     } while( t > g1 );
00120   }
00121   else if ( xm < getMaxMean() ) {
00122     if ( xm != om ) {
00123       setOldMean(xm);
00124       sq = std::sqrt(2.0*xm);
00125       alxm = std::log(xm);
00126       g1 = xm*alxm - gammln(xm + 1.0);
00127     }
00128     do {
00129       do {
00130         y = std::tan(CLHEP::pi*anEngine->flat());
00131         em = sq*y + xm;
00132       } while( em < 0.0 );
00133       em = std::floor(em);
00134       t = 0.9*(1.0 + y*y)* std::exp(em*alxm - gammln(em + 1.0) - g1);
00135     } while( anEngine->flat() > t );
00136   }
00137   else {
00138     em = xm + std::sqrt(xm) * normal (anEngine);        // mf 1/13/06
00139     if ( static_cast<long>(em) < 0 ) 
00140       em = static_cast<long>(xm) >= 0 ? xm : getMaxMean();
00141   }    
00142   setPStatus(sq,alxm,g1);
00143   return long(em);
00144 }
00145 
00146 void RandPoisson::shootArray(const int size, long* vect, double m1)
00147 {
00148   for( long* v = vect; v != vect + size; ++v )
00149     *v = shoot(m1);
00150 }
00151 
00152 long RandPoisson::shoot(HepRandomEngine* anEngine, double xm) {
00153 
00154 // Returns as a floating-point number an integer value that is a random
00155 // deviation drawn from a Poisson distribution of mean xm, using flat()
00156 // of a given Random Engine as a source of uniform random numbers.
00157 // (Adapted from Numerical Recipes in C)
00158 
00159   double em, t, y;
00160   double sq, alxm, g1;
00161   double om = getOldMean();
00162 
00163   double* status = getPStatus();
00164   sq = status[0];
00165   alxm = status[1];
00166   g1 = status[2];
00167 
00168   if( xm == -1 ) return 0;
00169   if( xm < 12.0 ) {
00170     if( xm != om ) {
00171       setOldMean(xm);
00172       g1 = std::exp(-xm);
00173     }
00174     em = -1;
00175     t = 1.0;
00176     do {
00177       em += 1.0;
00178       t *= anEngine->flat();
00179     } while( t > g1 );
00180   }
00181   else if ( xm < getMaxMean() ) {
00182     if ( xm != om ) {
00183       setOldMean(xm);
00184       sq = std::sqrt(2.0*xm);
00185       alxm = std::log(xm);
00186       g1 = xm*alxm - gammln(xm + 1.0);
00187     }
00188     do {
00189       do {
00190         y = std::tan(CLHEP::pi*anEngine->flat());
00191         em = sq*y + xm;
00192       } while( em < 0.0 );
00193       em = std::floor(em);
00194       t = 0.9*(1.0 + y*y)* std::exp(em*alxm - gammln(em + 1.0) - g1);
00195     } while( anEngine->flat() > t );
00196   }
00197   else {
00198     em = xm + std::sqrt(xm) * normal (anEngine);        // mf 1/13/06
00199     if ( static_cast<long>(em) < 0 ) 
00200       em = static_cast<long>(xm) >= 0 ? xm : getMaxMean();
00201   }    
00202   setPStatus(sq,alxm,g1);
00203   return long(em);
00204 }
00205 
00206 void RandPoisson::shootArray(HepRandomEngine* anEngine, const int size,
00207                              long* vect, double m1)
00208 {
00209   for( long* v = vect; v != vect + size; ++v )
00210     *v = shoot(anEngine,m1);
00211 }
00212 
00213 long RandPoisson::fire() {
00214   return long(fire( defaultMean ));
00215 }
00216 
00217 long RandPoisson::fire(double xm) {
00218 
00219 // Returns as a floating-point number an integer value that is a random
00220 // deviation drawn from a Poisson distribution of mean xm, using flat()
00221 // as a source of uniform random numbers.
00222 // (Adapted from Numerical Recipes in C)
00223 
00224   double em, t, y;
00225   double sq, alxm, g1;
00226 
00227   sq = status[0];
00228   alxm = status[1];
00229   g1 = status[2];
00230 
00231   if( xm == -1 ) return 0;
00232   if( xm < 12.0 ) {
00233     if( xm != oldm ) {
00234       oldm = xm;
00235       g1 = std::exp(-xm);
00236     }
00237     em = -1;
00238     t = 1.0;
00239     do {
00240       em += 1.0;
00241       t *= localEngine->flat();
00242     } while( t > g1 );
00243   }
00244   else if ( xm < meanMax ) {
00245     if ( xm != oldm ) {
00246       oldm = xm;
00247       sq = std::sqrt(2.0*xm);
00248       alxm = std::log(xm);
00249       g1 = xm*alxm - gammln(xm + 1.0);
00250     }
00251     do {
00252       do {
00253         y = std::tan(CLHEP::pi*localEngine->flat());
00254         em = sq*y + xm;
00255       } while( em < 0.0 );
00256       em = std::floor(em);
00257       t = 0.9*(1.0 + y*y)* std::exp(em*alxm - gammln(em + 1.0) - g1);
00258     } while( localEngine->flat() > t );
00259   }
00260   else {
00261     em = xm + std::sqrt(xm) * normal (localEngine.get());       // mf 1/13/06
00262     if ( static_cast<long>(em) < 0 ) 
00263       em = static_cast<long>(xm) >= 0 ? xm : getMaxMean();
00264   }    
00265   status[0] = sq; status[1] = alxm; status[2] = g1;
00266   return long(em);
00267 }
00268 
00269 void RandPoisson::fireArray(const int size, long* vect )
00270 {
00271   for( long* v = vect; v != vect + size; ++v )
00272     *v = fire( defaultMean );
00273 }
00274 
00275 void RandPoisson::fireArray(const int size, long* vect, double m1)
00276 {
00277   for( long* v = vect; v != vect + size; ++v )
00278     *v = fire( m1 );
00279 }
00280 
00281 std::ostream & RandPoisson::put ( std::ostream & os ) const {
00282   int pr=os.precision(20);
00283   std::vector<unsigned long> t(2);
00284   os << " " << name() << "\n";
00285   os << "Uvec" << "\n";
00286   t = DoubConv::dto2longs(meanMax);
00287   os << meanMax << " " << t[0] << " " << t[1] << "\n";
00288   t = DoubConv::dto2longs(defaultMean);
00289   os << defaultMean << " " << t[0] << " " << t[1] << "\n";
00290   t = DoubConv::dto2longs(status[0]);
00291   os << status[0] << " " << t[0] << " " << t[1] << "\n";
00292   t = DoubConv::dto2longs(status[1]);
00293   os << status[1] << " " << t[0] << " " << t[1] << "\n";
00294   t = DoubConv::dto2longs(status[2]);
00295   os << status[2] << " " << t[0] << " " << t[1] << "\n";
00296   t = DoubConv::dto2longs(oldm);
00297   os << oldm << " " << t[0] << " " << t[1] << "\n";
00298   os.precision(pr);
00299   return os;
00300 }
00301 
00302 std::istream & RandPoisson::get ( std::istream & is ) {
00303   std::string inName;
00304   is >> inName;
00305   if (inName != name()) {
00306     is.clear(std::ios::badbit | is.rdstate());
00307     std::cerr << "Mismatch when expecting to read state of a "
00308               << name() << " distribution\n"
00309               << "Name found was " << inName
00310               << "\nistream is left in the badbit state\n";
00311     return is;
00312   }
00313   if (possibleKeywordInput(is, "Uvec", meanMax)) {
00314     std::vector<unsigned long> t(2);
00315     is >> meanMax     >> t[0] >> t[1]; meanMax     = DoubConv::longs2double(t); 
00316     is >> defaultMean >> t[0] >> t[1]; defaultMean = DoubConv::longs2double(t); 
00317     is >> status[0]   >> t[0] >> t[1]; status[0]   = DoubConv::longs2double(t); 
00318     is >> status[1]   >> t[0] >> t[1]; status[1]   = DoubConv::longs2double(t); 
00319     is >> status[2]   >> t[0] >> t[1]; status[2]   = DoubConv::longs2double(t); 
00320     is >> oldm        >> t[0] >> t[1]; oldm        = DoubConv::longs2double(t); 
00321     return is;
00322   }
00323   // is >> meanMax encompassed by possibleKeywordInput
00324   is >> defaultMean >> status[0] >> status[1] >> status[2];
00325   return is;
00326 }
00327 
00328 }  // namespace CLHEP
00329 

Generated on Mon May 27 17:50:33 2013 for Geant4 by  doxygen 1.4.7