libMesh
Loading...
Searching...
No Matches
petsc_diff_solver.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#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
30namespace 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.
39extern "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
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
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
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
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)
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
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#if PETSC_VERSION_LESS_THAN(3,25,0)
263 case SNES_DIVERGED_FNORM_NAN:
264#else
265 case SNES_DIVERGED_FUNCTION_NANORINF:
266#endif
267#if !PETSC_VERSION_LESS_THAN(3,12,0)
268 case SNES_DIVERGED_TR_DELTA:
269#endif
270 case SNES_DIVERGED_INNER:
271 case SNES_DIVERGED_LINEAR_SOLVE:
272 case SNES_DIVERGED_LOCAL_MIN:
274 case SNES_DIVERGED_MAX_IT:
276 case SNES_DIVERGED_LINE_SEARCH:
278 // In PETSc, SNES_CONVERGED_ITERATING means
279 // the solve is still iterating, but by the
280 // time we get here, we must have either
281 // converged or diverged, so
282 // SNES_CONVERGED_ITERATING is invalid.
283 case SNES_CONVERGED_ITERATING:
285 default:
286 break;
287 }
289}
290
291
292
294{
295 LOG_SCOPE("solve()", "PetscDiffSolver");
296
297#if !PETSC_VERSION_LESS_THAN(3,7,3)
298#if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
299 // GMG is currently not supported if we enable children to be associated with
300 // boundary sides
302#endif
303#endif
304
306 *(cast_ptr<PetscVector<Number> *>(_system.solution.get()));
308 *(cast_ptr<PetscMatrixBase<Number> *>(_system.matrix));
310 *(cast_ptr<PetscVector<Number> *>(_system.rhs));
311
312 LibmeshPetscCall(SNESSetFunction (_snes, r.vec(),
314
315 LibmeshPetscCall(SNESSetJacobian (_snes, jac.mat(), jac.mat(),
317
318 LibmeshPetscCall(SNESSetFromOptions(_snes));
319
320 LibmeshPetscCall(SNESSolve (_snes, LIBMESH_PETSC_NULLPTR, x.vec()));
321
322#ifdef LIBMESH_ENABLE_CONSTRAINTS
325#endif
326
327 SNESConvergedReason reason;
328 LibmeshPetscCall(SNESGetConvergedReason(_snes, &reason));
329
330 PetscInt l_its, nl_its;
331 LibmeshPetscCall(SNESGetLinearSolveIterations(_snes, &l_its));
332 this->_inner_iterations = l_its;
333
334 LibmeshPetscCall(SNESGetIterationNumber(_snes, &nl_its));
335 this->_outer_iterations = nl_its;
336
337 return convert_solve_result(reason);
338}
339
341{
342 LibmeshPetscCall(SNESCreate(this->comm().get(), _snes.get()));
343
344 LibmeshPetscCall(SNESMonitorSet (_snes, __libmesh_petsc_diff_solver_monitor,
345 this, LIBMESH_PETSC_NULLPTR));
346
347 if (libMesh::on_command_line("--solver-system-names"))
348 LibmeshPetscCall(SNESSetOptionsPrefix(_snes, (_system.name()+"_").c_str()));
349
350 bool use_petsc_dm = libMesh::on_command_line("--use_petsc_dm");
351
352 // This needs to be called before SNESSetFromOptions
353#if !PETSC_VERSION_LESS_THAN(3,7,3)
354#if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
355 if (use_petsc_dm)
357#endif
358#endif
359
360 // If we're not using PETSc DM, let's keep around
361 // the old style for fieldsplit
362 if (!use_petsc_dm)
363 {
364 LibmeshPetscCall(SNESSetFromOptions(_snes));
365
366 KSP my_ksp;
367 LibmeshPetscCall(SNESGetKSP(_snes, &my_ksp));
368
369 PC my_pc;
370 LibmeshPetscCall(KSPGetPC(my_ksp, &my_pc));
371
373 }
374}
375
376} // namespace libMesh
377
378#endif // LIBMESH_HAVE_PETSC
bool is_children_on_boundary_side() const
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition diff_solver.h:70
unsigned int _inner_iterations
The number of inner iterations used by the last solve.
std::unique_ptr< LinearSolutionMonitor > linear_solution_monitor
Pointer to functor which is called right after each linear solve.
bool exact_constraint_enforcement()
const sys_type & system() const
virtual void init()
The initialization function.
Definition diff_solver.C:72
sys_type & _system
A reference to the system we are solving.
SolveResult
Enumeration return type for the solve() function.
@ DIVERGED_BACKTRACKING_FAILURE
The DiffSolver failed to find a descent direction by backtracking (See newton_solver....
@ DIVERGED_MAX_NONLINEAR_ITERATIONS
The DiffSolver reached the maximum allowed number of nonlinear iterations before satisfying any conve...
@ CONVERGED_RELATIVE_STEP
The DiffSolver achieved the desired relative step size tolerance.
@ CONVERGED_ABSOLUTE_RESIDUAL
The DiffSolver achieved the desired absolute residual tolerance.
@ DIVERGED_NO_REASON
The DiffSolver diverged but no particular reason is specified.
@ CONVERGED_NO_REASON
The solver converged but no particular reason is specified.
@ INVALID_SOLVE_RESULT
A default or invalid solve result.
@ CONVERGED_RELATIVE_RESIDUAL
The DiffSolver achieved the desired relative residual tolerance.
unsigned int _outer_iterations
The number of outer iterations used by the last solve.
virtual void reinit()
The reinitialization function.
Definition diff_solver.C:63
bool _exact_constraint_enforcement
Whether we should enforce exact constraints globally during a solve.
bool verbose
The DiffSolver may print a lot more to libMesh::out if verbose is set to true; default is false.
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:2518
NumericVector< Number > * rhs
The system matrix.
Manages consistently variables, degrees of freedom, coefficient vectors, and matrices for implicit sy...
SparseMatrix< Number > * matrix
The system matrix.
virtual void assembly(bool, bool, bool=false, bool=false)
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
const Parallel::Communicator & comm() const
void init_and_attach_petscdm(System &system, SNES snes)
void clear()
Destroys and clears all build DM-related data.
This class defines a solver which uses a PETSc SNES context to handle a DifferentiableSystem.
virtual unsigned int solve() override
This method performs a solve.
void clear()
The clear function.
virtual void init() override
The initialization function.
void setup_petsc_data()
Common helper function to setup PETSc data structures.
PetscDMWrapper _dm_wrapper
Wrapper object for interacting with PetscDM.
PetscDiffSolver(sys_type &system)
Constructor.
virtual void reinit() override
The reinitialization function.
virtual ~PetscDiffSolver()
Destructor.
WrappedPetsc< SNES > _snes
Nonlinear solver context.
This class provides a nice interface to the PETSc C-based data structures for parallel,...
virtual void close() override
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
This class provides a nice interface to PETSc's Vec object.
virtual void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual Real l2_norm() const override
const std::string & name() const
Definition system.h:2385
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
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
const DofMap & get_dof_map() const
Definition system.h:2417
const MeshBase & get_mesh() const
Definition system.h:2401
The libMesh namespace provides an interface to certain functionality in the library.
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
PetscErrorCode __libmesh_petsc_diff_solver_monitor(SNES snes, PetscInt its, PetscReal fnorm, void *ctx)
libmesh_assert(ctx)
DiffSolver::SolveResult convert_solve_result(SNESConvergedReason r)
OStreamProxy out
PetscErrorCode __libmesh_petsc_diff_solver_jacobian(SNES, Vec x, Mat libmesh_dbg_var(j), Mat libmesh_dbg_var(pc), void *ctx)
void petsc_auto_fieldsplit(PC my_pc, const System &sys)
bool on_command_line(std::string arg)
Definition libmesh.C:934
PetscErrorCode __libmesh_petsc_diff_solver_residual(SNES, Vec x, Vec r, void *ctx)
void destroy()
Must be specialized to call the appropriate XXXDestroy() routine in order for a WrappedPetsc<T> objec...