NiHu  2.0
math_functions.hpp
Go to the documentation of this file.
1 // This file is a part of NiHu, a C++ BEM template library.
2 //
3 // Copyright (C) 2012-2014 Peter Fiala <fiala@hit.bme.hu>
4 // Copyright (C) 2012-2014 Peter Rucz <rucz@hit.bme.hu>
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
25 #include <boost/math/constants/constants.hpp>
26 
27 #ifndef MATH_FUNCTIONS_HPP_INCLUDED
28 #define MATH_FUNCTIONS_HPP_INCLUDED
29 
30 #include <cmath>
31 #include <complex>
32 #include <iostream>
33 #include <stdexcept>
34 
35 namespace NiHu
36 {
37 
42 template <typename T>
43 int sgn(T val)
44 {
45  return (T(0) < val) - (val < T(0));
46 }
47 
54 template <class T>
55 static T sinc(T const &x)
56 {
57  if (std::abs(x) > 1e-3)
58  return std::sin(x) / x;
59  else
60  return 1. - x*x/6. * (1. - x*x/20.);
61 }
62 
64 namespace bessel
65 {
67  template <class T>
68  struct make_complex
69  {
70  typedef std::complex<T> type;
71  };
72 
73  template <class T>
74  struct make_complex<std::complex<T> >
75  {
76  typedef std::complex<T> type;
77  };
78 
80  double const large_lim(7.);
81 
90  template <class T>
91  void mag_arg_large(int nu, T const &z, T &u, T &phi)
92  {
93  using namespace boost::math::double_constants;
94 
95  double mag[3][7] = {
96  {
97  1.,
98  -6.25e-2,
99  1.03515625e-1,
100  -5.428466796875e-1,
101  5.8486995697021484375,
102  -1.06886793971061706543e2,
103  2.96814293784275650978e3
104  },
105  {
106  1.,
107  1.875e-1,
108  -1.93359375e-1,
109  8.052978515625e-1,
110  -7.7399539947509765625,
111  1.32761824250221252441e2,
112  -3.54330366536602377892e3
113  },
114  {
115  1,
116  9.3750000000e-01,
117  7.9101562500e-01,
118  -3.0487060547e+00,
119  1.9199895859e+01,
120  -2.5916166008e+02,
121  6.0841126316e+03
122  }
123  };
124  double arg[3][7] = {
125  {
126  -1.25e-1,
127  6.51041666666666712926e-2,
128  -2.09570312499999994449e-1,
129  1.63806588309151779370,
130  -2.34751277499728736586e1,
131  5.35640519510615945364e2,
132  -1.78372796889474739146e4
133  },
134  {
135  3.75e-1,
136  -1.640625e-1,
137  3.70898437500000011102e-1,
138  -2.36939784458705338110,
139  3.06240119934082031250e1,
140  -6.59185221823778988437e2,
141  2.11563140455278044101e4
142  },
143  {
144  1.8750000000e0,
145  -3.5156250000e-1,
146  -1.4501953125e0,
147  8.3074297224e0,
148  -7.1739864349e1,
149  1.2458673851e3,
150  -3.5571449717e4
151  }
152  };
153 
154  u = phi = T(0.);
155  auto q(1./z/z);
156  for (int m = sizeof(mag[0])/sizeof(double)-1; m >= 0; --m)
157  {
158  u = q * u + mag[nu][m];
159  phi = q * phi + arg[nu][m];
160  }
161  phi = phi/z + z - (nu/2.+.25)*pi;
162  }
163 
171  template <int nu, class T>
172  T J_small(T const &z)
173  {
174  // upper limit for 1e-8 error
175  int N = (int)(3+2.*std::abs(z));
176 
177  T q = z/2.;
178 
179  T res(1.), q2(q*q);
180  for (int k = N; k > 0; --k)
181  res = 1. - q2*(1./(k*(k+nu)))*res;
182  for (int k = 1; k <= nu; ++k)
183  res *= q/T(k);
184  return res;
185  }
186 
194  template <int nu, class T>
195  T J_large(T const &z)
196  {
197  using boost::math::double_constants::pi;
198 
199  static_assert(nu >= 0 && nu <= 2 , "unimplemented Bessel J order");
200 
201  T mag, arg;
202  if (std::real(z) < 0)
203  {
204  double const C(nu%2==0 ? 1. : -1);
205  mag_arg_large(nu, -z, mag, arg);
206  return std::sqrt(2./(pi * -z)) * mag * std::cos(arg) * C;
207  }
208  else
209  {
210  mag_arg_large(nu, z, mag, arg);
211  return std::sqrt(2./(pi * z)) * mag * std::cos(arg);
212  }
213  }
214 
222  template <int nu, class T>
223  T J(T const &z)
224  {
225  return std::abs(z) < large_lim ? J_small<nu>(z) : J_large<nu>(z);
226  }
227 
228 
235  template <int nu>
236  std::complex<double> Y_small(std::complex<double> const &z)
237  {
238  using boost::math::double_constants::pi;
239  using boost::math::double_constants::euler;
240 
241  // upper limit for 1e-8 error
242  int const N = (int)(4+2.*std::abs(z));
243 
244  std::complex<double> q(z/2.0), q2(q*q);
245  std::complex<double> first(2.0*J_small<nu>(z)*(std::log(q) + euler));
246  std::complex<double> second;
247  switch (nu)
248  {
249  case 0: second = 0.; break;
250  case 1: second = -1./q; break;
251  case 2: second = -1. -1./q2; break;
252  }
253 
254  std::complex<double> third(0.0);
255  std::complex<double> q2pow(-std::pow(q, nu));
256 
257  double a(0.);
258  for (int k = 1; k <= nu; ++k)
259  a += 1./k;
260 
261  double div = 1.;
262  for (int k = 1; k <= nu; ++k)
263  div /= k;
264 
265  for (int k = 0; k < N; ++k)
266  {
267  third += div*q2pow*a;
268 
269  div /= -(k+1)*(k+nu+1);
270  q2pow *= q2;
271  a += 1./(k+1.) + 1./(k+nu+1.);
272  }
273 
274  return 1./pi * (first + second + third);
275  }
276 
283  template <int nu>
284  std::complex<double> Y_large(std::complex<double> const &z)
285  {
286  using boost::math::double_constants::pi;
287 
288  static_assert(nu >= 0 || nu <= 2, "unimplemented Bessel Y order");
289 
290  std::complex<double> mag, arg;
291  if (std::real(z) < 0)
292  {
293  double const C1(nu%2 == 0 ? 1. : -1.);
294  std::complex<double> const C2(0., std::imag(z) < 0 ? -2. : 2.);
295  std::complex<double> const MAG(std::sqrt(C2*C2+1.));
296  std::complex<double> const ARG(std::atan(1./C2));
297  mag_arg_large(nu, -z, mag, arg);
298  return std::sqrt(2./(pi * -z)) * mag * MAG * std::cos(arg-ARG) * C1;
299  }
300  else
301  {
302  mag_arg_large(nu, z, mag, arg);
303  return std::sqrt(2./(pi * z)) * mag * std::sin(arg);
304  }
305  }
306 
307 
314  template <int nu>
315  std::complex<double> Y(std::complex<double> const &z)
316  {
317  return std::abs(z) < large_lim ? Y_small<nu>(z) : Y_large<nu>(z);
318  }
319 
327  template <int nu, int kind, class T>
328  typename make_complex<T>::type H_large(T const &z)
329  {
330  using namespace std::complex_literals;
331  using boost::math::double_constants::pi;
332 
333  static_assert((kind == 1) || (kind == 2), "invalid kind argument of bessel::H");
334  double const C = (kind == 2 ? -1. : 1.);
335 
336  typename make_complex<T>::type mag, arg;
337 
338  if (std::real(z) < 0 && std::abs(std::imag(z)) < 8.)
339  {
340  double const C1(nu%2 == 0 ? 1. : -1.);
341 
342  mag_arg_large(nu, -z, mag, arg);
343 
344  double sgn = std::imag(z) < 0 ? -1. : 1.;
345  double MAG(-sgn*std::sqrt(3.));
346  std::complex<double> const ARG(std::atan(-sgn*.5i));
347 
348  return std::sqrt(2./(pi * -z)) * mag * (std::cos(arg) + C * MAG * std::cos(arg-ARG)) * C1;
349  }
350 
351  mag_arg_large(nu, z, mag, arg);
352 
353  return std::sqrt(2./pi/z) * mag * std::exp(C*1.i*arg);
354  }
355 
364  template <int nu, int kind, class T>
365  typename make_complex<T>::type H(T const &z)
366  {
367  using namespace std::complex_literals;
368  static_assert(kind == 1 || kind == 2, "invalid kind argument of bessel::H");
369  double const C = (kind == 2 ? -1. : 1.);
370  if (std::abs(z) < large_lim)
371  return J_small<nu>(z) + C * 1.i * Y_small<nu>(z);
372  else
373  return H_large<nu, kind>(z);
374  }
375 
383  template <int nu, class T>
384  typename make_complex<T>::type K(T const &z);
385 } // end of namespace bessel
386 
387 
394 template <class T = double>
395 T chebroot(size_t n, size_t i)
396 {
397  using boost::math::double_constants::pi;
398  return std::cos(pi / 2. * (2 * (n - i) - 1) / T(n));
399 }
400 
401 
408 template <class I>
409 I Ipow(I base, I exp)
410 {
411  I res = 1;
412  for (unsigned i = 0; i < exp; ++i)
413  res *= base;
414  return res;
415 }
416 
417 
422 template < unsigned Base, unsigned Exp >
423 struct IpowC
424 {
425  static unsigned const value = IpowC<Base, Exp - 1>::value * Base;
426 };
427 
429 template <unsigned Base>
430 struct IpowC < Base, 0 >
431 {
432  static unsigned const value = 1U;
433 };
434 
436 template <unsigned Exp>
437 struct IpowC < 0, Exp >
438 {
439  static unsigned const value = 0U;
440 };
441 
443 template <>
444 struct IpowC < 0, 0 >
445 {
446  // undefined
447 };
448 
449 
450 } // end of namespace NiHu
451 
452 #endif /* MATH_FUNCTIONS_HPP_INCLUDED */
453 
NiHu::bessel::J
T J(T const &z)
Bessel function J_nu(z)
Definition: math_functions.hpp:223
NiHu::bessel::mag_arg_large
void mag_arg_large(int nu, T const &z, T &u, T &phi)
large argument Bessel function Taylor series coefficients
Definition: math_functions.hpp:91
NiHu::bessel::K
make_complex< T >::type K(T const &z)
K_nu(z) modified Bessel function.
NiHu::bessel::H
make_complex< T >::type H(T const &z)
H^(K)_nu(z) Bessel function.
Definition: math_functions.hpp:365
C
Definition: bbfmm_covariance.cpp:47
NiHu::bessel::J_small
T J_small(T const &z)
small argument expansion of J_nu(z) for nu = 0, 1, 2
Definition: math_functions.hpp:172
NiHu::bessel::Y_small
std::complex< double > Y_small(std::complex< double > const &z)
small argument expansion of Y_nu(z)
Definition: math_functions.hpp:236
NiHu::bessel::make_complex
metafunction converting a floating point type to a complex type
Definition: math_functions.hpp:68
NiHu::Ipow
I Ipow(I base, I exp)
compute integer power
Definition: math_functions.hpp:409
NiHu::bessel::Y_large
std::complex< double > Y_large(std::complex< double > const &z)
large argument expansion of Y_nu(z) for nu = 0, 1, 2
Definition: math_functions.hpp:284
NiHu::bessel::large_lim
const double large_lim(7.)
limit between small and large argument series
NiHu::IpowC
metafunction computing integer power
Definition: math_functions.hpp:423
NiHu::sgn
int sgn(T val)
signum function
Definition: math_functions.hpp:43
NiHu::bessel::J_large
T J_large(T const &z)
large argument expansion of J_nu(z) for nu = 0, 1, 2
Definition: math_functions.hpp:195
NiHu::bessel::H_large
make_complex< T >::type H_large(T const &z)
large argument expansion of H^(K)_nu(z)
Definition: math_functions.hpp:328
NiHu::chebroot
T chebroot(size_t n, size_t i)
roots of Chebyshev polynomials
Definition: math_functions.hpp:395
NiHu::bessel::Y
std::complex< double > Y(std::complex< double > const &z)
Bessel function Y_nu(z)
Definition: math_functions.hpp:315