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{
43 // Set default parameters
44 // These were chosen to match the Petsc defaults
45 es.parameters.set<Real> ("linear solver tolerance") = 1e-5;
46 es.parameters.set<Real> ("linear solver minimum tolerance") = 1e-5;
47 es.parameters.set<unsigned int>("linear solver maximum iterations") = 10000;
48
49 es.parameters.set<unsigned int>("nonlinear solver maximum iterations") = 50;
50 es.parameters.set<unsigned int>("nonlinear solver maximum function evaluations") = 10000;
51
52 es.parameters.set<Real>("nonlinear solver absolute residual tolerance") = 1e-35;
53 es.parameters.set<Real>("nonlinear solver relative residual tolerance") = 1e-8;
54 es.parameters.set<Real>("nonlinear solver divergence tolerance") = 1e+4;
55 es.parameters.set<Real>("nonlinear solver absolute step tolerance") = 1e-8;
56 es.parameters.set<Real>("nonlinear solver relative step tolerance") = 1e-8;
57
58 es.parameters.set<bool>("reuse preconditioner") = false;
59 es.parameters.set<unsigned int>("reuse preconditioner maximum linear iterations") = 1;
60
61 if (this->has_static_condensation())
63}
64
65
66
68
69
70
76
77
78
80{
81 // clear the nonlinear solver
82 nonlinear_solver->clear();
83
84 // FIXME - this is necessary for petsc_auto_fieldsplit
85 // nonlinear_solver->init_names(*this);
86
87 // clear the parent data
89
90 // And restore any StaticCondensation to defaults
91 if (this->has_static_condensation())
93}
94
95
96
98{
99 // re-initialize the nonlinear solver interface
100 nonlinear_solver->clear();
101
102 // force the solver to get a new preconditioner, in
103 // case reuse was set
104 nonlinear_solver->force_new_preconditioner();
105
106 // FIXME - this is necessary for petsc_auto_fieldsplit
107 // nonlinear_solver->init_names(*this);
108
109 if (diff_solver.get())
110 diff_solver->reinit();
111
112 // initialize parent data
114}
115
116
117
119{
120 // Get a reference to the EquationSystems
121 const EquationSystems & es =
122 this->get_equation_systems();
123
124 // Get the user-specified nonlinear solver tolerances
125 const unsigned int maxits = parameters.have_parameter<unsigned int>("nonlinear solver maximum iterations") ?
126 parameters.get<unsigned int>("nonlinear solver maximum iterations") :
127 es.parameters.get<unsigned int>("nonlinear solver maximum iterations");
128
129 const unsigned int maxfuncs = parameters.have_parameter<unsigned int>("nonlinear solver maximum function evaluations") ?
130 parameters.get<unsigned int>("nonlinear solver maximum function evaluations") :
131 es.parameters.get<unsigned int>("nonlinear solver maximum function evaluations");
132
133 const double abs_resid_tol = parameters.have_parameter<Real>("nonlinear solver absolute residual tolerance") ?
134 double(parameters.get<Real>("nonlinear solver absolute residual tolerance")) :
135 double(es.parameters.get<Real>("nonlinear solver absolute residual tolerance"));
136
137 const double rel_resid_tol = parameters.have_parameter<Real>("nonlinear solver relative residual tolerance") ?
138 double(parameters.get<Real>("nonlinear solver relative residual tolerance")) :
139 double(es.parameters.get<Real>("nonlinear solver relative residual tolerance"));
140
141 const double div_tol = parameters.have_parameter<Real>("nonlinear solver divergence tolerance") ?
142 double(parameters.get<Real>("nonlinear solver divergence tolerance")) :
143 double(es.parameters.get<Real>("nonlinear solver divergence tolerance"));
144
145 const double abs_step_tol = parameters.have_parameter<Real>("nonlinear solver absolute step tolerance") ?
146 double(parameters.get<Real>("nonlinear solver absolute step tolerance")) :
147 double(es.parameters.get<Real>("nonlinear solver absolute step tolerance"));
148
149 const double rel_step_tol = parameters.have_parameter<Real>("nonlinear solver relative step tolerance")?
150 double(parameters.get<Real>("nonlinear solver relative step tolerance")) :
151 double(es.parameters.get<Real>("nonlinear solver relative step tolerance"));
152
153 // Get the user-specified linear solver tolerances
154 const auto [maxlinearits, linear_tol] = this->Parent::get_linear_solve_parameters();
155
156 const double linear_min_tol = parameters.have_parameter<Real>("linear solver minimum tolerance") ?
157 double(parameters.get<Real>("linear solver minimum tolerance")) :
158 double(es.parameters.get<Real>("linear solver minimum tolerance"));
159
160 const bool reuse_preconditioner = parameters.have_parameter<unsigned int>("reuse preconditioner") ?
161 parameters.get<unsigned int>("reuse preconditioner") :
162 es.parameters.get<bool>("reuse preconditioner");
163 const unsigned int reuse_preconditioner_max_linear_its =
164 parameters.have_parameter<unsigned int>("reuse preconditioner maximum linear iterations") ?
165 parameters.get<unsigned int>("reuse preconditioner maximum linear iterations") :
166 es.parameters.get<unsigned int>("reuse preconditioner maximum linear iterations");
167
168 // Set all the parameters on the NonlinearSolver
169 nonlinear_solver->max_nonlinear_iterations = maxits;
170 nonlinear_solver->max_function_evaluations = maxfuncs;
171 nonlinear_solver->absolute_residual_tolerance = abs_resid_tol;
172 nonlinear_solver->relative_residual_tolerance = rel_resid_tol;
173 nonlinear_solver->divergence_tolerance = div_tol;
174 nonlinear_solver->absolute_step_tolerance = abs_step_tol;
175 nonlinear_solver->relative_step_tolerance = rel_step_tol;
176 nonlinear_solver->max_linear_iterations = maxlinearits;
177 nonlinear_solver->initial_linear_tolerance = linear_tol;
178 nonlinear_solver->minimum_linear_tolerance = linear_min_tol;
179 nonlinear_solver->set_reuse_preconditioner(reuse_preconditioner);
180 nonlinear_solver->set_reuse_preconditioner_max_linear_its(reuse_preconditioner_max_linear_its);
181
182 if (diff_solver.get())
183 {
184 diff_solver->max_nonlinear_iterations = maxits;
185 diff_solver->absolute_residual_tolerance = abs_resid_tol;
186 diff_solver->relative_residual_tolerance = rel_resid_tol;
187 diff_solver->absolute_step_tolerance = abs_step_tol;
188 diff_solver->relative_step_tolerance = rel_step_tol;
189 diff_solver->max_linear_iterations = maxlinearits;
190 diff_solver->initial_linear_tolerance = linear_tol;
191 diff_solver->minimum_linear_tolerance = linear_min_tol;
192 }
193}
194
195
196
198{
199 // Log how long the nonlinear solve takes.
200 LOG_SCOPE("solve()", "System");
201
202 this->set_solver_parameters();
203
204 if (diff_solver.get())
205 {
206 diff_solver->solve();
207
208 // Store the number of nonlinear iterations required to
209 // solve and the final residual.
210 _n_nonlinear_iterations = diff_solver->total_outer_iterations();
211 _final_nonlinear_residual = 0.; // FIXME - support this!
212 }
213 else
214 {
215 if (this->prefix_with_name())
216 nonlinear_solver->init(this->prefix().c_str());
217 else
218 nonlinear_solver->init();
219
220 // FIXME - this is necessary for petsc_auto_fieldsplit
221 // nonlinear_solver->init_names(*this);
222
223 // Solve the nonlinear system.
224 // Store the number of nonlinear iterations required to
225 // solve and the final residual.
227 nonlinear_solver->solve (*matrix, *solution, *rhs,
228 nonlinear_solver->relative_residual_tolerance,
229 nonlinear_solver->max_linear_iterations);
230 }
231
232 // Update the system after the solve
233 this->update();
234}
235
236
237
238std::pair<unsigned int, Real> NonlinearImplicitSystem::get_linear_solve_parameters() const
239{
240 if (diff_solver.get())
241 return std::make_pair(this->diff_solver->max_linear_iterations,
242 this->diff_solver->relative_residual_tolerance);
243 return std::make_pair(this->nonlinear_solver->max_linear_iterations,
244 this->nonlinear_solver->relative_residual_tolerance);
245}
246
247
248
250 bool get_jacobian,
251 bool /*apply_heterogeneous_constraints*/,
252 bool /*apply_no_constraints*/)
253{
254 // Get current_local_solution in sync
255 this->update();
256
257 //-----------------------------------------------------------------------------
258 // if the user has provided both function pointers and objects only the pointer
259 // will be used, so catch that as an error
260 libmesh_error_msg_if(nonlinear_solver->jacobian && nonlinear_solver->jacobian_object,
261 "ERROR: cannot specify both a function and object to compute the Jacobian!");
262
263 libmesh_error_msg_if(nonlinear_solver->residual && nonlinear_solver->residual_object,
264 "ERROR: cannot specify both a function and object to compute the Residual!");
265
266 libmesh_error_msg_if(nonlinear_solver->matvec && nonlinear_solver->residual_and_jacobian_object,
267 "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
268
269
270 if (get_jacobian)
271 {
272 if (nonlinear_solver->jacobian != nullptr)
273 nonlinear_solver->jacobian (*current_local_solution.get(), *matrix, *this);
274
275 else if (nonlinear_solver->jacobian_object != nullptr)
276 nonlinear_solver->jacobian_object->jacobian (*current_local_solution.get(), *matrix, *this);
277
278 else if (nonlinear_solver->matvec != nullptr)
279 nonlinear_solver->matvec (*current_local_solution.get(), get_residual ? rhs : nullptr, matrix, *this);
280
281 else if (nonlinear_solver->residual_and_jacobian_object != nullptr)
282 nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian (*current_local_solution.get(), get_residual ? rhs : nullptr, matrix, *this);
283
284 else
285 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
286 }
287
288 if (get_residual)
289 {
290 if (nonlinear_solver->residual != nullptr)
291 nonlinear_solver->residual (*current_local_solution.get(), *rhs, *this);
292
293 else if (nonlinear_solver->residual_object != nullptr)
294 nonlinear_solver->residual_object->residual (*current_local_solution.get(), *rhs, *this);
295
296 else if (nonlinear_solver->matvec != nullptr)
297 {
298 // we might have already grabbed the residual and jacobian together
299 if (!get_jacobian)
300 nonlinear_solver->matvec (*current_local_solution.get(), rhs, nullptr, *this);
301 }
302
303 else if (nonlinear_solver->residual_and_jacobian_object != nullptr)
304 {
305 // we might have already grabbed the residual and jacobian together
306 if (!get_jacobian)
307 nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian (*current_local_solution.get(), rhs, nullptr, *this);
308 }
309
310 else
311 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
312 }
313 else
314 libmesh_assert(get_jacobian); // I can't believe you really wanted to assemble *nothing*
315}
316
317
318
319
321{
322 return nonlinear_solver->get_current_nonlinear_iteration_number();
323}
324
325
326
327} // 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.
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