libMesh
Loading...
Searching...
No Matches
nonlinear_implicit_system.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20// Local includes
21#include "libmesh/nonlinear_implicit_system.h"
22#include "libmesh/diff_solver.h"
23#include "libmesh/equation_systems.h"
24#include "libmesh/libmesh_logging.h"
25#include "libmesh/nonlinear_solver.h"
26#include "libmesh/sparse_matrix.h"
27#include "libmesh/static_condensation.h"
28#include "libmesh/static_condensation_preconditioner.h"
29
30namespace libMesh
31{
32
34 const std::string & name_in,
35 const unsigned int number_in) :
36
37 Parent (es, name_in, number_in),
38 nonlinear_solver (NonlinearSolver<Number>::build(*this)),
39 diff_solver (),
40 _n_nonlinear_iterations (0),
41 _final_nonlinear_residual (1.e20),
42 _operator_matrix (nullptr)
43{
44 // Set default parameters
45 // These were chosen to match the Petsc defaults
46 es.parameters.set<Real> ("linear solver tolerance") = 1e-5;
47 es.parameters.set<Real> ("linear solver minimum tolerance") = 1e-5;
48 es.parameters.set<unsigned int>("linear solver maximum iterations") = 10000;
49
50 es.parameters.set<unsigned int>("nonlinear solver maximum iterations") = 50;
51 es.parameters.set<unsigned int>("nonlinear solver maximum function evaluations") = 10000;
52
53 es.parameters.set<Real>("nonlinear solver absolute residual tolerance") = 1e-35;
54 es.parameters.set<Real>("nonlinear solver relative residual tolerance") = 1e-8;
55 es.parameters.set<Real>("nonlinear solver divergence tolerance") = 1e+4;
56 es.parameters.set<Real>("nonlinear solver absolute step tolerance") = 1e-8;
57 es.parameters.set<Real>("nonlinear solver relative step tolerance") = 1e-8;
58
59 es.parameters.set<bool>("reuse preconditioner") = false;
60 es.parameters.set<unsigned int>("reuse preconditioner maximum linear iterations") = 1;
61
62 if (this->has_static_condensation())
64}
65
66
67
69
70
71
77
78
79
81{
82 // clear the nonlinear solver
83 nonlinear_solver->clear();
84
85 // FIXME - this is necessary for petsc_auto_fieldsplit
86 // nonlinear_solver->init_names(*this);
87
88 // clear the parent data
90
91 // And restore any StaticCondensation to defaults
92 if (this->has_static_condensation())
94}
95
96
97
99{
100 // re-initialize the nonlinear solver interface
101 nonlinear_solver->clear();
102
103 // force the solver to get a new preconditioner, in
104 // case reuse was set
105 nonlinear_solver->force_new_preconditioner();
106
107 // FIXME - this is necessary for petsc_auto_fieldsplit
108 // nonlinear_solver->init_names(*this);
109
110 if (diff_solver.get())
111 diff_solver->reinit();
112
113 // initialize parent data
115}
116
117
118
120{
121 // Get a reference to the EquationSystems
122 const EquationSystems & es =
123 this->get_equation_systems();
124
125 // Get the user-specified nonlinear solver tolerances
126 const unsigned int maxits = parameters.have_parameter<unsigned int>("nonlinear solver maximum iterations") ?
127 parameters.get<unsigned int>("nonlinear solver maximum iterations") :
128 es.parameters.get<unsigned int>("nonlinear solver maximum iterations");
129
130 const unsigned int maxfuncs = parameters.have_parameter<unsigned int>("nonlinear solver maximum function evaluations") ?
131 parameters.get<unsigned int>("nonlinear solver maximum function evaluations") :
132 es.parameters.get<unsigned int>("nonlinear solver maximum function evaluations");
133
134 const double abs_resid_tol = parameters.have_parameter<Real>("nonlinear solver absolute residual tolerance") ?
135 double(parameters.get<Real>("nonlinear solver absolute residual tolerance")) :
136 double(es.parameters.get<Real>("nonlinear solver absolute residual tolerance"));
137
138 const double rel_resid_tol = parameters.have_parameter<Real>("nonlinear solver relative residual tolerance") ?
139 double(parameters.get<Real>("nonlinear solver relative residual tolerance")) :
140 double(es.parameters.get<Real>("nonlinear solver relative residual tolerance"));
141
142 const double div_tol = parameters.have_parameter<Real>("nonlinear solver divergence tolerance") ?
143 double(parameters.get<Real>("nonlinear solver divergence tolerance")) :
144 double(es.parameters.get<Real>("nonlinear solver divergence tolerance"));
145
146 const double abs_step_tol = parameters.have_parameter<Real>("nonlinear solver absolute step tolerance") ?
147 double(parameters.get<Real>("nonlinear solver absolute step tolerance")) :
148 double(es.parameters.get<Real>("nonlinear solver absolute step tolerance"));
149
150 const double rel_step_tol = parameters.have_parameter<Real>("nonlinear solver relative step tolerance")?
151 double(parameters.get<Real>("nonlinear solver relative step tolerance")) :
152 double(es.parameters.get<Real>("nonlinear solver relative step tolerance"));
153
154 // Get the user-specified linear solver tolerances
155 const auto [maxlinearits, linear_tol] = this->Parent::get_linear_solve_parameters();
156
157 const double linear_min_tol = parameters.have_parameter<Real>("linear solver minimum tolerance") ?
158 double(parameters.get<Real>("linear solver minimum tolerance")) :
159 double(es.parameters.get<Real>("linear solver minimum tolerance"));
160
161 const bool reuse_preconditioner = parameters.have_parameter<unsigned int>("reuse preconditioner") ?
162 parameters.get<unsigned int>("reuse preconditioner") :
163 es.parameters.get<bool>("reuse preconditioner");
164 const unsigned int reuse_preconditioner_max_linear_its =
165 parameters.have_parameter<unsigned int>("reuse preconditioner maximum linear iterations") ?
166 parameters.get<unsigned int>("reuse preconditioner maximum linear iterations") :
167 es.parameters.get<unsigned int>("reuse preconditioner maximum linear iterations");
168
169 // Set all the parameters on the NonlinearSolver
170 nonlinear_solver->max_nonlinear_iterations = maxits;
171 nonlinear_solver->max_function_evaluations = maxfuncs;
172 nonlinear_solver->absolute_residual_tolerance = abs_resid_tol;
173 nonlinear_solver->relative_residual_tolerance = rel_resid_tol;
174 nonlinear_solver->divergence_tolerance = div_tol;
175 nonlinear_solver->absolute_step_tolerance = abs_step_tol;
176 nonlinear_solver->relative_step_tolerance = rel_step_tol;
177 nonlinear_solver->max_linear_iterations = maxlinearits;
178 nonlinear_solver->initial_linear_tolerance = linear_tol;
179 nonlinear_solver->minimum_linear_tolerance = linear_min_tol;
180 nonlinear_solver->set_reuse_preconditioner(reuse_preconditioner);
181 nonlinear_solver->set_reuse_preconditioner_max_linear_its(reuse_preconditioner_max_linear_its);
182
183 if (diff_solver.get())
184 {
185 diff_solver->max_nonlinear_iterations = maxits;
186 diff_solver->absolute_residual_tolerance = abs_resid_tol;
187 diff_solver->relative_residual_tolerance = rel_resid_tol;
188 diff_solver->absolute_step_tolerance = abs_step_tol;
189 diff_solver->relative_step_tolerance = rel_step_tol;
190 diff_solver->max_linear_iterations = maxlinearits;
191 diff_solver->initial_linear_tolerance = linear_tol;
192 diff_solver->minimum_linear_tolerance = linear_min_tol;
193 }
194}
195
196
197
199{
200 // Log how long the nonlinear solve takes.
201 LOG_SCOPE("solve()", "System");
202
203 this->set_solver_parameters();
204
205 if (diff_solver.get())
206 {
207 diff_solver->solve();
208
209 // Store the number of nonlinear iterations required to
210 // solve and the final residual.
211 _n_nonlinear_iterations = diff_solver->total_outer_iterations();
212 _final_nonlinear_residual = 0.; // FIXME - support this!
213 }
214 else
215 {
216 if (this->prefix_with_name())
217 nonlinear_solver->init(this->prefix().c_str());
218 else
219 nonlinear_solver->init();
220
221 // FIXME - this is necessary for petsc_auto_fieldsplit
222 // nonlinear_solver->init_names(*this);
223
224 // Solve the nonlinear system.
225 // Store the number of nonlinear iterations required to
226 // solve and the final residual.
227 //
228 // If a distinct Jacobian operator matrix has been registered (see
229 // set_operator_matrix()), use it as Amat while *matrix remains the preconditioning matrix
230 // (Pmat); otherwise use the ordinary single-matrix solve.
234 nonlinear_solver->relative_residual_tolerance,
235 nonlinear_solver->max_linear_iterations);
236 else
238 nonlinear_solver->solve (*matrix, *solution, *rhs,
239 nonlinear_solver->relative_residual_tolerance,
240 nonlinear_solver->max_linear_iterations);
241 }
242
243 // Update the system after the solve
244 this->update();
245}
246
247
248
249std::pair<unsigned int, Real> NonlinearImplicitSystem::get_linear_solve_parameters() const
250{
251 if (diff_solver.get())
252 return std::make_pair(this->diff_solver->max_linear_iterations,
253 this->diff_solver->relative_residual_tolerance);
254 return std::make_pair(this->nonlinear_solver->max_linear_iterations,
255 this->nonlinear_solver->relative_residual_tolerance);
256}
257
258
259
261 bool get_jacobian,
262 bool /*apply_heterogeneous_constraints*/,
263 bool /*apply_no_constraints*/)
264{
265 // Get current_local_solution in sync
266 this->update();
267
268 //-----------------------------------------------------------------------------
269 // if the user has provided both function pointers and objects only the pointer
270 // will be used, so catch that as an error
271 libmesh_error_msg_if(nonlinear_solver->jacobian && nonlinear_solver->jacobian_object,
272 "ERROR: cannot specify both a function and object to compute the Jacobian!");
273
274 libmesh_error_msg_if(nonlinear_solver->residual && nonlinear_solver->residual_object,
275 "ERROR: cannot specify both a function and object to compute the Residual!");
276
277 libmesh_error_msg_if(nonlinear_solver->matvec && nonlinear_solver->residual_and_jacobian_object,
278 "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
279
280
281 if (get_jacobian)
282 {
283 if (nonlinear_solver->jacobian != nullptr)
284 nonlinear_solver->jacobian (*current_local_solution.get(), *matrix, *this);
285
286 else if (nonlinear_solver->jacobian_object != nullptr)
287 nonlinear_solver->jacobian_object->jacobian (*current_local_solution.get(), *matrix, *this);
288
289 else if (nonlinear_solver->matvec != nullptr)
290 nonlinear_solver->matvec (*current_local_solution.get(), get_residual ? rhs : nullptr, matrix, *this);
291
292 else if (nonlinear_solver->residual_and_jacobian_object != nullptr)
293 nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian (*current_local_solution.get(), get_residual ? rhs : nullptr, matrix, *this);
294
295 else
296 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
297 }
298
299 if (get_residual)
300 {
301 if (nonlinear_solver->residual != nullptr)
302 nonlinear_solver->residual (*current_local_solution.get(), *rhs, *this);
303
304 else if (nonlinear_solver->residual_object != nullptr)
305 nonlinear_solver->residual_object->residual (*current_local_solution.get(), *rhs, *this);
306
307 else if (nonlinear_solver->matvec != nullptr)
308 {
309 // we might have already grabbed the residual and jacobian together
310 if (!get_jacobian)
311 nonlinear_solver->matvec (*current_local_solution.get(), rhs, nullptr, *this);
312 }
313
314 else if (nonlinear_solver->residual_and_jacobian_object != nullptr)
315 {
316 // we might have already grabbed the residual and jacobian together
317 if (!get_jacobian)
318 nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian (*current_local_solution.get(), rhs, nullptr, *this);
319 }
320
321 else
322 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
323 }
324 else
325 libmesh_assert(get_jacobian); // I can't believe you really wanted to assemble *nothing*
326}
327
328
329
330
332{
333 return nonlinear_solver->get_current_nonlinear_iteration_number();
334}
335
336
337
338} // namespace libMesh
This is the EquationSystems class.
Parameters parameters
Data structure holding arbitrary parameters.
NumericVector< Number > * rhs
The system matrix.
Manages consistently variables, degrees of freedom, coefficient vectors, and matrices for implicit sy...
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const
SparseMatrix< Number > * matrix
The system matrix.
virtual void clear() override
Clear all the data structures associated with the system.
virtual void create_static_condensation() override
Request that static condensation be performed for this system.
void setup_static_condensation_preconditioner(T &solver)
Sets up the static condensation preconditioner for the supplied solver.
void set_solver_parameters()
Copies system parameters into nonlinear solver parameters.
virtual void solve() override
Assembles & solves the nonlinear system R(x) = 0.
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const override
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
unsigned get_current_nonlinear_iteration_number() const
If called during the solve(), for example by the user-specified residual or Jacobian function,...
NonlinearImplicitSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
unsigned int _n_nonlinear_iterations
The number of nonlinear iterations required to solve the nonlinear system R(x)=0.
virtual void assembly(bool get_residual, bool get_jacobian, bool apply_heterogeneous_constraints=false, bool apply_no_constraints=false) override
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
The NonlinearSolver defines the default interface used to solve the nonlinear_implicit system.
SparseMatrix< Number > * _operator_matrix
An optional matrix to use as the actual Jacobian operator (what is Amat in PETSc lingo for the linear...
std::unique_ptr< DiffSolver > diff_solver
The DiffSolver defines an optional interface used to solve the nonlinear_implicit system.
Real _final_nonlinear_residual
The final residual for the nonlinear system R(x)
virtual void create_static_condensation() override
Request that static condensation be performed for this system.
virtual void clear() override
Clear all the data structures associated with the system.
This base class can be inherited from to provide interfaces to nonlinear solvers from different packa...
bool have_parameter(std::string_view) const
Definition parameters.h:420
T & set(const std::string &)
Definition parameters.h:494
const T & get(std::string_view) const
Definition parameters.h:451
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition system.C:442
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
Definition system.h:1667
bool prefix_with_name() const
Definition system.h:1974
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition system.C:498
bool has_static_condensation() const
Definition system.C:2669
Parameters parameters
Parameters for the system. If a parameter is not provided, it should be retrieved from the EquationSy...
Definition system.h:1588
std::string prefix() const
Definition system.h:1980
const EquationSystems & get_equation_systems() const
Definition system.h:767
The libMesh namespace provides an interface to certain functionality in the library.
libmesh_assert(ctx)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real