File: NewtonSolver.h

package info (click to toggle)
fenics-dolfinx 1%3A0.9.0-11
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 5,376 kB
  • sloc: cpp: 33,701; python: 22,338; makefile: 230; sh: 171; xml: 55
file content (213 lines) | stat: -rw-r--r-- 6,418 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// Copyright (C) 2005-2021 Garth N. Wells
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
// SPDX-License-Identifier:    LGPL-3.0-or-later

#pragma once

#ifdef HAS_PETSC

#include <dolfinx/common/MPI.h>
#include <dolfinx/la/petsc.h>
#include <functional>
#include <memory>
#include <petscmat.h>
#include <petscvec.h>
#include <utility>

namespace dolfinx
{

namespace la::petsc
{
class KrylovSolver;
} // namespace la::petsc

namespace nls::petsc
{

/// This class defines a Newton solver for nonlinear systems of
/// equations of the form \f$F(x) = 0\f$.

class NewtonSolver
{
public:
  /// Create nonlinear solver
  /// @param[in] comm The MPI communicator for the solver
  explicit NewtonSolver(MPI_Comm comm);

  /// Move constructor
  NewtonSolver(NewtonSolver&& solver) = default;

  // Copy constructor (deleted)
  NewtonSolver(const NewtonSolver& solver) = delete;

  /// Move assignment constructor
  NewtonSolver& operator=(NewtonSolver&& solver) = default;

  // Assignment operator (deleted)
  NewtonSolver& operator=(const NewtonSolver& solver) = delete;

  /// Destructor
  ~NewtonSolver();

  /// @brief Set the function for computing the residual and the vector
  /// to the assemble the residual into.
  /// @param[in] F Function to compute the residual vector b (x, b)
  /// @param[in] b The vector to assemble to residual into
  void setF(std::function<void(const Vec, Vec)> F, Vec b);

  /// @brief Set the function for computing the Jacobian (dF/dx) and the
  /// matrix to assemble the residual into.
  /// @param[in] J Function to compute the Jacobian matrix b (x, A)
  /// @param[in] Jmat The matrix to assemble the Jacobian into
  void setJ(std::function<void(const Vec, Mat)> J, Mat Jmat);

  /// @brief Set the function for computing the preconditioner matrix
  /// (optional).
  /// @param[in] P Function to compute the preconditioner matrix b (x, P)
  /// @param[in] Pmat The matrix to assemble the preconditioner into
  void setP(std::function<void(const Vec, Mat)> P, Mat Pmat);

  /// @brief Get the internal Krylov solver used to solve for the Newton
  /// updates (const version).
  ///
  /// The Krylov solver prefix is `nls_solve_`.
  ///
  /// @return The Krylov solver
  const la::petsc::KrylovSolver& get_krylov_solver() const;

  /// @brief Get the internal Krylov solver used to solve for the Newton
  /// updates (non-const version).
  ///
  /// The Krylov solver prefix is `nls_solve_`.
  ///
  /// @return The Krylov solver
  la::petsc::KrylovSolver& get_krylov_solver();

  /// @brief Set the function that is called before the residual or
  /// Jacobian are computed. It is commonly used to update ghost values.
  /// @param[in] form The function to call. It takes the latest solution
  /// vector `x` as an argument.
  void set_form(std::function<void(Vec)> form);

  /// @brief Set function that is called at the end of each Newton
  /// iteration to test for convergence.
  /// @param[in] c The function that tests for convergence
  void set_convergence_check(
      std::function<std::pair<double, bool>(const NewtonSolver&, const Vec)> c);

  /// @brief Set function that is called after each Newton iteration to
  /// update the solution.
  /// @param[in] update The function that updates the solution
  void set_update(
      std::function<void(const NewtonSolver& solver, const Vec, Vec)> update);

  /// @brief Solve the nonlinear problem \f$`F(x) = 0\f$ for given
  /// \f$F\f$ and Jacobian \f$\dfrac{\partial F}{\partial x}\f$.
  ///
  /// @param[in,out] x The vector
  /// @return (number of Newton iterations, whether iteration converged)
  std::pair<int, bool> solve(Vec x);

  /// @brief The number of Newton iterations. It can can called by
  /// functions that check for convergence during a solve.
  /// @return The number of Newton iterations performed
  int iteration() const;

  /// @brief Get number of Krylov iterations elapsed since solve
  /// started.
  /// @return Number of iterations.
  int krylov_iterations() const;

  /// @brief Get current residual.
  /// @return Current residual
  double residual() const;

  /// @brief Return initial residual.
  /// @return Initial residual
  double residual0() const;

  /// @brief Get MPI communicator.
  MPI_Comm comm() const;

  /// Maximum number of iterations
  int max_it = 50;

  /// Relative tolerance
  double rtol = 1e-9;

  /// Absolute tolerance
  double atol = 1e-10;

  // FIXME: change to string to enum
  /// Convergence criterion
  std::string convergence_criterion = "residual";

  /// Monitor convergence
  bool report = true;

  /// Throw error if solver fails to converge
  bool error_on_nonconvergence = true;

  /// Relaxation parameter
  double relaxation_parameter = 1.0;

private:
  // Function for computing the residual vector. The first argument is
  // the latest solution vector x and the second argument is the
  // residual vector.
  std::function<void(const Vec x, Vec b)> _fnF;

  // Function for computing the Jacobian matrix operator. The first
  // argument is the latest solution vector x and the second argument is
  // the matrix operator.
  std::function<void(const Vec x, Mat J)> _fnJ;

  // Function for computing the preconditioner matrix operator. The
  // first argument is the latest solution vector x and the second
  // argument is the matrix operator.
  std::function<void(const Vec x, Mat P)> _fnP;

  // Function called before the residual and Jacobian function at each
  // iteration.
  std::function<void(const Vec x)> _system;

  // Residual vector
  Vec _b = nullptr;

  // Jacobian matrix and preconditioner matrix
  Mat _matJ = nullptr, _matP = nullptr;

  // Function to check for convergence
  std::function<std::pair<double, bool>(const NewtonSolver& solver,
                                        const Vec r)>
      _converged;

  // Function to update the solution once convergence is reached
  std::function<void(const NewtonSolver& solver, const Vec dx, Vec x)>
      _update_solution;

  // Accumulated number of Krylov iterations since solve began
  int _krylov_iterations;

  // Number of iterations
  int _iteration;

  // Most recent residual and initial residual
  double _residual, _residual0;

  // Linear solver
  la::petsc::KrylovSolver _solver;

  // Solution vector
  Vec _dx = nullptr;

  // MPI communicator
  dolfinx::MPI::Comm _comm;
};
} // namespace nls::petsc
} // namespace dolfinx

#endif