dune-geometry  2.11
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 
14 #include <dune/common/debugstream.hh>
15 #include <dune/common/fmatrix.hh>
16 #include <dune/common/ftraits.hh>
17 #include <dune/common/fvector.hh>
19 
20 namespace Dune {
21 namespace Impl {
22 
23 template <class R = double>
24 struct 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 
41 enum 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 
62 template <class F, class DF, class Domain,
63  class Range = std::invoke_result_t<F, Domain>,
64  class R = typename Dune::FieldTraits<Domain>::real_type>
65 GaussNewtonErrorCode 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  for (int i = 0; i < opts.maxIt; ++i)
75  {
76  // Get descent direction dx: (J^T*J)dx = J^T*dy
77  const bool invertible = FieldMatrixHelper<R>::xTRightInvA(df(x), dy, dx);
78 
79  // break if jacobian is not invertible
80  if (!invertible)
81  return GaussNewtonErrorCode::JACOBIAN_NOT_INVERTIBLE;
82 
83  // line-search procedure to update x with correction dx
84  R alpha = 1;
85  for (int j = 0; j < opts.maxInnerIt; ++j) {
86  x = x0 - alpha * dx;
87  dy = f(x) - y;
88  resNorm = dy.two_norm();
89 
90  if (resNorm < resNorm0)
91  break;
92 
93  alpha *= opts.theta;
94  }
95 
96  // cannot reduce the residual
97  if (!(resNorm < resNorm0))
98  return GaussNewtonErrorCode::STAGNATION;
99 
100  x0 = x;
101  resNorm0 = resNorm;
102 
103  // break if tolerance is reached.
104  if (resNorm < opts.absTol)
105  return GaussNewtonErrorCode::OK;
106  }
107 
108  // tolerance could not be reached
109  if (!(resNorm < opts.absTol))
110  return GaussNewtonErrorCode::TOLERANCE_NOT_REACHED;
111 
112  return GaussNewtonErrorCode::OK;
113 }
114 
115 } // end namespace Impl
116 } // end namespace Dune
117 
118 #endif // DUNE_GEOMETRY_UTILITY_ALGORITHMS_HH
Definition: affinegeometry.hh:21