00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "CLHEP/Random/RandPoisson.h"
00029 #include "CLHEP/Units/PhysicalConstants.h"
00030 #include "CLHEP/Random/DoubConv.h"
00031 #include <cmath>
00032
00033 namespace CLHEP {
00034
00035 std::string RandPoisson::name() const {return "RandPoisson";}
00036 HepRandomEngine & RandPoisson::engine() {return *localEngine;}
00037
00038
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
00057
00058
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)
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
00094
00095
00096
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);
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
00155
00156
00157
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);
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
00220
00221
00222
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());
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
00324 is >> defaultMean >> status[0] >> status[1] >> status[2];
00325 return is;
00326 }
00327
00328 }
00329