Forked from
ogs / ogs
20409 commits behind the upstream repository.
-
Norihiro Watanabe authoredNorihiro Watanabe authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
TestNonlinearNewton.cpp 7.33 KiB
/**
* \author Norihiro Watanabe
* \date 2012-06-25
*
* \copyright
* Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*/
#include <gtest/gtest.h>
#include <valarray>
#include "MathLib/LinAlg/Dense/DenseMatrix.h"
#include "MathLib/LinAlg/Solvers/GaussAlgorithm.h"
#include "MathLib/Nonlinear/NewtonRaphson.h"
#include "Tests/TestTools.h"
namespace
{
typedef MathLib::DenseMatrix<double> MatrixType;
typedef std::valarray<double> VectorType;
typedef MathLib::GaussAlgorithm<MatrixType,VectorType> DenseSolverType;
template<class F_JACOBIAN>
class ScalarDx
{
public:
ScalarDx(F_JACOBIAN &f_J) : _f_Jacobian(f_J) {}
// dx = - r/J
void operator()(const double &x, const double &r, double &dx)
{
double j;
_f_Jacobian(x, j);
dx = - r/j;
}
private:
F_JACOBIAN &_f_Jacobian;
};
template<class F_JACOBIAN>
class VectorDx
{
public:
VectorDx(F_JACOBIAN &f_J, MatrixType &matJ) : _f_Jacobian(f_J), _matJ(matJ) {}
// dx = - r/J
void operator()(const VectorType &x, const VectorType &r, VectorType &dx)
{
_f_Jacobian(x, _matJ);
DenseSolverType solver;
VectorType rhs(r);
rhs *= -1.;
solver.solve(_matJ, rhs, dx);
}
private:
F_JACOBIAN &_f_Jacobian;
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 (10 variables)
//##############################################################################
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);
}