MINT2
RooAbsGaussModelEfficiency.cpp
Go to the documentation of this file.
1 #include <cmath>
2 
3 #include "RVersion.h"
4 #include "RooMath.h"
5 #include "TMath.h"
6 
8 
9 //ClassImp(RooAbsGaussModelEfficiency);
11 
12 namespace {
13  using std::exp;
14  using std::sqrt;
15  //using std::erf;
16 
17  static const Double_t rootpi(sqrt(TMath::Pi())) ;
18  std::complex<double> evalApprox(Double_t x, const std::complex<double>& z) {
19  // compute exp(-x^2)cwerf(-i(z-x)), cwerf(z) = exp(-z^2)erfc(-iz)
20  // use the approximation: erfc(z) = exp(-z*z)/(sqrt(pi)*z)
21  // to explicitly cancel the divergent exp(y*y) behaviour of
22  // CWERF for z = x + i y with large negative y
23  static const std::complex<double> mi(0,-1);
24  std::complex<double> zp = mi*(z-x);
25  std::complex<double> zsq = zp*zp;
26  std::complex<double> v = -zsq - x*x;
27  std::complex<double> iz(z.imag()+x,z.real()-x); // ???
28  return exp(v)*(exp(zsq)/(iz*rootpi) + 1.)*2. ;
29  }
30 
31  // Calculate exp(-x^2) cwerf(i(z-x)), taking care of numerical instabilities
32  std::complex<double> eval(Double_t x, const std::complex<double>& z) {
33  Double_t re = z.real()-x;
34 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,34,8)
35  return (re>-5.0) ? RooMath::faddeeva_fast(std::complex<double>(-z.imag(),re))*exp(-x*x)
36  : evalApprox(x,z) ;
37 #else
38  if (re > -5.0) {
39  RooComplex erfc = RooMath::FastComplexErrFunc(RooComplex(-z.imag(),re));
40  return std::complex<double>(erfc.re(), erfc.im())*exp(-x*x);
41  } else {
42  return evalApprox(x,z) ;
43  }
44 #endif
45  }
46 
47  class N {
48  public:
49  N(double x, const std::complex<double>& z) ;
50  std::complex<double> operator()(unsigned i) const { return _N[i]; }
51  private:
52  std::complex<double> _N[3];
53  };
54 
55  class L {
56  double _x;
57  public:
58  L(double x) : _x(x) { }
59  double operator()(unsigned j, unsigned k) const ;
60  };
61 
62 }
63 
64 N::N(double x, const std::complex<double>& z)
65 {
66  _N[0] = TMath::Erf(x);
67  _N[1] = exp(-x*x);
68  _N[2] = eval(x,z);
69 }
70 
71 double
72 L::operator()(unsigned j, unsigned k) const
73 {
74  assert(j < 18);
75  assert(k < 3);
76  switch(k) {
77  case 0: return !j;
78  case 1: {
79  static const double factor = 2. / rootpi;
80  switch(j) {
81  case 0: return 0;
82  default: return factor*(*this)(j-1,2);
83  }
84  }
85  case 2:
86  {
87  double x2 = _x * _x;
88  switch (j) {
89  // Mathematica:
90  // W[z_] = Exp[-z^2]*Erfc[-I*z]
91  // J[x_, z_, y_] = Erf[x - y] - Exp[-(x - y)^2] W[I*(z - x)]
92  // M[x_, z_, n_] = Derivative[0, 0, n][J][x, z, 0]
93  // case n:
94  // pick Erfc[-x+z]*Exp[(x-z)^2] coefficient, Simplify[Exp[x*x]/2 *M[x, z, n]]
95  // This next bit could be done much more elegantly in C++11 with variadic templates...
96  case 0: return -1.;
97  case 1: return -2.*_x;
98  case 2: return 2.* ( 1.-x2*2.);
99  case 3: return 4.*_x*( 3.-x2*2.);
100  case 4: return -4.* ( 3.-x2*( 12.-x2*4.));
101  case 5: return -8.*_x*( 15.-x2*( 20.-x2*4.));
102  case 6: return 8.* ( 15.-x2*( 90.-x2*( 60.-x2*8.)));
103  case 7: return 16.*_x*( 105.-x2*( 210.-x2*( 84.-x2*8.)));
104  case 8: return -16.* ( 105.-x2*( 840.-x2*( 840.-x2*( 224.-x2*16.))));
105  case 9: return -32.*_x*( 945.-x2*( 2520.-x2*( 1512.-x2*( 288.-x2*16.))));
106  case 10: return 32.* ( 945.-x2*( 9450.-x2*( 12600.-x2*( 5040.-x2*( 720.-x2*32.)))));
107  case 11: return 64.*_x*( 10395.-x2*( 34650.-x2*( 27720.-x2*( 7920.-x2*( 880.-x2*32.)))));
108  case 12: return -64.* ( 10395.-x2*( 124740.-x2*( 207900.-x2*( 110880.-x2*( 23760.-x2*( 2112.-x2*64.))))));
109  case 13: return -128.*_x*( 135135.-x2*( 540540.-x2*( 540540.-x2*( 205920.-x2*( 34320.-x2*( 2496.-x2*64.))))));
110  case 14: return 128.* ( 135135.-x2*( 1891890.-x2*( 3783780.-x2*( 2522520.-x2*( 720720.-x2*( 96096.-x2*( 5824.-x2*128.)))))));
111  case 15: return 256.*_x*( 2027025.-x2*( 9459450.-x2*( 11351340.-x2*( 5405400.-x2*( 1201200.-x2*( 131040.-x2*( 6720.-x2*128.)))))));
112  case 16: return -256.* ( 2027025.-x2*( 32432400.-x2*( 75675600.-x2*( 60540480.-x2*(21621600.-x2*(3843840.-x2*(349440.-x2*(15360.-x2*256.))))))));
113  case 17: return -512.*_x*(34459425.-x2*(183783600.-x2*(257297040.-x2*(147026880.-x2*(40840800.-x2*(5940480.-x2*(456960.-x2*(17408.-x2*256.))))))));
114  default: goto error;
115  }
116  }
117  default: goto error;
118  }
119 error:
120  assert(false);
121  return 0;
122 }
123 
124 template <unsigned MaxOrder>
125 RooGaussModelAcceptance::M_n<MaxOrder>::M_n(double x, const std::complex<double>& z)
126 {
127  L l(x); N n(x,z);
128  for (unsigned i=0;i<MaxOrder;++i) _m[i] = n(0)*l(i,0) + n(1)*l(i,1) + n(2)*l(i,2);
129 }
130 
131 
132 #include <iostream>
133 
134 std::complex<double>
136  assert(i<14);
137  const std::complex<double> zi2 = _zi*_zi ;
138  std::complex<double> f(1,0);
139  switch(i) {
140  // mathematica:
141  // K[z_, y_] = Exp[y*y]/(2*(z - y))
142  // F[z_, y_] = Derivative[0, y][K][z, 0]
143  // case n: F[z,n]
144  case 13: f *= 13.*_zi;
145  case 12: return f* 332640.*_zi*(1.+6.*zi2*(1.+5.*zi2*(1.+4.*zi2*(1.+3.*zi2*(1.+2.*zi2*(1.+zi2))))));
146  case 11: f *= 11.*_zi;
147  case 10: return f* 15120.*_zi*(1.+5.*zi2*(1.+4.*zi2*(1.+3.*zi2*(1.+2.*zi2*(1.+zi2)))));
148  case 9: f *= 9.*_zi;
149  case 8: return f* 840.*_zi*(1.+4.*zi2*(1.+3.*zi2*(1.+2.*zi2*(1.+zi2))));
150  case 7: f *= 7.*_zi;
151  case 6: return f* 60.*_zi*(1.+3.*zi2*(1.+2.*zi2*(1.+zi2)));
152  case 5: f *= 5.*_zi;
153  case 4: return f* 6.*_zi*(1.+2.*zi2*(1.+zi2));
154  case 3: f *= 3.*_zi;
155  case 2: return f* _zi*(1.+zi2);
156  case 1: f *= _zi;
157  case 0: return f* 0.5*_zi;
158  default: goto error;
159  }
160 error:
161  std::cerr << "K_n only implemented upto (and including) 13th order" << std::endl;
162  assert(false);
163  return 0;
164 }
165 
166 // explicitly instantiate some templates...
167 template class RooGaussModelAcceptance::M_n<1U>;
168 template class RooGaussModelAcceptance::M_n<2U>;
169 template class RooGaussModelAcceptance::M_n<3U>;
170 template class RooGaussModelAcceptance::M_n<4U>;
171 template class RooGaussModelAcceptance::M_n<5U>;
172 template class RooGaussModelAcceptance::M_n<6U>;
173 template class RooGaussModelAcceptance::M_n<7U>;
std::complex< double > operator()(unsigned i) const
M_n(double x, const std::complex< double > &z)