dune-geometry 2.12-git
Loading...
Searching...
No Matches
algorithms.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5#ifndef DUNE_GEOMETRY_UTILITY_ALGORITHMS_HH
6#define DUNE_GEOMETRY_UTILITY_ALGORITHMS_HH
7
8#include <algorithm>
9#include <cmath>
10#include <limits>
11#include <optional>
12#include <type_traits>
13
19
20namespace Dune {
21namespace Impl {
22
23template <class R = double>
24struct GaussNewtonOptions
25{
27 int maxIt = 100;
28
30 R absTol = []{ using std::sqrt; return sqrt(std::numeric_limits<R>::epsilon()); }();
31
33 int maxInnerIt = 10;
34
36 R theta = 0.5;
37};
38
39
41enum class GaussNewtonErrorCode
42{
43 OK = 0, //< A solution is found
44 JACOBIAN_NOT_INVERTIBLE, //< The Jacobian is not invertible at the current point
45 STAGNATION, //< No reduction of the residul norm possible
46 TOLERANCE_NOT_REACHED //< The break tolerance for the resodual norm is not reached
47};
48
49
62template <class F, class DF, class Domain,
64 class R = typename Dune::FieldTraits<Domain>::real_type>
65GaussNewtonErrorCode gaussNewton (const F& f, const DF& df, Range y, Domain& x0,
66 GaussNewtonOptions<R> opts = {})
67{
68 Domain x = x0;
69 Domain dx{};
70 Range dy = f(x0) - y;
71 R resNorm0 = dy.two_norm();
72 R resNorm = 0;
73
74 if (resNorm0 < opts.absTol)
75 return GaussNewtonErrorCode::OK;
76
77 for (int i = 0; i < opts.maxIt; ++i)
78 {
79 // Get descent direction dx: (J^T*J)dx = J^T*dy
80 const bool invertible = FieldMatrixHelper<R>::xTRightInvA(df(x), dy, dx);
81
82 // break if jacobian is not invertible
83 if (!invertible)
84 return GaussNewtonErrorCode::JACOBIAN_NOT_INVERTIBLE;
85
86 // line-search procedure to update x with correction dx
87 R alpha = 1;
88 for (int j = 0; j < opts.maxInnerIt; ++j) {
89 x = x0 - alpha * dx;
90 dy = f(x) - y;
91 resNorm = dy.two_norm();
92
93 if (resNorm < resNorm0)
94 break;
95
96 alpha *= opts.theta;
97 }
98
99 // cannot reduce the residual
100 if (!(resNorm < resNorm0))
101 return GaussNewtonErrorCode::STAGNATION;
102
103 x0 = x;
104 resNorm0 = resNorm;
105
106 // break if tolerance is reached.
107 if (resNorm < opts.absTol)
108 return GaussNewtonErrorCode::OK;
109 }
110
111 // tolerance could not be reached
112 if (!(resNorm < opts.absTol))
113 return GaussNewtonErrorCode::TOLERANCE_NOT_REACHED;
114
115 return GaussNewtonErrorCode::OK;
116}
117
118} // end namespace Impl
119} // end namespace Dune
120
121#endif // DUNE_GEOMETRY_UTILITY_ALGORITHMS_HH
T sqrt(T... args)