File indexing completed on 2025-01-18 09:14:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include <DDDigi/DigiRandomGenerator.h>
0028 #include <Math/ProbFuncMathCore.h>
0029 #include <Math/SpecFuncMathCore.h>
0030 #include <Math/QuantFuncMathCore.h>
0031 #include <cmath>
0032
0033
0034 using namespace dd4hep::digi;
0035
0036 static constexpr double PIOVER2 = M_PI / 2.0;
0037 static constexpr double TWOPI = M_PI * 2.0;
0038
0039 double DigiRandomGenerator::random() const {
0040 return engine();
0041 }
0042
0043 double DigiRandomGenerator::uniform(double x1) const {
0044 double ans = engine();
0045 return x1*ans;
0046 }
0047
0048 double DigiRandomGenerator::uniform(double x1, double x2) const {
0049 double ans= engine();
0050 return x1 + (x2-x1)*ans;
0051 }
0052
0053 int DigiRandomGenerator::binomial(int ntot, double prob) const {
0054 if (prob < 0 || prob > 1) return 0;
0055 int n = 0;
0056 for (int i=0;i<ntot;i++) {
0057 if (engine() > prob) continue;
0058 n++;
0059 }
0060 return n;
0061 }
0062
0063 double DigiRandomGenerator::exponential(double tau) const {
0064 double x = engine();
0065 double t = -tau * std::log( x );
0066 return t;
0067 }
0068
0069 double DigiRandomGenerator::gaussian(double mean, double sigma) const {
0070 const double kC1 = 1.448242853;
0071 const double kC2 = 3.307147487;
0072 const double kC3 = 1.46754004;
0073 const double kD1 = 1.036467755;
0074 const double kD2 = 5.295844968;
0075 const double kD3 = 3.631288474;
0076 const double kHm = 0.483941449;
0077 const double kZm = 0.107981933;
0078 const double kHp = 4.132731354;
0079 const double kZp = 18.52161694;
0080 const double kPhln = 0.4515827053;
0081 const double kHm1 = 0.516058551;
0082 const double kHp1 = 3.132731354;
0083 const double kHzm = 0.375959516;
0084 const double kHzmp = 0.591923442;
0085
0086
0087 const double kAs = 0.8853395638;
0088 const double kBs = 0.2452635696;
0089 const double kCs = 0.2770276848;
0090 const double kB = 0.5029324303;
0091 const double kX0 = 0.4571828819;
0092 const double kYm = 0.187308492 ;
0093 const double kS = 0.7270572718 ;
0094 const double kT = 0.03895759111;
0095
0096 double result;
0097 double rn,x,y,z;
0098
0099 do {
0100 y = engine();
0101
0102 if (y>kHm1) {
0103 result = kHp*y-kHp1; break; }
0104
0105 else if (y<kZm) {
0106 rn = kZp*y-1;
0107 result = (rn>0) ? (1+rn) : (-1+rn);
0108 break;
0109 }
0110
0111 else if (y<kHm) {
0112 rn = engine();
0113 rn = rn-1+rn;
0114 z = (rn>0) ? 2-rn : -2-rn;
0115 if ((kC1-y)*(kC3+std::abs(z))<kC2) {
0116 result = z; break; }
0117 else {
0118 x = rn*rn;
0119 if ((y+kD1)*(kD3+x)<kD2) {
0120 result = rn; break; }
0121 else if (kHzmp-y<exp(-(z*z+kPhln)/2)) {
0122 result = z; break; }
0123 else if (y+kHzm<exp(-(x+kPhln)/2)) {
0124 result = rn; break; }
0125 }
0126 }
0127
0128 while (1) {
0129 x = engine();
0130 y = kYm * engine();
0131 z = kX0 - kS*x - y;
0132 if (z>0)
0133 rn = 2+y/x;
0134 else {
0135 x = 1-x;
0136 y = kYm-y;
0137 rn = -(2+y/x);
0138 }
0139 if ((y-kAs+x)*(kCs+x)+kBs<0) {
0140 result = rn; break; }
0141 else if (y<x+kT)
0142 if (rn*rn<4*(kB-log(x))) {
0143 result = rn; break; }
0144 }
0145 } while(0);
0146
0147 return mean + sigma * result;
0148 }
0149
0150 double DigiRandomGenerator::landau (double mu, double sigma) const {
0151 if (sigma <= 0) return 0;
0152 double x = engine();
0153 double res = mu + ROOT::Math::landau_quantile(x, sigma);
0154 return res;
0155 }
0156
0157 double DigiRandomGenerator::breitWigner(double mean, double gamma) const {
0158 double rval = 2*engine() - 1;
0159 double displ = 0.5*gamma*std::tan(rval*PIOVER2);
0160 return (mean+displ);
0161 }
0162
0163 double DigiRandomGenerator::poisson(double mean) const {
0164 int n;
0165 if (mean <= 0) return 0;
0166 if (mean < 25) {
0167 double expmean = std::exp(-mean);
0168 double pir = 1;
0169 n = -1;
0170 while(1) {
0171 n++;
0172 pir *= engine();
0173 if (pir <= expmean) break;
0174 }
0175 return static_cast<double>(n);
0176 }
0177
0178 else if (mean < 1E9) {
0179 double em, t, y;
0180 double sq, alxm, g;
0181 double pi = M_PI;
0182
0183 sq = std::sqrt(2.0*mean);
0184 alxm = std::log(mean);
0185 g = mean*alxm - ::ROOT::Math::lgamma(mean + 1.0);
0186
0187 do {
0188 do {
0189 y = std::tan(pi*engine());
0190 em = sq*y + mean;
0191 } while( em < 0.0 );
0192
0193 em = std::floor(em);
0194 t = 0.9*(1.0 + y*y)* std::exp(em*alxm - ::ROOT::Math::lgamma(em + 1.0) - g);
0195 } while( engine() > t );
0196
0197 return em;
0198
0199 } else {
0200
0201 return gaussian(0,1)*std::sqrt(mean) + mean +0.5;
0202 }
0203 }
0204
0205 void DigiRandomGenerator::rannor(float& a, float& b) const {
0206 double r, x, y, z;
0207
0208 y = engine();
0209 z = engine();
0210 x = z * 6.28318530717958623;
0211 r = std::sqrt(-2*std::log(y));
0212 a = (float)(r * std::sin(x));
0213 b = (float)(r * std::cos(x));
0214 }
0215
0216 void DigiRandomGenerator::rannor(double& a, double& b) const {
0217 double r, x, y, z;
0218
0219 y = engine();
0220 z = engine();
0221 x = z * 6.28318530717958623;
0222 r = std::sqrt(-2*std::log(y));
0223 a = (float)(r * std::sin(x));
0224 b = (float)(r * std::cos(x));
0225 }
0226
0227 void DigiRandomGenerator::sphere(double& x, double& y, double& z, double r) const {
0228 double a=0,b=0,r2=1;
0229 while (r2 > 0.25) {
0230 a = engine() - 0.5;
0231 b = engine() - 0.5;
0232 r2 = a*a + b*b;
0233 }
0234 z = r* ( -1. + 8.0 * r2 );
0235
0236 double scale = 8.0 * r * std::sqrt(0.25 - r2);
0237 x = a*scale;
0238 y = b*scale;
0239 }
0240
0241 void DigiRandomGenerator::circle(double &x, double &y, double r) const {
0242 double phi = uniform(0,TWOPI);
0243 x = r*std::cos(phi);
0244 y = r*std::sin(phi);
0245 }