From 16945500d65eb38f05d46dc5cdb12189df1e27b0 Mon Sep 17 00:00:00 2001
From: Norihiro Watanabe <norihiro.watanabe@ufz.de>
Date: Fri, 7 Mar 2014 17:13:35 +0100
Subject: [PATCH] add tests for NewtonRaphson

---
 Tests/MathLib/TestNonlinearNewton.cpp | 295 ++++++++++++++++++++++++++
 1 file changed, 295 insertions(+)
 create mode 100644 Tests/MathLib/TestNonlinearNewton.cpp

diff --git a/Tests/MathLib/TestNonlinearNewton.cpp b/Tests/MathLib/TestNonlinearNewton.cpp
new file mode 100644
index 00000000000..a921d9f894d
--- /dev/null
+++ b/Tests/MathLib/TestNonlinearNewton.cpp
@@ -0,0 +1,295 @@
+/**
+ * Copyright (c) 2012, OpenGeoSys Community (http://www.opengeosys.com)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.com/LICENSE.txt
+ *
+ *
+ * Created on 2012-08-03 by Norihiro Watanabe
+ */
+
+#include <gtest/gtest.h>
+
+#include "MathLib/LinAlg/Dense/DenseMatrix.h"
+#include "MathLib/LinAlg/Dense/DenseVector.h"
+#include "MathLib/LinAlg/Solvers/GaussAlgorithm.h"
+#include "MathLib/Nonlinear/NewtonRaphson.h"
+#include "Tests/TestTools.h"
+
+namespace
+{
+
+typedef MathLib::DenseMatrix<double> MatrixType;
+typedef MathLib::DenseVector<double> VectorType;
+typedef MathLib::GaussAlgorithm<MatrixType,VectorType> DenseSolverType;
+
+template<class F_JACOBIAN>
+class ScalarDx
+{
+public:
+    ScalarDx(F_JACOBIAN &f_J) : _f_Jacobain(f_J) {}
+    // dx = - r/J
+    void operator()(const double &x, const double &r, double &dx)
+    {
+        double j;
+        _f_Jacobain(x, j);
+        dx = - r/j;
+    }
+
+private:
+    F_JACOBIAN &_f_Jacobain;
+};
+
+template<class F_JACOBIAN>
+class VectorDx
+{
+public:
+    VectorDx(F_JACOBIAN &f_J, MatrixType &matJ) : _f_Jacobain(f_J), _matJ(matJ) {}
+
+    // dx = - r/J
+    void operator()(const VectorType &x, const VectorType &r, VectorType &dx)
+    {
+        _f_Jacobain(x, _matJ);
+        DenseSolverType solver(_matJ);
+        VectorType rhs(r);
+        rhs *= -1.;
+        solver.solve(rhs, dx);
+    }
+
+private:
+    F_JACOBIAN &_f_Jacobain;
+    MatrixType &_matJ;
+};
+
+//##############################################################################
+// Example problem 1 (one variable)
+// f(x) = x*x -4 = 0
+// x = 2,-2
+//##############################################################################
+namespace Example1
+{
+
+class Residual
+{
+public:
+    void operator()(const double &x, double &r) { r = x*x-4.; }
+};
+
+class Jacobian
+{
+public:
+    void operator()(const double &x, double &j) { j = 2*x; }
+};
+
+} // Example1
+
+
+//##############################################################################
+// Example problem 2 (two variables)
+// 3x-y=-2
+// 2x^2-y=0
+// (x,y) = (-1/2, 1/2) and (2, 8)
+//##############################################################################
+namespace Example2
+{
+
+class Residual
+{
+public:
+    void operator()(const VectorType &x, VectorType &r)
+    {
+        r[0] = 3*x[0]-x[1]+2.;
+        r[1] = 2*x[0]*x[0]-x[1];
+    }
+};
+
+class Jacobian
+{
+public:
+    void operator()(const VectorType &x, MatrixType &j)
+    {
+        j(0,0) = 3.;
+        j(0,1) = -1.0;
+        j(1,0) = 4.*x[0];
+        j(1,1) = -1.0;
+    }
+};
+
+} // Example2
+
+
+//##############################################################################
+// Example problem 3 (two variables)
+// 3x-y=-2
+// 2x^2-y=0
+// (x,y) = (-1/2, 1/2) and (2, 8)
+//##############################################################################
+
+namespace Example3
+{
+
+class Residual
+{
+public:
+    void operator()(const VectorType &x, VectorType &r)
+    {
+        double P = 1.;
+        double R = 10.;
+        double s = sqrt(2.);
+        r[1-1]= (9*P*x[1-1])/4 + (9*x[2-1]*x[3-1])/(8*s) + (P*R*x[7-1])/s;
+        r[2-1]= (81*P*x[2-1])/4 + (9*x[1-1]*x[3-1])/(8*s) + (P*R*x[8-1])/s;
+        r[3-1]= (-9*x[1-1]*x[2-1])/(4*s) + 9*P*x[3-1] + s*P*R*x[9-1];
+        r[4-1]= 36*P*x[4-1] + s*P*R*x[10-1];
+        r[5-1]= -2*x[5-1] + (x[2-1]*x[7-1])/(2*s) + (x[1-1]*x[8-1])/(2*s) - (x[4-1]*x[9-1])/s + s*x[4-1]*x[9-1] - (x[3-1]*x[10-1])/s + s*x[3-1]*x[10-1];
+        r[6-1]= -8*x[6-1] - (x[1-1]*x[7-1])/s - s*x[3-1]*x[9-1];
+        r[7-1]= -(x[1-1]/s) - (x[2-1]*x[5-1])/(2*s) + (x[1-1]*x[6-1])/s - (3*x[7-1])/2.0 + (3*x[3-1]*x[8-1])/(4*s) + (3*x[2-1]*x[9-1])/(4*s);
+        r[8-1]= -(x[2-1]/s) - (x[1-1]*x[5-1])/(2*s) - (3*x[3-1]*x[7-1])/(4*s) - (9*x[8-1])/2.0 - (3*x[1-1]*x[9-1])/(4*s);
+        r[9-1]= -(s*x[3-1]) - (x[4-1]*x[5-1])/s + s*x[3-1]*x[6-1] - (3*x[2-1]*x[7-1])/(4*s) + (3*x[1-1]*x[8-1])/(4*s) - 3*x[9-1];
+        r[10-1]= -(s*x[4-1]) - (x[3-1]*x[5-1])/s - 6*x[10-1];
+    }
+};
+
+class Jacobian
+{
+public:
+    void operator()(const VectorType &x, MatrixType &j)
+    {
+        double P = 1.;
+        double R = 10.;
+        double s = sqrt(2.);
+        j = .0;
+        j(1-1,1-1) = (9*P)/4.0;
+        j(7-1,1-1) = -(1/s)+x[6-1]/s;
+        j(1-1,2-1) = (9*x[3-1])/(8*s);
+        j(7-1,2-1) = -x[5-1]/(2*s) + (3*x[9-1])/(4*s);
+        j(1-1,3-1) = (9*x[2-1])/(8*s);
+        j(7-1,3-1) = (3*x[8-1])/(4*s);
+        j(1-1,7-1) = (P*R)/s;
+        j(7-1,5-1) = -x[2-1]/(2*s);
+        j(2-1,1-1) = (9*x[3-1])/(8*s);
+        j(7-1,6-1) = x[1-1]/s;
+        j(2-1,2-1) = (81*P)/4.0;
+        j(7-1,7-1) = -1.5;
+        j(2-1,3-1) = (9*x[1-1])/(8*s);
+        j(7-1,8-1) = (3*x[3-1])/(4*s);
+        j(2-1,8-1) = (P*R)/s;
+        j(7-1,9-1) = (3*x[2-1])/(4*s);
+        j(3-1,1-1) = (-9*x[2-1])/(4*s);
+        j(8-1,1-1) = -x[5-1]/(2*s) - (3*x[9-1])/(4*s);
+        j(3-1,2-1) = (-9*x[1-1])/(4*s);
+        j(8-1,2-1) = -(1/s);
+        j(3-1,3-1) = 9*P;
+        j(8-1,3-1) = (-3*x[7-1])/(4*s);
+        j(3-1,9-1) = s*P*R;
+        j(8-1,5-1) = -x[1-1]/(2*s);
+        j(4-1,4-1) = 36*P;
+        j(8-1,7-1) = (-3*x[3-1])/(4*s);
+        j(4-1,10-1)= s*P*R;
+        j(8-1,8-1) = -4.5;
+        j(5-1,1-1) = x[8-1]/(2*s);
+        j(8-1,9-1) = (-3*x[1-1])/(4*s);
+        j(5-1,2-1) = x[7-1]/(2*s);
+        j(9-1,1-1) = (3*x[8-1])/(4*s);
+        j(5-1,3-1) = -(x[10-1]/s) + s*x[10-1];
+        j(9-1,2-1) = (-3*x[7-1])/(4*s);
+        j(5-1,4-1) = -(x[9-1]/s) + s*x[9-1];
+        j(9-1,3-1) = -s + s*x[6-1];
+        j(5-1,5-1) = -2.0;
+        j(9-1,4-1) = -(x[5-1]/s);
+        j(5-1,7-1) = x[2-1]/(2*s);
+        j(9-1,5-1) = -(x[4-1]/s);
+        j(5-1,8-1) = x[1-1]/(2*s);
+        j(9-1,6-1) = s*x[3-1];
+        j(5-1,9-1) = -(x[4-1]/s) + s*x[4-1];
+        j(9-1,7-1) = (-3*x[2-1])/(4*s);
+        j(5-1,10-1)= -(x[3-1]/s) + s*x[3-1];
+        j(9-1,8-1) = (3*x[1-1])/(4*s);
+        j(6-1,1-1) = -(x[7-1]/s);
+        j(9-1,9-1) = -3.0;
+        j(6-1,3-1) = -(s*x[9-1]);
+        j(10-1,3-1) = -(x[5-1]/s);
+        j(6-1,6-1) = -8.0;
+        j(10-1,4-1) = -s;
+        j(6-1,7-1) = -(x[1-1]/s);
+        j(10-1,5-1) = -(x[3-1]/s);
+        j(6-1,9-1) = -(s*x[3-1]);
+        j(10-1,10-1)= -6.0;
+    }
+};
+
+} // Example 3
+
+} //namespace
+
+//##############################################################################
+// Tests
+//##############################################################################
+TEST(MathLib, NonlinearNR_double)
+{
+    Example1::Residual f_r;
+    Example1::Jacobian f_j;
+    ScalarDx<Example1::Jacobian> f_dx(f_j);
+    double x0 = 6.0;
+    double x = .0;
+    MathLib::Nonlinear::NewtonRaphson nr;
+    nr.solve(f_r, f_dx, x0, x);
+
+    ASSERT_NEAR(2.0, x, 1e-5);
+}
+
+TEST(MathLib, NonlinearNR_dense)
+{
+    Example2::Residual f_r;
+    Example2::Jacobian f_j;
+    MatrixType matJ(2, 2);
+    VectorDx<Example2::Jacobian> f_dx(f_j, matJ);
+    VectorType x0(2), x(2);
+    x0 = 6.0;
+    x = .0;
+    MathLib::Nonlinear::NewtonRaphson nr;
+    nr.solve(f_r, f_dx, x0, x);
+
+    double my_expect[] = {2., 8.};
+    ASSERT_ARRAY_NEAR(my_expect, x, 2, 1e-5);
+}
+
+TEST(MathLib, NonlinearNR_dense2)
+{
+    Example3::Residual f_r;
+    Example3::Jacobian f_j;
+    const std::size_t n = 10;
+    MatrixType matJ(n, n, .0);
+    VectorDx<Example3::Jacobian> f_dx(f_j, matJ);
+    VectorType x0(n), x(n);
+    x0 = 1.;
+    x = 0.;
+    MathLib::Nonlinear::NewtonRaphson nr;
+    nr.solve(f_r, f_dx, x0, x);
+
+    double my_expect[] = {3.39935, 3.70074e-018, -1.42576e-017, 1.4903e-021, 4.35602e-018, 0.325, -1.08167, -5.61495e-018, 7.58394e-018, -3.79368e-021};
+    ASSERT_ARRAY_NEAR(my_expect, x, n, 1e-5);
+}
+
+#if 0
+TEST(MathLib, NonlinearNR_sparse)
+{
+    typedef std::valarray<double> MyVector;
+    typedef MathLib::CRSMatrix<double, signed> MyMatrix;
+    typedef NRCheckConvergence<MyVector,NRErrorAbsResMNormOrRelDxMNorm > MyConverge;
+    typedef NewtonFunctionDXVector<NL3_NR_D1, MathLib::LisLinearEquation> MyDxFunction;
+
+    NL3_NR f;
+    NL3_NR_D1 df(f.getLinearSolver());
+    MyVector x0(6.0, 2);
+    MyVector x(0.0, 2);
+    MyVector r(2), dx(2);
+    //MyMatrix* j = f.getLinearSolver()->getA();
+    MyDxFunction f_dx(df, *f.getLinearSolver());
+
+    NewtonRaphsonMethod nr;
+    nr.solve<NL3_NR,MyDxFunction,MyVector,MyConverge, NRIterationStepInitializerDummy>(f, f_dx, x0, x, r, dx);
+
+    double my_expect[] = {2., 8.};
+    ASSERT_DOUBLE_ARRAY_EQ(my_expect, x, 2, 1e-5);
+}
+#endif
-- 
GitLab