Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
specfunc.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/** @file
23 * This file contains implementations for some special functions which are
24 * needed by the MMM family of algorithms. These are the modified Hurwitz
25 * zeta function and the modified Bessel functions of second kind. The
26 * implementations are based on the GSL code (see @ref specfunc.cpp for the
27 * original GSL header).
28 *
29 * The Hurwitz zeta function is evaluated using the Euler-Maclaurin summation
30 * formula, the Bessel functions are evaluated using several different
31 * Chebychev expansions. Both achieve a precision of nearly machine precision,
32 * which is no problem for the Hurwitz zeta function, which is only used when
33 * determining the coefficients for the modified polygamma functions.
34 */
35
36#pragma once
37
38#include <cassert>
39#include <numeric>
40#include <span>
41#include <utility>
42
43/** Hurwitz zeta function. This function was taken from the GSL code. */
44double hzeta(double order, double x);
45
46/** Modified Bessel function of second kind, order 0. This function was taken
47 * from the GSL code. Precise roughly up to machine precision.
48 * It is 16 times faster than <tt>std::cyl_bessel_k</tt>.
49 * If @c MMM1D_MACHINE_PREC is not defined, @ref LPK0 is used instead.
50 */
51double K0(double x);
52
53/** Modified Bessel function of second kind, order 1. This function was taken
54 * from the GSL code. Precise roughly up to machine precision.
55 * If @c MMM1D_MACHINE_PREC is not defined, @ref LPK1 is used instead.
56 */
57double K1(double x);
58
59/** Modified Bessel function of second kind, order 0, low precision.
60 * The implementation has an absolute precision of around 10^(-14), which is
61 * comparable to the relative precision sqrt implementation of current
62 * hardware in the ranges @f$ ]0, 8[ @f$ and @f$ ]8, 23[ @f$. Above 23,
63 * the precision starts to degrade, and above 27 the result drifts and
64 * slowly converges to 96% of the real value.
65 * It is 25 times faster than <tt>std::cyl_bessel_k</tt>
66 * and 1.5 times faster than @ref K0.
67 */
68double LPK0(double x);
69
70/** Modified Bessel function of second kind, order 1, low precision.
71 * The implementation has an absolute precision of around 10^(-14), which is
72 * comparable to the relative precision sqrt implementation of current
73 * hardware in the ranges @f$ ]0, 8[ @f$ and @f$ ]8, 23[ @f$. Above 23,
74 * the precision starts to degrade, and above 27 the result drifts and
75 * slowly converges to 111% of the real value.
76 * It is 25 times faster than <tt>std::cyl_bessel_k</tt>
77 * and 1.5 times faster than @ref K1.
78 */
79double LPK1(double x);
80
81/** Modified Bessel functions of second kind, order 0 and 1, low precision.
82 * The implementation has an absolute precision of around 10^(-14), which is
83 * comparable to the relative precision sqrt implementation of current
84 * hardware.
85 */
86std::pair<double, double> LPK01(double x);
87
88/** Evaluate the polynomial interpreted as a Taylor series via the
89 * Horner scheme.
90 */
91inline double evaluateAsTaylorSeriesAt(std::span<const double> series,
92 double x) {
93 assert(not series.empty());
94 auto const value = std::accumulate(
95 series.rbegin(), series.rend(), 0.,
96 [x](auto const &acc, auto const &coeff) { return acc * x + coeff; });
97 return value;
98}
99
100/** Evaluate the polynomial interpreted as a Chebychev series. Requires a
101 * series with at least three coefficients, i.e. no linear approximations!
102 */
103inline double evaluateAsChebychevSeriesAt(std::span<const double> series,
104 double x) {
105 assert(series.size() >= 3);
106
107 auto const *c = series.data();
108 auto const x2 = 2.0 * x;
109 auto dd = c[series.size() - 1];
110 auto d = x2 * dd + c[series.size() - 2];
111 for (auto j = static_cast<int>(series.size()) - 3; j >= 1; j--) {
112 auto const tmp = d;
113 d = x2 * d - dd + c[j];
114 dd = tmp;
115 }
116 return x * d - dd + 0.5 * c[0];
117}
double LPK1(double x)
Modified Bessel function of second kind, order 1, low precision.
Definition specfunc.cpp:348
std::pair< double, double > LPK01(double x)
Modified Bessel functions of second kind, order 0 and 1, low precision.
Definition specfunc.cpp:408
double K1(double x)
Modified Bessel function of second kind, order 1.
Definition specfunc.cpp:262
double evaluateAsChebychevSeriesAt(std::span< const double > series, double x)
Evaluate the polynomial interpreted as a Chebychev series.
Definition specfunc.hpp:103
double hzeta(double order, double x)
Hurwitz zeta function.
Definition specfunc.cpp:215
double evaluateAsTaylorSeriesAt(std::span< const double > series, double x)
Evaluate the polynomial interpreted as a Taylor series via the Horner scheme.
Definition specfunc.hpp:91
double K0(double x)
Modified Bessel function of second kind, order 0.
Definition specfunc.cpp:250
double LPK0(double x)
Modified Bessel function of second kind, order 0, low precision.
Definition specfunc.cpp:288