Added robust primitive cubic/quadratic/linear equation solutions.

Applied to eigen-value calculations. Fixed repeated-eigen-value issues
in eigen-vector generation.
This commit is contained in:
Will Bainbridge 2017-03-22 15:11:54 +00:00
parent b3e4c547e8
commit 997b66913d
19 changed files with 1477 additions and 216 deletions

View file

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

View file

@ -0,0 +1,3 @@
EXE_INC =
EXE_LIBS =

View file

@ -0,0 +1,101 @@
#include <ctime>
#include <random>
#include "cubicEqn.H"
#include "IOstreams.H"
#include "stringList.H"
using namespace Foam;
scalar randomScalar(const scalar min, const scalar max)
{
static_assert
(
sizeof(long) == sizeof(scalar),
"Scalar and long are not the same size"
);
static std::default_random_engine generator(std::time(0));
static std::uniform_int_distribution<long>
distribution
(
std::numeric_limits<long>::min(),
std::numeric_limits<long>::max()
);
scalar x;
do
{
long i = distribution(generator);
x = reinterpret_cast<scalar&>(i);
}
while (min > mag(x) || mag(x) > max || !std::isfinite(x));
return x;
};
template <class Type>
void test(const Type& polynomialEqn, const scalar tol)
{
Roots<Type::nComponents - 1> r = polynomialEqn.roots();
const scalar nan = std::numeric_limits<scalar>::quiet_NaN();
const scalar inf = std::numeric_limits<scalar>::infinity();
FixedList<label, Type::nComponents - 1> t;
FixedList<scalar, Type::nComponents - 1> v(nan);
FixedList<scalar, Type::nComponents - 1> e(nan);
bool ok = true;
forAll(r, i)
{
t[i] = r.type(i);
switch (t[i])
{
case roots::real:
v[i] = polynomialEqn.value(r[i]);
e[i] = polynomialEqn.error(r[i]);
ok = ok && mag(v[i]) < tol*mag(e[i]);
break;
case roots::posInf:
v[i] = + inf;
e[i] = nan;
break;
case roots::negInf:
v[i] = - inf;
e[i] = nan;
break;
default:
v[i] = e[i] = nan;
break;
}
}
if (!ok)
{
Info<< "Coeffs: " << polynomialEqn << endl
<< " Types: " << t << endl
<< " Roots: " << r << endl
<< "Values: " << v << endl
<< "Errors: " << e << endl << endl;
}
}
int main()
{
const int nTests = 1000000;
for (int t = 0; t < nTests; ++ t)
{
test
(
cubicEqn
(
randomScalar(1e-50, 1e+50),
randomScalar(1e-50, 1e+50),
randomScalar(1e-50, 1e+50),
randomScalar(1e-50, 1e+50)
),
100
);
}
Info << nTests << " cubics tested" << endl;
return 0;
}

View file

@ -125,6 +125,9 @@ $(spatialVectorAlgebra)/SpatialVector/spatialVector/spatialVector.C
$(spatialVectorAlgebra)/SpatialTensor/spatialTensor/spatialTensor.C $(spatialVectorAlgebra)/SpatialTensor/spatialTensor/spatialTensor.C
$(spatialVectorAlgebra)/CompactSpatialTensor/compactSpatialTensor/compactSpatialTensor.C $(spatialVectorAlgebra)/CompactSpatialTensor/compactSpatialTensor/compactSpatialTensor.C
primitives/polynomialEqns/cubicEqn/cubicEqn.C
primitives/polynomialEqns/quadraticEqn/quadraticEqn.C
containers/HashTables/HashTable/HashTableCore.C containers/HashTables/HashTable/HashTableCore.C
containers/HashTables/StaticHashTable/StaticHashTableCore.C containers/HashTables/StaticHashTable/StaticHashTableCore.C
containers/Lists/SortableList/ParSortableListName.C containers/Lists/SortableList/ParSortableListName.C

View file

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "tensor.H" #include "tensor.H"
#include "cubicEqn.H"
#include "mathematicalConstants.H" #include "mathematicalConstants.H"
using namespace Foam::constant::mathematical; using namespace Foam::constant::mathematical;
@ -72,137 +73,76 @@ const Foam::tensor Foam::tensor::I
Foam::vector Foam::eigenValues(const tensor& t) Foam::vector Foam::eigenValues(const tensor& t)
{ {
// The eigenvalues // Coefficients of the characteristic cubic polynomial (a = 1)
scalar i, ii, iii; const scalar b =
- t.xx() - t.yy() - t.zz();
const scalar c =
t.xx()*t.yy() + t.xx()*t.zz() + t.yy()*t.zz()
- t.xy()*t.yx() - t.yz()*t.zy() - t.zx()*t.xz();
const scalar d =
- t.xx()*t.yy()*t.zz()
- t.xy()*t.yz()*t.zx() - t.xz()*t.zy()*t.yx()
+ t.xx()*t.yz()*t.zy() + t.yy()*t.zx()*t.xz() + t.zz()*t.xy()*t.yx();
// diagonal matrix // Solve
if Roots<3> roots = cubicEqn(1, b, c, d).roots();
(
( // Check the root types
mag(t.xy()) + mag(t.xz()) + mag(t.yx()) vector lambda = vector::zero;
+ mag(t.yz()) + mag(t.zx()) + mag(t.zy()) forAll(roots, i)
)
< SMALL
)
{ {
i = t.xx(); switch (roots.type(i))
ii = t.yy();
iii = t.zz();
}
// non-diagonal matrix
else
{
// Coefficients of the characteristic polynmial
// x^3 + a*x^2 + b*x + c = 0
scalar a =
- t.xx() - t.yy() - t.zz();
scalar b =
t.xx()*t.yy() + t.xx()*t.zz() + t.yy()*t.zz()
- t.xy()*t.yx() - t.yz()*t.zy() - t.zx()*t.xz();
scalar c =
- t.xx()*t.yy()*t.zz()
- t.xy()*t.yz()*t.zx() - t.xz()*t.zy()*t.yx()
+ t.xx()*t.yz()*t.zy() + t.yy()*t.zx()*t.xz() + t.zz()*t.xy()*t.yx();
// Auxillary variables
scalar aBy3 = a/3;
scalar P = (a*a - 3*b)/9; // == -p_wikipedia/3
scalar PPP = P*P*P;
scalar Q = (2*a*a*a - 9*a*b + 27*c)/54; // == q_wikipedia/2
scalar QQ = Q*Q;
// Three identical roots
if (mag(P) < SMALL && mag(Q) < SMALL)
{ {
return vector(- aBy3, - aBy3, - aBy3); case roots::real:
} lambda[i] = roots[i];
break;
// Two identical roots and one distinct root case roots::complex:
else if (mag(QQ) > SMALL && mag(PPP/QQ - 1) < SMALL) WarningInFunction
{ << "Complex eigenvalues detected for tensor: " << t
scalar sqrtP = sqrt(P); << endl;
scalar signQ = sign(Q); lambda[i] = 0;
break;
i = ii = signQ*sqrtP - aBy3; case roots::posInf:
iii = - 2*signQ*sqrtP - aBy3; lambda[i] = VGREAT;
} break;
case roots::negInf:
// Three distinct roots lambda[i] = - VGREAT;
else if (PPP > QQ) break;
{ case roots::nan:
scalar sqrtP = sqrt(P); FatalErrorInFunction
scalar value = cos(acos(Q/sqrt(PPP))/3); << "Eigenvalue calculation failed for tensor: " << t
scalar delta = sqrt(3 - 3*value*value); << exit(FatalError);
i = - 2*sqrtP*value - aBy3;
ii = sqrtP*(value + delta) - aBy3;
iii = sqrtP*(value - delta) - aBy3;
}
// One real root, two imaginary roots
// based on the above logic, PPP must be less than QQ
else
{
WarningInFunction
<< "complex eigenvalues detected for tensor: " << t
<< endl;
if (mag(P) < SMALL)
{
i = cbrt(QQ/2);
}
else
{
scalar w = cbrt(- Q - sqrt(QQ - PPP));
i = w + P/w - aBy3;
}
return vector(-VGREAT, i, VGREAT);
} }
} }
// Sort the eigenvalues into ascending order // Sort the eigenvalues into ascending order
if (i > ii) if (lambda.x() > lambda.y())
{ {
Swap(i, ii); Swap(lambda.x(), lambda.y());
}
if (lambda.y() > lambda.z())
{
Swap(lambda.y(), lambda.z());
}
if (lambda.x() > lambda.y())
{
Swap(lambda.x(), lambda.y());
} }
if (ii > iii) return lambda;
{
Swap(ii, iii);
}
if (i > ii)
{
Swap(i, ii);
}
return vector(i, ii, iii);
} }
Foam::vector Foam::eigenVector Foam::vector Foam::eigenVector
( (
const tensor& t, const tensor& T,
const scalar lambda const scalar lambda,
const vector& direction1,
const vector& direction2
) )
{ {
// Constantly rotating direction ensures different eigenvectors are
// generated when called sequentially with a multiple eigenvalue
static vector direction(1,0,0);
vector oldDirection(direction);
scalar temp = direction[2];
direction[2] = direction[1];
direction[1] = direction[0];
direction[0] = temp;
// Construct the linear system for this eigenvalue // Construct the linear system for this eigenvalue
tensor A(t - lambda*I); tensor A(T - lambda*I);
// Determinants of the 2x2 sub-matrices used to find the eigenvectors // Determinants of the 2x2 sub-matrices used to find the eigenvectors
scalar sd0, sd1, sd2; scalar sd0, sd1, sd2;
@ -252,9 +192,9 @@ Foam::vector Foam::eigenVector
} }
// Sub-determinants for a repeated eigenvalue // Sub-determinants for a repeated eigenvalue
sd0 = A.yy()*direction.z() - A.yz()*direction.y(); sd0 = A.yy()*direction1.z() - A.yz()*direction1.y();
sd1 = A.zz()*direction.x() - A.zx()*direction.z(); sd1 = A.zz()*direction1.x() - A.zx()*direction1.z();
sd2 = A.xx()*direction.y() - A.xy()*direction.x(); sd2 = A.xx()*direction1.y() - A.xy()*direction1.x();
magSd0 = mag(sd0); magSd0 = mag(sd0);
magSd1 = mag(sd1); magSd1 = mag(sd1);
magSd2 = mag(sd2); magSd2 = mag(sd2);
@ -265,8 +205,8 @@ Foam::vector Foam::eigenVector
vector ev vector ev
( (
1, 1,
(A.yz()*direction.x() - direction.z()*A.yx())/sd0, (A.yz()*direction1.x() - direction1.z()*A.yx())/sd0,
(direction.y()*A.yx() - A.yy()*direction.x())/sd0 (direction1.y()*A.yx() - A.yy()*direction1.x())/sd0
); );
return ev/mag(ev); return ev/mag(ev);
@ -275,9 +215,9 @@ Foam::vector Foam::eigenVector
{ {
vector ev vector ev
( (
(direction.z()*A.zy() - A.zz()*direction.y())/sd1, (direction1.z()*A.zy() - A.zz()*direction1.y())/sd1,
1, 1,
(A.zx()*direction.y() - direction.x()*A.zy())/sd1 (A.zx()*direction1.y() - direction1.x()*A.zy())/sd1
); );
return ev/mag(ev); return ev/mag(ev);
@ -286,8 +226,8 @@ Foam::vector Foam::eigenVector
{ {
vector ev vector ev
( (
(A.xy()*direction.z() - direction.y()*A.xz())/sd2, (A.xy()*direction1.z() - direction1.y()*A.xz())/sd2,
(direction.x()*A.xz() - A.xx()*direction.z())/sd2, (direction1.x()*A.xz() - A.xx()*direction1.z())/sd2,
1 1
); );
@ -295,40 +235,57 @@ Foam::vector Foam::eigenVector
} }
// Triple eigenvalue // Triple eigenvalue
return oldDirection; return direction1^direction2;
} }
Foam::tensor Foam::eigenVectors(const tensor& t) Foam::tensor Foam::eigenVectors(const tensor& T, const vector& lambdas)
{ {
vector evals(eigenValues(t)); vector Ux(1, 0, 0), Uy(0, 1, 0), Uz(0, 0, 1);
tensor evs Ux = eigenVector(T, lambdas.x(), Uy, Uz);
( Uy = eigenVector(T, lambdas.y(), Uz, Ux);
eigenVector(t, evals.x()), Uz = eigenVector(T, lambdas.z(), Ux, Uy);
eigenVector(t, evals.y()),
eigenVector(t, evals.z())
);
return evs; return tensor(Ux, Uy, Uz);
} }
Foam::vector Foam::eigenValues(const symmTensor& t) Foam::tensor Foam::eigenVectors(const tensor& T)
{ {
return eigenValues(tensor(t)); const vector lambdas(eigenValues(T));
return eigenVectors(T, lambdas);
} }
Foam::vector Foam::eigenVector(const symmTensor& t, const scalar lambda) Foam::vector Foam::eigenValues(const symmTensor& T)
{ {
return eigenVector(tensor(t), lambda); return eigenValues(tensor(T));
} }
Foam::tensor Foam::eigenVectors(const symmTensor& t) Foam::vector Foam::eigenVector
(
const symmTensor& T,
const scalar lambda,
const vector& direction1,
const vector& direction2
)
{ {
return eigenVectors(tensor(t)); return eigenVector(tensor(T), lambda, direction1, direction2);
}
Foam::tensor Foam::eigenVectors(const symmTensor& T, const vector& lambdas)
{
return eigenVectors(tensor(T), lambdas);
}
Foam::tensor Foam::eigenVectors(const symmTensor& T)
{
return eigenVectors(tensor(T));
} }

View file

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -50,13 +50,27 @@ namespace Foam
typedef Tensor<scalar> tensor; typedef Tensor<scalar> tensor;
vector eigenValues(const tensor&); vector eigenValues(const tensor& T);
vector eigenVector(const tensor&, const scalar lambda); vector eigenVector
tensor eigenVectors(const tensor&); (
const tensor& T,
const scalar lambda,
const vector& direction1,
const vector& direction2
);
tensor eigenVectors(const tensor& T, const vector& lambdas);
tensor eigenVectors(const tensor& T);
vector eigenValues(const symmTensor&); vector eigenValues(const symmTensor& T);
vector eigenVector(const symmTensor&, const scalar lambda); vector eigenVector
tensor eigenVectors(const symmTensor&); (
const symmTensor& T,
const scalar lambda,
const vector& direction1,
const vector& direction2
);
tensor eigenVectors(const symmTensor& T, const vector& lambdas);
tensor eigenVectors(const symmTensor& T);
//- Data associated with tensor type are contiguous //- Data associated with tensor type are contiguous
template<> template<>

View file

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -24,6 +24,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "tensor2D.H" #include "tensor2D.H"
#include "quadraticEqn.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -85,95 +86,96 @@ const Foam::tensor2D Foam::tensor2D::I
Foam::vector2D Foam::eigenValues(const tensor2D& t) Foam::vector2D Foam::eigenValues(const tensor2D& t)
{ {
scalar i = 0; // Coefficients of the characteristic quadratic polynomial (a = 1)
scalar ii = 0; const scalar b = - t.xx() - t.yy();
const scalar c = t.xx()*t.yy() - t.xy()*t.yx();
if (mag(t.xy()) < SMALL && mag(t.yx()) < SMALL) // Solve
Roots<2> roots = quadraticEqn(1, b, c).roots();
// Check the root types
vector2D lambda = vector2D::zero;
forAll(roots, i)
{ {
i = t.xx(); switch (roots.type(i))
ii = t.yy();
}
else
{
scalar mb = t.xx() + t.yy();
scalar c = t.xx()*t.yy() - t.xy()*t.yx();
// If there is a zero root
if (mag(c) < SMALL)
{ {
i = 0; case roots::real:
ii = mb; lambda[i] = roots[i];
} break;
else case roots::complex:
{ WarningInFunction
scalar disc = sqr(mb) - 4*c; << "Complex eigenvalues detected for tensor: " << t
<< endl;
if (disc > 0) lambda[i] = 0;
{ break;
scalar q = sqrt(disc); case roots::posInf:
lambda[i] = VGREAT;
i = 0.5*(mb - q); break;
ii = 0.5*(mb + q); case roots::negInf:
} lambda[i] = - VGREAT;
else break;
{ case roots::nan:
FatalErrorInFunction FatalErrorInFunction
<< "zero and complex eigenvalues in tensor2D: " << t << "Eigenvalue calculation failed for tensor: " << t
<< abort(FatalError); << exit(FatalError);
}
} }
} }
// Sort the eigenvalues into ascending order // Sort the eigenvalues into ascending order
if (i > ii) if (lambda.x() > lambda.y())
{ {
Swap(i, ii); Swap(lambda.x(), lambda.y());
} }
return vector2D(i, ii); return lambda;
} }
Foam::vector2D Foam::eigenVector(const tensor2D& t, const scalar lambda) Foam::vector2D Foam::eigenVector
(
const tensor2D& T,
const scalar lambda,
const vector2D& direction1
)
{ {
if (lambda < SMALL) // Construct the linear system for this eigenvalue
tensor2D A(T - lambda*tensor2D::I);
// Evaluate the eigenvector using the largest divisor
if (mag(A.yy()) > mag(A.xx()) && mag(A.yy()) > SMALL)
{ {
return vector2D::zero; vector2D ev(1, - A.yx()/A.yy());
return ev/mag(ev);
}
else if (mag(A.xx()) > SMALL)
{
vector2D ev(- A.xy()/A.xx(), 1);
return ev/mag(ev);
} }
if (mag(t.xy()) < SMALL && mag(t.yx()) < SMALL) // Repeated eigenvalue
{ return vector2D(- direction1.y(), direction1.x());
if (lambda > min(t.xx(), t.yy()))
{
return vector2D(1, 0);
}
else
{
return vector2D(0, 1);
}
}
else if (mag(t.xy()) < SMALL)
{
return vector2D(lambda - t.yy(), t.yx());
}
else
{
return vector2D(t.xy(), lambda - t.yy());
}
} }
Foam::tensor2D Foam::eigenVectors(const tensor2D& t) Foam::tensor2D Foam::eigenVectors(const tensor2D& T, const vector2D& lambdas)
{ {
vector2D evals(eigenValues(t)); vector2D Ux(1, 0), Uy(0, 1);
tensor2D evs Ux = eigenVector(T, lambdas.x(), Uy);
( Uy = eigenVector(T, lambdas.y(), Ux);
eigenVector(t, evals.x()),
eigenVector(t, evals.y())
);
return evs; return tensor2D(Ux, Uy);
}
Foam::tensor2D Foam::eigenVectors(const tensor2D& T)
{
const vector2D lambdas(eigenValues(T));
return eigenVectors(T, lambdas);
} }

View file

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -49,7 +49,13 @@ namespace Foam
typedef Tensor2D<scalar> tensor2D; typedef Tensor2D<scalar> tensor2D;
vector2D eigenValues(const tensor2D& t); vector2D eigenValues(const tensor2D& t);
vector2D eigenVector(const tensor2D& t, const scalar lambda); vector2D eigenVector
(
const tensor2D& t,
const scalar lambda,
const vector2D& direction1
);
tensor2D eigenVectors(const tensor2D& t, const vector2D& lambdas);
tensor2D eigenVectors(const tensor2D& t); tensor2D eigenVectors(const tensor2D& t);
//- Data associated with tensor2D type are contiguous //- Data associated with tensor2D type are contiguous

View file

@ -0,0 +1,131 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::Roots
Description
Templated storage for the roots of polynomial equations, plus flags to
indicate the nature of the roots.
SourceFiles
RootsI.H
Roots.C
\*---------------------------------------------------------------------------*/
#ifndef Roots_H
#define Roots_H
#include "VectorSpace.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace roots
{
//- Types of root
enum type
{
real = 0,
complex,
posInf,
negInf,
nan
};
}
/*---------------------------------------------------------------------------*\
Class Roots Declaration
\*---------------------------------------------------------------------------*/
template<direction N>
class Roots
:
public VectorSpace<Roots<N>, scalar, N>
{
// Private data
//- Root types, encoded into a single integer
label types_;
public:
// Constructors
//- Construct null
inline Roots();
//- Construct with a uniform value
inline Roots(const roots::type t, const scalar x);
//- Construct by concatenation
inline Roots
(
const roots::type t,
const scalar x,
const Roots<N - 1>& xs
);
//- Construct by concatenation
inline Roots
(
const Roots<N - 1>& xs,
const roots::type t,
const scalar x
);
//- Construct by concatenation
template <direction M>
inline Roots(const Roots<M>& xs, const Roots<N - M>& ys);
// Member Functions
//- Set the type of the i-th root
inline void type(const direction i, const roots::type t);
//- Return the type of the i-th root
inline roots::type type(const direction i) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "RootsI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,136 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template <Foam::direction N>
inline Foam::Roots<N>::Roots()
:
types_(0)
{
forAll(*this, i)
{
type(i, roots::nan);
}
}
template <Foam::direction N>
inline Foam::Roots<N>::Roots(const roots::type t, const scalar x)
:
types_(0)
{
forAll(*this, i)
{
this->v_[i] = x;
type(i, t);
}
}
template <Foam::direction N>
inline Foam::Roots<N>::Roots
(
const roots::type t,
const scalar x,
const Roots<N - 1>& xs
)
:
types_(0)
{
this->v_[0] = x;
type(0, t);
forAll(xs, i)
{
this->v_[i+1] = xs[i];
type(i + 1, xs.type(i));
}
}
template <Foam::direction N>
inline Foam::Roots<N>::Roots
(
const Roots<N - 1>& xs,
const roots::type t,
const scalar x
)
:
types_(0)
{
forAll(xs, i)
{
this->v_[i] = xs[i];
type(i, xs.type(i));
}
this->v_[N-1] = x;
type(N - 1, t);
}
template <Foam::direction N>
template <Foam::direction M>
inline Foam::Roots<N>::Roots
(
const Roots<M>& xs,
const Roots<N - M>& ys
)
:
types_(0)
{
forAll(xs, i)
{
this->v_[i] = xs[i];
type(i, xs.type(i));
}
forAll(ys, i)
{
this->v_[i + M] = ys[i];
type(i + M, ys.type(i));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template <Foam::direction N>
inline void Foam::Roots<N>::type
(
const direction i,
const roots::type t
)
{
types_ += (t - type(i)) << 3*i;
}
template <Foam::direction N>
inline Foam::roots::type Foam::Roots<N>::type(const direction i) const
{
return static_cast<roots::type>((types_ >> 3*i) & 7);
}
// ************************************************************************* //

View file

@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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 "linearEqn.H"
#include "quadraticEqn.H"
#include "cubicEqn.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Roots<3> Foam::cubicEqn::roots() const
{
/*
This function solves a cubic equation of the following form:
a*x^3 + b*x^2 + c*x + d = 0
x^3 + B*x^2 + C*x + D = 0
The following two substitutions are used:
x = t - B/3
t = w - P/3/w
This reduces the problem to a quadratic in w^3.
w^6 + Q*w^3 - P = 0
Where Q and P are given in the code below.
The properties of the cubic can be related to the properties of this
quadratic in w^3. If it has a repeated root a zero, the cubic has a tripl
root. If it has a repeated root not at zero, the cubic has two real roots,
one repeated and one not. If it has two complex roots, the cubic has three
real roots. If it has two real roots, then the cubic has one real root and
two complex roots.
This is solved for the most numerically accurate value of w^3. See the
quadratic function for details on how to pick a value. This single value of
w^3 can yield up to three cube roots for w, which relate to the three
solutions for x.
Only a single root, or pair of conjugate roots, is directly evaluated; the
one, or ones with the lowest relative numerical error. Root identities are
then used to recover the remaining roots, possibly utilising a quadratic
and/or linear solution. This seems to be a good way of maintaining the
accuracy of roots at very different magnitudes.
*/
const scalar a = this->a();
const scalar b = this->b();
const scalar c = this->c();
const scalar d = this->d();
if (a == 0)
{
return Roots<3>(quadraticEqn(b, c, d).roots(), roots::nan, 0);
}
// This is assumed not to over- or under-flow. If it does, all bets are off.
const scalar p = c*a - b*b/3;
const scalar q = b*b*b*(2.0/27.0) - b*c*a/3 + d*a*a;
const scalar disc = p*p*p/27 + q*q/4;
// How many roots of what types are available?
const bool oneReal = disc == 0 && p == 0;
const bool twoReal = disc == 0 && p != 0;
const bool threeReal = disc < 0;
//const bool oneRealTwoComplex = disc > 0;
static const scalar sqrt3 = sqrt(3.0);
scalar x;
if (oneReal)
{
const Roots<1> r = linearEqn(- a, b/3).roots();
return Roots<3>(r.type(0), r[0]);
}
else if (twoReal)
{
if (q*b > 0)
{
x = - 2*cbrt(q/2) - b/3;
}
else
{
x = cbrt(q/2) - b/3;
const Roots<1> r = linearEqn(- a, x).roots();
return Roots<3>(Roots<2>(r, r), linearEqn(x*x, a*d).roots());
}
}
else if (threeReal)
{
const scalar wCbRe = - q/2, wCbIm = sqrt(- disc);
const scalar wAbs = cbrt(hypot(wCbRe, wCbIm));
const scalar wArg = atan2(wCbIm, wCbRe)/3;
const scalar wRe = wAbs*cos(wArg), wIm = wAbs*sin(wArg);
if (b > 0)
{
x = - wRe - mag(wIm)*sqrt3 - b/3;
}
else
{
x = 2*wRe - b/3;
}
}
else // if (oneRealTwoComplex)
{
const scalar wCb = - q/2 - sign(q)*sqrt(disc);
const scalar w = cbrt(wCb);
const scalar t = w - p/(3*w);
if (p + t*b < 0)
{
x = t - b/3;
}
else
{
const scalar xRe = - t/2 - b/3, xIm = sqrt3/2*(w + p/3/w);
x = - a*a*d/(xRe*xRe + xIm*xIm);
// This form of solving for the remaining roots seems more stable
// for this case. This has been determined by trial and error.
return
Roots<3>
(
linearEqn(- a, x).roots(),
quadraticEqn(a*x, x*x + b*x, - a*d).roots()
);
}
}
return
Roots<3>
(
linearEqn(- a, x).roots(),
quadraticEqn(- x*x, c*x + a*d, d*x).roots()
);
}
// ************************************************************************* //

View file

@ -0,0 +1,115 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::cubicEqn
Description
Cubic equation of the form a*x^3 + b*x^2 + c*x + d = 0
SourceFiles
cubicEqnI.H
cubicEqn.C
\*---------------------------------------------------------------------------*/
#ifndef cubicEqn_H
#define cubicEqn_H
#include "Roots.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class cubicEqn Declaration
\*---------------------------------------------------------------------------*/
class cubicEqn
:
public VectorSpace<cubicEqn, scalar, 4>
{
public:
//- Component labeling enumeration
enum components { A, B, C, D };
// Constructors
//- Construct null
inline cubicEqn();
//- Construct initialized to zero
inline cubicEqn(const Foam::zero);
//- Construct from components
inline cubicEqn
(
const scalar a,
const scalar b,
const scalar c,
const scalar d
);
// Member Functions
// Access
inline scalar a() const;
inline scalar b() const;
inline scalar c() const;
inline scalar d() const;
inline scalar& a();
inline scalar& b();
inline scalar& c();
inline scalar& d();
//- Evaluate at x
inline scalar value(const scalar x) const;
//- Estimate the error of evaluation at x
inline scalar error(const scalar x) const;
//- Get the roots
Roots<3> roots() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "cubicEqnI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,115 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::cubicEqn::cubicEqn()
{}
inline Foam::cubicEqn::cubicEqn(const Foam::zero)
:
VectorSpace<cubicEqn, scalar, 4>(Foam::zero())
{}
inline Foam::cubicEqn::cubicEqn
(
const scalar a,
const scalar b,
const scalar c,
const scalar d
)
{
this->v_[A] = a;
this->v_[B] = b;
this->v_[C] = c;
this->v_[D] = d;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline Foam::scalar Foam::cubicEqn::a() const
{
return this->v_[A];
}
inline Foam::scalar Foam::cubicEqn::b() const
{
return this->v_[B];
}
inline Foam::scalar Foam::cubicEqn::c() const
{
return this->v_[C];
}
inline Foam::scalar Foam::cubicEqn::d() const
{
return this->v_[D];
}
inline Foam::scalar& Foam::cubicEqn::a()
{
return this->v_[A];
}
inline Foam::scalar& Foam::cubicEqn::b()
{
return this->v_[B];
}
inline Foam::scalar& Foam::cubicEqn::c()
{
return this->v_[C];
}
inline Foam::scalar& Foam::cubicEqn::d()
{
return this->v_[D];
}
inline Foam::scalar Foam::cubicEqn::value(const scalar x) const
{
return x*(x*(x*a() + b()) + c()) + d();
}
inline Foam::scalar Foam::cubicEqn::error(const scalar x) const
{
return mag(SMALL*x*(x*(x*3*a() + 2*b()) + c()));
}
// ************************************************************************* //

View file

@ -0,0 +1,104 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::linearEqn
Description
Linear equation of the form a*x + b = 0
SourceFiles
linearEqnI.H
\*---------------------------------------------------------------------------*/
#ifndef linearEqn_H
#define linearEqn_H
#include "Roots.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class linearEqn Declaration
\*---------------------------------------------------------------------------*/
class linearEqn
:
public VectorSpace<linearEqn, scalar, 2>
{
public:
//- Component labeling enumeration
enum components { A, B };
// Constructors
//- Construct null
inline linearEqn();
//- Construct initialized to zero
inline linearEqn(const Foam::zero);
//- Construct from components
inline linearEqn(const scalar a, const scalar b);
// Member Functions
// Access
inline scalar a() const;
inline scalar b() const;
inline scalar& a();
inline scalar& b();
//- Evaluate at x
inline scalar value(const scalar x) const;
//- Estimate the error of evaluation at x
inline scalar error(const scalar x) const;
//- Get the roots
inline Roots<1> roots() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "linearEqnI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,111 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::linearEqn::linearEqn()
{}
inline Foam::linearEqn::linearEqn(const Foam::zero)
:
VectorSpace<linearEqn, scalar, 2>(Foam::zero())
{}
inline Foam::linearEqn::linearEqn(const scalar a, const scalar b)
{
this->v_[A] = a;
this->v_[B] = b;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline Foam::scalar Foam::linearEqn::a() const
{
return this->v_[A];
}
inline Foam::scalar Foam::linearEqn::b() const
{
return this->v_[B];
}
inline Foam::scalar& Foam::linearEqn::a()
{
return this->v_[A];
}
inline Foam::scalar& Foam::linearEqn::b()
{
return this->v_[B];
}
inline Foam::scalar Foam::linearEqn::value(const scalar x) const
{
return x*a() + b();
}
inline Foam::scalar Foam::linearEqn::error(const scalar x) const
{
return mag(SMALL*x*a());
}
inline Foam::Roots<1> Foam::linearEqn::roots() const
{
/*
This function solves a linear equation of the following form:
a*x + b = 0
x + B = 0
*/
const scalar a = this->a();
const scalar b = this->b();
if (a == 0)
{
return Roots<1>(roots::nan, 0);
}
if (mag(b/VGREAT) >= mag(a))
{
return Roots<1>(sign(a) == sign(b) ? roots::negInf : roots::posInf, 0);
}
return Roots<1>(roots::real, - b/a);
}
// ************************************************************************* //

View file

@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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 "linearEqn.H"
#include "quadraticEqn.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Roots<2> Foam::quadraticEqn::roots() const
{
/*
This function solves a quadraticEqn equation of the following form:
a*x^2 + b*x + c = 0
x^2 + B*x + C = 0
The quadraticEqn formula is as follows:
x = - B/2 +- sqrt(B*B - 4*C)/2
If the sqrt generates a complex number, this provides the result. If not
then the real root with the smallest floating point error is calculated.
x0 = - B/2 - sign(B)*sqrt(B*B - 4*C)/2
The other root is the obtained using an identity.
x1 = C/x0
*/
const scalar a = this->a();
const scalar b = this->b();
const scalar c = this->c();
if (a == 0)
{
return Roots<2>(linearEqn(b, c).roots(), roots::nan, 0);
}
// This is assumed not to over- or under-flow. If it does, all bets are off.
const scalar disc = b*b/4 - a*c;
// How many roots of what types are available?
const bool oneReal = disc == 0;
const bool twoReal = disc > 0;
//const bool twoComplex = disc < 0;
if (oneReal)
{
const Roots<1> r = linearEqn(- a, b/2).roots();
return Roots<2>(r, r);
}
else if (twoReal)
{
const scalar x = - b/2 - sign(b)*sqrt(disc);
return Roots<2>(linearEqn(- a, x).roots(), linearEqn(- x, c).roots());
}
else // if (twoComplex)
{
return Roots<2>(roots::complex, 0);
}
}
// ************************************************************************* //

View file

@ -0,0 +1,107 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::quadraticEqn
Description
Quadratic equation of the form a*x^2 + b*x + c = 0
SourceFiles
quadraticEqnI.H
quadraticEqn.C
\*---------------------------------------------------------------------------*/
#ifndef quadraticEqn_H
#define quadraticEqn_H
#include "Roots.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class quadraticEqn Declaration
\*---------------------------------------------------------------------------*/
class quadraticEqn
:
public VectorSpace<quadraticEqn, scalar, 3>
{
public:
//- Component labeling enumeration
enum components { A, B, C };
// Constructors
//- Construct null
inline quadraticEqn();
//- Construct initialized to zero
inline quadraticEqn(const Foam::zero);
//- Construct from components
inline quadraticEqn(const scalar a, const scalar b, const scalar c);
// Member Functions
// Access
inline scalar a() const;
inline scalar b() const;
inline scalar c() const;
inline scalar& a();
inline scalar& b();
inline scalar& c();
//- Evaluate at x
inline scalar value(const scalar x) const;
//- Estimate the error of evaluation at x
inline scalar error(const scalar x) const;
//- Get the roots
Roots<2> roots() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "quadraticEqnI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::quadraticEqn::quadraticEqn()
{}
inline Foam::quadraticEqn::quadraticEqn(const Foam::zero)
:
VectorSpace<quadraticEqn, scalar, 3>(Foam::zero())
{}
inline Foam::quadraticEqn::quadraticEqn
(
const scalar a,
const scalar b,
const scalar c
)
{
this->v_[A] = a;
this->v_[B] = b;
this->v_[C] = c;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline Foam::scalar Foam::quadraticEqn::a() const
{
return this->v_[A];
}
inline Foam::scalar Foam::quadraticEqn::b() const
{
return this->v_[B];
}
inline Foam::scalar Foam::quadraticEqn::c() const
{
return this->v_[C];
}
inline Foam::scalar& Foam::quadraticEqn::a()
{
return this->v_[A];
}
inline Foam::scalar& Foam::quadraticEqn::b()
{
return this->v_[B];
}
inline Foam::scalar& Foam::quadraticEqn::c()
{
return this->v_[C];
}
inline Foam::scalar Foam::quadraticEqn::value(const scalar x) const
{
return x*(x*a() + b()) + c();
}
inline Foam::scalar Foam::quadraticEqn::error(const scalar x) const
{
return mag(SMALL*x*(x*2*a() + b()));
}
// ************************************************************************* //

View file

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -458,7 +458,7 @@ void Foam::edgeCollapser::faceCollapseAxisAndAspectRatio
// normal, as it has the greatest value. The minimum eigenvalue // normal, as it has the greatest value. The minimum eigenvalue
// is the dominant collapse axis for high aspect ratio faces. // is the dominant collapse axis for high aspect ratio faces.
collapseAxis = eigenVector(J, eVals.x()); collapseAxis = eigenVectors(J, eVals).x();
// The inertia calculation describes the mass distribution as a // The inertia calculation describes the mass distribution as a
// function of distance squared to the axis, so the square root of // function of distance squared to the axis, so the square root of