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
|