https://mooseframework.inl.gov
NonlinearSystem.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 // moose includes
11 #include "NonlinearSystem.h"
12 #include "FEProblem.h"
13 #include "DisplacedProblem.h"
14 #include "TimeIntegrator.h"
16 #include "PetscSupport.h"
17 #include "ComputeResidualFunctor.h"
19 #include "MooseVariableScalar.h"
20 #include "MooseTypes.h"
21 #include "AuxiliarySystem.h"
22 #include "Console.h"
23 
24 #include "libmesh/nonlinear_solver.h"
25 #include "libmesh/petsc_nonlinear_solver.h"
26 #include "libmesh/sparse_matrix.h"
27 #include "libmesh/petsc_matrix.h"
28 #include "libmesh/diagonal_matrix.h"
29 #include "libmesh/default_coupling.h"
30 #include "libmesh/petsc_solver_exception.h"
31 
32 using namespace libMesh;
33 
34 namespace Moose
35 {
36 void
38  SparseMatrix<Number> & jacobian,
40 {
41  FEProblemBase * p =
42  sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
43  p->computeJacobianSys(sys, soln, jacobian);
44 }
45 
46 void
48  NumericVector<Number> & upper,
50 {
51  FEProblemBase * p =
52  sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
53  p->computeBounds(sys, lower, upper);
54 }
55 
56 void
58 {
59  FEProblemBase * p =
60  sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
61  p->computeNullSpace(sys, sp);
62 }
63 
64 void
67 {
68  FEProblemBase * p =
69  sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
70  p->computeTransposeNullSpace(sys, sp);
71 }
72 
73 void
75 {
76  FEProblemBase * p =
77  sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
78  p->computeNearNullSpace(sys, sp);
79 }
80 
81 void
83  NumericVector<Number> & search_direction,
84  NumericVector<Number> & new_soln,
85  bool & changed_search_direction,
86  bool & changed_new_soln,
88 {
89  FEProblemBase * p =
90  sys.get_equation_systems().parameters.get<FEProblemBase *>("_fe_problem_base");
92  sys, old_soln, search_direction, new_soln, changed_search_direction, changed_new_soln);
93 }
94 } // namespace Moose
95 
96 NonlinearSystem::NonlinearSystem(FEProblemBase & fe_problem, const std::string & name)
98  fe_problem, fe_problem.es().add_system<NonlinearImplicitSystem>(name), name),
99  _nl_implicit_sys(fe_problem.es().get_system<NonlinearImplicitSystem>(name)),
100  _nl_residual_functor(_fe_problem),
101  _fd_residual_functor(_fe_problem),
102  _resid_and_jac_functor(_fe_problem),
103  _use_coloring_finite_difference(false)
104 {
105  nonlinearSolver()->residual_object = &_nl_residual_functor;
109  nonlinearSolver()->transpose_nullspace = Moose::compute_transpose_nullspace;
111 
112  PetscNonlinearSolver<Real> * petsc_solver =
114  if (petsc_solver)
115  {
116  petsc_solver->set_residual_zero_out(false);
117  petsc_solver->set_jacobian_zero_out(false);
118  petsc_solver->use_default_monitor(false);
119  }
120 }
121 
123 
124 void
126 {
128  {
131  }
132 
133  PetscNonlinearSolver<Real> & solver =
136 
138 }
139 
140 void
142 {
143  // Only attach the postcheck function to the solver if we actually
144  // have dampers or if the FEProblemBase needs to update the solution,
145  // which is also done during the linesearch postcheck. It doesn't
146  // hurt to do this multiple times, it is just setting a pointer.
150 
152  {
153  TIME_SECTION("nlPreSMOResidual", 3, "Computing Pre-SMO Residual");
154  // Calculate the pre-SMO residual for use in the convergence criterion.
160  _console << " * Nonlinear |R| = "
162  << " (Before preset BCs, predictors, correctors, and constraints)\n";
163  _console << std::flush;
164  }
165 
166  const bool presolve_succeeded = preSolve();
167  if (!presolve_succeeded)
168  return;
169 
171 
172  const bool time_integrator_solve = std::any_of(_time_integrators.begin(),
173  _time_integrators.end(),
174  [](auto & ti) { return ti->overridesSolve(); });
175  if (time_integrator_solve)
176  mooseAssert(_time_integrators.size() == 1,
177  "If solve is overridden, then there must be only one time integrator");
178 
179  if (time_integrator_solve)
180  _time_integrators.front()->solve();
181  else
182  system().solve();
183 
184  for (auto & ti : _time_integrators)
185  {
186  if (!ti->overridesSolve())
187  ti->setNumIterationsLastSolve();
188  ti->postSolve();
189  }
190 
191  if (!_time_integrators.empty())
192  {
193  _n_iters = _time_integrators.front()->getNumNonlinearIterations();
194  _n_linear_iters = _time_integrators.front()->getNumLinearIterations();
195  }
196  else
197  {
199  _n_linear_iters = _nl_implicit_sys.nonlinear_solver->get_total_linear_iterations();
200  }
201 
202  // store info about the solve
204 
205  // determine whether solution invalid occurs in the converged solution
207 
209  LibmeshPetscCall(MatFDColoringDestroy(&_fdcoloring));
210 }
211 
212 void
214  const std::set<TagID> & vector_tags_to_close)
215 {
216  PetscNonlinearSolver<Real> & solver =
218 
219  if (exec_flag == EXEC_LINEAR || exec_flag == EXEC_POSTCHECK)
220  {
221  LibmeshPetscCall(SNESSetFunctionDomainError(solver.snes()));
222 
223  // Clean up by getting vectors into a valid state for a
224  // (possible) subsequent solve.
225  closeTaggedVectors(vector_tags_to_close);
226  }
227  else if (exec_flag == EXEC_NONLINEAR)
228  LibmeshPetscCall(SNESSetJacobianDomainError(solver.snes()));
229  else
230  mooseError("Unsupported execute flag: ", Moose::stringify(exec_flag));
231 }
232 
233 void
235 {
236  std::shared_ptr<FiniteDifferencePreconditioner> fdp =
238  if (!fdp)
239  mooseError("Did not setup finite difference preconditioner, and please add a preconditioning "
240  "block with type = fdp");
241 
242  if (fdp->finiteDifferenceType() == "coloring")
243  {
246  }
247 
248  else if (fdp->finiteDifferenceType() == "standard")
249  {
252  }
253  else
254  mooseError("Unknown finite difference type");
255 }
256 
257 void
259 {
260  // Make sure that libMesh isn't going to override our preconditioner
261  _nl_implicit_sys.nonlinear_solver->jacobian = nullptr;
262 
263  PetscNonlinearSolver<Number> * petsc_nonlinear_solver =
265 
266  PetscMatrix<Number> * petsc_mat =
268 
269  LibmeshPetscCall(SNESSetJacobian(petsc_nonlinear_solver->snes(),
270  petsc_mat->mat(),
271  petsc_mat->mat(),
272  SNESComputeJacobianDefault,
273  nullptr));
274 }
275 
276 void
278 {
279  // Make sure that libMesh isn't going to override our preconditioner
280  _nl_implicit_sys.nonlinear_solver->jacobian = nullptr;
281 
282  PetscNonlinearSolver<Number> & petsc_nonlinear_solver =
284 
285  // Pointer to underlying PetscMatrix type
286  PetscMatrix<Number> * petsc_mat =
288 
290 
291  if (!petsc_mat)
292  mooseError("Could not convert to Petsc matrix.");
293 
294  petsc_mat->close();
295 
296  ISColoring iscoloring;
297 
298  // PETSc 3.5.x
299  MatColoring matcoloring;
300  LibmeshPetscCallA(_communicator.get(), MatColoringCreate(petsc_mat->mat(), &matcoloring));
301  LibmeshPetscCallA(_communicator.get(), MatColoringSetType(matcoloring, MATCOLORINGLF));
302  LibmeshPetscCallA(_communicator.get(), MatColoringSetFromOptions(matcoloring));
303  LibmeshPetscCallA(_communicator.get(), MatColoringApply(matcoloring, &iscoloring));
304  LibmeshPetscCallA(_communicator.get(), MatColoringDestroy(&matcoloring));
305 
306  LibmeshPetscCallA(_communicator.get(),
307  MatFDColoringCreate(petsc_mat->mat(), iscoloring, &_fdcoloring));
308  LibmeshPetscCallA(_communicator.get(), MatFDColoringSetFromOptions(_fdcoloring));
309  // clang-format off
310 #if PETSC_VERSION_LESS_THAN(3, 24, 0)
311  LibmeshPetscCallA(_communicator.get(),
312  MatFDColoringSetFunction(_fdcoloring,
313  (PetscErrorCode(*)(void))(void (*)(void))
315  &petsc_nonlinear_solver));
316 #else
317  LibmeshPetscCallA(_communicator.get(),
318  MatFDColoringSetFunction(_fdcoloring,
319  (MatFDColoringFn*)
321  &petsc_nonlinear_solver));
322 #endif
323  // clang-format on
324  LibmeshPetscCallA(_communicator.get(),
325  MatFDColoringSetUp(petsc_mat->mat(), iscoloring, _fdcoloring));
326  LibmeshPetscCallA(_communicator.get(),
327  SNESSetJacobian(petsc_nonlinear_solver.snes(),
328  petsc_mat->mat(),
329  petsc_mat->mat(),
330  SNESComputeJacobianDefaultColor,
331  _fdcoloring));
332  // PETSc >=3.3.0
333  LibmeshPetscCallA(_communicator.get(), ISColoringDestroy(&iscoloring));
334 }
335 
336 bool
338 {
340  return false;
341  // When not computing the residual (for example at the beginning of a time step),
342  // we may be in the process of counting invalid solution warnings, so the call to
343  // acceptInvalidSolution() would fail due to lack of parallel synchronization
344  // TODO: think of a better solution
346  {
347  mooseWarning("The solution is not converged due to the solution being invalid.");
348  return false;
349  }
350  return _nl_implicit_sys.nonlinear_solver->converged;
351 }
352 
353 void
355 {
356  nonlinearSolver()->attach_preconditioner(preconditioner);
357 }
358 
359 void
361 {
363 }
364 
365 void
367 {
369 }
370 
371 SNES
373 {
374  PetscNonlinearSolver<Number> * petsc_solver =
376 
377  if (petsc_solver)
378  {
379  const char * snes_prefix = nullptr;
380  std::string snes_prefix_str;
381  if (system().prefix_with_name())
382  {
383  snes_prefix_str = system().prefix();
384  snes_prefix = snes_prefix_str.c_str();
385  }
386  return petsc_solver->snes(snes_prefix);
387  }
388  else
389  mooseError("It is not a petsc nonlinear solver");
390 }
391 
392 void
394 {
396  mooseError(
397  "Evaluting the residual and Jacobian together does not make sense for a JFNK solve type in "
398  "which only function evaluations are required, e.g. there is no need to form a matrix");
399 
400  nonlinearSolver()->residual_object = nullptr;
401  nonlinearSolver()->jacobian = nullptr;
402  nonlinearSolver()->residual_and_jacobian_object = &_resid_and_jac_functor;
403 }
std::string name(const ElemQuality q)
std::vector< std::shared_ptr< TimeIntegrator > > _time_integrators
Time integrator.
Definition: SystemBase.h:1049
void compute_jacobian(const NumericVector< Number > &soln, SparseMatrix< Number > &jacobian, NonlinearImplicitSystem &sys)
SNES snes(const char *name=nullptr)
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver() override
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
virtual void solve() override
Solve the system (using libMesh magic)
PetscErrorCode libmesh_petsc_snes_fd_residual(SNES, Vec x, Vec r, void *ctx)
libMesh::NonlinearImplicitSystem & _nl_implicit_sys
void use_default_monitor(bool state)
void checkInvalidSolution()
Definition: SolverSystem.C:165
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
void compute_nearnullspace(std::vector< NumericVector< Number > *> &sp, NonlinearImplicitSystem &sys)
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:345
const EquationSystems & get_equation_systems() const
NonlinearSystem(FEProblemBase &problem, const std::string &name)
virtual void setupFiniteDifferencedPreconditioner() override
NumericVector< Number > * rhs
ComputeResidualFunctor _nl_residual_functor
void compute_bounds(NumericVector< Number > &lower, NumericVector< Number > &upper, NonlinearImplicitSystem &sys)
virtual void computeNearNullSpace(libMesh::NonlinearImplicitSystem &sys, std::vector< NumericVector< libMesh::Number > *> &sp)
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
unsigned int n_nonlinear_iterations() const
std::unique_ptr< libMesh::DiagonalMatrix< Number > > _scaling_matrix
A diagonal matrix used for computing scaling.
const Parallel::Communicator & _communicator
virtual void residualAndJacobianTogether() override
Call this method if you want the residual and Jacobian to be computed simultaneously.
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
Real _pre_smo_residual
The pre-SMO residual, see setPreSMOResidual for a detailed explanation.
bool hasDampers()
Whether or not this system has dampers.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
virtual void computeJacobianSys(libMesh::NonlinearImplicitSystem &sys, const NumericVector< libMesh::Number > &soln, libMesh::SparseMatrix< libMesh::Number > &jacobian)
Form a Jacobian matrix.
auto max(const L &left, const R &right)
Nonlinear system to be solved.
void compute_postcheck(const NumericVector< Number > &old_soln, NumericVector< Number > &search_direction, NumericVector< Number > &new_soln, bool &changed_search_direction, bool &changed_new_soln, NonlinearImplicitSystem &sys)
virtual void stopSolve(const ExecFlagType &exec_flag, const std::set< TagID > &vector_tags_to_close) override
Quit the current solve as soon as possible.
virtual void computeResidualSys(libMesh::NonlinearImplicitSystem &sys, const NumericVector< libMesh::Number > &soln, NumericVector< libMesh::Number > &residual)
This function is called by Libmesh to form a residual.
const T & get(std::string_view) const
virtual Real l2_norm() const=0
ComputeFDResidualFunctor _fd_residual_functor
virtual bool shouldUpdateSolution()
Check to see whether the problem should update the solution.
std::string prefix() const
ComputeResidualAndJacobian _resid_and_jac_functor
SolutionInvalidity & solutionInvalidity()
Get the SolutionInvalidity for this app.
Definition: MooseApp.h:184
std::shared_ptr< MoosePreconditioner > _preconditioner
Preconditioner.
Jacobian-Free Newton Krylov.
Definition: MooseTypes.h:894
bool _use_finite_differenced_preconditioner
Whether or not to use a finite differenced preconditioner.
void needsPreviousNewtonIteration(bool state)
Set a flag that indicated that user required values for the previous Newton iterate.
void setupColoringFiniteDifferencedPreconditioner()
According to the nonzero pattern provided in the matrix, a graph is constructed.
bool shouldEvaluatePreSMOResidual() const
We offer the option to check convergence against the pre-SMO residual.
Moose::SolveType _type
Definition: SolverParams.h:19
virtual void computeNullSpace(libMesh::NonlinearImplicitSystem &sys, std::vector< NumericVector< libMesh::Number > *> &sp)
void compute_transpose_nullspace(std::vector< NumericVector< Number > *> &sp, NonlinearImplicitSystem &sys)
bool _use_coloring_finite_difference
void computeScalingResidual() override
Compute a "residual" for automatic scaling purposes.
virtual libMesh::NonlinearImplicitSystem & sys()
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1158
const ExecFlagType EXEC_LINEAR
Definition: Moose.C:31
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
void closeTaggedVectors(const std::set< TagID > &tags)
Close all vectors for given tags.
Definition: SystemBase.C:668
virtual NumericVector< Number > & RHS() override
virtual void solve()
virtual void close()=0
virtual bool converged() override
Returns the convergence state.
const NumericVector< Number > * _current_solution
solution vector from solver
Definition: SolverSystem.h:120
void set_residual_zero_out(bool state)
void set_jacobian_zero_out(bool state)
bool hasSynced() const
Whether the solution invalidity has synchronized iteration counts across MPI processes.
virtual SNES getSNES() override
const ExecFlagType EXEC_POSTCHECK
Definition: Moose.C:35
const ExecFlagType EXEC_NONLINEAR
Definition: Moose.C:33
MooseApp & _app
Definition: SystemBase.h:988
FEProblemBase & _fe_problem
the governing finite element/volume problem
Definition: SystemBase.h:986
Finite difference preconditioner.
virtual void attachPreconditioner(libMesh::Preconditioner< Number > *preconditioner) override
Attach a customized preconditioner that requires physics knowledge.
virtual void potentiallySetupFiniteDifferencing() override
Create finite differencing contexts for assembly of the Jacobian and/or approximating the action of t...
Class for containing MooseEnum item information.
Definition: MooseEnumItem.h:18
static std::string outputNorm(const Real &old_norm, const Real &norm, const unsigned int precision=6)
A helper function for outputting norms in color.
Definition: Console.C:619
bool acceptInvalidSolution() const
Whether or not to accept the solution based on its invalidity.
void compute_nullspace(std::vector< NumericVector< Number > *> &sp, NonlinearImplicitSystem &sys)
if(!dmm->_nl) SETERRQ(PETSC_COMM_WORLD
virtual void computeBounds(libMesh::NonlinearImplicitSystem &sys, NumericVector< libMesh::Number > &lower, NumericVector< libMesh::Number > &upper)
virtual void computePostCheck(libMesh::NonlinearImplicitSystem &sys, const NumericVector< libMesh::Number > &old_soln, NumericVector< libMesh::Number > &search_direction, NumericVector< libMesh::Number > &new_soln, bool &changed_search_direction, bool &changed_new_soln)
void set_snesmf_reuse_base(bool state)
bool getFailNextNonlinearConvergenceCheck() const
Whether it will skip further residual evaluations and fail the next nonlinear convergence check(s) ...
NonlinearImplicitSystem::ComputeResidual * mffd_residual_object
SolverParams & solverParams(unsigned int solver_sys_num=0)
Get the solver parameters.
std::unique_ptr< NumericVector< Number > > current_local_solution
virtual void computeTransposeNullSpace(libMesh::NonlinearImplicitSystem &sys, std::vector< NumericVector< libMesh::Number > *> &sp)
void setupStandardFiniteDifferencedPreconditioner()
Form preconditioning matrix via a standard finite difference method column-by-column.
void computeScalingJacobian() override
Compute a "Jacobian" for automatic scaling purposes.
bool useSNESMFReuseBase()
Return a flag that indicates if we are reusing the vector base.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
bool preSolve()
Perform some steps to get ready for the solver.
void prefix_with_name(bool value)
virtual bool hasException()
Whether or not an exception has occurred.
const SparseMatrix< Number > & get_system_matrix() const
virtual ~NonlinearSystem()
virtual libMesh::System & system() override
Get the reference to the libMesh system.