Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:09

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 //
0014 // Please note: This code comes straight from the TRandom class of ROOT
0015 // See for details:  https://root.cern.ch/root/html534/TRandom.html
0016 //
0017 // The basic [0...1] generator is a std::function object to allow users
0018 // to plug their own implementations
0019 //
0020 // I know this is not nice, but I did not see any other way to overcome
0021 // the virtualization mechanism
0022 //
0023 // M.Frank
0024 //==========================================================================
0025 
0026 // Framework include files
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();              // uniform on ] 0, 1 ]
0065   double t = -tau * std::log( x ); // convert to exponential distribution
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   /*zhm 0.967882898*/
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   // for large value we use inversion method
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     // use Gaussian approximation vor very large values
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 }