diff --git a/NumLib/ODESolver/NonlinearSolver-impl.h b/NumLib/ODESolver/NonlinearSolver-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..5fc9b8ed11add845be222d6f480e3a999a8bb6ef --- /dev/null +++ b/NumLib/ODESolver/NonlinearSolver-impl.h @@ -0,0 +1,135 @@ +/** + * \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 <logog/include/logog.hpp> + +// for debugging +// #include <iostream> + +#include "MathLib/LinAlg/BLAS.h" + +#include "NonlinearSolver.h" + +#include "MathLib/LinAlg/VectorNorms.h" + +// TODO: change +#include "ODETypes.h" // for one shot linear solver + + +namespace NumLib +{ + +template<typename Matrix, typename Vector> +void +NonlinearSolver<Matrix, Vector, NonlinearSolverTag::Picard>:: +assemble(NonlinearSystem<Matrix, Vector, NonlinearSolverTag::Picard> &sys, + Vector const& x) const +{ + sys.assembleMatricesPicard(x); +} + +template<typename Matrix, typename Vector> +bool +NonlinearSolver<Matrix, Vector, NonlinearSolverTag::Picard>:: +solve(NonlinearSystem<Matrix, Vector, NonlinearSolverTag::Picard> &sys, Vector &x) +{ + namespace BLAS = MathLib::BLAS; + + bool success = false; + + for (unsigned iteration=1; iteration<_maxiter; ++iteration) + { + sys.assembleMatricesPicard(x); + sys.getA(_A); + sys.getRhs(_rhs); + // TODO _x_new might not have been initialized + sys.applyKnownComponentsPicard(_A, _rhs, _x_new); + + // std::cout << "A:\n" << Eigen::MatrixXd(A) << "\n"; + // std::cout << "rhs:\n" << rhs << "\n\n"; + + oneShotLinearSolve(_A, _rhs, _x_new); + + BLAS::aypx(x, -1.0, _x_new); // x = _x_new - x + auto const error = norm(x); + // INFO(" picard iteration %u error: %e", iteration, error); + + x = _x_new; + + if (error < _tol) { + success = true; + break; + } + + if (sys.isLinear()) { + // INFO(" picard linear system. not looping"); + success = true; + break; + } + } + + return success; +} + + +template<typename Matrix, typename Vector> +void +NonlinearSolver<Matrix, Vector, NonlinearSolverTag::Newton>:: +assemble(NonlinearSystem<Matrix, Vector, NonlinearSolverTag::Newton> &sys, + Vector const& x) const +{ + sys.assembleResidualNewton(x); +} + +template<typename Matrix, typename Vector> +bool +NonlinearSolver<Matrix, Vector, NonlinearSolverTag::Newton>:: +solve(NonlinearSystem<Matrix, Vector, NonlinearSolverTag::Newton> &sys, Vector &x) +{ + namespace BLAS = MathLib::BLAS; + + bool success = false; + + for (unsigned iteration=1; iteration<_maxiter; ++iteration) + { + sys.assembleResidualNewton(x); + sys.getResidual(x, _res); + + // std::cout << " res:\n" << res << std::endl; + + if (norm(_res) < _tol) { + success = true; + break; + } + + sys.assembleJacobian(x); + sys.getJacobian(_J); + // TODO _minus_delta_x might not have been initialized + sys.applyKnownComponentsNewton(_J, _res, _minus_delta_x); + + // std::cout << " J:\n" << Eigen::MatrixXd(J) << std::endl; + + oneShotLinearSolve(_J, _res, _minus_delta_x); + + // auto const dx_norm = _minus_delta_x.norm(); + // INFO(" newton iteration %u, norm of delta x: %e", iteration, dx_norm); + + BLAS::axpy(x, -1.0, _minus_delta_x); + + if (sys.isLinear()) { + // INFO(" newton linear system. not looping"); + success = true; + break; + } + } + + return success; +} + +} diff --git a/NumLib/ODESolver/NonlinearSolver.h b/NumLib/ODESolver/NonlinearSolver.h new file mode 100644 index 0000000000000000000000000000000000000000..02f1ca009d919020ebebadb204e97f6cd75aaa92 --- /dev/null +++ b/NumLib/ODESolver/NonlinearSolver.h @@ -0,0 +1,149 @@ +/** + * \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 + * + */ + +#ifndef NUMLIB_NONLINEARSOLVER_H +#define NUMLIB_NONLINEARSOLVER_H + +#include <logog/include/logog.hpp> + +#include "Types.h" +#include "NonlinearSystem.h" + + +namespace NumLib +{ + +//! \addtogroup ODESolver +//! @{ + +/*! Find a solution to a nonlinear equation. + * + * \tparam Matrix the type of matrices occuring in the linearization of the equation. + * \tparam Vector the type of the solution vector of the equation. + * \tparam NLTag a tag indicating the method used for solving the equation. + */ +template<typename Matrix, typename Vector, NonlinearSolverTag NLTag> +class NonlinearSolver; + + +/*! Find a solution to a nonlinear equation using the Newton-Raphson method. + * + * \tparam Matrix the type of matrices occuring in the linearization of the equation. + * \tparam Vector the type of the solution vector of the equation. + */ +template<typename Matrix, typename Vector> +class NonlinearSolver<Matrix, Vector, NonlinearSolverTag::Newton> final +{ +public: + //! Type of the nonlinear equation system to be solved. + using System = NonlinearSystem<Matrix, Vector, NonlinearSolverTag::Newton>; + + /*! Constructs a new instance. + * + * \param tol the tolerance of the solver. \todo Be more specific about that! + * \param maxiter the maximum number of iterations used to solve the equation. + */ + explicit + NonlinearSolver(double const tol, const unsigned maxiter) + : _tol(tol) + , _maxiter(maxiter) + {} + + /*! Only assemble the equation system. + * + * \note This method is needed to preload CrankNicolson time discretization scheme. + * It is not used for the general solver steps; in those only the solve() method + * is needed. + * + * \param sys the equation system to be assembled. + * \param x the state at which the equation system will be assembled. + */ + void assemble(System& sys, Vector const& x) const; + + /*! Assemble and solve the equation system. + * + * \param sys the equation system to be solved. + * \param x in: the initial guess, out: the solution. + * + * \retval true if the equation system could be solved + * \retval false otherwise + */ + bool solve(System& sys, Vector& x); + +private: + const double _tol; //!< tolerance of the solver + const unsigned _maxiter; //!< maximum number of iterations + + Vector _res; //!< The residual. + Matrix _J; //!< The Jacobian of the residual. + Vector _minus_delta_x; //!< The Newton-Raphson method solves the linearized equation + //!< \f$ J \cdot (-\Delta x) = r \f$ repeatedly. +}; + + +/*! Find a solution to a nonlinear equation using the Picard fixpoint iteration method. + * + * \tparam Matrix the type of matrices occuring in the linearization of the equation. + * \tparam Vector the type of the solution vector of the equation. + */ +template<typename Matrix, typename Vector> +class NonlinearSolver<Matrix, Vector, NonlinearSolverTag::Picard> final +{ +public: + //! Type of the nonlinear equation system to be solved. + using System = NonlinearSystem<Matrix, Vector, NonlinearSolverTag::Picard>; + + /*! Constructs a new instance. + * + * \param tol the tolerance of the solver. \todo Be more specific about that! + * \param maxiter the maximum number of iterations used to solve the equation. + */ + explicit + NonlinearSolver(double const tol, const unsigned maxiter) + : _tol(tol) + , _maxiter(maxiter) + {} + + /*! Only assemble the equation system. + * + * \note This method is needed to preload CrankNicolson time discretization scheme. + * It is not used for the general solver steps; in those only the solve() method + * is needed. + * + * \param sys the equation system to be assembled. + * \param x the state at which the equation system will be assembled. + */ + void assemble(System& sys, Vector const& x) const; + + /*! Assemble and solve the equation system. + * + * \param sys the equation system to be solved. + * \param x in: the initial guess, out: the solution. + * + * \retval true if the equation system could be solved + * \retval false otherwise + */ + bool solve(System& sys, Vector& x); + +private: + const double _tol; //!< tolerance of the solver + const unsigned _maxiter; //!< maximum number of iterations + + Matrix _A; //!< \c Matrix describing the linearized system. + Vector _rhs; //!< \c Vector describing the linearized system. + Vector _x_new; //!< \c Vector to store solutions of \f$ A \cdot x = \mathit{rhs} \f$. +}; + +//! @} + +} + +#include "NonlinearSolver-impl.h" + +#endif // NUMLIB_NONLINEARSOLVER_H