From c7399b02740fad7ce8b575aa07184444b54672e3 Mon Sep 17 00:00:00 2001 From: Christoph Lehmann <christoph.lehmann@ufz.de> Date: Fri, 19 Aug 2016 10:51:43 +0200 Subject: [PATCH] [NL] nonlinear solver uses conv criteria --- NumLib/ODESolver/NonlinearSolver.cpp | 100 +++++++++++++-------------- NumLib/ODESolver/NonlinearSolver.h | 33 ++++++--- NumLib/ODESolver/TimeLoopSingleODE.h | 16 +++-- 3 files changed, 84 insertions(+), 65 deletions(-) diff --git a/NumLib/ODESolver/NonlinearSolver.cpp b/NumLib/ODESolver/NonlinearSolver.cpp index c8569a2881a..0ab6d7e5bf1 100644 --- a/NumLib/ODESolver/NonlinearSolver.cpp +++ b/NumLib/ODESolver/NonlinearSolver.cpp @@ -19,6 +19,7 @@ #include "BaseLib/RunTime.h" #include "MathLib/LinAlg/LinAlg.h" #include "NumLib/DOF/GlobalMatrixProviders.h" +#include "ConvergenceCriterion.h" namespace NumLib { @@ -32,7 +33,7 @@ bool NonlinearSolver<NonlinearSolverTag::Picard>::solve( GlobalVector& x, std::function<void(unsigned, GlobalVector const&)> const& postIterationCallback) { - namespace LinAlg= MathLib::LinAlg; + namespace LinAlg = MathLib::LinAlg; auto& sys = *_equation_system; auto& A = @@ -51,6 +52,8 @@ bool NonlinearSolver<NonlinearSolverTag::Picard>::solve( unsigned iteration = 1; for (; iteration <= _maxiter; ++iteration) { + _convergence_criterion->reset(); + BaseLib::RunTime time_iteration; time_iteration.start(); @@ -69,6 +72,13 @@ bool NonlinearSolver<NonlinearSolverTag::Picard>::solve( sys.applyKnownSolutionsPicard(A, rhs, x_new); INFO("[time] Applying Dirichlet BCs took %g s.", time_dirichlet.elapsed()); + if (_convergence_criterion->hasResidualCheck()) { + GlobalVector res; + LinAlg::matMult(A, x_new, res); // res = A * x_new + LinAlg::axpy(res, -1.0, rhs); // res -= rhs + _convergence_criterion->checkResidual(res); + } + BaseLib::RunTime time_linear_solver; time_linear_solver.start(); bool iteration_succeeded = _linear_solver.solve(A, rhs, x_new); @@ -114,14 +124,18 @@ bool NonlinearSolver<NonlinearSolverTag::Picard>::solve( break; } - auto const norm_x = LinAlg::norm2(x); - // x is used as delta_x in order to compute the error. - LinAlg::aypx(x, -1.0, x_new); // x = _x_new - x - auto const error_dx = LinAlg::norm2(x); - INFO( - "Picard: Iteration #%u |dx|=%.4e, |x|=%.4e, |dx|/|x|=%.4e," - " tolerance(dx)=%.4e", - iteration, error_dx, norm_x, error_dx / norm_x, _tol); + if (sys.isLinear()) { + error_norms_met = true; + } else { + if (_convergence_criterion->hasDeltaXCheck()) { + GlobalVector minus_delta_x(x); + LinAlg::axpy(minus_delta_x, -1.0, + x_new); // minus_delta_x = x - x_new + _convergence_criterion->checkDeltaX(minus_delta_x, x_new); + } + + error_norms_met = _convergence_criterion->isSatisfied(); + } // Update x s.t. in the next iteration we will compute the right delta x LinAlg::copy(x_new, x); @@ -129,17 +143,8 @@ bool NonlinearSolver<NonlinearSolverTag::Picard>::solve( INFO("[time] Iteration #%u took %g s.", iteration, time_iteration.elapsed()); - if (error_dx < _tol) - { - error_norms_met = true; - break; - } - - if (sys.isLinear()) - { - error_norms_met = true; + if (error_norms_met) break; - } } if (iteration > _maxiter) @@ -190,6 +195,8 @@ bool NonlinearSolver<NonlinearSolverTag::Newton>::solve( unsigned iteration = 1; for (; iteration <= _maxiter; ++iteration) { + _convergence_criterion->reset(); + BaseLib::RunTime time_iteration; time_iteration.start(); @@ -208,7 +215,8 @@ bool NonlinearSolver<NonlinearSolverTag::Newton>::solve( sys.applyKnownSolutionsNewton(J, res, minus_delta_x); INFO("[time] Applying Dirichlet BCs took %g s.", time_dirichlet.elapsed()); - auto const error_res = LinAlg::norm2(res); + if (_convergence_criterion->hasResidualCheck()) + _convergence_criterion->checkResidual(res); BaseLib::RunTime time_linear_solver; time_linear_solver.start(); @@ -266,28 +274,22 @@ bool NonlinearSolver<NonlinearSolverTag::Newton>::solve( break; } - auto const error_dx = LinAlg::norm2(minus_delta_x); - auto const norm_x = LinAlg::norm2(x); - INFO( - "Newton: Iteration #%u |dx|=%.4e, |r|=%.4e, |x|=%.4e, " - "|dx|/|x|=%.4e," - " tolerance(dx)=%.4e", - iteration, error_dx, error_res, norm_x, error_dx / norm_x, _tol); + if (sys.isLinear()) { + error_norms_met = true; + } else { + if (_convergence_criterion->hasDeltaXCheck()) { + // Note: x contains the new solution! + _convergence_criterion->checkDeltaX(minus_delta_x, x); + } + + error_norms_met = _convergence_criterion->isSatisfied(); + } INFO("[time] Iteration #%u took %g s.", iteration, time_iteration.elapsed()); - if (error_dx < _tol) - { - error_norms_met = true; - break; - } - - if (sys.isLinear()) - { - error_norms_met = true; + if (error_norms_met) break; - } } if (iteration > _maxiter) @@ -313,27 +315,23 @@ createNonlinearSolver(GlobalLinearSolver& linear_solver, //! \ogs_file_param{prj__nonlinear_solvers__nonlinear_solver__type} auto const type = config.getConfigParameter<std::string>("type"); - //! \ogs_file_param{prj__nonlinear_solvers__nonlinear_solver__tol} - auto const tol = config.getConfigParameter<double>("tol"); //! \ogs_file_param{prj__nonlinear_solvers__nonlinear_solver__max_iter} auto const max_iter = config.getConfigParameter<unsigned>("max_iter"); - //! \ogs_file_param_special{prj__nonlinear_solvers__nonlinear_solver__Picard} - if (type == "Picard") - { + if (type == "Picard") { auto const tag = NonlinearSolverTag::Picard; using ConcreteNLS = NonlinearSolver<tag>; - return std::make_pair(std::unique_ptr<AbstractNLS>(new ConcreteNLS{ - linear_solver, tol, max_iter}), - tag); - } - else if (type == "Newton") - { + return std::make_pair( + std::unique_ptr<AbstractNLS>( + new ConcreteNLS{linear_solver, max_iter}), + tag); + } else if (type == "Newton") { auto const tag = NonlinearSolverTag::Newton; using ConcreteNLS = NonlinearSolver<tag>; - return std::make_pair(std::unique_ptr<AbstractNLS>(new ConcreteNLS{ - linear_solver, tol, max_iter}), - tag); + return std::make_pair( + std::unique_ptr<AbstractNLS>( + new ConcreteNLS{linear_solver, max_iter}), + tag); } OGS_FATAL("Unsupported nonlinear solver type"); } diff --git a/NumLib/ODESolver/NonlinearSolver.h b/NumLib/ODESolver/NonlinearSolver.h index 4a7de970df3..1a16fc98fdf 100644 --- a/NumLib/ODESolver/NonlinearSolver.h +++ b/NumLib/ODESolver/NonlinearSolver.h @@ -14,6 +14,7 @@ #include <utility> #include <logog/include/logog.hpp> +#include "ConvergenceCriterion.h" #include "NonlinearSystem.h" #include "Types.h" @@ -88,14 +89,21 @@ public: * \param maxiter the maximum number of iterations used to solve the * equation. */ - explicit NonlinearSolver(GlobalLinearSolver& linear_solver, double const tol, - const unsigned maxiter) - : _linear_solver(linear_solver), _tol(tol), _maxiter(maxiter) + explicit NonlinearSolver( + GlobalLinearSolver& linear_solver, + const unsigned maxiter) + : _linear_solver(linear_solver), + _maxiter(maxiter) { } //! Set the nonlinear equation system that will be solved. - void setEquationSystem(System& eq) { _equation_system = &eq; } + //! TODO doc + void setEquationSystem(System& eq, ConvergenceCriterion& conv_crit) + { + _equation_system = &eq; + _convergence_criterion = &conv_crit; + } void assemble(GlobalVector const& x) const override; bool solve(GlobalVector& x, @@ -106,7 +114,8 @@ private: GlobalLinearSolver& _linear_solver; System* _equation_system = nullptr; - const double _tol; //!< tolerance of the solver + // TODO doc + ConvergenceCriterion* _convergence_criterion = nullptr; const unsigned _maxiter; //!< maximum number of iterations double const _alpha = @@ -139,14 +148,19 @@ public: * \param maxiter the maximum number of iterations used to solve the * equation. */ - explicit NonlinearSolver(GlobalLinearSolver& linear_solver, double const tol, + explicit NonlinearSolver(GlobalLinearSolver& linear_solver, const unsigned maxiter) - : _linear_solver(linear_solver), _tol(tol), _maxiter(maxiter) + : _linear_solver(linear_solver), _maxiter(maxiter) { } //! Set the nonlinear equation system that will be solved. - void setEquationSystem(System& eq) { _equation_system = &eq; } + //! TODO doc + void setEquationSystem(System& eq, ConvergenceCriterion& conv_crit) + { + _equation_system = &eq; + _convergence_criterion = &conv_crit; + } void assemble(GlobalVector const& x) const override; bool solve(GlobalVector& x, @@ -157,7 +171,8 @@ private: GlobalLinearSolver& _linear_solver; System* _equation_system = nullptr; - const double _tol; //!< tolerance of the solver + // TODO doc + ConvergenceCriterion* _convergence_criterion = nullptr; const unsigned _maxiter; //!< maximum number of iterations std::size_t _A_id = 0u; //!< ID of the \f$ A \f$ matrix. diff --git a/NumLib/ODESolver/TimeLoopSingleODE.h b/NumLib/ODESolver/TimeLoopSingleODE.h index 228a5153786..29df9d6e26f 100644 --- a/NumLib/ODESolver/TimeLoopSingleODE.h +++ b/NumLib/ODESolver/TimeLoopSingleODE.h @@ -36,13 +36,18 @@ public: * \param linear_solver the linear solver used to solve the linearized ODE * system. * \param nonlinear_solver The solver to be used to resolve nonlinearities. + * \param convergence_criterion The convergence criterion used by the + * nonlinear solver. */ - TimeLoopSingleODE(TDiscODESys& ode_sys, - std::unique_ptr<GlobalLinearSolver>&& linear_solver, - std::unique_ptr<NLSolver>&& nonlinear_solver) + TimeLoopSingleODE( + TDiscODESys& ode_sys, + std::unique_ptr<GlobalLinearSolver>&& linear_solver, + std::unique_ptr<NLSolver>&& nonlinear_solver, + std::unique_ptr<ConvergenceCriterion>&& convergence_criterion) : _ode_sys(ode_sys), _linear_solver(std::move(linear_solver)), - _nonlinear_solver(std::move(nonlinear_solver)) + _nonlinear_solver(std::move(nonlinear_solver)), + _convergence_criterion(std::move(convergence_criterion)) { } @@ -69,6 +74,7 @@ private: TDiscODESys& _ode_sys; std::unique_ptr<GlobalLinearSolver> _linear_solver; std::unique_ptr<NLSolver> _nonlinear_solver; + std::unique_ptr<ConvergenceCriterion> _convergence_criterion; }; //! @} @@ -87,7 +93,7 @@ bool TimeLoopSingleODE<NLTag>::loop(const double t0, GlobalVector const& x0, time_disc.setInitialState(t0, x0); // push IC - _nonlinear_solver->setEquationSystem(_ode_sys); + _nonlinear_solver->setEquationSystem(_ode_sys, *_convergence_criterion); if (time_disc.needsPreload()) { -- GitLab