mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: 'Math' namespace for mathematical functions
- centralises existing functions (erfInv, incGamma*, invIncGamma*). Provides a location for additional functions in the future. - adjusted existing models to use these functions (e.g. distributionModels::normal)
This commit is contained in:
committed by
Mark Olesen
parent
0b1a33e9be
commit
66d1b54a79
122
src/OpenFOAM/primitives/functions/Math/MathFunctions.H
Normal file
122
src/OpenFOAM/primitives/functions/Math/MathFunctions.H
Normal file
@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Namespace
|
||||
Foam::Math
|
||||
|
||||
Description
|
||||
A namespace for various mathematical functions.
|
||||
|
||||
Reference:
|
||||
\verbatim
|
||||
Inverse error function (tag:W):
|
||||
Winitzki, S. (2008).
|
||||
A handy approximation for the error function and its inverse.
|
||||
A lecture note obtained through private communication.
|
||||
URL:https://sites.google.com/site/winitzki/sergei-winitzkis-files
|
||||
(Retrieved on: 16 Feb 2021).
|
||||
|
||||
Incomplete gamma functions (tag:DM):
|
||||
DiDonato, A. R., & Morris Jr, A. H. (1986).
|
||||
Computation of the incomplete gamma
|
||||
function ratios and their inverse.
|
||||
ACM Transactions on Mathematical Software (TOMS), 12(4), 377-393.
|
||||
DOI:10.1145/22721.23109
|
||||
\endverbatim
|
||||
|
||||
Note
|
||||
- The algorithm in \c invIncGamma is described in (DM:Sec. 4).
|
||||
- The algorithm in \c incGammaRatio_Q is described in (DM:Sec. 3).
|
||||
- The accuracy parameter \c IND is set to a value of 1.
|
||||
|
||||
SourceFiles
|
||||
erfInv.C
|
||||
incGamma.C
|
||||
invIncGamma.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef MathFunctions_H
|
||||
#define MathFunctions_H
|
||||
|
||||
#include "scalar.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Namespace Math Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
namespace Math
|
||||
{
|
||||
|
||||
//- Inverse error function of a real-number argument
|
||||
// \param y Real-number argument at which to evaluate. Domain: (-1, 1)
|
||||
// \return The inverse of error function of y
|
||||
scalar erfInv(const scalar y);
|
||||
|
||||
|
||||
// Incomplete gamma functions
|
||||
|
||||
//- Inverse of regularised lower incomplete gamma function
|
||||
// \param a Real-number argument. Domain: (0, infty]
|
||||
// \param P Real-number argument. Domain: [0,1]
|
||||
scalar invIncGamma(const scalar a, const scalar P);
|
||||
|
||||
//- Regularised upper incomplete gamma function
|
||||
// \param a Real-number argument. Domain: (0, infty]
|
||||
// \param x Real-number argument. Domain: [0, infty]
|
||||
scalar incGammaRatio_Q(const scalar a, const scalar x);
|
||||
|
||||
//- Regularised lower incomplete gamma function
|
||||
// \param a Real-number argument. Domain: (0, infty]
|
||||
// \param x Real-number argument. Domain: [0, infty]
|
||||
scalar incGammaRatio_P(const scalar a, const scalar x);
|
||||
|
||||
//- Upper incomplete gamma function
|
||||
// \param a Real-number argument. Domain: (0, infty]
|
||||
// \param x Real-number argument. Domain: [0, infty]
|
||||
scalar incGamma_Q(const scalar a, const scalar x);
|
||||
|
||||
//- Lower incomplete gamma function
|
||||
// \param a Real-number argument. Domain: (0, infty]
|
||||
// \param x Real-number argument. Domain: [0, infty]
|
||||
scalar incGamma_P(const scalar a, const scalar x);
|
||||
|
||||
|
||||
} // End namespace Math
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
68
src/OpenFOAM/primitives/functions/Math/erfInv.C
Normal file
68
src/OpenFOAM/primitives/functions/Math/erfInv.C
Normal file
@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "MathFunctions.H"
|
||||
#include "mathematicalConstants.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::scalar Foam::Math::erfInv(const scalar y)
|
||||
{
|
||||
#ifdef FULLDEBUG
|
||||
if (mag(y) >= scalar(1))
|
||||
{
|
||||
WarningInFunction
|
||||
<< "The domain of inverse error function argument "
|
||||
<< "(i.e. y) should be limited to (-1, 1):" << nl
|
||||
<< " y = " << y
|
||||
<< endl;
|
||||
|
||||
return std::numeric_limits<scalar>::infinity();
|
||||
}
|
||||
#endif
|
||||
|
||||
// (W:p. 2) to reduce the max relative error to O(1e-4)
|
||||
constexpr scalar a = 0.147;
|
||||
|
||||
const scalar k =
|
||||
scalar(2)/(a*constant::mathematical::pi) + 0.5*log(scalar(1) - sqr(y));
|
||||
|
||||
const scalar h = log(scalar(1) - sqr(y))/a;
|
||||
|
||||
// (W:Eq. 7)
|
||||
const scalar x = sqrt(-k + sqrt(sqr(k) - h));
|
||||
|
||||
if (y < 0)
|
||||
{
|
||||
return -x;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
457
src/OpenFOAM/primitives/functions/Math/incGamma.C
Normal file
457
src/OpenFOAM/primitives/functions/Math/incGamma.C
Normal file
@ -0,0 +1,457 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2019 OpenFOAM Foundation
|
||||
Copyright (C) 2021 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Global
|
||||
Foam::Math::incGamma
|
||||
|
||||
Description
|
||||
Implementation of the incomplete gamma functions.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "MathFunctions.H"
|
||||
#include "mathematicalConstants.H"
|
||||
#include <cmath>
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// (DM:Eq. 13)
|
||||
static scalar calcQE11(const scalar a, const scalar x, const int e = 30)
|
||||
{
|
||||
scalar a_2n = 0;
|
||||
scalar b_2n = 1;
|
||||
|
||||
scalar a_2np1 = 1;
|
||||
scalar b_2np1 = x;
|
||||
|
||||
int n = 1;
|
||||
for (n = 1; (2*n) <= e; n++)
|
||||
{
|
||||
const scalar a_2nm1 = a_2np1;
|
||||
const scalar b_2nm1 = b_2np1;
|
||||
|
||||
a_2n = a_2nm1 + (n - a)*a_2n;
|
||||
b_2n = b_2nm1 + (n - a)*b_2n;
|
||||
|
||||
a_2np1 = x*a_2n + n*a_2nm1;
|
||||
b_2np1 = x*b_2n + n*b_2nm1;
|
||||
}
|
||||
|
||||
if (2*(n - 1) < e)
|
||||
{
|
||||
return a_2np1/b_2np1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a_2n/b_2n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// (DM:Eq. 15)
|
||||
static scalar calcPE15(const scalar a, const scalar x, const int nmax = 20)
|
||||
{
|
||||
scalar prod = 1;
|
||||
scalar sum = 0;
|
||||
|
||||
for (int n = 1; n <= nmax; n++)
|
||||
{
|
||||
prod *= (a + n);
|
||||
sum += pow(x, n)/prod;
|
||||
}
|
||||
|
||||
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
|
||||
|
||||
return R/a*(1 + sum);
|
||||
}
|
||||
|
||||
|
||||
// (DM:Eq. 16)
|
||||
static scalar calcQE16(const scalar a, const scalar x, const int N = 20)
|
||||
{
|
||||
scalar an = 1;
|
||||
scalar sum = 0;
|
||||
|
||||
for (int n = 1; n <= (N - 1); n++)
|
||||
{
|
||||
an *= (a - n);
|
||||
sum += an/pow(x, n);
|
||||
}
|
||||
|
||||
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
|
||||
|
||||
return R/x*(1 + sum);
|
||||
}
|
||||
|
||||
|
||||
// (DM:Eq. 18)
|
||||
static scalar calcTE18
|
||||
(
|
||||
const scalar a,
|
||||
const scalar e0,
|
||||
const scalar x,
|
||||
const scalar lambda,
|
||||
const scalar sigma,
|
||||
const scalar phi
|
||||
)
|
||||
{
|
||||
constexpr scalar D0_0 = -0.333333333333333E-00;
|
||||
constexpr scalar D0_1 = 0.833333333333333E-01;
|
||||
constexpr scalar D0_2 = -0.148148148148148E-01;
|
||||
constexpr scalar D0_3 = 0.115740740740741E-02;
|
||||
constexpr scalar D0_4 = 0.352733686067019E-03;
|
||||
constexpr scalar D0_5 = -0.178755144032922E-03;
|
||||
constexpr scalar D0_6 = 0.391926317852244E-04;
|
||||
// unused: constexpr scalar D0_7 = -0.218544851067999E-05;
|
||||
// unused: constexpr scalar D0_8 = -0.185406221071516E-05;
|
||||
// unused: constexpr scalar D0_9 = 0.829671134095309E-06;
|
||||
// unused: constexpr scalar D0_10 = -0.176659527368261E-06;
|
||||
// unused: constexpr scalar D0_11 = 0.670785354340150E-08;
|
||||
// unused: constexpr scalar D0_12 = 0.102618097842403E-07;
|
||||
// unused: constexpr scalar D0_13 = -0.438203601845335E-08;
|
||||
|
||||
constexpr scalar D1_0 = -0.185185185185185E-02;
|
||||
constexpr scalar D1_1 = -0.347222222222222E-02;
|
||||
constexpr scalar D1_2 = 0.264550264550265E-02;
|
||||
constexpr scalar D1_3 = -0.990226337448560E-03;
|
||||
constexpr scalar D1_4 = 0.205761316872428E-03;
|
||||
// unused: constexpr scalar D1_5 = -0.401877572016461E-06;
|
||||
// unused: constexpr scalar D1_6 = -0.180985503344900E-04;
|
||||
// unused: constexpr scalar D1_7 = 0.764916091608111E-05;
|
||||
// unused: constexpr scalar D1_8 = -0.161209008945634E-05;
|
||||
// unused: constexpr scalar D1_9 = 0.464712780280743E-08;
|
||||
// unused: constexpr scalar D1_10 = 0.137863344691572E-06;
|
||||
// unused: constexpr scalar D1_11 = -0.575254560351770E-07;
|
||||
// unused: constexpr scalar D1_12 = 0.119516285997781E-07;
|
||||
|
||||
constexpr scalar D2_0 = 0.413359788359788E-02;
|
||||
constexpr scalar D2_1 = -0.268132716049383E-02;
|
||||
// unused: constexpr scalar D2_2 = 0.771604938271605E-03;
|
||||
// unused: constexpr scalar D2_3 = 0.200938786008230E-05;
|
||||
// unused: constexpr scalar D2_4 = -0.107366532263652E-03;
|
||||
// unused: constexpr scalar D2_5 = 0.529234488291201E-04;
|
||||
// unused: constexpr scalar D2_6 = -0.127606351886187E-04;
|
||||
// unused: constexpr scalar D2_7 = 0.342357873409614E-07;
|
||||
// unused: constexpr scalar D2_8 = 0.137219573090629E-05;
|
||||
// unused: constexpr scalar D2_9 = -0.629899213838006E-06;
|
||||
// unused: constexpr scalar D2_10 = 0.142806142060642E-06;
|
||||
|
||||
const scalar u = 1/a;
|
||||
scalar z = sqrt(2*phi);
|
||||
|
||||
if (lambda < 1)
|
||||
{
|
||||
z = -z;
|
||||
}
|
||||
|
||||
if (sigma > (e0/sqrt(a)))
|
||||
{
|
||||
const scalar C0 =
|
||||
D0_6*pow6(z) + D0_5*pow5(z) + D0_4*pow4(z)
|
||||
+ D0_3*pow3(z) + D0_2*sqr(z) + D0_1*z + D0_0;
|
||||
|
||||
const scalar C1 =
|
||||
D1_4*pow4(z) + D1_3*pow3(z) + D1_2*sqr(z) + D1_1*z + D1_0;
|
||||
|
||||
const scalar C2 = D2_1*z + D2_0;
|
||||
|
||||
return C2*sqr(u) + C1*u + C0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const scalar C0 = D0_2*sqr(z) + D0_1*z + D0_0;
|
||||
const scalar C1 = D1_1*z + D1_0;
|
||||
const scalar C2 = D2_1*z + D2_0;
|
||||
|
||||
return C2*sqr(u) + C1*u + C0;
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::scalar Foam::Math::incGammaRatio_Q(const scalar a, const scalar x)
|
||||
{
|
||||
using namespace Foam::constant::mathematical;
|
||||
|
||||
#ifdef FULLDEBUG
|
||||
if (a <= 0)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "The parameter (i.e. a) cannot be negative or zero"
|
||||
<< " a = " << a
|
||||
<< endl;
|
||||
|
||||
return std::numeric_limits<scalar>::infinity();
|
||||
}
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "The parameter (i.e. x) cannot be negative"
|
||||
<< " x = " << x
|
||||
<< endl;
|
||||
|
||||
return std::numeric_limits<scalar>::infinity();
|
||||
}
|
||||
#endif
|
||||
|
||||
constexpr scalar BIG = 14;
|
||||
constexpr scalar x0 = 17;
|
||||
constexpr scalar e0 = 0.025;
|
||||
|
||||
if (a < 1)
|
||||
{
|
||||
if (a == 0.5)
|
||||
{
|
||||
// (DM:Eq. 8)
|
||||
if (x < 0.25)
|
||||
{
|
||||
return 1 - erf(sqrt(x));
|
||||
}
|
||||
else
|
||||
{
|
||||
return erfc(sqrt(x));
|
||||
}
|
||||
}
|
||||
else if ( x < 1.1)
|
||||
{
|
||||
// (DM:Eq. 12)
|
||||
scalar alpha = x/2.59;
|
||||
|
||||
if (x < 0.5)
|
||||
{
|
||||
alpha = log(sqrt(0.765))/log(x);
|
||||
}
|
||||
|
||||
scalar sum = 0;
|
||||
|
||||
for (int n = 1; n <= 10; n++)
|
||||
{
|
||||
sum += pow((-x), n)/((a + n)*factorial(n));
|
||||
}
|
||||
|
||||
const scalar J = -a*sum;
|
||||
|
||||
if (a > alpha || a == alpha)
|
||||
{
|
||||
// (DM:Eq. 9)
|
||||
return 1 - (pow(x, a)*(1 - J))/tgamma(a + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 10)
|
||||
const scalar L = exp(a*log(x)) - 1;
|
||||
const scalar H = 1/(tgamma(a + 1)) - 1;
|
||||
|
||||
return (pow(x, a)*J - L)/tgamma(a + 1) - H;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 11)
|
||||
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
|
||||
|
||||
return R*calcQE11(a, x);
|
||||
}
|
||||
}
|
||||
else if (a >= BIG)
|
||||
{
|
||||
const scalar sigma = fabs(1 - x/a);
|
||||
|
||||
if (sigma <= e0/sqrt(a))
|
||||
{
|
||||
// (DM:Eq. 19)
|
||||
const scalar lambda = x/a;
|
||||
const scalar phi = lambda - 1 - log(lambda);
|
||||
const scalar y = a*phi;
|
||||
|
||||
const scalar E = 0.5 - (1 - y/3)*sqrt(y/pi);
|
||||
|
||||
if (lambda <= 1)
|
||||
{
|
||||
return
|
||||
1
|
||||
- (
|
||||
E
|
||||
- (1 - y)/sqrt(2*pi*a)
|
||||
*calcTE18(a, e0, x, lambda, sigma, phi)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return
|
||||
E
|
||||
+ (1 - y)/sqrt(2*pi*a)
|
||||
*calcTE18(a, e0, x, lambda, sigma, phi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sigma <= 0.4)
|
||||
{
|
||||
// (DM:Eq. 17)
|
||||
const scalar lambda = x/a;
|
||||
const scalar phi = lambda - 1 - log(lambda);
|
||||
const scalar y = a*phi;
|
||||
|
||||
if (lambda <= 1)
|
||||
{
|
||||
return
|
||||
1
|
||||
- (0.5*erfc(sqrt(y))
|
||||
- exp(-y)/sqrt(2*pi*a)
|
||||
*calcTE18(a, e0, x, lambda, sigma, phi));
|
||||
}
|
||||
else
|
||||
{
|
||||
return
|
||||
0.5*erfc(sqrt(y))
|
||||
+ exp(-y)/sqrt(2*pi*a)
|
||||
*calcTE18(a, e0, x, lambda, sigma, phi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x <= max(a, log(10.0)))
|
||||
{
|
||||
// (DM:Eq. 15)
|
||||
return 1 - calcPE15(a, x);
|
||||
}
|
||||
else if (x < x0)
|
||||
{
|
||||
// (DM:Eq. 11)
|
||||
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
|
||||
|
||||
return R*calcQE11(a, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 16)
|
||||
return calcQE16(a, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a > x || x >= x0)
|
||||
{
|
||||
if (x <= max(a, log(10.0)))
|
||||
{
|
||||
// (DM:Eq. 15)
|
||||
return 1 - calcPE15(a, x);
|
||||
}
|
||||
else if ( x < x0)
|
||||
{
|
||||
// (DM:Eq. 11)
|
||||
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
|
||||
|
||||
return R*calcQE11(a, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 16)
|
||||
return calcQE16(a, x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (floor(2*a) == 2*a)
|
||||
{
|
||||
// (DM:Eq. 14)
|
||||
if (floor(a) == a)
|
||||
{
|
||||
scalar sum = 0;
|
||||
|
||||
for (int n = 0; n <= (a - 1); n++)
|
||||
{
|
||||
sum += pow(x, n)/factorial(n);
|
||||
}
|
||||
|
||||
return exp(-x)*sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = a - 0.5;
|
||||
scalar prod = 1;
|
||||
scalar sum = 0;
|
||||
|
||||
for (int n = 1; n <= i; n++)
|
||||
{
|
||||
prod *= (n - 0.5);
|
||||
sum += pow(x, n)/prod;
|
||||
}
|
||||
|
||||
return erfc(sqrt(x)) + exp(-x)/sqrt(pi*x)*sum;
|
||||
}
|
||||
}
|
||||
else if (x <= max(a, log(10.0)))
|
||||
{
|
||||
// (DM:Eq. 15)
|
||||
return 1 - calcPE15(a, x);
|
||||
}
|
||||
else if (x < x0)
|
||||
{
|
||||
// (DM:Eq. 11)
|
||||
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
|
||||
|
||||
return R*calcQE11(a, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 16)
|
||||
return calcQE16(a, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::scalar Foam::Math::incGammaRatio_P(const scalar a, const scalar x)
|
||||
{
|
||||
return 1 - incGammaRatio_Q(a, x);
|
||||
}
|
||||
|
||||
|
||||
Foam::scalar Foam::Math::incGamma_Q(const scalar a, const scalar x)
|
||||
{
|
||||
return incGammaRatio_Q(a, x)*tgamma(a);
|
||||
}
|
||||
|
||||
|
||||
Foam::scalar Foam::Math::incGamma_P(const scalar a, const scalar x)
|
||||
{
|
||||
return incGammaRatio_P(a, x)*tgamma(a);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
322
src/OpenFOAM/primitives/functions/Math/invIncGamma.C
Normal file
322
src/OpenFOAM/primitives/functions/Math/invIncGamma.C
Normal file
@ -0,0 +1,322 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016 OpenFOAM Foundation
|
||||
Copyright (C) 2021 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Global
|
||||
Foam::Math::invIncGamma
|
||||
|
||||
Description
|
||||
Implementation of the inverse incomplete gamma function.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "MathFunctions.H"
|
||||
#include "mathematicalConstants.H"
|
||||
|
||||
using namespace Foam::constant::mathematical;
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
static scalar minimaxs(const scalar P)
|
||||
{
|
||||
// (DM:Eq. 32)
|
||||
|
||||
constexpr scalar a_0 = 3.31125922108741;
|
||||
constexpr scalar a_1 = 11.6616720288968;
|
||||
constexpr scalar a_2 = 4.28342155967104;
|
||||
constexpr scalar a_3 = 0.213623493715853;
|
||||
|
||||
constexpr scalar b_0 = 6.61053765625462;
|
||||
constexpr scalar b_1 = 6.40691597760039;
|
||||
constexpr scalar b_2 = 1.27364489782223;
|
||||
constexpr scalar b_3 = 0.03611708101884203;
|
||||
|
||||
const scalar t = P < 0.5 ? sqrt(-2*log(P)) : sqrt(-2*log(1 - P));
|
||||
|
||||
const scalar s =
|
||||
t
|
||||
- (a_0 + t*(a_1 + t*(a_2 + t*a_3)))
|
||||
/(1 + t*(b_0 + t*(b_1 + t*(b_2 + t*b_3))));
|
||||
|
||||
return P < 0.5 ? -s : s;
|
||||
}
|
||||
|
||||
|
||||
static scalar Sn(const scalar a, const scalar x)
|
||||
{
|
||||
// (DM:Eq. 34)
|
||||
|
||||
scalar Sn = 1;
|
||||
scalar Si = 1;
|
||||
|
||||
for (int i=1; i<100; ++i)
|
||||
{
|
||||
Si *= x/(a + i);
|
||||
Sn += Si;
|
||||
|
||||
if (Si < 1e-4) break;
|
||||
}
|
||||
|
||||
return Sn;
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::scalar Foam::Math::invIncGamma(const scalar a, const scalar P)
|
||||
{
|
||||
#ifdef FULLDEBUG
|
||||
if (a <= 0)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "The parameter (i.e. a) cannot be negative or zero"
|
||||
<< " a = " << a
|
||||
<< endl;
|
||||
|
||||
return std::numeric_limits<scalar>::infinity();
|
||||
}
|
||||
|
||||
if (P < 0 || P > 1)
|
||||
{
|
||||
WarningInFunction
|
||||
<< "The domain of the parameter (i.e. P) should be limited to [0,1]"
|
||||
<< " P = " << P
|
||||
<< endl;
|
||||
|
||||
return std::numeric_limits<scalar>::infinity();
|
||||
}
|
||||
#endif
|
||||
|
||||
const scalar Q = 1 - P;
|
||||
|
||||
if (a == 1)
|
||||
{
|
||||
return -log(Q);
|
||||
}
|
||||
else if (a < 1)
|
||||
{
|
||||
const scalar Ga = tgamma(a);
|
||||
const scalar B = Q*Ga;
|
||||
|
||||
if (B > 0.6 || (B >= 0.45 && a >= 0.3))
|
||||
{
|
||||
// (DM:Eq. 21)
|
||||
const scalar u =
|
||||
(B*Q > 1e-8) ? pow(P*Ga*a, 1/a) : exp((-Q/a) - Eu);
|
||||
|
||||
return u/(1 - (u/(a + 1)));
|
||||
}
|
||||
else if (a < 0.3 && B >= 0.35)
|
||||
{
|
||||
// (DM:Eq. 22)
|
||||
const scalar t = exp(-Eu - B);
|
||||
const scalar u = t*exp(t);
|
||||
|
||||
return t*exp(u);
|
||||
}
|
||||
else if (B > 0.15 || a >= 0.3)
|
||||
{
|
||||
// (DM:Eq. 23)
|
||||
const scalar y = -log(B);
|
||||
const scalar u = y - (1 - a)*log(y);
|
||||
|
||||
return y - (1 - a)*log(u) - log(1 + (1 - a)/(1 + u));
|
||||
}
|
||||
else if (B > 0.1)
|
||||
{
|
||||
// (DM:Eq. 24)
|
||||
const scalar y = -log(B);
|
||||
const scalar u = y - (1 - a)*log(y);
|
||||
|
||||
return y
|
||||
- (1 - a)*log(u)
|
||||
- log
|
||||
(
|
||||
(sqr(u) + 2*(3 - a)*u + (2 - a)*(3 - a))
|
||||
/(sqr(u) + (5 - a)*u + 2)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 25)
|
||||
const scalar y = -log(B);
|
||||
const scalar c1 = (a - 1)*log(y);
|
||||
const scalar c12 = c1*c1;
|
||||
const scalar c13 = c12*c1;
|
||||
const scalar c14 = c12*c12;
|
||||
const scalar a2 = a*a;
|
||||
const scalar a3 = a2*a;
|
||||
const scalar c2 = (a - 1)*(1 + c1);
|
||||
const scalar c3 = (a - 1)*(-(c12/2) + (a - 2)*c1 + (3*a - 5)/2);
|
||||
const scalar c4 =
|
||||
(a - 1)
|
||||
*(
|
||||
(c13/3)
|
||||
- (3*a - 5)*c12/2
|
||||
+ (a2 - 6*a + 7)*c1
|
||||
+ (11*a2 - 46*a + 47)/6
|
||||
);
|
||||
const scalar c5 =
|
||||
(a - 1)*(-(c14/4)
|
||||
+ (11*a - 17)*c13/6
|
||||
+ (-3*a2 + 13*a - 13)*c12
|
||||
+ (2*a3 - 25*a2 + 72*a - 61)*c1/2
|
||||
+ (25*a3 - 195*a2 + 477*a - 379)/12);
|
||||
const scalar y2 = y*y;
|
||||
const scalar y3 = y2*y;
|
||||
const scalar y4 = y2*y2;
|
||||
|
||||
return y + c1 + (c2/y) + (c3/y2) + (c4/y3) + (c5/y4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 31)
|
||||
scalar s = minimaxs(P);
|
||||
|
||||
const scalar s2 = sqr(s);
|
||||
const scalar s3 = s*s2;
|
||||
const scalar s4 = s2*s2;
|
||||
const scalar s5 = s*s4;
|
||||
const scalar sqrta = sqrt(a);
|
||||
|
||||
const scalar w =
|
||||
a + s*sqrta + (s2 - 1)/3
|
||||
+ (s3 - 7*s)/(36*sqrta)
|
||||
- (3*s4 + 7*s2 - 16)/(810*a)
|
||||
+ (9*s5 + 256*s3 - 433*s)/(38880*a*sqrta);
|
||||
|
||||
if (a >= 500 && mag(1 - w/a) < 1e-6)
|
||||
{
|
||||
return w;
|
||||
}
|
||||
else if (P > 0.5)
|
||||
{
|
||||
if (w < 3*a)
|
||||
{
|
||||
return w;
|
||||
}
|
||||
else
|
||||
{
|
||||
const scalar D = max(scalar(2), scalar(a*(a - 1)));
|
||||
const scalar lnGa = lgamma(a);
|
||||
const scalar lnB = log(Q) + lnGa;
|
||||
|
||||
if (lnB < -2.3*D)
|
||||
{
|
||||
// (DM:Eq. 25)
|
||||
const scalar y = -lnB;
|
||||
const scalar c1 = (a - 1)*log(y);
|
||||
const scalar c12 = c1*c1;
|
||||
const scalar c13 = c12*c1;
|
||||
const scalar c14 = c12*c12;
|
||||
const scalar a2 = a*a;
|
||||
const scalar a3 = a2*a;
|
||||
|
||||
const scalar c2 = (a - 1)*(1 + c1);
|
||||
const scalar c3 =
|
||||
(a - 1)
|
||||
*(
|
||||
- (c12/2)
|
||||
+ (a - 2)*c1
|
||||
+ (3*a - 5)/2
|
||||
);
|
||||
const scalar c4 =
|
||||
(a - 1)
|
||||
*(
|
||||
(c13/3)
|
||||
- (3*a - 5)*c12/2
|
||||
+ (a2 - 6*a + 7)*c1
|
||||
+ (11*a2 - 46*a + 47)/6
|
||||
);
|
||||
const scalar c5 =
|
||||
(a - 1)
|
||||
*(
|
||||
- (c14/4)
|
||||
+ (11*a - 17)*c13/6
|
||||
+ (-3*a2 + 13*a - 13)*c12
|
||||
+ (2*a3 - 25*a2 + 72*a - 61)*c1/2
|
||||
+ (25*a3 - 195*a2 + 477*a - 379)/12
|
||||
);
|
||||
|
||||
const scalar y2 = y*y;
|
||||
const scalar y3 = y2*y;
|
||||
const scalar y4 = y2*y2;
|
||||
|
||||
return y + c1 + (c2/y) + (c3/y2) + (c4/y3) + (c5/y4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 33)
|
||||
const scalar u =
|
||||
-lnB + (a - 1)*log(w) - log(1 + (1 - a)/(1 + w));
|
||||
|
||||
return -lnB + (a - 1)*log(u) - log(1 + (1 - a)/(1 + u));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scalar z = w;
|
||||
const scalar ap1 = a + 1;
|
||||
|
||||
if (w < 0.15*ap1)
|
||||
{
|
||||
// (DM:Eq. 35)
|
||||
const scalar ap2 = a + 2;
|
||||
const scalar v = log(P) + lgamma(ap1);
|
||||
z = exp((v + w)/a);
|
||||
s = log1p(z/ap1*(1 + z/ap2));
|
||||
z = exp((v + z - s)/a);
|
||||
s = log1p(z/ap1*(1 + z/ap2));
|
||||
z = exp((v + z - s)/a);
|
||||
s = log1p(z/ap1*(1 + z/ap2*(1 + z/(a + 3))));
|
||||
z = exp((v + z - s)/a);
|
||||
}
|
||||
|
||||
if (z <= 0.01*ap1 || z > 0.7*ap1)
|
||||
{
|
||||
return z;
|
||||
}
|
||||
else
|
||||
{
|
||||
// (DM:Eq. 36)
|
||||
const scalar lnSn = log(Sn(a, z));
|
||||
const scalar v = log(P) + lgamma(ap1);
|
||||
z = exp((v + z - lnSn)/a);
|
||||
|
||||
return z*(1 - (a*log(z) - z - v + lnSn)/(a - z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user