From 5e7a766159e0a2f8a1267b8968cf2802befe6476 Mon Sep 17 00:00:00 2001
From: Will Bainbridge <http://cfd.direct>
Date: Tue, 24 Jul 2018 15:54:32 +0100
Subject: [PATCH] BUG: cubicEqn, quadraticEqn: Correction to repeated roots

Also extended the cubic equation test routine and modified the error
methods so that they more accurately generate the round of error of
evaluation.

This resolves bug report https://bugs.openfoam.org/view.php?id=3015
---
 applications/test/cubicEqn/Test-cubicEqn.C    | 27 +++++++++++++++----
 .../polynomialEqns/cubicEqn/cubicEqn.C        |  4 +--
 .../polynomialEqns/cubicEqn/cubicEqnI.H       |  5 +++-
 .../polynomialEqns/linearEqn/linearEqnI.H     |  2 +-
 .../quadraticEqn/quadraticEqn.C               |  2 +-
 .../quadraticEqn/quadraticEqnI.H              |  4 ++-
 6 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/applications/test/cubicEqn/Test-cubicEqn.C b/applications/test/cubicEqn/Test-cubicEqn.C
index d0ab6066662..aa0579a4194 100644
--- a/applications/test/cubicEqn/Test-cubicEqn.C
+++ b/applications/test/cubicEqn/Test-cubicEqn.C
@@ -51,7 +51,7 @@ void test(const Type& polynomialEqn, const scalar tol)
             case roots::real:
                 v[i] = polynomialEqn.value(r[i]);
                 e[i] = polynomialEqn.error(r[i]);
-                ok = ok && mag(v[i]) < tol*mag(e[i]);
+                ok = ok && mag(v[i]) <= tol*mag(e[i]);
                 break;
             case roots::posInf:
                 v[i] = + inf;
@@ -79,8 +79,10 @@ void test(const Type& polynomialEqn, const scalar tol)
 
 int main()
 {
-    const int nTests = 1000000;
-    for (int t = 0; t < nTests; ++ t)
+    const scalar tol = 5;
+
+    const label nTests = 1000000;
+    for (label t = 0; t < nTests; ++ t)
     {
         test
         (
@@ -91,11 +93,26 @@ int main()
                 randomScalar(1e-50, 1e+50),
                 randomScalar(1e-50, 1e+50)
             ),
-            100
+            tol
         );
     }
+    Info << nTests << " random cubics tested" << endl;
 
-    Info << nTests << " cubics tested" << endl;
+    const label coeffMin = -9, coeffMax = 10, nCoeff = coeffMax - coeffMin;
+    for (label a = coeffMin; a < coeffMax; ++ a)
+    {
+        for (label b = coeffMin; b < coeffMax; ++ b)
+        {
+            for (label c = coeffMin; c < coeffMax; ++ c)
+            {
+                for (label d = coeffMin; d < coeffMax; ++ d)
+                {
+                    test(cubicEqn(a, b, c, d), tol);
+                }
+            }
+        }
+    }
+    Info<< nCoeff*nCoeff*nCoeff*nCoeff << " integer cubics tested" << endl;
 
     return 0;
 }
diff --git a/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqn.C b/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqn.C
index c46b794c38e..3aad6740018 100644
--- a/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqn.C
+++ b/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqn.C
@@ -81,7 +81,7 @@ Foam::Roots<3> Foam::cubicEqn::roots() const
 
     // 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 q = b*b*b*scalar(2)/27 - 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?
@@ -96,7 +96,7 @@ Foam::Roots<3> Foam::cubicEqn::roots() const
 
     if (oneReal)
     {
-        const Roots<1> r = linearEqn(- a, b/3).roots();
+        const Roots<1> r = linearEqn(a, b/3).roots();
         return Roots<3>(r.type(0), r[0]);
     }
     else if (twoReal)
diff --git a/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqnI.H b/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqnI.H
index da5fc3cba14..cb528b6be4a 100644
--- a/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqnI.H
+++ b/src/OpenFOAM/primitives/polynomialEqns/cubicEqn/cubicEqnI.H
@@ -114,7 +114,10 @@ inline Foam::scalar Foam::cubicEqn::derivative(const scalar x) const
 
 inline Foam::scalar Foam::cubicEqn::error(const scalar x) const
 {
-    return mag(SMALL*x*(x*(x*3*a() + 2*b()) + c()));
+    return
+        SMALL*magSqr(x)*(mag(x*a()) + mag(b()))
+      + SMALL*mag(x)*(mag(x*(x*a() + b())) + mag(c()))
+      + SMALL*(mag(x*(x*(x*a() + b()) + c())) + mag(d()));
 }
 
 
diff --git a/src/OpenFOAM/primitives/polynomialEqns/linearEqn/linearEqnI.H b/src/OpenFOAM/primitives/polynomialEqns/linearEqn/linearEqnI.H
index 17bfdf452da..f5c4f2b7c94 100644
--- a/src/OpenFOAM/primitives/polynomialEqns/linearEqn/linearEqnI.H
+++ b/src/OpenFOAM/primitives/polynomialEqns/linearEqn/linearEqnI.H
@@ -82,7 +82,7 @@ inline Foam::scalar Foam::linearEqn::derivative(const scalar x) const
 
 inline Foam::scalar Foam::linearEqn::error(const scalar x) const
 {
-    return mag(SMALL*x*a());
+    return SMALL*(mag(x*a()) + mag(b()));
 }
 
 
diff --git a/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqn.C b/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqn.C
index d84c2928c25..d2ac0ea8a12 100644
--- a/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqn.C
+++ b/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqn.C
@@ -71,7 +71,7 @@ Foam::Roots<2> Foam::quadraticEqn::roots() const
 
     if (oneReal)
     {
-        const Roots<1> r = linearEqn(- a, b/2).roots();
+        const Roots<1> r = linearEqn(a, b/2).roots();
         return Roots<2>(r, r);
     }
     else if (twoReal)
diff --git a/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqnI.H b/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqnI.H
index 7672a74d724..15ffe4e4e22 100644
--- a/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqnI.H
+++ b/src/OpenFOAM/primitives/polynomialEqns/quadraticEqn/quadraticEqnI.H
@@ -100,7 +100,9 @@ inline Foam::scalar Foam::quadraticEqn::derivative(const scalar x) const
 
 inline Foam::scalar Foam::quadraticEqn::error(const scalar x) const
 {
-    return mag(SMALL*x*(x*2*a() + b()));
+    return
+        SMALL*mag(x)*(mag(x*a()) + mag(b()))
+      + SMALL*(mag(x*(x*a() + b())) + mag(c()));
 }
 
 
-- 
GitLab