libMesh
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 
30 namespace 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 
72 {
75 }
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
88  Parent::clear();
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
113  Parent::reinit();
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 
238 std::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 
249 void NonlinearImplicitSystem::assembly(bool get_residual,
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
void set_solver_parameters()
Copies system parameters into nonlinear solver parameters.
This is the EquationSystems class.
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
The NonlinearSolver defines the default interface used to solve the nonlinear_implicit system...
bool have_parameter(std::string_view) const
Definition: parameters.h:420
virtual void create_static_condensation() override
Request that static condensation be performed for this system.
virtual void create_static_condensation() override
Request that static condensation be performed for this system.
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition: system.C:442
const EquationSystems & get_equation_systems() const
Definition: system.h:767
virtual void clear() override
Clear all the data structures associated with the system.
NumericVector< Number > * rhs
The system matrix.
This base class can be inherited from to provide interfaces to nonlinear solvers from different packa...
NonlinearImplicitSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
virtual void clear() override
Clear all the data structures associated with the system.
bool has_static_condensation() const
Definition: system.C:2669
The libMesh namespace provides an interface to certain functionality in the library.
Parameters parameters
Parameters for the system. If a parameter is not provided, it should be retrieved from the EquationSy...
Definition: system.h:1588
void setup_static_condensation_preconditioner(T &solver)
Sets up the static condensation preconditioner for the supplied solver.
const T & get(std::string_view) const
Definition: parameters.h:451
unsigned int _n_nonlinear_iterations
The number of nonlinear iterations required to solve the nonlinear system R(x)=0. ...
std::string prefix() const
Definition: system.h:1980
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:98
Real _final_nonlinear_residual
The final residual for the nonlinear system R(x)
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1655
libmesh_assert(ctx)
std::unique_ptr< DiffSolver > diff_solver
The DiffSolver defines an optional interface used to solve the nonlinear_implicit system...
unsigned get_current_nonlinear_iteration_number() const
If called during the solve(), for example by the user-specified residual or Jacobian function...
virtual void solve() override
Assembles & solves the nonlinear system R(x) = 0.
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:498
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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.
T & set(const std::string &)
Definition: parameters.h:494
SparseMatrix< Number > * matrix
The system matrix.
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
Parameters parameters
Data structure holding arbitrary parameters.
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
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const override
bool prefix_with_name() const
Definition: system.h:1974