libMesh
petsc_diff_solver.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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.h"
24 #include "libmesh/petsc_vector.h"
25 #include "libmesh/petsc_auto_fieldsplit.h"
26 
27 #ifdef LIBMESH_HAVE_PETSC
28 
29 namespace libMesh
30 {
31 
32 //--------------------------------------------------------------------
33 // Functions with C linkage to pass to PETSc. PETSc will call these
34 // methods as needed.
35 //
36 // Since they must have C linkage they have no knowledge of a namespace.
37 // Give them an obscure name to avoid namespace pollution.
38 extern "C"
39 {
40  // Function to hand to PETSc's SNES,
41  // which monitors convergence at X
42  PetscErrorCode
44  PetscInt its,
45  PetscReal fnorm,
46  void * ctx)
47  {
48  PetscDiffSolver & solver =
49  *(static_cast<PetscDiffSolver *> (ctx));
50 
51  if (solver.verbose)
52  libMesh::out << " PetscDiffSolver step " << its
53  << ", |residual|_2 = " << fnorm << std::endl;
54  if (solver.linear_solution_monitor.get()) {
55  int ierr = 0;
56 
57  Vec petsc_delta_u;
58  ierr = SNESGetSolutionUpdate(snes, &petsc_delta_u);
59  CHKERRABORT(solver.comm().get(), ierr);
60  PetscVector<Number> delta_u(petsc_delta_u, solver.comm());
61  delta_u.close();
62 
63  Vec petsc_u;
64  ierr = SNESGetSolution(snes, &petsc_u);
65  CHKERRABORT(solver.comm().get(), ierr);
66  PetscVector<Number> u(petsc_u, solver.comm());
67  u.close();
68 
69  Vec petsc_res;
70  ierr = SNESGetFunction(snes, &petsc_res, nullptr, nullptr);
71  CHKERRABORT(solver.comm().get(), ierr);
72  PetscVector<Number> res(petsc_res, solver.comm());
73  res.close();
74 
75  (*solver.linear_solution_monitor)(
76  delta_u, delta_u.l2_norm(),
77  u, u.l2_norm(),
78  res, res.l2_norm(), its);
79  }
80  return 0;
81  }
82 
83  // Functions to hand to PETSc's SNES,
84  // which compute the residual or jacobian at X
85  PetscErrorCode
86  __libmesh_petsc_diff_solver_residual (SNES, Vec x, Vec r, void * ctx)
87  {
88  libmesh_assert(x);
89  libmesh_assert(r);
91 
92  PetscDiffSolver & solver =
93  *(static_cast<PetscDiffSolver*> (ctx));
94  ImplicitSystem & sys = solver.system();
95 
96  if (solver.verbose)
97  libMesh::out << "Assembling the residual" << std::endl;
98 
99  PetscVector<Number> & X_system =
100  *cast_ptr<PetscVector<Number> *>(sys.solution.get());
101  PetscVector<Number> & R_system =
102  *cast_ptr<PetscVector<Number> *>(sys.rhs);
103  PetscVector<Number> X_input(x, sys.comm()), R_input(r, sys.comm());
104 
105  // DiffSystem assembles from the solution and into the rhs, so swap
106  // those with our input vectors before assembling. They'll probably
107  // already be references to the same vectors, but PETSc might do
108  // something tricky.
109  X_input.swap(X_system);
110  R_input.swap(R_system);
111 
112  // We may need to localize a parallel solution
113  sys.update();
114 
115  // We may need to correct a non-conforming solution
117 
118  // Do DiffSystem assembly
119  sys.assembly(true, false);
120  R_system.close();
121 
122  // Swap back
123  X_input.swap(X_system);
124  R_input.swap(R_system);
125 
126  // No errors, we hope
127  return 0;
128  }
129 
130 
131  PetscErrorCode
133  Vec x,
134 #if PETSC_RELEASE_LESS_THAN(3,5,0)
135  Mat * libmesh_dbg_var(j),
136  Mat * pc,
137  MatStructure * msflag,
138 #else
139  Mat libmesh_dbg_var(j),
140  Mat pc,
141 #endif
142  void * ctx)
143  {
144  libmesh_assert(x);
145  libmesh_assert(j);
146  // libmesh_assert_equal_to (pc, j); // We don't use separate preconditioners yet
148 
149  PetscDiffSolver & solver =
150  *(static_cast<PetscDiffSolver*> (ctx));
151  ImplicitSystem & sys = solver.system();
152 
153  if (solver.verbose)
154  libMesh::out << "Assembling the Jacobian" << std::endl;
155 
156  PetscVector<Number> & X_system =
157  *cast_ptr<PetscVector<Number> *>(sys.solution.get());
158  PetscVector<Number> X_input(x, sys.comm());
159 
160 #if PETSC_RELEASE_LESS_THAN(3,5,0)
161  PetscMatrix<Number> J_input(*pc, sys.comm());
162 #else
163  PetscMatrix<Number> J_input(pc, sys.comm());
164 #endif
165  PetscMatrix<Number> & J_system =
166  *cast_ptr<PetscMatrix<Number> *>(sys.matrix);
167 
168  // DiffSystem assembles from the solution and into the jacobian, so
169  // swap those with our input vectors before assembling. They'll
170  // probably already be references to the same vectors, but PETSc
171  // might do something tricky.
172  X_input.swap(X_system);
173  J_input.swap(J_system);
174 
175  // We may need to localize a parallel solution
176  sys.update();
177 
178  // We may need to correct a non-conforming solution
180 
181  // Do DiffSystem assembly
182  sys.assembly(false, true);
183  J_system.close();
184 
185  // Swap back
186  X_input.swap(X_system);
187  J_input.swap(J_system);
188 
189 #if PETSC_RELEASE_LESS_THAN(3,5,0)
190  *msflag = SAME_NONZERO_PATTERN;
191 #endif
192  // No errors, we hope
193  return 0;
194  }
195 
196 } // extern "C"
197 
198 
200  : Parent(s)
201 {
202 }
203 
204 
206 {
207  LOG_SCOPE("init()", "PetscDiffSolver");
208 
209  Parent::init();
210 
211  this->setup_petsc_data();
212 }
213 
214 
215 
217 {
218  this->clear();
219 }
220 
221 
222 
224 {
225  LOG_SCOPE("clear()", "PetscDiffSolver");
226 
227  int ierr = LibMeshSNESDestroy(&_snes);
228  LIBMESH_CHKERR(ierr);
229 
230 #if !PETSC_VERSION_LESS_THAN(3,7,3)
231 #if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
232  _dm_wrapper.clear();
233 #endif
234 #endif
235 }
236 
237 
238 
240 {
241  LOG_SCOPE("reinit()", "PetscDiffSolver");
242 
243  // We need to wipe out all the old PETSc data
244  // if we are reinit'ing, since we'll need to build
245  // it all back up again.
246  this->clear();
247 
248  Parent::reinit();
249 
250  this->setup_petsc_data();
251 }
252 
253 
254 
256 {
257  switch (r)
258  {
259  case SNES_CONVERGED_FNORM_ABS:
261  case SNES_CONVERGED_FNORM_RELATIVE:
263 #if PETSC_VERSION_LESS_THAN(3,2,1)
264  case SNES_CONVERGED_PNORM_RELATIVE:
265 #else
266  case SNES_CONVERGED_SNORM_RELATIVE:
267 #endif
269  case SNES_CONVERGED_ITS:
270  // SNES_CONVERGED_TR_DELTA was changed to a diverged condition,
271  // SNES_DIVERGED_TR_DELTA, in PETSc 1c6b2ff8df. This change will
272  // likely be in 3.12 and later releases.
273 #if PETSC_RELEASE_LESS_THAN(3,12,0)
274  case SNES_CONVERGED_TR_DELTA:
275 #endif
277  case SNES_DIVERGED_FUNCTION_DOMAIN:
278  case SNES_DIVERGED_FUNCTION_COUNT:
279  case SNES_DIVERGED_FNORM_NAN:
280 #if !PETSC_VERSION_LESS_THAN(3,3,0)
281  case SNES_DIVERGED_INNER:
282 #endif
283  case SNES_DIVERGED_LINEAR_SOLVE:
284  case SNES_DIVERGED_LOCAL_MIN:
286  case SNES_DIVERGED_MAX_IT:
288 #if PETSC_VERSION_LESS_THAN(3,2,0)
289  case SNES_DIVERGED_LS_FAILURE:
290 #else
291  case SNES_DIVERGED_LINE_SEARCH:
292 #endif
294  // In PETSc, SNES_CONVERGED_ITERATING means
295  // the solve is still iterating, but by the
296  // time we get here, we must have either
297  // converged or diverged, so
298  // SNES_CONVERGED_ITERATING is invalid.
299  case SNES_CONVERGED_ITERATING:
301  default:
302  break;
303  }
305 }
306 
307 
308 
310 {
311  LOG_SCOPE("solve()", "PetscDiffSolver");
312 
313  PetscVector<Number> & x =
314  *(cast_ptr<PetscVector<Number> *>(_system.solution.get()));
315  PetscMatrix<Number> & jac =
316  *(cast_ptr<PetscMatrix<Number> *>(_system.matrix));
317  PetscVector<Number> & r =
318  *(cast_ptr<PetscVector<Number> *>(_system.rhs));
319 
320  int ierr = 0;
321 
322  ierr = SNESSetFunction (_snes, r.vec(),
324  LIBMESH_CHKERR(ierr);
325 
326  ierr = SNESSetJacobian (_snes, jac.mat(), jac.mat(),
328  LIBMESH_CHKERR(ierr);
329 
330  ierr = SNESSetFromOptions(_snes);
331  LIBMESH_CHKERR(ierr);
332 
333  ierr = SNESSolve (_snes, PETSC_NULL, x.vec());
334  LIBMESH_CHKERR(ierr);
335 
336 #ifdef LIBMESH_ENABLE_CONSTRAINTS
338 #endif
339 
340  SNESConvergedReason reason;
341  SNESGetConvergedReason(_snes, &reason);
342 
343  PetscInt l_its, nl_its;
344  ierr = SNESGetLinearSolveIterations(_snes,&l_its);
345  LIBMESH_CHKERR(ierr);
346  this->_inner_iterations = l_its;
347 
348  ierr = SNESGetIterationNumber(_snes,&nl_its);
349  LIBMESH_CHKERR(ierr);
350  this->_outer_iterations = nl_its;
351 
352  return convert_solve_result(reason);
353 }
354 
356 {
357  int ierr=0;
358 
359  ierr = SNESCreate(this->comm().get(),&_snes);
360  LIBMESH_CHKERR(ierr);
361 
363  this, PETSC_NULL);
364  LIBMESH_CHKERR(ierr);
365 
366  if (libMesh::on_command_line("--solver-system-names"))
367  {
368  ierr = SNESSetOptionsPrefix(_snes, (_system.name()+"_").c_str());
369  LIBMESH_CHKERR(ierr);
370  }
371 
372  bool use_petsc_dm = libMesh::on_command_line("--use_petsc_dm");
373 
374  // This needs to be called before SNESSetFromOptions
375 #if !PETSC_VERSION_LESS_THAN(3,7,3)
376 #if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
377  if (use_petsc_dm)
379 #endif
380 #endif
381 
382  // If we're not using PETSc DM, let's keep around
383  // the old style for fieldsplit
384  if (!use_petsc_dm)
385  {
386  ierr = SNESSetFromOptions(_snes);
387  LIBMESH_CHKERR(ierr);
388 
389  KSP my_ksp;
390  ierr = SNESGetKSP(_snes, &my_ksp);
391  LIBMESH_CHKERR(ierr);
392 
393  PC my_pc;
394  ierr = KSPGetPC(my_ksp, &my_pc);
395  LIBMESH_CHKERR(ierr);
396 
398  }
399 }
400 
401 } // namespace libMesh
402 
403 #endif // LIBMESH_HAVE_PETSC
libMesh::DiffSolver::reinit
virtual void reinit()
The reinitialization function.
Definition: diff_solver.C:60
libMesh::PetscDiffSolver::clear
void clear()
The clear function.
Definition: petsc_diff_solver.C:223
libMesh::__libmesh_petsc_diff_solver_residual
PetscErrorCode __libmesh_petsc_diff_solver_residual(SNES, Vec x, Vec r, void *ctx)
Definition: petsc_diff_solver.C:86
libMesh::ImplicitSystem
Manages consistently variables, degrees of freedom, coefficient vectors, and matrices for implicit sy...
Definition: implicit_system.h:57
libMesh::ExplicitSystem::rhs
NumericVector< Number > * rhs
The system matrix.
Definition: explicit_system.h:114
libMesh::DiffSolver::CONVERGED_RELATIVE_STEP
The DiffSolver achieved the desired relative step size tolerance.
Definition: diff_solver.h:257
libMesh::PetscDiffSolver::~PetscDiffSolver
virtual ~PetscDiffSolver()
Destructor.
Definition: petsc_diff_solver.C:216
libMesh::PetscDiffSolver::_dm_wrapper
PetscDMWrapper _dm_wrapper
Wrapper object for interacting with PetscDM.
Definition: petsc_diff_solver.h:107
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::PetscMatrix::mat
Mat mat()
Definition: petsc_matrix.h:281
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::DiffSolver
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition: diff_solver.h:70
libMesh::DiffSolver::DIVERGED_BACKTRACKING_FAILURE
The DiffSolver failed to find a descent direction by backtracking (See newton_solver....
Definition: diff_solver.h:276
libMesh::DiffSolver::CONVERGED_RELATIVE_RESIDUAL
The DiffSolver achieved the desired relative residual tolerance.
Definition: diff_solver.h:245
libMesh::DiffSolver::system
const sys_type & system() const
Definition: diff_solver.h:137
libMesh::DiffSolver::_inner_iterations
unsigned int _inner_iterations
The number of inner iterations used by the last solve.
Definition: diff_solver.h:313
libMesh::ierr
ierr
Definition: petsc_dm_wrapper.C:72
libMesh::DiffSolver::init
virtual void init()
The initialization function.
Definition: diff_solver.C:69
libMesh::__libmesh_petsc_diff_solver_jacobian
PetscErrorCode __libmesh_petsc_diff_solver_jacobian(SNES, Vec x, #if PETSC_RELEASE_LESS_THAN(3, 5, 0) Mat *libmesh_dbg_var(j), Mat *pc, MatStructure *msflag, #else Mat libmesh_dbg_var(j), Mat pc, #endif void *ctx)
Definition: petsc_diff_solver.C:132
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::convert_solve_result
DiffSolver::SolveResult convert_solve_result(SNESConvergedReason r)
Definition: petsc_diff_solver.C:255
libMesh::PetscVector::close
virtual void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
Definition: petsc_vector.h:821
libMesh::PetscDiffSolver::setup_petsc_data
void setup_petsc_data()
Common helper function to setup PETSc data structures.
Definition: petsc_diff_solver.C:355
libMesh::DiffSolver::verbose
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:168
libMesh::ImplicitSystem::assembly
virtual void assembly(bool, bool, bool=false, bool=false)
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
Definition: implicit_system.h:161
libMesh::DofMap::enforce_constraints_exactly
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:2054
libMesh::System::current_local_solution
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:1551
libMesh::ImplicitSystem::matrix
SparseMatrix< Number > * matrix
The system matrix.
Definition: implicit_system.h:393
libMesh::PetscMatrix::swap
void swap(PetscMatrix< T > &)
Swaps the internal data pointers of two PetscMatrices, no actual values are swapped.
Definition: petsc_matrix.C:1338
libMesh::PetscVector
This class provides a nice interface to PETSc's Vec object.
Definition: petsc_vector.h:72
libMesh::DiffSolver::CONVERGED_NO_REASON
The solver converged but no particular reason is specified.
Definition: diff_solver.h:233
libMesh::DiffSolver::CONVERGED_ABSOLUTE_RESIDUAL
The DiffSolver achieved the desired absolute residual tolerance.
Definition: diff_solver.h:239
libMesh::DiffSolver::DIVERGED_NO_REASON
The DiffSolver diverged but no particular reason is specified.
Definition: diff_solver.h:263
libMesh::PetscDMWrapper::init_and_attach_petscdm
void init_and_attach_petscdm(System &system, SNES &snes)
Definition: petsc_dm_wrapper.C:445
libMesh::DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS
The DiffSolver reached the maximum allowed number of nonlinear iterations before satisfying any conve...
Definition: diff_solver.h:270
libMesh::PetscDMWrapper::clear
void clear()
Destroys and clears all build DM-related data.
Definition: petsc_dm_wrapper.C:430
libMesh::System::solution
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1539
libMesh::DiffSolver::linear_solution_monitor
std::unique_ptr< LinearSolutionMonitor > linear_solution_monitor
Pointer to functor which is called right after each linear solve.
Definition: diff_solver.h:288
libMesh::ReferenceElem::get
const Elem & get(const ElemType type_in)
Definition: reference_elem.C:237
libMesh::DiffSolver::SolveResult
SolveResult
Enumeration return type for the solve() function.
Definition: diff_solver.h:222
libMesh::DiffSolver::_outer_iterations
unsigned int _outer_iterations
The number of outer iterations used by the last solve.
Definition: diff_solver.h:308
libMesh::PetscMatrix
This class provides a nice interface to the PETSc C-based data structures for parallel,...
Definition: petsc_matrix.h:87
libMesh::System::name
const std::string & name() const
Definition: system.h:2067
libMesh::PetscDiffSolver::reinit
virtual void reinit() override
The reinitialization function.
Definition: petsc_diff_solver.C:239
libMesh::PetscDiffSolver::solve
virtual unsigned int solve() override
This method performs a solve.
Definition: petsc_diff_solver.C:309
libMesh::ctx
void * ctx
Definition: petsc_dm_wrapper.C:71
libMesh::PetscDiffSolver::PetscDiffSolver
PetscDiffSolver(sys_type &system)
Constructor.
Definition: petsc_diff_solver.C:199
libMesh::on_command_line
bool on_command_line(std::string arg)
Definition: libmesh.C:898
libMesh::__libmesh_petsc_diff_solver_monitor
PetscErrorCode __libmesh_petsc_diff_solver_monitor(SNES snes, PetscInt its, PetscReal fnorm, void *ctx)
Definition: petsc_diff_solver.C:43
libMesh::PetscVector::vec
Vec vec()
Definition: petsc_vector.h:335
libMesh::System::get_dof_map
const DofMap & get_dof_map() const
Definition: system.h:2099
libMesh::PetscDiffSolver
This class defines a solver which uses a PETSc SNES context to handle a DifferentiableSystem.
Definition: petsc_diff_solver.h:55
libMesh::PetscVector::swap
virtual void swap(NumericVector< T > &v) override
Swaps the contents of this with v.
Definition: petsc_vector.h:1194
libMesh::petsc_auto_fieldsplit
void petsc_auto_fieldsplit(PC my_pc, const System &sys)
Definition: petsc_auto_fieldsplit.C:58
libMesh::out
OStreamProxy out
libMesh::PetscDiffSolver::init
virtual void init() override
The initialization function.
Definition: petsc_diff_solver.C:205
libMesh::System::update
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:408
libMesh::DiffSolver::_system
sys_type & _system
A reference to the system we are solving.
Definition: diff_solver.h:318
libMesh::PetscDiffSolver::_snes
SNES _snes
Nonlinear solver context.
Definition: petsc_diff_solver.h:100
libMesh::DiffSolver::INVALID_SOLVE_RESULT
A default or invalid solve result.
Definition: diff_solver.h:227