StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
PythiaStdlib.cc
1 // PythiaStdlib.cc is a part of the PYTHIA event generator.
2 // Copyright (C) 2018 Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
4 // Please respect the MCnet Guidelines, see GUIDELINES for details.
5 
6 // Function definitions (not found in the header) for the Gamma function.
7 
8 #include "Pythia8/PythiaStdlib.h"
9 
10 namespace Pythia8 {
11 
12 //==========================================================================
13 
14 // Convert string to lowercase for case-insensitive comparisons.
15 // By default remove any initial and trailing blanks or escape characters.
16 
17 string toLower(const string& name, bool trim) {
18 
19  // Copy string without initial and trailing blanks or escape characters.
20  string temp = name;
21  if (trim) {
22  if (name.find_first_not_of(" \n\t\v\b\r\f\a") == string::npos) return "";
23  int firstChar = name.find_first_not_of(" \n\t\v\b\r\f\a");
24  int lastChar = name.find_last_not_of(" \n\t\v\b\r\f\a");
25  temp = name.substr( firstChar, lastChar + 1 - firstChar);
26  }
27 
28  // Convert to lowercase letter by letter.
29  for (int i = 0; i < int(temp.length()); ++i) temp[i] = tolower(temp[i]);
30  return temp;
31 
32 }
33 
34 //--------------------------------------------------------------------------
35 
36 // The Gamma function for real arguments, using the Lanczos approximation.
37 // Code based on http://en.wikipedia.org/wiki/Lanczos_approximation
38 
39 double GammaCoef[9] = {
40  0.99999999999980993, 676.5203681218851, -1259.1392167224028,
41  771.32342877765313, -176.61502916214059, 12.507343278686905,
42  -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
43 
44 double GammaReal(double x) {
45 
46  // Reflection formula (recursive!) for x < 0.5.
47  if (x < 0.5) return M_PI / (sin(M_PI * x) * GammaReal(1 - x));
48 
49  // Iterate through terms.
50  double z = x - 1.;
51  double gamma = GammaCoef[0];
52  for (int i = 1; i < 9; ++i) gamma += GammaCoef[i] / (z + i);
53 
54  // Answer.
55  double t = z + 7.5;
56  gamma *= sqrt(2. * M_PI) * pow(t, z + 0.5) * exp(-t);
57  return gamma;
58 
59 }
60 
61 //--------------------------------------------------------------------------
62 
63 // Polynomial approximation for modified Bessel function of the first kind.
64 // Based on Abramowitz & Stegun, Handbook of mathematical functions (1964).
65 
66 double besselI0(double x){
67 
68  // Parametrize in terms of t.
69  double result = 0.;
70  double t = x / 3.75;
71  double t2 = pow2(t);
72 
73  // Only positive values relevant.
74  if ( t < 0.) ;
75  else if ( t < 1.) {
76  result = 1.0 + 3.5156229 * t2 + 3.0899424 * pow2(t2)
77  + 1.2067492 * pow3(t2) + 0.2659732 * pow4(t2)
78  + 0.0360768 * pow5(t2) * 0.0045813 * pow6(t2);
79  } else {
80  double u = 1. / t;
81  result = exp(x) / sqrt(x) * ( 0.39894228 + 0.01328592 * u
82  + 0.00225319 * pow2(u) - 0.00157565 * pow3(u)
83  + 0.00916281 * pow4(u) - 0.02057706 * pow5(u)
84  + 0.02635537 * pow6(u) - 0.01647633 * pow7(u)
85  + 0.00392377 * pow8(u) );
86  }
87 
88  return result;
89 }
90 
91 //--------------------------------------------------------------------------
92 
93 // Polynomial approximation for modified Bessel function of the first kind.
94 // Based on Abramowitz & Stegun, Handbook of mathematical functions (1964).
95 
96 double besselI1(double x){
97 
98  // Parametrize in terms of t.
99  double result = 0.;
100  double t = x / 3.75;
101  double t2 = pow2(t);
102 
103  // Only positive values relevant.
104  if ( t < 0.) ;
105  else if ( t < 1.) {
106  result = x * ( 0.5 + 0.87890594 * t2 + 0.51498869 * pow2(t2)
107  + 0.15084934 * pow3(t2) + 0.02658733 * pow4(t2)
108  + 0.00301532 * pow5(t2) * 0.00032411 * pow6(t2) );
109  } else {
110  double u = 1. / t;
111  result = exp(x) / sqrt(x) * ( 0.39894228 - 0.03988024 * u
112  - 0.00368018 * pow2(u) + 0.00163801 * pow3(u)
113  - 0.01031555 * pow4(u) + 0.02282967 * pow5(u)
114  - 0.02895312 * pow6(u) + 0.01787654 * pow7(u)
115  - 0.00420059 * pow8(u) );
116  }
117 
118  return result;
119 }
120 
121 //--------------------------------------------------------------------------
122 
123 // Polynomial approximation for modified Bessel function of a second kind.
124 // Based on Abramowitz & Stegun, Handbook of mathematical functions (1964).
125 
126 double besselK0(double x){
127 
128  double result = 0.;
129 
130  // Polynomial approximation valid ony for x > 0.
131  if ( x < 0.) ;
132  else if ( x < 2.) {
133  double x2 = pow2(0.5 * x);
134  result = -log(0.5 * x) * besselI0(x) - 0.57721566
135  + 0.42278420 * x2 + 0.23069756 * pow2(x2)
136  + 0.03488590 * pow3(x2) + 0.00262698 * pow4(x2)
137  + 0.00010750 * pow5(x2) + 0.00000740 * pow6(x2);
138  } else {
139  double z = 2. / x;
140  result = exp(-x) / sqrt(x) * ( 1.25331414 - 0.07832358 * z
141  + 0.02189568 * pow2(z) - 0.01062446 * pow3(z)
142  + 0.00587872 * pow4(z) - 0.00251540 * pow5(z)
143  + 0.00053208 * pow6(z) );
144  }
145 
146  return result;
147 }
148 
149 //--------------------------------------------------------------------------
150 
151 // Polynomial approximation for modified Bessel function of a second kind.
152 // Based on Abramowitz & Stegun, Handbook of mathematical functions (1964).
153 
154 double besselK1(double x){
155 
156  double result = 0.;
157 
158  // Polynomial approximation valid ony for x > 0.
159  if ( x < 0.) ;
160  else if ( x < 2.) {
161  double x2 = pow2(0.5 * x);
162  result = log(0.5 * x) * besselI1(x) + 1./x * ( 1. + 0.15443144 * x2
163  - 0.67278579 * pow2(x2) - 0.18156897 * pow3(x2)
164  - 0.01919402 * pow4(x2) - 0.00110404 * pow5(x2)
165  - 0.00004686 * pow6(x2) );
166  } else {
167  double z = 2. / x;
168  result = exp(-x) / sqrt(x) * ( 1.25331414 + 0.23498619 * z
169  - 0.03655620 * pow2(z) + 0.01504268 * pow3(z)
170  - 0.00780353 * pow4(z) + 0.00325614 * pow5(z)
171  - 0.00068245 * pow6(z) );
172  }
173 
174  return result;
175 }
176 
177 //==========================================================================
178 
179 // FunctionEncapsulator class.
180 // This class serves to encapsulate a function of an arbitrary number of
181 // arguments, all given as doubles. The intended use is for numerical
182 // integration (a Gaussian quadrature routine is implemented in
183 // the base class), root finding, etc, without having to use function
184 // pointers (so will probably become obsolete when moving to C++11.)
185 
186 //--------------------------------------------------------------------------
187 
188 // Definition of the function to be encapsulated; base class returns 0.
189 
190 double FunctionEncapsulator::f(vector<double>) {
191  return 0.0;
192 }
193 
194 //--------------------------------------------------------------------------
195 
196 // Integrate the encapsulated function, f, over argument number iArg,
197 // from xLo, to xHi, using Gaussian quadrature, with tolerance tol.
198 // Return false if precision target could not be reached.
199 // Adapted from the CERNLIB DGAUSS routine by K.S. Kolbig.
200 
201 bool FunctionEncapsulator::integrateGauss(double& result, int iArg, double xLo,
202  double xHi, vector<double> args, double tol) {
203 
204  // Initialize.
205  result = 0.0;
206 
207  // Sanity check.
208  if (iArg >= int(args.size())) return false;
209 
210  // Boundary check: return zero if xLo >= xHi.
211  if (xLo >= xHi) return true;
212 
213  // 8-point unweighted.
214  static double x8[4]={ 0.96028985649753623, 0.79666647741362674,
215  0.52553240991632899, 0.18343464249564980};
216  static double w8[4]={ 0.10122853629037626, 0.22238103445337447,
217  0.31370664587788729, 0.36268378337836198};
218  // 16-point unweighted.
219  static double x16[8]={ 0.98940093499164993, 0.94457502307323258,
220  0.86563120238783174, 0.75540440835500303, 0.61787624440264375,
221  0.45801677765722739, 0.28160355077925891, 0.09501250983763744};
222  static double w16[8]={ 0.027152459411754095, 0.062253523938647893,
223  0.095158511682492785, 0.12462897125553387, 0.14959598881657673,
224  0.16915651939500254, 0.18260341504492359, 0.18945061045506850};
225 
226  // Set up integration region.
227  double c = 0.001/abs(xHi-xLo);
228  double zLo = xLo;
229  double zHi = xHi;
230 
231  bool nextbin = true;
232  while ( nextbin ) {
233 
234  double zMid = 0.5*(zHi+zLo); // midpoint
235  double zDel = 0.5*(zHi-zLo); // midpoint, relative to zLo
236 
237  // Calculate 8-point and 16-point quadratures.
238  double s8=0.0;
239  for (int i=0;i<4;i++) {
240  double dz = zDel * x8[i];
241  args[iArg] = zMid+dz;
242  double f1 = f(args);
243  args[iArg] = zMid-dz;
244  double f2 = f(args);
245  s8 += w8[i]*(f1 + f2);
246  }
247  s8 *= zDel;
248  double s16=0.0;
249  for (int i=0;i<8;i++) {
250  double dz = zDel * x16[i];
251  args[iArg] = zMid+dz;
252  double f1 = f(args);
253  args[iArg] = zMid-dz;
254  double f2 = f(args);
255  s16 += w16[i]*(f1 + f2);
256  }
257  s16 *= zDel;
258 
259  // Precision in this bin OK, add to cumulative and go to next.
260  if (abs(s16-s8) < tol*(1+abs(s16))) {
261  nextbin=true;
262  result += s16;
263  // Next bin: LO = end of current, HI = end of integration region.
264  zLo=zHi;
265  zHi=xHi;
266  if ( zLo == zHi ) nextbin = false;
267 
268  // Precision in this bin not OK, subdivide.
269  } else {
270  if (1.0 + c*abs(zDel) == 1.0) {
271  // Cannot subdivide further at double precision. Fail.
272  cout << "\n FunctionEncapsulator::integrateGauss(): cannot "
273  << "reach desired tolerance at double precision." << endl;
274  result = 0.0 ;
275  return false;
276  }
277  zHi = zMid;
278  nextbin = true;
279  }
280  }
281 
282  return true;
283 }
284 
285 //--------------------------------------------------------------------------
286 
287 // Solve f(args) = targetValue for argument iArg, on interval from xLo to xHi,
288 // using Brent's method, with tolerance tol and a maximum number of iterations
289 // maxIter. Return false if precision target could not be reached.
290 
291 bool FunctionEncapsulator::brent(double& solution, double targetValue,
292  int iArg, double xLo, double xHi, vector<double> argsIn, double tol,
293  int maxIter) {
294 
295  // Initialize.
296  solution = 0.0;
297 
298  // Sanity and range checks.
299  if (iArg >= int(argsIn.size())) return false;
300  if (xLo > xHi) return false;
301 
302  vector<double> args(argsIn);
303  // Evaluate function - targetValue at lower boundary.
304  args[iArg] = xLo;
305  double f1 = f(args) - targetValue;
306  if (abs(f1) < tol) {
307  solution = xLo;
308  return true;
309  }
310  // Evaluate function - targetValue at upper boundary.
311  args[iArg] = xHi;
312  double f2 = f(args) - targetValue;
313  if (abs(f2) < tol) {
314  solution = xHi;
315  return true;
316  }
317 
318  // Check if root is bracketed.
319  if ( f1 * f2 > 0.0) return false;
320 
321  // Start searching for root.
322  double x1 = xLo;
323  double x2 = xHi;
324  double x3 = 0.5 * (xLo + xHi);
325 
326  int iter=0;
327  while(++iter < maxIter) {
328  // Now check at x = x3.
329  args[iArg] = x3;
330  double f3 = f(args) - targetValue;
331  // Check if tolerance on f has been reached.
332  if (abs(f3) < tol) {
333  solution = x3;
334  return true;
335  }
336  // Is root bracketed in lower or upper half?
337  if (f1 * f3 < 0.0) xHi = x3;
338  else xLo = x3;
339  // Check if tolerance on x has been reached.
340  if ((xHi - xLo) < tol * (abs(xHi) < 1.0 ? xHi : 1.0)) {
341  solution = 0.5 * (xLo + xHi);
342  return true;
343  }
344 
345  // Work out next step to take in x.
346  double den = (f2 - f1) * (f3 - f1) * (f2 - f3);
347  double num = x3 * (f1 - f2) * (f2 - f3 + f1) + f2 * x1 * (f2 - f3)
348  + f1 * x2 * (f3 - f1);
349  double dx = xHi - xLo;
350  if (den != 0.0) dx = f3 * num / den;
351 
352  // First attempt, using gradient
353  double x = x3 + dx;
354 
355  // If this was too far, just step to the middle
356  if ((xHi - x) * (x - xLo) < 0.0) {
357  dx = 0.5 * (xHi - xLo);
358  x = xLo + dx;
359  }
360  if (x < x3) {
361  x2 = x3;
362  f2 = f3;
363  }
364  else {
365  x1 = x3;
366  f1 = f3;
367  }
368  x3 = x;
369  }
370 
371  // Maximum number of iterations exceeded.
372  return false;
373 
374 }
375 
376 //==========================================================================
377 
378 } // end namespace Pythia8