star-wf

First-passage time of brownian motion
git clone git://git.meso-star.fr/star-wf.git
Log | Files | Refs | README | LICENSE

commit 0c4e3e0eb13663e6fcf47211c27096c176701e43
parent 70ebbd4523e821b7b944a37a4de682b81688e8cc
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Sun, 10 Mar 2024 11:06:30 +0100

Updated H calculation

Addition of an internal function H3d_eval that not only calculates H but
also evaluates its first, second and third derivatives. The swf_H3d_eval
function now relies on this function. The derivatives will be used to
evaluate interpolation errors and implement interpolations that are more
efficient than linear interpolation.

Diffstat:
Msrc/swf_H.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 70 insertions(+), 15 deletions(-)

diff --git a/src/swf_H.c b/src/swf_H.c @@ -48,32 +48,87 @@ check_swf_H_tabulate_args(const struct swf_H_tabulate_args* args) return RES_OK; } -/******************************************************************************* - * Exported symbols - ******************************************************************************/ - /* H(x) = 1 + 2 Sum(k=1..INF)((-1)^k * exp(-(PI*k)^2 * x)) */ -double -swf_H3d_eval(const double x) +/* H(x) = 1 + 2 Sum(k=1..INF)[(-1)^k * exp(-(PI*k)^2 * x)] + * H'(x) = - 2 Sum(k=1..INF)[(-1)^k * exp(-(PI*k)^2 * x) * (PI*k)^2] + * H''(x) = + 2 Sum(k=1..INF)[(-1)^k * exp(-(PI*k)^2 * x) * (PI*k)^4] + * H'''(x) = - 2 Sum(k=1..INF)[(-1)^k * exp(-(PI*k)^2 * x) * (PI*k)^6] */ +static INLINE double +H3d + (const double x, + double* dHx, /* Derivative. NULL <=> do not compute it */ + double* d2Hx, /* Second derivative. NULL <=> do not compute it */ + double* d3Hx) /* Third derivative. NULL <=> do not compute it */ { - double sign = -1; /* Sign of the term */ - double sum = 0; /* Sum */ - double error = INF; /* Error */ - unsigned k = 1; /* Index of the term */ + double Hx = 0; /* Value of the function */ + + /* Sum of the terms in the series */ + double sum = 0; /* Sum of the terms */ + double sumd = 0; /* Sum of the derivative terms */ + double sumd2 = 0; /* Sum of the second derivative terms */ + double sumd3 = 0; /* Sum of the third derivative terms */ + + double sign = -1; /* Sign of the serie term */ + unsigned k = 1; /* Index of the serie term */ + + /* Have the calculations converged or are there errors? */ + int error = 1; + int errord = dHx != NULL; + int errord2 = d2Hx != NULL; + int errord3 = d3Hx != NULL; + ASSERT(x >= 0); /* Check pre-condition */ + /* Do not attempt to calculate 0; it would be numerically catastrophic. + * Simply return its value */ if(x == 0) return 0; do { const double t = PI*(double)k; - const double term = sign * exp(-(t*t)*x); + const double t2 = t*t; + const double term = sign * exp(-t2*x); const double sum_next = sum + term; - error = sum_next - sum; + error = sum_next != sum; sum = sum_next; - sign *= -1; - } while(error != 0 && ++k < UINT_MAX); + sign = -sign; + + if(dHx) { /* Derivative */ + const double termd = term * t2; + const double sumd_next = sumd + termd; + errord = sumd_next != sumd; + sumd = sumd_next; + } + + if(d2Hx) { /* Second derivative */ + const double termd2 = term * t2*t2; + const double sumd2_next = sumd2 + termd2; + errord2 = sumd2_next != sumd2; + sumd2 = sumd2_next; + } + + if(d3Hx) { /* Third derivative */ + const double termd3 = term * t2*t2*t2; + const double sumd3_next = sumd3 + termd3; + errord3 = sumd3_next != sumd3; + sumd3 = sumd3_next; + } + } while((error || errord || errord2 || errord3) && ++k < UINT_MAX); + + Hx = 1.0 + 2.0 * sum; + + if(dHx) *dHx = -2.0 * sumd; /* Derivative */ + if(d2Hx) *d2Hx = 2.0 * sumd2; /* Second derivative */ + if(d3Hx) *d3Hx = -2.0 * sumd3; /* Third derivative */ + return Hx; +} - return 1.0 + 2.0 * sum; +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +double +swf_H3d_eval(const double x) +{ + return H3d(x, NULL, NULL, NULL); } double