libMesh
petsc_diff_solver.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 #include "libmesh/diff_system.h"
20 #include "libmesh/dof_map.h"
21 #include "libmesh/libmesh_logging.h"
22 #include "libmesh/petsc_diff_solver.h"
23 #include "libmesh/petsc_matrix_base.h"
24 #include "libmesh/petsc_vector.h"
25 #include "libmesh/petsc_auto_fieldsplit.h"
26 #include "libmesh/boundary_info.h"
27 
28 #ifdef LIBMESH_HAVE_PETSC
29 
30 namespace libMesh
31 {
32 
33 //--------------------------------------------------------------------
34 // Functions with C linkage to pass to PETSc. PETSc will call these
35 // methods as needed.
36 //
37 // Since they must have C linkage they have no knowledge of a namespace.
38 // Give them an obscure name to avoid namespace pollution.
39 extern "C"
40 {
41  // Function to hand to PETSc's SNES,
42  // which monitors convergence at X
43  PetscErrorCode
45  PetscInt its,
46  PetscReal fnorm,
47  void * ctx)
48  {
49  PetscFunctionBegin;
50 
51  PetscDiffSolver & solver =
52  *(static_cast<PetscDiffSolver *> (ctx));
53 
54  if (solver.verbose)
55  libMesh::out << " PetscDiffSolver step " << its
56  << ", |residual|_2 = " << fnorm << std::endl;
57  if (solver.linear_solution_monitor.get())
58  {
59  Vec petsc_delta_u;
60  LibmeshPetscCall2(solver.comm(), SNESGetSolutionUpdate(snes, &petsc_delta_u));
61  PetscVector<Number> delta_u(petsc_delta_u, solver.comm());
62  delta_u.close();
63 
64  Vec petsc_u;
65  LibmeshPetscCall2(solver.comm(), SNESGetSolution(snes, &petsc_u));
66  PetscVector<Number> u(petsc_u, solver.comm());
67  u.close();
68 
69  Vec petsc_res;
70  LibmeshPetscCall2(solver.comm(), SNESGetFunction(snes, &petsc_res, nullptr, nullptr));
71  PetscVector<Number> res(petsc_res, solver.comm());
72  res.close();
73 
74  (*solver.linear_solution_monitor)(
75  delta_u, delta_u.l2_norm(),
76  u, u.l2_norm(),
77  res, res.l2_norm(), its);
78  }
79  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
80  }
81 
82  // Functions to hand to PETSc's SNES,
83  // which compute the residual or jacobian at X
84  PetscErrorCode
85  __libmesh_petsc_diff_solver_residual (SNES, Vec x, Vec r, void * ctx)
86  {
87  PetscFunctionBegin;
88 
89  libmesh_assert(x);
90  libmesh_assert(r);
92 
93  PetscDiffSolver & solver =
94  *(static_cast<PetscDiffSolver*> (ctx));
95  ImplicitSystem & sys = solver.system();
96 
97  if (solver.verbose)
98  libMesh::out << "Assembling the residual" << std::endl;
99 
100  PetscVector<Number> & X_system =
101  *cast_ptr<PetscVector<Number> *>(sys.solution.get());
102  PetscVector<Number> & R_system =
103  *cast_ptr<PetscVector<Number> *>(sys.rhs);
104  PetscVector<Number> X_input(x, sys.comm()), R_input(r, sys.comm());
105 
106  // DiffSystem assembles from the solution and into the rhs, so swap
107  // those with our input vectors before assembling. They'll probably
108  // already be references to the same vectors, but PETSc might do
109  // something tricky.
110  X_input.swap(X_system);
111  R_input.swap(R_system);
112 
113  // We may need to localize a parallel solution
114  sys.update();
115 
116  // We may need to correct a non-conforming solution
117  if (solver.exact_constraint_enforcement())
119 
120  // Do DiffSystem assembly
121  sys.assembly(true, false, !solver.exact_constraint_enforcement());
122  R_system.close();
123 
124  // Swap back
125  X_input.swap(X_system);
126  R_input.swap(R_system);
127 
128  // No errors, we hope
129  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
130  }
131 
132 
133  PetscErrorCode
135  Vec x,
136  Mat libmesh_dbg_var(j),
137  Mat libmesh_dbg_var(pc),
138  void * ctx)
139  {
140  PetscFunctionBegin;
141 
142  libmesh_assert(x);
143  libmesh_assert(j);
144  // libmesh_assert_equal_to (pc, j); // We don't use separate preconditioners yet
146 
147  PetscDiffSolver & solver =
148  *(static_cast<PetscDiffSolver*> (ctx));
149  ImplicitSystem & sys = solver.system();
150 
151  if (solver.verbose)
152  libMesh::out << "Assembling the Jacobian" << std::endl;
153 
154  PetscVector<Number> & X_system =
155  *cast_ptr<PetscVector<Number> *>(sys.solution.get());
156  PetscVector<Number> X_input(x, sys.comm());
157 
158  PetscMatrixBase<Number> & J_system =
159  *cast_ptr<PetscMatrixBase<Number> *>(sys.matrix);
160  libmesh_assert(J_system.mat() == pc);
161 
162  // DiffSystem assembles from the solution and into the jacobian, so
163  // swap those with our input vectors before assembling. They'll
164  // probably already be references to the same vectors, but PETSc
165  // might do something tricky.
166  X_input.swap(X_system);
167 
168  // We may need to localize a parallel solution
169  sys.update();
170 
171  // We may need to correct a non-conforming solution
172  if (solver.exact_constraint_enforcement())
174 
175  // Do DiffSystem assembly
176  sys.assembly(false, true, !solver.exact_constraint_enforcement());
177  J_system.close();
178 
179  // Swap back
180  X_input.swap(X_system);
181 
182  // No errors, we hope
183  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
184  }
185 
186 } // extern "C"
187 
188 
190  : Parent(s)
191 {
192 }
193 
194 
196 {
197  LOG_SCOPE("init()", "PetscDiffSolver");
198 
199  Parent::init();
200 
201  this->setup_petsc_data();
202 }
203 
204 
205 
207 
208 
209 
211 {
212  LOG_SCOPE("clear()", "PetscDiffSolver");
213 
214  // calls custom deleter
215  _snes.destroy();
216 
217 #if !PETSC_VERSION_LESS_THAN(3,7,3)
218 #if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
219  _dm_wrapper.clear();
220 #endif
221 #endif
222 }
223 
224 
225 
227 {
228  LOG_SCOPE("reinit()", "PetscDiffSolver");
229 
230  // We need to wipe out all the old PETSc data
231  // if we are reinit'ing, since we'll need to build
232  // it all back up again.
233  this->clear();
234 
235  Parent::reinit();
236 
237  this->setup_petsc_data();
238 }
239 
240 
241 
243 {
244  switch (r)
245  {
246  case SNES_CONVERGED_FNORM_ABS:
248  case SNES_CONVERGED_FNORM_RELATIVE:
250  case SNES_CONVERGED_SNORM_RELATIVE:
252  case SNES_CONVERGED_ITS:
253  // SNES_CONVERGED_TR_DELTA was changed to a diverged condition,
254  // SNES_DIVERGED_TR_DELTA, in PETSc 1c6b2ff8df. This change will
255  // likely be in 3.12 and later releases.
256 #if PETSC_VERSION_LESS_THAN(3,12,0)
257  case SNES_CONVERGED_TR_DELTA:
258 #endif
260  case SNES_DIVERGED_FUNCTION_DOMAIN:
261  case SNES_DIVERGED_FUNCTION_COUNT:
262  case SNES_DIVERGED_FNORM_NAN:
263  case SNES_DIVERGED_INNER:
264  case SNES_DIVERGED_LINEAR_SOLVE:
265  case SNES_DIVERGED_LOCAL_MIN:
267  case SNES_DIVERGED_MAX_IT:
269  case SNES_DIVERGED_LINE_SEARCH:
271  // In PETSc, SNES_CONVERGED_ITERATING means
272  // the solve is still iterating, but by the
273  // time we get here, we must have either
274  // converged or diverged, so
275  // SNES_CONVERGED_ITERATING is invalid.
276  case SNES_CONVERGED_ITERATING:
278  default:
279  break;
280  }
282 }
283 
284 
285 
287 {
288  LOG_SCOPE("solve()", "PetscDiffSolver");
289 
290 #if !PETSC_VERSION_LESS_THAN(3,7,3)
291 #if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
292  // GMG is currently not supported if we enable children to be associated with
293  // boundary sides
295 #endif
296 #endif
297 
298  PetscVector<Number> & x =
299  *(cast_ptr<PetscVector<Number> *>(_system.solution.get()));
301  *(cast_ptr<PetscMatrixBase<Number> *>(_system.matrix));
302  PetscVector<Number> & r =
303  *(cast_ptr<PetscVector<Number> *>(_system.rhs));
304 
305  LibmeshPetscCall(SNESSetFunction (_snes, r.vec(),
307 
308  LibmeshPetscCall(SNESSetJacobian (_snes, jac.mat(), jac.mat(),
310 
311  LibmeshPetscCall(SNESSetFromOptions(_snes));
312 
313  LibmeshPetscCall(SNESSolve (_snes, LIBMESH_PETSC_NULLPTR, x.vec()));
314 
315 #ifdef LIBMESH_ENABLE_CONSTRAINTS
318 #endif
319 
320  SNESConvergedReason reason;
321  LibmeshPetscCall(SNESGetConvergedReason(_snes, &reason));
322 
323  PetscInt l_its, nl_its;
324  LibmeshPetscCall(SNESGetLinearSolveIterations(_snes, &l_its));
325  this->_inner_iterations = l_its;
326 
327  LibmeshPetscCall(SNESGetIterationNumber(_snes, &nl_its));
328  this->_outer_iterations = nl_its;
329 
330  return convert_solve_result(reason);
331 }
332 
334 {
335  LibmeshPetscCall(SNESCreate(this->comm().get(), _snes.get()));
336 
337  LibmeshPetscCall(SNESMonitorSet (_snes, __libmesh_petsc_diff_solver_monitor,
338  this, LIBMESH_PETSC_NULLPTR));
339 
340  if (libMesh::on_command_line("--solver-system-names"))
341  LibmeshPetscCall(SNESSetOptionsPrefix(_snes, (_system.name()+"_").c_str()));
342 
343  bool use_petsc_dm = libMesh::on_command_line("--use_petsc_dm");
344 
345  // This needs to be called before SNESSetFromOptions
346 #if !PETSC_VERSION_LESS_THAN(3,7,3)
347 #if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
348  if (use_petsc_dm)
350 #endif
351 #endif
352 
353  // If we're not using PETSc DM, let's keep around
354  // the old style for fieldsplit
355  if (!use_petsc_dm)
356  {
357  LibmeshPetscCall(SNESSetFromOptions(_snes));
358 
359  KSP my_ksp;
360  LibmeshPetscCall(SNESGetKSP(_snes, &my_ksp));
361 
362  PC my_pc;
363  LibmeshPetscCall(KSPGetPC(my_ksp, &my_pc));
364 
366  }
367 }
368 
369 } // namespace libMesh
370 
371 #endif // LIBMESH_HAVE_PETSC
bool exact_constraint_enforcement()
Definition: diff_solver.h:307
void petsc_auto_fieldsplit(PC my_pc, const System &sys)
This class provides a nice interface to PETSc&#39;s Vec object.
Definition: petsc_vector.h:73
virtual void init() override
The initialization function.
void clear()
The clear function.
void setup_petsc_data()
Common helper function to setup PETSc data structures.
virtual ~PetscDiffSolver()
Destructor.
bool _exact_constraint_enforcement
Whether we should enforce exact constraints globally during a solve.
Definition: diff_solver.h:318
DiffSolver::SolveResult convert_solve_result(SNESConvergedReason r)
NumericVector< Number > * rhs
The system matrix.
const Parallel::Communicator & comm() const
virtual void reinit()
The reinitialization function.
Definition: diff_solver.C:63
virtual unsigned int solve() override
This method performs a solve.
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
const MeshBase & get_mesh() const
Definition: system.h:2358
PetscDiffSolver(sys_type &system)
Constructor.
unsigned int _inner_iterations
The number of inner iterations used by the last solve.
Definition: diff_solver.h:341
virtual void swap(NumericVector< T > &v) override
Swaps the contents of this with v.
virtual void init()
The initialization function.
Definition: diff_solver.C:72
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition: diff_solver.h:68
The DiffSolver reached the maximum allowed number of nonlinear iterations before satisfying any conve...
Definition: diff_solver.h:268
This class defines a solver which uses a PETSc SNES context to handle a DifferentiableSystem.
The DiffSolver achieved the desired relative step size tolerance.
Definition: diff_solver.h:255
virtual void assembly(bool, bool, bool=false, bool=false)
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
sys_type & _system
A reference to the system we are solving.
Definition: diff_solver.h:346
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
libmesh_assert(ctx)
The DiffSolver achieved the desired relative residual tolerance.
Definition: diff_solver.h:243
const sys_type & system() const
Definition: diff_solver.h:135
bool verbose
The DiffSolver may print a lot more to libMesh::out if verbose is set to true; default is false...
Definition: diff_solver.h:166
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:510
The solver converged but no particular reason is specified.
Definition: diff_solver.h:231
PetscDMWrapper _dm_wrapper
Wrapper object for interacting with PetscDM.
WrappedPetsc< SNES > _snes
Nonlinear solver context.
The DiffSolver achieved the desired absolute residual tolerance.
Definition: diff_solver.h:237
SolveResult
Enumeration return type for the solve() function.
Definition: diff_solver.h:220
unsigned int _outer_iterations
The number of outer iterations used by the last solve.
Definition: diff_solver.h:336
OStreamProxy out
void init_and_attach_petscdm(System &system, SNES snes)
SparseMatrix< Number > * matrix
The system matrix.
PetscErrorCode __libmesh_petsc_diff_solver_jacobian(SNES, Vec x, Mat libmesh_dbg_var(j), Mat libmesh_dbg_var(pc), void *ctx)
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:1605
The DiffSolver failed to find a descent direction by backtracking (See newton_solver.C)
Definition: diff_solver.h:274
void * ctx
bool is_children_on_boundary_side() const
bool on_command_line(std::string arg)
Definition: libmesh.C:987
const std::string & name() const
Definition: system.h:2342
The DiffSolver diverged but no particular reason is specified.
Definition: diff_solver.h:261
A default or invalid solve result.
Definition: diff_solver.h:225
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
PetscErrorCode __libmesh_petsc_diff_solver_residual(SNES, Vec x, Vec r, void *ctx)
void clear()
Destroys and clears all build DM-related data.
const DofMap & get_dof_map() const
Definition: system.h:2374
virtual void reinit() override
The reinitialization function.
void destroy()
Must be specialized to call the appropriate XXXDestroy() routine in order for a WrappedPetsc<T> objec...
virtual void close() override
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
Definition: petsc_vector.h:869
std::unique_ptr< LinearSolutionMonitor > linear_solution_monitor
Pointer to functor which is called right after each linear solve.
Definition: diff_solver.h:286
void enforce_constraints_exactly(const System &system, NumericVector< Number > *v=nullptr, bool homogeneous=false) const
Constrains the numeric vector v, which represents a solution defined on the mesh. ...
Definition: dof_map.h:2350
PetscErrorCode __libmesh_petsc_diff_solver_monitor(SNES snes, PetscInt its, PetscReal fnorm, void *ctx)
Manages consistently variables, degrees of freedom, coefficient vectors, and matrices for implicit sy...