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:
Kutalmis Bercin 2021-02-16 11:12:19 +00:00 committed by Mark Olesen
parent 0b1a33e9be
commit 66d1b54a79
16 changed files with 559 additions and 222 deletions

View File

@ -0,0 +1,3 @@
Test-MathFunctions.C
EXE = $(FOAM_USER_APPBIN)/Test-MathFunctions

View File

@ -0,0 +1 @@
EXE_INC = -I../TestTools

View File

@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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/>.
Application
Test-MathFunctions
Description
Tests for \c Math namespace member functions
using \c doubleScalar base type.
\*---------------------------------------------------------------------------*/
#include "MathFunctions.H"
#include "mathematicalConstants.H"
#include "IOmanip.H"
#include "TestTools.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Execute each member functions of Foam::Math::, and print output
template<class Type>
void test_member_funcs(Type)
{
Random rndGen(1234);
const label numberOfTests = 10000;
const scalar tolerance = 1e-3;
for (label i = 0; i < numberOfTests; ++i)
{
Info<< "# Inverse error functions:" << endl;
const Type x1 = rndGen.sample01<Type>();
const Type x2 = rndGen.sample01<Type>();
Info<< " # Operands:" << nl
<< " x1 = " << x1 << nl
<< " x2 = " << x2 << endl;
cmp
(
" # erf(erfinv(x1)) = x1 = ",
x1,
Foam::erf(Foam::Math::erfInv(x1)),
tolerance
);
cmp
(
" # erf(erfinv(-x2)) = -x2 = ",
x2,
Foam::erf(Foam::Math::erfInv(x2)),
tolerance
);
Info<< "# Incomplete gamma functions:" << endl;
const Type a = rndGen.position(SMALL, Type(100));
const Type x = rndGen.position(Type(0), Type(100));
Info<< " # Operands:" << nl
<< " a = " << a << nl
<< " x = " << x << endl;
cmp
(
" # incGammaRatio_Q(a,x) + incGammaRatio_P(a,x) = 1 = ",
Foam::Math::incGammaRatio_Q(a,x) + Foam::Math::incGammaRatio_P(a,x),
scalar(1),
tolerance
);
cmp
(
" # incGamma_Q(1, x) = exp(-x) = ",
Foam::Math::incGamma_Q(1, x),
Foam::exp(-x),
tolerance
);
cmp
(
" # incGamma_Q(0.5, x) = sqrt(pi)*erfc(sqrt(x)) = ",
Foam::Math::incGamma_Q(0.5, x),
Foam::sqrt(Foam::constant::mathematical::pi)
*Foam::erfc(Foam::sqrt(x)),
tolerance
);
cmp
(
" # incGamma_P(1,x) = 1 - exp(x) = ",
Foam::Math::incGamma_P(1, x),
1 - Foam::exp(-x),
tolerance
);
cmp
(
" # incGamma_P(0.5, x) = sqrt(pi)*erf(sqrt(x)) = ",
Foam::Math::incGamma_P(0.5, x),
Foam::sqrt(Foam::constant::mathematical::pi)
*Foam::erf(Foam::sqrt(x)),
tolerance
);
}
}
// Do compile-time recursion over the given types
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
run_tests(const std::tuple<Tp...>& types, const List<word>& typeID){}
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
run_tests(const std::tuple<Tp...>& types, const List<word>& typeID)
{
Info<< nl << " ## Test member functions: "<< typeID[I] <<" ##" << nl;
test_member_funcs(std::get<I>(types));
run_tests<I + 1, Tp...>(types, typeID);
}
// * * * * * * * * * * * * * * * Main Program * * * * * * * * * * * * * * * //
int main()
{
Info<< setprecision(15);
const std::tuple<doubleScalar> types
(
std::make_tuple(Zero)
);
const List<word> typeID
({
"doubleScalar"
});
run_tests(types, typeID);
if (nFail_)
{
Info<< nl << " #### "
<< "Failed in " << nFail_ << " tests "
<< "out of total " << nTest_ << " tests "
<< "####\n" << endl;
return 1;
}
Info<< nl << " #### Passed all " << nTest_ <<" tests ####\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,6 +30,10 @@ Description
using namespace Foam;
#include "floatScalar.H"
#include "doubleScalar.H"
#include "complex.H"
#include "Matrix.H"
#include "Random.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -60,8 +60,6 @@ $(ints)/lists/labelListIOList.C
primitives/Scalar/doubleScalar/doubleScalar.C
primitives/Scalar/floatScalar/floatScalar.C
primitives/Scalar/scalar/scalar.C
primitives/Scalar/scalar/incGamma.C
primitives/Scalar/scalar/invIncGamma.C
primitives/Scalar/lists/scalarList.C
primitives/Scalar/lists/scalarIOList.C
primitives/Scalar/lists/scalarListIOList.C
@ -117,6 +115,12 @@ primitives/functions/Function1/quarterCosineRamp/quarterCosineRamp.C
primitives/functions/Function1/halfCosineRamp/halfCosineRamp.C
primitives/functions/Polynomial/polynomialFunction.C
/* Math functions */
math = primitives/functions/Math
$(math)/erfInv.C
$(math)/incGamma.C
$(math)/invIncGamma.C
primitives/subModelBase/subModelBase.C
strings = primitives/strings

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -213,25 +213,9 @@ inline float narrowFloat(const double val)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Additional transcendental functions and specialisations
namespace Foam
{
//- Inverse normalized incomplete gamma function
scalar invIncGamma(const scalar a, const scalar P);
//- Normalized upper incomplete gamma function
scalar incGammaRatio_Q(const scalar a, const scalar x);
//- Normalized lower incomplete gamma function
scalar incGammaRatio_P(const scalar a, const scalar x);
//- Upper incomplete gamma function
scalar incGamma_Q(const scalar a, const scalar x);
//- Lower incomplete gamma function
scalar incGamma_P(const scalar a, const scalar x);
//- Type to use for extended precision
template<>
class typeOfSolve<scalar>

View 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
// ************************************************************************* //

View 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;
}
// ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -24,38 +25,23 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Global
Foam::incGamma
Foam::Math::incGamma
Description
Calculates the upper and lower incomplete gamma functions as well as their
normalized versions.
The algorithm is described in detail in DiDonato et al. (1986).
\verbatim
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.
\endverbatim
All equation numbers in the following code refer to the above paper.
The algorithm in function 'incGammaRatio_Q' is described in section 3.
The accuracy parameter IND is set to a value of 1.
Implementation of the incomplete gamma functions.
\*---------------------------------------------------------------------------*/
#include "MathFunctions.H"
#include "mathematicalConstants.H"
#include <cmath>
using namespace Foam::constant::mathematical;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Eqn. (13)
// (DM:Eq. 13)
static scalar calcQE11(const scalar a, const scalar x, const int e = 30)
{
scalar a_2n = 0;
@ -88,7 +74,7 @@ static scalar calcQE11(const scalar a, const scalar x, const int e = 30)
}
// Eqn. (15)
// (DM:Eq. 15)
static scalar calcPE15(const scalar a, const scalar x, const int nmax = 20)
{
scalar prod = 1;
@ -106,7 +92,7 @@ static scalar calcPE15(const scalar a, const scalar x, const int nmax = 20)
}
// Eq. (16)
// (DM:Eq. 16)
static scalar calcQE16(const scalar a, const scalar x, const int N = 20)
{
scalar an = 1;
@ -124,7 +110,7 @@ static scalar calcQE16(const scalar a, const scalar x, const int N = 20)
}
// Eq. (18)
// (DM:Eq. 18)
static scalar calcTE18
(
const scalar a,
@ -135,55 +121,46 @@ static scalar calcTE18
const scalar phi
)
{
static const scalar D0[] =
{
-0.333333333333333E-00,
0.833333333333333E-01,
-0.148148148148148E-01,
0.115740740740741E-02,
0.352733686067019E-03,
-0.178755144032922E-03,
0.391926317852244E-04,
-0.218544851067999E-05,
-0.185406221071516E-05,
0.829671134095309E-06,
-0.176659527368261E-06,
0.670785354340150E-08,
0.102618097842403E-07,
-0.438203601845335E-08
};
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;
static const scalar D1[] =
{
-0.185185185185185E-02,
-0.347222222222222E-02,
0.264550264550265E-02,
-0.990226337448560E-03,
0.205761316872428E-03,
-0.401877572016461E-06,
-0.180985503344900E-04,
0.764916091608111E-05,
-0.161209008945634E-05,
0.464712780280743E-08,
0.137863344691572E-06,
-0.575254560351770E-07,
0.119516285997781E-07
};
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;
static const scalar D2[] =
{
0.413359788359788E-02,
-0.268132716049383E-02,
0.771604938271605E-03,
0.200938786008230E-05,
-0.107366532263652E-03,
0.529234488291201E-04,
-0.127606351886187E-04,
0.342357873409614E-07,
0.137219573090629E-05,
-0.629899213838006E-06,
0.142806142060642E-06
};
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);
@ -196,44 +173,66 @@ static scalar calcTE18
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];
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];
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];
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];
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::incGammaRatio_Q(const scalar a, const scalar x)
Foam::scalar Foam::Math::incGammaRatio_Q(const scalar a, const scalar x)
{
const scalar BIG = 14;
const scalar x0 = 17;
const scalar e0 = 0.025;
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)
{
// Eqn. (8)
// (DM:Eq. 8)
if (x < 0.25)
{
return 1 - erf(sqrt(x));
@ -245,7 +244,7 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
}
else if ( x < 1.1)
{
// Eqn. (12)
// (DM:Eq. 12)
scalar alpha = x/2.59;
if (x < 0.5)
@ -264,12 +263,12 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
if (a > alpha || a == alpha)
{
// Eqn. (9)
// (DM:Eq. 9)
return 1 - (pow(x, a)*(1 - J))/tgamma(a + 1);
}
else
{
// Eqn. (10)
// (DM:Eq. 10)
const scalar L = exp(a*log(x)) - 1;
const scalar H = 1/(tgamma(a + 1)) - 1;
@ -278,7 +277,7 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
}
else
{
// Eqn. (11)
// (DM:Eq. 11)
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
return R*calcQE11(a, x);
@ -290,7 +289,7 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
if (sigma <= e0/sqrt(a))
{
// Eqn. (19)
// (DM:Eq. 19)
const scalar lambda = x/a;
const scalar phi = lambda - 1 - log(lambda);
const scalar y = a*phi;
@ -319,7 +318,7 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
{
if (sigma <= 0.4)
{
// Eqn. (17)
// (DM:Eq. 17)
const scalar lambda = x/a;
const scalar phi = lambda - 1 - log(lambda);
const scalar y = a*phi;
@ -344,19 +343,19 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
{
if (x <= max(a, log(10.0)))
{
// Eqn. (15)
// (DM:Eq. 15)
return 1 - calcPE15(a, x);
}
else if (x < x0)
{
// Eqn. (11)
// (DM:Eq. 11)
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
return R*calcQE11(a, x);
}
else
{
// Eqn. (16)
// (DM:Eq. 16)
return calcQE16(a, x);
}
}
@ -368,19 +367,19 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
{
if (x <= max(a, log(10.0)))
{
// Eqn. (15)
// (DM:Eq. 15)
return 1 - calcPE15(a, x);
}
else if ( x < x0)
{
// Eqn. (11)
// (DM:Eq. 11)
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
return R*calcQE11(a, x);
}
else
{
// Eqn. (16)
// (DM:Eq. 16)
return calcQE16(a, x);
}
}
@ -388,7 +387,7 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
{
if (floor(2*a) == 2*a)
{
// Eqn. (14)
// (DM:Eq. 14)
if (floor(a) == a)
{
scalar sum = 0;
@ -417,19 +416,19 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
}
else if (x <= max(a, log(10.0)))
{
// Eqn. (15)
// (DM:Eq. 15)
return 1 - calcPE15(a, x);
}
else if ( x < x0)
else if (x < x0)
{
// Eqn. (11)
// (DM:Eq. 11)
const scalar R = (exp(-x)*pow(x, a))/tgamma(a);
return R*calcQE11(a, x);
}
else
{
// Eqn. (16)
// (DM:Eq. 16)
return calcQE16(a, x);
}
}
@ -437,19 +436,19 @@ Foam::scalar Foam::incGammaRatio_Q(const scalar a, const scalar x)
}
Foam::scalar Foam::incGammaRatio_P(const scalar a, const scalar x)
Foam::scalar Foam::Math::incGammaRatio_P(const scalar a, const scalar x)
{
return 1 - incGammaRatio_Q(a, x);
}
Foam::scalar Foam::incGamma_Q(const scalar a, const scalar x)
Foam::scalar Foam::Math::incGamma_Q(const scalar a, const scalar x)
{
return incGammaRatio_Q(a, x)*tgamma(a);
}
Foam::scalar Foam::incGamma_P(const scalar a, const scalar x)
Foam::scalar Foam::Math::incGamma_P(const scalar a, const scalar x)
{
return incGammaRatio_P(a, x)*tgamma(a);
}

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -24,60 +25,43 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Global
Foam::invIncGamma
Foam::Math::invIncGamma
Description
Function to calculate the inverse of the
normalized incomplete gamma function.
The algorithm is described in detain in reference:
\verbatim
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.
\endverbatim
All equation numbers in the following code refer to the above text and
the algorithm in the function 'invIncGamma' is described in section 4.
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)
{
// Eqn. 32
// (DM:Eq. 32)
static const scalar a[] =
{
3.31125922108741,
11.6616720288968,
4.28342155967104,
0.213623493715853
};
constexpr scalar a_0 = 3.31125922108741;
constexpr scalar a_1 = 11.6616720288968;
constexpr scalar a_2 = 4.28342155967104;
constexpr scalar a_3 = 0.213623493715853;
static const scalar b[] =
{
6.61053765625462,
6.40691597760039,
1.27364489782223,
0.03611708101884203
};
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]))));
- (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;
}
@ -85,12 +69,12 @@ static scalar minimaxs(const scalar P)
static scalar Sn(const scalar a, const scalar x)
{
//- Eqn. 34
// (DM:Eq. 34)
scalar Sn = 1;
scalar Si = 1;
for (int i=1; i<100; i++)
for (int i=1; i<100; ++i)
{
Si *= x/(a + i);
Sn += Si;
@ -101,15 +85,35 @@ static scalar Sn(const scalar a, const scalar x)
return Sn;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Inverse normalized incomplete gamma function
Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
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)
@ -123,7 +127,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
if (B > 0.6 || (B >= 0.45 && a >= 0.3))
{
// Eqn. 21
// (DM:Eq. 21)
const scalar u =
(B*Q > 1e-8) ? pow(P*Ga*a, 1/a) : exp((-Q/a) - Eu);
@ -131,7 +135,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else if (a < 0.3 && B >= 0.35)
{
// Eqn. 22
// (DM:Eq. 22)
const scalar t = exp(-Eu - B);
const scalar u = t*exp(t);
@ -139,7 +143,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else if (B > 0.15 || a >= 0.3)
{
// Eqn. 23
// (DM:Eq. 23)
const scalar y = -log(B);
const scalar u = y - (1 - a)*log(y);
@ -147,7 +151,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else if (B > 0.1)
{
// Eqn. 24
// (DM:Eq. 24)
const scalar y = -log(B);
const scalar u = y - (1 - a)*log(y);
@ -161,7 +165,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else
{
// Eqn. 25:
// (DM:Eq. 25)
const scalar y = -log(B);
const scalar c1 = (a - 1)*log(y);
const scalar c12 = c1*c1;
@ -194,7 +198,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else
{
// Eqn. 31:
// (DM:Eq. 31)
scalar s = minimaxs(P);
const scalar s2 = sqr(s);
@ -227,7 +231,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
if (lnB < -2.3*D)
{
// Eqn. 25:
// (DM:Eq. 25)
const scalar y = -lnB;
const scalar c1 = (a - 1)*log(y);
const scalar c12 = c1*c1;
@ -270,7 +274,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else
{
// Eqn. 33
// (DM:Eq. 33)
const scalar u =
-lnB + (a - 1)*log(w) - log(1 + (1 - a)/(1 + w));
@ -285,7 +289,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
if (w < 0.15*ap1)
{
// Eqn. 35
// (DM:Eq. 35)
const scalar ap2 = a + 2;
const scalar v = log(P) + lgamma(ap1);
z = exp((v + w)/a);
@ -303,7 +307,7 @@ Foam::scalar Foam::invIncGamma(const scalar a, const scalar P)
}
else
{
// Eqn. 36
// (DM:Eq. 36)
const scalar lnSn = log(Sn(a, z));
const scalar v = log(P) + lgamma(ap1);
z = exp((v + z - lnSn)/a);

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/
#include "massRosinRammler.H"
#include "MathFunctions.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -87,7 +89,7 @@ Foam::scalar Foam::distributionModels::massRosinRammler::sample() const
{
const scalar a = 3/n_ + 1;
const scalar P = rndGen_.sample01<scalar>();
const scalar x = invIncGamma(a, P);
const scalar x = Math::invIncGamma(a, P);
d = d_*pow(x, 1/n_);
} while (d < minValue_ || d > maxValue_);

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,7 +28,7 @@ License
#include "normal.H"
#include "addToRunTimeSelectionTable.H"
#include "mathematicalConstants.H"
#include "MathFunctions.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -99,7 +100,7 @@ Foam::scalar Foam::distributionModels::normal::sample() const
scalar b = erf((maxValue_ - expectation_)/variance_);
scalar y = rndGen_.sample01<scalar>();
scalar x = erfInv(y*(b - a) + a)*variance_ + expectation_;
scalar x = Math::erfInv(y*(b - a) + a)*variance_ + expectation_;
// Note: numerical approximation of the inverse function yields slight
// inaccuracies
@ -128,17 +129,4 @@ Foam::scalar Foam::distributionModels::normal::meanValue() const
}
Foam::scalar Foam::distributionModels::normal::erfInv(const scalar y) const
{
scalar k = 2.0/(constant::mathematical::pi*a_) + 0.5*log(1.0 - y*y);
scalar h = log(1.0 - y*y)/a_;
scalar x = sqrt(-k + sqrt(k*k - h));
if (y < 0.0)
{
x *= -1.0;
}
return x;
}
// ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -60,8 +61,7 @@ class normal
:
public distributionModel
{
// Private data
// Private Data
//- Distribution minimum
scalar minValue_;
@ -116,8 +116,6 @@ public:
//- Return the mean value
virtual scalar meanValue() const;
virtual scalar erfInv(const scalar y) const;
};

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,25 +36,6 @@ using namespace Foam::constant;
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
template<class CloudType>
Foam::scalar Foam::BrownianMotionForce<CloudType>::erfInv(const scalar y) const
{
const scalar a = 0.147;
scalar k = 2.0/(mathematical::pi*a) + 0.5*log(1.0 - y*y);
scalar h = log(1.0 - y*y)/a;
scalar x = sqrt(-k + sqrt(k*k - h));
if (y < 0.0)
{
return -x;
}
else
{
return x;
}
}
template<class CloudType>
Foam::tmp<Foam::volScalarField>
Foam::BrownianMotionForce<CloudType>::kModel() const
@ -200,7 +182,7 @@ Foam::forceSuSp Foam::BrownianMotionForce<CloudType>::calcCoupled
// for (direction dir = 0; dir < vector::nComponents; dir++)
// {
// const scalar x = rndGen_.sample01<scalar>();
// const scalar eta = sqrt2*erfInv(2*x - 1.0);
// const scalar eta = sqrt2*Math::erfInv(2*x - 1.0);
// value.Su()[dir] = f*eta;
// }

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -84,9 +85,6 @@ class BrownianMotionForce
// Private Member Functions
//- Inverse erf for Gaussian distribution
scalar erfInv(const scalar y) const;
//- Return the k field from the turbulence model
tmp<volScalarField> kModel() const;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,6 +30,7 @@ License
#include "addToRunTimeSelectionTable.H"
#include "phaseCompressibleTurbulenceModel.H"
#include "tableBounds.H"
#include "MathFunctions.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -99,19 +100,19 @@ Foam::diameterModels::binaryBreakupModels::LuoSvendsen::LuoSvendsen
Tuple2<scalar, scalar> gamma2by11
(
z,
incGammaRatio_Q(2.0/11.0, z)
Math::incGammaRatio_Q(2.0/11.0, z)
);
Tuple2<scalar, scalar> gamma5by11
(
z,
incGammaRatio_Q(5.0/11.0, z)
Math::incGammaRatio_Q(5.0/11.0, z)
);
Tuple2<scalar, scalar> gamma8by11
(
z,
incGammaRatio_Q(8.0/11.0, z)
Math::incGammaRatio_Q(8.0/11.0, z)
);
gammaUpperReg2by11Table.append(gamma2by11);