Logo ROOT  
Reference Guide
RooMath.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * File: $Id: RooMath.h,v 1.16 2007/05/11 09:11:30 verkerke Exp $
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 #ifndef ROO_MATH
17 #define ROO_MATH
18 
19 #include <cmath>
20 #include <complex>
21 
22 #include "TMath.h"
23 
25 
26 class RooMath {
27 public:
28 
29  virtual ~RooMath() {};
30 
31  /** @brief evaluate Faddeeva function for complex argument
32  *
33  * @author Manuel Schiller <manuel.schiller@nikhef.nl>
34  * @date 2013-02-21
35  *
36  * Calculate the value of the Faddeeva function @f$w(z) = \exp(-z^2)
37  * \mathrm{erfc}(-i z)@f$.
38  *
39  * The method described in
40  *
41  * S.M. Abrarov, B.M. Quine: "Efficient algotithmic implementation of
42  * Voigt/complex error function based on exponential series approximation"
43  * published in Applied Mathematics and Computation 218 (2011) 1894-1902
44  * doi:10.1016/j.amc.2011.06.072
45  *
46  * is used. At the heart of the method (equation (14) of the paper) is the
47  * following Fourier series based approximation:
48  *
49  * @f[ w(z) \approx \frac{i}{2\sqrt{\pi}}\left(
50  * \sum^N_{n=0} a_n \tau_m\left(
51  * \frac{1-e^{i(n\pi+\tau_m z)}}{n\pi + \tau_m z} -
52  * \frac{1-e^{i(-n\pi+\tau_m z)}}{n\pi - \tau_m z}
53  * \right) - a_0 \frac{1-e^{i \tau_m z}}{z}
54  * \right) @f]
55  *
56  * The coefficients @f$a_b@f$ are given by:
57  *
58  * @f[ a_n=\frac{2\sqrt{\pi}}{\tau_m}
59  * \exp\left(-\frac{n^2\pi^2}{\tau_m^2}\right) @f]
60  *
61  * To achieve machine accuracy in double precision floating point arithmetic
62  * for most of the upper half of the complex plane, chose @f$t_m=12@f$ and
63  * @f$N=23@f$ as is done in the paper.
64  *
65  * There are two complications: For Im(z) negative, the exponent in the
66  * equation above becomes so large that the roundoff in the rest of the
67  * calculation is amplified enough that the result cannot be trusted.
68  * Therefore, for Im(z) < 0, the symmetry of the erfc function under the
69  * transformation z --> -z is used to avoid accuracy issues for Im(z) < 0 by
70  * formulating the problem such that the calculation can be done for Im(z) > 0
71  * where the accuracy of the method is fine, and some postprocessing then
72  * yields the desired final result.
73  *
74  * Second, the denominators in the equation above become singular at
75  * @f$z = n * pi / 12@f$ (for 0 <= n < 24). In a tiny disc around these
76  * points, Taylor expansions are used to overcome that difficulty.
77  *
78  * This routine precomputes everything it can, and tries to write out complex
79  * operations to minimise subroutine calls, e.g. for the multiplication of
80  * complex numbers.
81  *
82  * In the square -8 <= Re(z) <= 8, -8 <= Im(z) <= 8, the routine is accurate
83  * to better than 4e-13 relative, the average relative error is better than
84  * 7e-16. On a modern x86_64 machine, the routine is roughly three times as
85  * fast than the old CERNLIB implementation and offers better accuracy.
86  *
87  * For large @f$|z|@f$, the familiar continued fraction approximation
88  *
89  * @f[ w(z)=\frac{-iz/\sqrt{\pi}}{-z^2+\frac{1/2}{1+\frac{2/2}{-z^2 +
90  * \frac{3/2}{1+\frac{4/2}{-z^2+\frac{5/2}{1+\frac{6/2}{-z^2+\frac{7/2
91  * }{1+\frac{8/2}{-z^2+\frac{9/2}{1+\ldots}}}}}}}}}} @f]
92  *
93  * is used, truncated at the ellipsis ("...") in the formula; for @f$|z| >
94  * 12@f$, @f$Im(z)>0@f$ it will give full double precision at a smaller
95  * computational cost than the method described above. (For @f$|z|>12@f$,
96  * @f$Im(z)<0@f$, the symmetry property @f$w(x-iy)=2e^{-(x+iy)^2-w(x+iy)}@f$
97  * is used.
98  */
99  static std::complex<double> faddeeva(std::complex<double> z);
100  /** @brief evaluate Faddeeva function for complex argument (fast version)
101  *
102  * @author Manuel Schiller <manuel.schiller@nikhef.nl>
103  * @date 2013-02-21
104  *
105  * Calculate the value of the Faddeeva function @f$w(z) = \exp(-z^2)
106  * \mathrm{erfc}(-i z)@f$.
107  *
108  * This is the "fast" version of the faddeeva routine above. Fast means that
109  * is takes roughly half the amount of CPU of the slow version of the
110  * routine, but is a little less accurate.
111  *
112  * To be fast, chose @f$t_m=8@f$ and @f$N=11@f$ which should give accuracies
113  * around 1e-7.
114  *
115  * In the square -8 <= Re(z) <= 8, -8 <= Im(z) <= 8, the routine is accurate
116  * to better than 4e-7 relative, the average relative error is better than
117  * 5e-9. On a modern x86_64 machine, the routine is roughly five times as
118  * fast than the old CERNLIB implementation, or about 30% faster than the
119  * interpolation/lookup table based fast method used previously in RooFit,
120  * and offers better accuracy than the latter (the relative error is roughly
121  * a factor 280 smaller than the old interpolation/table lookup routine).
122  *
123  * For large @f$|z|@f$, the familiar continued fraction approximation
124  *
125  * @f[ w(z)=\frac{-iz/\sqrt{\pi}}{-z^2+\frac{1/2}{1+\frac{2/2}{-z^2 +
126  * \frac{3/2}{1+\ldots}}}} @f]
127  *
128  * is used, truncated at the ellipsis ("...") in the formula; for @f$|z| >
129  * 8@f$, @f$Im(z)>0@f$ it will give full float precision at a smaller
130  * computational cost than the method described above. (For @f$|z|>8@f$,
131  * @f$Im(z)<0@f$, the symmetry property @f$w(x-iy)=2e^{-(x+iy)^2-w(x+iy)}@f$
132  * is used.
133  */
134  static std::complex<double> faddeeva_fast(std::complex<double> z);
135 
136  /** @brief complex erf function
137  *
138  * @author Manuel Schiller <manuel.schiller@nikhef.nl>
139  * @date 2013-02-21
140  *
141  * Calculate erf(z) for complex z.
142  */
143  static std::complex<double> erf(const std::complex<double> z);
144 
145  /** @brief complex erf function (fast version)
146  *
147  * @author Manuel Schiller <manuel.schiller@nikhef.nl>
148  * @date 2013-02-21
149  *
150  * Calculate erf(z) for complex z. Use the code in faddeeva_fast to save some time.
151  */
152  static std::complex<double> erf_fast(const std::complex<double> z);
153  /** @brief complex erfc function
154  *
155  * @author Manuel Schiller <manuel.schiller@nikhef.nl>
156  * @date 2013-02-21
157  *
158  * Calculate erfc(z) for complex z.
159  */
160  static std::complex<double> erfc(const std::complex<double> z);
161  /** @brief complex erfc function (fast version)
162  *
163  * @author Manuel Schiller <manuel.schiller@nikhef.nl>
164  * @date 2013-02-21
165  *
166  * Calculate erfc(z) for complex z. Use the code in faddeeva_fast to save some time.
167  */
168  static std::complex<double> erfc_fast(const std::complex<double> z);
169 
170  // 1-D nth order polynomial interpolation routines
171  static Double_t interpolate(Double_t yArr[],Int_t nOrder, Double_t x) ;
172  static Double_t interpolate(Double_t xa[], Double_t ya[], Int_t n, Double_t x) ;
173 
174  static inline Double_t erf(Double_t x)
175  { return TMath::Erf(x); }
176 
177  static inline Double_t erfc(Double_t x)
178  { return TMath::Erfc(x); }
179 
180 };
181 
182 #endif
RooMath::erf
static std::complex< double > erf(const std::complex< double > z)
complex erf function
Definition: RooMath.cxx:580
RooMath::faddeeva_fast
static std::complex< double > faddeeva_fast(std::complex< double > z)
evaluate Faddeeva function for complex argument (fast version)
Definition: RooMath.cxx:549
n
const Int_t n
Definition: legend1.C:16
RooMath
Definition: RooMath.h:26
Int_t
int Int_t
Definition: RtypesCore.h:45
x
Double_t x[n]
Definition: legend1.C:17
TMath::Erf
Double_t Erf(Double_t x)
Computation of the error function erf(x).
Definition: TMath.cxx:184
RooMath::erfc_fast
static std::complex< double > erfc_fast(const std::complex< double > z)
complex erfc function (fast version)
Definition: RooMath.cxx:568
RooMath::erf
static Double_t erf(Double_t x)
Definition: RooMath.h:174
RooMath::erfc
static std::complex< double > erfc(const std::complex< double > z)
complex erfc function
Definition: RooMath.cxx:556
RooMath::interpolate
static Double_t interpolate(Double_t yArr[], Int_t nOrder, Double_t x)
Definition: RooMath.cxx:605
pDouble_t
Double_t * pDouble_t
Definition: RooMath.h:24
RooMath::~RooMath
virtual ~RooMath()
Definition: RooMath.h:29
TMath::Erfc
Double_t Erfc(Double_t x)
Compute the complementary error function erfc(x).
Definition: TMath.cxx:194
RooMath::faddeeva
static std::complex< double > faddeeva(std::complex< double > z)
evaluate Faddeeva function for complex argument
Definition: RooMath.cxx:542
Double_t
double Double_t
Definition: RtypesCore.h:59
RooMath::erfc
static Double_t erfc(Double_t x)
Definition: RooMath.h:177
RooMath::erf_fast
static std::complex< double > erf_fast(const std::complex< double > z)
complex erf function (fast version)
Definition: RooMath.cxx:592
TMath.h