OGS
NewtonRaphson.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include <Eigen/Core>
7#include <optional>
8
9#include "BaseLib/Logging.h"
10
11namespace NumLib
12{
19
24template <typename LinearSolver, typename JacobianMatrixUpdate,
25 typename ResidualUpdate, typename SolutionUpdate>
26class NewtonRaphson final
27{
28private:
29 template <typename T>
31 {
32 static_assert(
33 !std::is_same_v<T, T>,
34 "For the type T in the expression !std::is_same_v<T, T>: Could not "
35 "find overload for FirstArgument<T>. Expected T to be a callable "
36 "with one argument. Could be a missing overload of FirstArgument "
37 "for the type T.");
38 };
39
40 // Specialization for lambdas and functors with const operator()
41 template <typename C, typename R, typename Arg, typename... Args>
42 struct FirstArgument<R (C::*)(Arg, Args...) const>
43 {
44 using type = std::remove_reference_t<Arg>;
45 };
46
47 template <typename F>
49 decltype(&std::remove_reference_t<F>::operator())>::type;
50
53
54public:
55 NewtonRaphson(LinearSolver& linear_solver,
56 JacobianMatrixUpdate jacobian_update,
57 ResidualUpdate residual_update,
58 SolutionUpdate solution_update,
59 NewtonRaphsonSolverParameters const& solver_parameters)
60 : _linear_solver(linear_solver),
61 _jacobian_update(jacobian_update),
62 _residual_update(residual_update),
63 _solution_update(solution_update),
64 _maximum_iterations(solver_parameters.maximum_iterations),
65 _residuum_tolerance_squared(solver_parameters.residuum_tolerance *
66 solver_parameters.residuum_tolerance),
67 _increment_tolerance_squared(solver_parameters.increment_tolerance *
68 solver_parameters.increment_tolerance)
69 {
70 }
71
74 std::optional<int> solve(JacobianMatrix& jacobian) const
75 {
76 int iteration = 0;
77 ResidualVector increment;
78 ResidualVector residual;
79 do
80 {
81 // The jacobian and the residual are updated simultaneously to keep
82 // consistency. The jacobian is used after the non-linear solver
83 // onward.
84 _jacobian_update(jacobian);
85 _residual_update(residual);
86
87 if (residual.squaredNorm() < _residuum_tolerance_squared)
88 {
89 break; // convergence criteria fulfilled.
90 }
91
92 increment.noalias() =
93 _linear_solver.compute(jacobian).solve(-residual);
94 // DBUG("Local linear solver accuracy |J dx - r| = {:g}",
95 // (jacobian * increment + residual).norm());
96
97 _solution_update(increment);
98
99 if (increment.squaredNorm() < _increment_tolerance_squared)
100 {
101 break; // increment to small.
102 }
103
104 // DBUG("Local Newton: Iteration #{:d} |dx| = {:g}, |r| = {:g}",
105 // iteration, increment.norm(), residual.norm());
106 // fmt::print("Local Newton: Increment {}\n",
107 // fmt::join(increment.data(),
108 // increment.data() + increment.size(), ", "));
109 // fmt::print("Local Newton: Residuum {}\n",
110 // fmt::join(residual.data(),
111 // residual.data() + residual.size(), ", "));
112 } while (iteration++ < _maximum_iterations);
113
114 if (iteration > _maximum_iterations)
115 {
116 ERR("The local Newton method did not converge within the given "
117 "number of iterations. Iteration: {:d}, increment {:g}, "
118 "residual: "
119 "{:g}",
120 iteration - 1, increment.norm(), residual.norm());
121 return std::nullopt;
122 }
123
124 return iteration;
125 };
126
127private:
128 LinearSolver& _linear_solver;
129 JacobianMatrixUpdate _jacobian_update;
130 ResidualUpdate _residual_update;
131 SolutionUpdate _solution_update;
133 const double
135 const double
137};
138
139template <typename LinearSolver, typename JacobianMatrixUpdate,
140 typename ResidualUpdate, typename SolutionUpdate>
141NewtonRaphson<LinearSolver, JacobianMatrixUpdate, ResidualUpdate,
142 SolutionUpdate>
143makeNewtonRaphson(LinearSolver& linear_solver,
144 JacobianMatrixUpdate&& jacobian_update,
145 ResidualUpdate&& residual_update,
146 SolutionUpdate&& solution_update,
147 NewtonRaphsonSolverParameters const& solver_parameters)
148{
149 return NewtonRaphson<LinearSolver, JacobianMatrixUpdate, ResidualUpdate,
150 SolutionUpdate>(
151 linear_solver, std::forward<JacobianMatrixUpdate>(jacobian_update),
152 std::forward<ResidualUpdate>(residual_update),
153 std::forward<SolutionUpdate>(solution_update), solver_parameters);
154}
155} // namespace NumLib
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
ResidualUpdate _residual_update
JacobianMatrixUpdate _jacobian_update
const int _maximum_iterations
Maximum number of iterations.
FirstArgumentType< JacobianMatrixUpdate > JacobianMatrix
NewtonRaphson(LinearSolver &linear_solver, JacobianMatrixUpdate jacobian_update, ResidualUpdate residual_update, SolutionUpdate solution_update, NewtonRaphsonSolverParameters const &solver_parameters)
LinearSolver & _linear_solver
const double _residuum_tolerance_squared
Error tolerance for the residuum.
SolutionUpdate _solution_update
FirstArgumentType< ResidualUpdate > ResidualVector
typename FirstArgument< decltype(&std::remove_reference_t< F >::operator())>::type FirstArgumentType
std::optional< int > solve(JacobianMatrix &jacobian) const
const double _increment_tolerance_squared
Error tolerance for the increment.
NewtonRaphson< LinearSolver, JacobianMatrixUpdate, ResidualUpdate, SolutionUpdate > makeNewtonRaphson(LinearSolver &linear_solver, JacobianMatrixUpdate &&jacobian_update, ResidualUpdate &&residual_update, SolutionUpdate &&solution_update, NewtonRaphsonSolverParameters const &solver_parameters)