libMesh
petsc_nonlinear_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 
20 #include "libmesh/libmesh_common.h"
21 
22 #ifdef LIBMESH_HAVE_PETSC
23 
24 // Local Includes
25 #include "libmesh/libmesh_logging.h"
26 #include "libmesh/nonlinear_implicit_system.h"
27 #include "libmesh/petsc_nonlinear_solver.h"
28 #include "libmesh/petsc_linear_solver.h"
29 #include "libmesh/petsc_vector.h"
30 #include "libmesh/petsc_mffd_matrix.h"
31 #include "libmesh/dof_map.h"
32 #include "libmesh/preconditioner.h"
33 #include "libmesh/solver_configuration.h"
34 #include "libmesh/petscdmlibmesh.h"
35 #include "libmesh/petsc_mffd_matrix.h"
36 
37 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \
38  !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE)
39 #include <HYPRE_utilities.h>
40 #endif
41 
42 namespace libMesh
43 {
45 {
46 public:
48  solver(solver_in),
49  sys(sys_in)
50  {}
51 
54 };
55 
57 libmesh_petsc_snes_residual_helper (SNES snes, Vec x, void * ctx)
58 {
59  LOG_SCOPE("residual()", "PetscNonlinearSolver");
60 
61  libmesh_assert(x);
63 
64  // No way to safety-check this cast, since we got a void *...
66  static_cast<PetscNonlinearSolver<Number> *> (ctx);
67 
68  libmesh_parallel_only(solver->comm());
69 
70  // Get the current iteration number from the snes object,
71  // store it in the PetscNonlinearSolver object for possible use
72  // by the user's residual function.
73  {
74  PetscInt n_iterations = 0;
75  LibmeshPetscCall2(solver->comm(), SNESGetIterationNumber(snes, &n_iterations));
76  solver->_current_nonlinear_iteration_number = cast_int<unsigned>(n_iterations);
77  }
78 
79  NonlinearImplicitSystem & sys = solver->system();
80 
81  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
82 
83  PetscVector<Number> X_global(x, sys.comm());
84 
85  // Use the system's update() to get a good local version of the
86  // parallel solution. This operation does not modify the incoming
87  // "x" vector, it only localizes information from "x" into
88  // sys.current_local_solution.
89  X_global.swap(X_sys);
90  sys.update();
91  X_global.swap(X_sys);
92 
93  // Enforce constraints (if any) exactly on the
94  // current_local_solution. This is the solution vector that is
95  // actually used in the computation of the residual below, and is
96  // not locked by debug-enabled PETSc the way that "x" is.
99 
100  return ResidualContext(solver, sys);
101 }
102 
103 //--------------------------------------------------------------------
104 // Functions with C linkage to pass to PETSc. PETSc will call these
105 // methods as needed.
106 //
107 // Since they must have C linkage they have no knowledge of a namespace.
108 // Give them an obscure name to avoid namespace pollution.
109 extern "C"
110 {
111  // -----------------------------------------------------------------
112  // this function monitors the nonlinear solve and checks to see
113  // if we want to recalculate the preconditioner. It only gets
114  // added to the SNES instance if we're reusing the preconditioner
115  PetscErrorCode
116  libmesh_petsc_recalculate_monitor(SNES snes, PetscInt, PetscReal, void* ctx)
117  {
118  PetscFunctionBegin;
119 
120  // No way to safety-check this cast, since we got a void *...
122  static_cast<PetscNonlinearSolver<Number> *> (ctx);
123 
124  KSP ksp;
125  LibmeshPetscCall2(solver->comm(), SNESGetKSP(snes, &ksp));
126 
127  PetscInt niter;
128  LibmeshPetscCall2(solver->comm(), KSPGetIterationNumber(ksp, &niter));
129 
130  if (niter > cast_int<PetscInt>(solver->reuse_preconditioner_max_linear_its()))
131  {
132  // -2 is a magic number for "recalculate next time you need it
133  // and then not again"
134  LibmeshPetscCall2(solver->comm(), SNESSetLagPreconditioner(snes, -2));
135  }
136  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
137  }
138 
139  //-------------------------------------------------------------------
140  // this function is called by PETSc at the end of each nonlinear step
141  PetscErrorCode
142  libmesh_petsc_snes_monitor (SNES, PetscInt its, PetscReal fnorm, void *)
143  {
144  PetscFunctionBegin;
145  libMesh::out << " NL step "
146  << std::setw(2) << its
147  << std::scientific
148  << ", |residual|_2 = " << fnorm
149  << std::endl;
150  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
151  }
152 
153 #ifdef LIBMESH_ENABLE_DEPRECATED
154  PetscErrorCode
155  __libmesh_petsc_snes_monitor (SNES, PetscInt its, PetscReal fnorm, void *)
156  {
157  PetscFunctionBegin;
158  libmesh_deprecated();
159  PetscFunctionReturn(libmesh_petsc_snes_monitor(nullptr, its, fnorm, nullptr));
160  }
161 #endif
162 
163 
164  //---------------------------------------------------------------
165  // this function is called by PETSc to evaluate the residual at X
166  PetscErrorCode
167  libmesh_petsc_snes_residual (SNES snes, Vec x, Vec r, void * ctx)
168  {
169  PetscFunctionBegin;
170 
172 
173  libmesh_parallel_only(rc.sys.comm());
174 
175  libmesh_assert(r);
176  PetscVector<Number> R(r, rc.sys.comm());
177 
178  if (rc.solver->_zero_out_residual)
179  R.zero();
180 
181  //-----------------------------------------------------------------------------
182  // if the user has provided both function pointers and objects only the pointer
183  // will be used, so catch that as an error
184  libmesh_error_msg_if(rc.solver->residual && rc.solver->residual_object,
185  "ERROR: cannot specify both a function and object to compute the Residual!");
186 
187  libmesh_error_msg_if(rc.solver->matvec && rc.solver->residual_and_jacobian_object,
188  "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
189 
190  if (rc.solver->residual != nullptr)
191  rc.solver->residual(*rc.sys.current_local_solution.get(), R, rc.sys);
192 
193  else if (rc.solver->residual_object != nullptr)
195 
196  else if (rc.solver->matvec != nullptr)
197  rc.solver->matvec (*rc.sys.current_local_solution.get(), &R, nullptr, rc.sys);
198 
199  else if (rc.solver->residual_and_jacobian_object != nullptr)
200  {
201  auto & jac = rc.sys.get_system_matrix();
202 
203  if (rc.solver->_zero_out_jacobian)
204  jac.zero();
205 
207  *rc.sys.current_local_solution.get(), &R, &jac, rc.sys);
208 
209  jac.close();
211  {
213  jac.close();
214  }
215  }
216 
217  else
218  libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
219 
220 
221  // Synchronize PETSc x to local solution since the local solution may be changed due to the constraints
222  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(rc.sys.solution.get());
223  PetscVector<Number> X_global(x, rc.sys.comm());
224 
225  X_global.swap(X_sys);
226  rc.sys.update();
227  X_global.swap(X_sys);
228 
229  R.close();
230 
232  {
234  R.close();
235  }
236 
237  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
238  }
239 
240 #ifdef LIBMESH_ENABLE_DEPRECATED
241  PetscErrorCode
242  __libmesh_petsc_snes_residual (SNES snes, Vec x, Vec r, void * ctx)
243  {
244  PetscFunctionBegin;
245  libmesh_deprecated();
247  }
248 #endif
249 
250  //-----------------------------------------------------------------------------------------
251  // this function is called by PETSc to approximate the Jacobian at X via finite differences
252  PetscErrorCode
253  libmesh_petsc_snes_fd_residual (SNES snes, Vec x, Vec r, void * ctx)
254  {
255  PetscFunctionBegin;
256 
258 
259  libmesh_parallel_only(rc.sys.comm());
260 
261  libmesh_assert(r);
262  PetscVector<Number> R(r, rc.sys.comm());
263 
264  if (rc.solver->_zero_out_residual)
265  R.zero();
266 
267  if (rc.solver->fd_residual_object != nullptr)
269 
270  else if (rc.solver->residual_object != nullptr)
272 
273  else
274  libmesh_error_msg("Error! Unable to compute residual for forming finite difference Jacobian!");
275 
276  // Synchronize PETSc x to local solution since the local solution may be changed due to the constraints
277  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(rc.sys.solution.get());
278  PetscVector<Number> X_global(x, rc.sys.comm());
279 
280  X_global.swap(X_sys);
281  rc.sys.update();
282  X_global.swap(X_sys);
283 
284  R.close();
285 
287  {
289  R.close();
290  }
291 
292  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
293  }
294 
295 #ifdef LIBMESH_ENABLE_DEPRECATED
296  PetscErrorCode
297  __libmesh_petsc_snes_fd_residual (SNES snes, Vec x, Vec r, void * ctx)
298  {
299  PetscFunctionBegin;
300  libmesh_deprecated();
302  }
303 #endif
304 
305  //----------------------------------------------------------------
306  // this function is called by PETSc to approximate Jacobian-vector
307  // products at X via finite differences
308  PetscErrorCode
309  libmesh_petsc_snes_mffd_residual (SNES snes, Vec x, Vec r, void * ctx)
310  {
311  PetscFunctionBegin;
312 
314 
315  libmesh_parallel_only(rc.sys.comm());
316 
317  libmesh_assert(r);
318  PetscVector<Number> R(r, rc.sys.comm());
319 
320  if (rc.solver->_zero_out_residual)
321  R.zero();
322 
323  if (rc.solver->mffd_residual_object != nullptr)
325 
326  else if (rc.solver->residual_object != nullptr)
328 
329  else
330  libmesh_error_msg("Error! Unable to compute residual for forming finite differenced"
331  "Jacobian-vector products!");
332 
333  // Synchronize PETSc x to local solution since the local solution may be changed due to the constraints
334  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(rc.sys.solution.get());
335  PetscVector<Number> X_global(x, rc.sys.comm());
336 
337  X_global.swap(X_sys);
338  rc.sys.update();
339  X_global.swap(X_sys);
340 
341  R.close();
342 
344  {
346  R.close();
347  }
348 
349  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
350  }
351 
352  //----------------------------------------------------------
353  // this function serves an interface between the petsc layer
354  // and the actual mffd residual computing routine
355  PetscErrorCode
356  libmesh_petsc_snes_mffd_interface (void * ctx, Vec x, Vec r)
357  {
358  PetscFunctionBegin;
359 
360  // No way to safety-check this cast, since we got a void *...
362  static_cast<PetscNonlinearSolver<Number> *> (ctx);
363 
364  LibmeshPetscCall2(solver->comm(), libmesh_petsc_snes_mffd_residual(solver->snes(), x, r, ctx));
365 
366 #if !PETSC_VERSION_LESS_THAN(3,8,4)
367 #ifndef NDEBUG
368 
369  // When the user requested to reuse the nonlinear residual as the base for doing matrix-free
370  // approximation of the Jacobian, we'll do a sanity check to make sure that that was safe to do
371  if (solver->snes_mf_reuse_base() && (solver->comm().size() == 1) && (libMesh::n_threads() == 1))
372  {
373  SNES snes = solver->snes();
374 
375  KSP ksp;
376  LibmeshPetscCall2(solver->comm(), SNESGetKSP(snes, &ksp));
377 
378  PetscInt ksp_it;
379  LibmeshPetscCall2(solver->comm(), KSPGetIterationNumber(ksp, &ksp_it));
380 
381  SNESType snes_type;
382  LibmeshPetscCall2(solver->comm(), SNESGetType(snes, &snes_type));
383 
384  libmesh_assert_msg(snes_type, "We're being called from SNES; snes_type should be non-null");
385 
386  Mat J;
387  LibmeshPetscCall2(solver->comm(), SNESGetJacobian(snes, &J, NULL, NULL, NULL));
388  libmesh_assert_msg(J, "We're being called from SNES; J should be non-null");
389 
390  MatType mat_type;
391  LibmeshPetscCall2(solver->comm(), MatGetType(J, &mat_type));
392  libmesh_assert_msg(mat_type, "We're being called from SNES; mat_type should be non-null");
393 
394  bool is_operator_mffd = strcmp(mat_type, MATMFFD) == 0;
395 
396  if ((ksp_it == PetscInt(0)) && is_operator_mffd)
397  {
398  bool computing_base_vector = solver->computing_base_vector();
399 
400  if (computing_base_vector)
401  {
402  Vec nonlinear_residual;
403 
404  LibmeshPetscCall2(solver->comm(), SNESGetFunction(snes, &nonlinear_residual, NULL, NULL));
405 
406  PetscBool vecs_equal;
407  LibmeshPetscCall2(solver->comm(), VecEqual(r, nonlinear_residual, &vecs_equal));
408 
409  libmesh_error_msg_if(!(vecs_equal == PETSC_TRUE),
410  "You requested to reuse the nonlinear residual vector as the base vector for "
411  "computing the action of the matrix-free Jacobian, but the vectors are not "
412  "the same. Your physics must have states; either remove the states "
413  "from your code or make sure that you set_mf_reuse_base(false)");
414  }
415 
416  // There are always exactly two function evaluations for the zeroth ksp iteration when doing
417  // matrix-free approximation of the Jacobian action: one corresponding to the evaluation of
418  // the base vector, and the other corresponding to evaluation of the perturbed vector. So we
419  // toggle back and forth between states
420  solver->set_computing_base_vector(!computing_base_vector);
421  }
422  }
423 #endif
424 #endif
425 
426  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
427  }
428 
429 #ifdef LIBMESH_ENABLE_DEPRECATED
430  PetscErrorCode
432  {
433  PetscFunctionBegin;
434  libmesh_deprecated();
436  }
437 #endif
438 
439  //---------------------------------------------------------------
440  // this function is called by PETSc to evaluate the Jacobian at X
441  PetscErrorCode
442  libmesh_petsc_snes_jacobian(SNES snes, Vec x, Mat jac, Mat pc, void * ctx)
443  {
444  PetscFunctionBegin;
445 
446  LOG_SCOPE("jacobian()", "PetscNonlinearSolver");
447 
449 
450  // No way to safety-check this cast, since we got a void *...
452  static_cast<PetscNonlinearSolver<Number> *> (ctx);
453 
454  libmesh_parallel_only(solver->comm());
455 
456  // Get the current iteration number from the snes object,
457  // store it in the PetscNonlinearSolver object for possible use
458  // by the user's Jacobian function.
459  {
460  PetscInt n_iterations = 0;
461  LibmeshPetscCall2(solver->comm(), SNESGetIterationNumber(snes, &n_iterations));
462  solver->_current_nonlinear_iteration_number = cast_int<unsigned>(n_iterations);
463  }
464 
465  //-----------------------------------------------------------------------------
466  // if the user has provided both function pointers and objects only the pointer
467  // will be used, so catch that as an error
468  libmesh_error_msg_if(solver->jacobian && solver->jacobian_object,
469  "ERROR: cannot specify both a function and object to compute the Jacobian!");
470 
471  libmesh_error_msg_if(solver->matvec && solver->residual_and_jacobian_object,
472  "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
473 
474  NonlinearImplicitSystem & sys = solver->system();
475 
476  PetscMatrixBase<Number> * const PC = pc ? PetscMatrixBase<Number>::get_context(pc, sys.comm()) : nullptr;
477  PetscMatrixBase<Number> * Jac = jac ? PetscMatrixBase<Number>::get_context(jac, sys.comm()) : nullptr;
478  PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
479  PetscVector<Number> X_global(x, sys.comm());
480 
481  PetscMFFDMatrix<Number> mffd_jac(sys.comm());
482  PetscBool p_is_shell = PETSC_FALSE;
483  PetscBool j_is_mffd = PETSC_FALSE;
484  PetscBool j_is_shell = PETSC_FALSE;
485  if (pc)
486  LibmeshPetscCall2(sys.comm(), PetscObjectTypeCompare((PetscObject)pc, MATSHELL, &p_is_shell));
487  libmesh_assert(jac);
488  LibmeshPetscCall2(sys.comm(), PetscObjectTypeCompare((PetscObject)jac, MATMFFD, &j_is_mffd));
489  LibmeshPetscCall2(sys.comm(), PetscObjectTypeCompare((PetscObject)jac, MATSHELL, &j_is_shell));
490  if (j_is_mffd == PETSC_TRUE)
491  {
492  libmesh_assert(!Jac);
493  Jac = &mffd_jac;
494  mffd_jac = jac;
495  }
496 
497  // We already computed the Jacobian during the residual evaluation
498  if (solver->residual_and_jacobian_object)
499  {
500  // We could be doing matrix-free in which case we cannot rely on closing of explicit matrices
501  // that occurs during the PETSc residual callback
502  if ((j_is_shell == PETSC_TRUE) || (j_is_mffd == PETSC_TRUE))
503  Jac->close();
504 
505  if (pc && (p_is_shell == PETSC_TRUE))
506  PC->close();
507 
508  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
509  }
510 
511  // Set the dof maps
512  PC->attach_dof_map(sys.get_dof_map());
513  Jac->attach_dof_map(sys.get_dof_map());
514 
515  // Use the systems update() to get a good local version of the parallel solution
516  X_global.swap(X_sys);
517  sys.update();
518  X_global.swap(X_sys);
519 
520  // Enforce constraints (if any) exactly on the
521  // current_local_solution. This is the solution vector that is
522  // actually used in the computation of the residual below, and is
523  // not locked by debug-enabled PETSc the way that "x" is.
524  if (solver->_exact_constraint_enforcement)
526 
527  if (solver->_zero_out_jacobian)
528  PC->zero();
529 
530 
531  if (solver->jacobian != nullptr)
532  solver->jacobian(*sys.current_local_solution.get(), *PC, sys);
533 
534  else if (solver->jacobian_object != nullptr)
535  solver->jacobian_object->jacobian(*sys.current_local_solution.get(), *PC, sys);
536 
537  else if (solver->matvec != nullptr)
538  solver->matvec(*sys.current_local_solution.get(), nullptr, PC, sys);
539 
540  else
541  libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
542 
543  PC->close();
544  if (solver->_exact_constraint_enforcement)
545  {
547  PC->close();
548  }
549 
550  if (Jac != PC)
551  {
552  // Assume that shells know what they're doing
553  libmesh_assert(!solver->_exact_constraint_enforcement || (j_is_mffd == PETSC_TRUE) ||
554  (j_is_shell == PETSC_TRUE));
555  Jac->close();
556  }
557 
558  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
559  }
560 
561  // This function gets called by PETSc in place of the standard Petsc line searches
562  // if a linesearch object is supplied to the PetscNonlinearSolver class. It wraps
563  // the linesearch algorithm implemented on the linesearch object.
564  // * "linesearch" is an object that can be used to access the non-linear and linear solution
565  // vectors as well as the residual and SNES object
566  // * "ctx" is the PetscNonlinearSolver context
567  PetscErrorCode libmesh_petsc_linesearch_shellfunc (SNESLineSearch linesearch, void * ctx)
568  {
569  PetscFunctionBegin;
570 
571  // No way to safety-check this cast, since we got a void *...
573  static_cast<PetscNonlinearSolver<Number> *> (ctx);
574 
575  libmesh_parallel_only(solver->comm());
576 
577  solver->linesearch_object->linesearch(linesearch);
578  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
579  }
580 
581 #ifdef LIBMESH_ENABLE_DEPRECATED
582  PetscErrorCode
583  __libmesh_petsc_snes_jacobian(SNES snes, Vec x, Mat jac, Mat pc, void * ctx)
584  {
585  PetscFunctionBegin;
586  libmesh_deprecated();
588  }
589 #endif
590 
591  // This function gets called by PETSc after the SNES linesearch is
592  // complete. We use it to exactly enforce any constraints on the
593  // solution which may have drifted during the linear solve. In the
594  // PETSc nomenclature:
595  // * "x" is the old solution vector,
596  // * "y" is the search direction (Newton step) vector,
597  // * "w" is the candidate solution vector, and
598  // the user is responsible for setting changed_y and changed_w
599  // appropriately, depending on whether or not the search
600  // direction or solution vector was changed, respectively.
601  PetscErrorCode libmesh_petsc_snes_postcheck(SNESLineSearch, Vec x, Vec y, Vec w, PetscBool * changed_y, PetscBool * changed_w, void * context)
602  {
603  PetscFunctionBegin;
604 
605  LOG_SCOPE("postcheck()", "PetscNonlinearSolver");
606 
607  // PETSc almost certainly initializes these to false already, but
608  // it doesn't hurt to be explicit.
609  *changed_w = PETSC_FALSE;
610  *changed_y = PETSC_FALSE;
611 
612  libmesh_assert(context);
613 
614  // Cast the context to a NonlinearSolver object.
616  static_cast<PetscNonlinearSolver<Number> *> (context);
617 
618  libmesh_parallel_only(solver->comm());
619 
620  // If the user has provided both postcheck function pointer and
621  // object, this is ambiguous, so throw an error.
622  libmesh_error_msg_if(solver->postcheck && solver->postcheck_object,
623  "ERROR: cannot specify both a function and object for performing the solve postcheck!");
624 
625  // It's also possible that we don't need to do anything at all, in
626  // that case return early...
627  NonlinearImplicitSystem & sys = solver->system();
628 
629  if (!solver->postcheck && !solver->postcheck_object)
630  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
631 
632  // We definitely need to wrap at least "w"
633  PetscVector<Number> petsc_w(w, sys.comm());
634 
635  // The user sets these flags in his/her postcheck function to
636  // indicate whether they changed something.
637  bool
638  changed_search_direction = false,
639  changed_new_soln = false;
640 
641  if (solver->postcheck || solver->postcheck_object)
642  {
643  PetscVector<Number> petsc_x(x, sys.comm());
644  PetscVector<Number> petsc_y(y, sys.comm());
645 
646  if (solver->postcheck)
647  solver->postcheck(petsc_x,
648  petsc_y,
649  petsc_w,
650  changed_search_direction,
651  changed_new_soln,
652  sys);
653 
654  else if (solver->postcheck_object)
655  solver->postcheck_object->postcheck(petsc_x,
656  petsc_y,
657  petsc_w,
658  changed_search_direction,
659  changed_new_soln,
660  sys);
661  }
662 
663  // Record whether the user changed the solution or the search direction.
664  if (changed_search_direction)
665  *changed_y = PETSC_TRUE;
666 
667  if (changed_new_soln)
668  *changed_w = PETSC_TRUE;
669 
670  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
671  }
672 
673 #ifdef LIBMESH_ENABLE_DEPRECATED
674  PetscErrorCode __libmesh_petsc_snes_postcheck(SNESLineSearch, Vec x, Vec y, Vec w, PetscBool * changed_y, PetscBool * changed_w, void * context)
675  {
676  PetscFunctionBegin;
677  libmesh_deprecated();
678  PetscFunctionReturn(libmesh_petsc_snes_postcheck(nullptr, x, y, w, changed_y, changed_w, context));
679  }
680 #endif
681 
682  PetscErrorCode libmesh_petsc_snes_precheck(SNESLineSearch, Vec X, Vec Y, PetscBool * changed, void * context)
683  {
684  PetscFunctionBegin;
685 
686  LOG_SCOPE("precheck()", "PetscNonlinearSolver");
687 
688  // PETSc almost certainly initializes these to false already, but
689  // it doesn't hurt to be explicit.
690  *changed = PETSC_FALSE;
691 
692  libmesh_assert(context);
693 
694  // Cast the context to a NonlinearSolver object.
696  static_cast<PetscNonlinearSolver<Number> *> (context);
697 
698  libmesh_parallel_only(solver->comm());
699 
700  // It's possible that we don't need to do anything at all, in
701  // that case return early...
702  if (!solver->precheck_object)
703  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
704 
705  // The user sets these flags in his/her postcheck function to
706  // indicate whether they changed something.
707  bool
708  petsc_changed = false;
709 
710  auto & sys = solver->system();
711  auto & x_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
712  PetscVector<Number> petsc_x(X, sys.comm());
713  PetscVector<Number> petsc_y(Y, sys.comm());
714 
715  // Use the systems update() to get a good local version of the parallel solution
716  petsc_x.swap(x_sys);
717  sys.update();
718  petsc_x.swap(x_sys);
719 
720  // Enforce constraints (if any) exactly on the
721  // current_local_solution. This is the solution vector that is
722  // actually used in the computation of residuals and Jacobians, and is
723  // not locked by debug-enabled PETSc the way that "x" is.
724  libmesh_assert(sys.current_local_solution.get());
725  auto & local_soln = *sys.current_local_solution.get();
726  if (solver->_exact_constraint_enforcement)
727  sys.get_dof_map().enforce_constraints_exactly(sys, &local_soln);
728 
729  solver->precheck_object->precheck(local_soln,
730  petsc_y,
731  petsc_changed,
732  sys);
733 
734  // Record whether the user changed the solution or the search direction.
735  if (petsc_changed)
736  *changed = PETSC_TRUE;
737 
738  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
739  }
740 
741 } // end extern "C"
742 
743 
744 
745 //---------------------------------------------------------------------
746 // PetscNonlinearSolver<> methods
747 template <typename T>
749  NonlinearSolver<T>(system_in),
750  linesearch_object(nullptr),
751  _reason(SNES_CONVERGED_ITERATING/*==0*/), // Arbitrary initial value...
752  _n_linear_iterations(0),
753  _current_nonlinear_iteration_number(0),
754  _zero_out_residual(true),
755  _zero_out_jacobian(true),
756  _default_monitor(true),
757  _snesmf_reuse_base(true),
758  _computing_base_vector(true),
759  _setup_reuse(false),
760  _mffd_jac(this->_communicator)
761 {
762 }
763 
764 
765 
766 template <typename T>
768 
769 
770 
771 template <typename T>
773 {
774  if (this->initialized())
775  {
776  this->_is_initialized = false;
777 
778  // If we don't need the preconditioner next time
779  // retain the original behavior of clearing the data
780  // between solves.
781  if (!(reuse_preconditioner()))
782  {
783  // SNESReset really ought to work but replacing destroy() with
784  // SNESReset causes a very slight change in behavior that
785  // manifests as two failed MOOSE tests...
786  _snes.destroy();
787  }
788 
789  // Reset the nonlinear iteration counter. This information is only relevant
790  // *during* the solve(). After the solve is completed it should return to
791  // the default value of 0.
792  _current_nonlinear_iteration_number = 0;
793  }
794 }
795 
796 template <typename T>
798 {
799  parallel_object_only();
800 
801  // Initialize the data structures if not done so already.
802  if (!this->initialized())
803  {
804  this->_is_initialized = true;
805 
806  // Make only if we don't already have a retained snes
807  // hanging around from the last solve
808  if (!_snes)
809  LibmeshPetscCall(SNESCreate(this->comm().get(), _snes.get()));
810 
811  // I believe all of the following can be safely repeated
812  // even on an old snes instance from the last solve
813 
814  if (name)
815  {
816  libmesh_assert(std::string(name).front() != '-');
817  libmesh_assert(std::string(name).back() == '_');
818  LibmeshPetscCall(SNESSetOptionsPrefix(_snes, name));
819  }
820 
821  // Attaching a DM to SNES.
822 #if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
823  bool use_petsc_dm = libMesh::on_command_line(
824  "--" + (name ? std::string(name) : std::string("")) + "use_petsc_dm");
825 
826  // This needs to be called before SNESSetFromOptions
827  if (use_petsc_dm)
828  this->_dm_wrapper.init_and_attach_petscdm(this->system(), _snes);
829  else
830 #endif
831  {
832  WrappedPetsc<DM> dm;
833  LibmeshPetscCall(DMCreate(this->comm().get(), dm.get()));
834  LibmeshPetscCall(DMSetType(dm, DMLIBMESH));
835  LibmeshPetscCall(DMlibMeshSetSystem(dm, this->system()));
836 
837  if (name)
838  LibmeshPetscCall(DMSetOptionsPrefix(dm, name));
839 
840  LibmeshPetscCall(DMSetFromOptions(dm));
841  LibmeshPetscCall(DMSetUp(dm));
842  LibmeshPetscCall(SNESSetDM(_snes, dm));
843  // SNES now owns the reference to dm.
844  }
845 
846  setup_default_monitor();
847 
848  // If the SolverConfiguration object is provided, use it to set
849  // options during solver initialization.
850  if (this->_solver_configuration)
851  {
852  this->_solver_configuration->set_options_during_init();
853  }
854 
855  if (this->_preconditioner)
856  {
857  KSP ksp;
858  LibmeshPetscCall(SNESGetKSP (_snes, &ksp));
859  PC pc;
860  LibmeshPetscCall(KSPGetPC(ksp,&pc));
861 
862  this->_preconditioner->init();
863 
864  LibmeshPetscCall(PCSetType(pc, PCSHELL));
865  LibmeshPetscCall(PCShellSetContext(pc,(void *)this->_preconditioner));
866 
867  //Re-Use the shell functions from petsc_linear_solver
868  LibmeshPetscCall(PCShellSetSetUp(pc,libmesh_petsc_preconditioner_setup));
869  LibmeshPetscCall(PCShellSetApply(pc,libmesh_petsc_preconditioner_apply));
870  }
871  }
872 
873 
874  // Tell PETSc about our linesearch "post-check" function, but only
875  // if the user has provided one. There seem to be extra,
876  // unnecessary residual calculations if a postcheck function is
877  // attached for no reason.
878  if (this->postcheck || this->postcheck_object)
879  {
880  SNESLineSearch linesearch;
881  LibmeshPetscCall(SNESGetLineSearch(_snes, &linesearch));
882 
883  LibmeshPetscCall(SNESLineSearchSetPostCheck(linesearch, libmesh_petsc_snes_postcheck, this));
884  }
885 
886  if (this->precheck_object)
887  {
888  SNESLineSearch linesearch;
889  LibmeshPetscCall(SNESGetLineSearch(_snes, &linesearch));
890 
891  LibmeshPetscCall(SNESLineSearchSetPreCheck(linesearch, libmesh_petsc_snes_precheck, this));
892  }
893 }
894 
895 
896 template <typename T>
898 {
899  this->init(name);
900  return _snes;
901 }
902 
903 
904 
905 template <typename T>
906 void
908  void (*computeSubspace)(std::vector<NumericVector<Number> *> &, sys_type &),
909  MatNullSpace * msp)
910 {
911  parallel_object_only();
912 
913  std::vector<NumericVector<Number> *> sp;
914  if (computeSubspaceObject)
915  (*computeSubspaceObject)(sp, this->system());
916  else
917  (*computeSubspace)(sp, this->system());
918 
919  *msp = LIBMESH_PETSC_NULLPTR;
920  if (sp.size())
921  {
922  PetscInt nmodes = cast_int<PetscInt>(sp.size());
923 
924  std::vector<Vec> modes(nmodes);
925  std::vector<PetscScalar> dots(nmodes);
926 
927  for (PetscInt i=0; i<nmodes; ++i)
928  {
929  auto pv = cast_ptr<PetscVector<T> *>(sp[i]);
930 
931  LibmeshPetscCall(VecDuplicate(pv->vec(), &modes[i]));
932 
933  LibmeshPetscCall(VecCopy(pv->vec(), modes[i]));
934  }
935 
936  // Normalize.
937  LibmeshPetscCall(VecNormalize(modes[0], LIBMESH_PETSC_NULLPTR));
938 
939  for (PetscInt i=1; i<nmodes; i++)
940  {
941  // Orthonormalize vec[i] against vec[0:i-1]
942  LibmeshPetscCall(VecMDot(modes[i], i, modes.data(), dots.data()));
943 
944  for (PetscInt j=0; j<i; j++)
945  dots[j] *= -1.;
946 
947  LibmeshPetscCall(VecMAXPY(modes[i], i, dots.data(), modes.data()));
948 
949  LibmeshPetscCall(VecNormalize(modes[i], LIBMESH_PETSC_NULLPTR));
950  }
951 
952  LibmeshPetscCall(MatNullSpaceCreate(this->comm().get(), PETSC_FALSE, nmodes, modes.data(), msp));
953 
954  for (PetscInt i=0; i<nmodes; ++i)
955  LibmeshPetscCall(VecDestroy(&modes[i]));
956  }
957 }
958 
959 template <typename T>
960 std::pair<unsigned int, Real>
961 PetscNonlinearSolver<T>::solve (SparseMatrix<T> & pre_in, // System Preconditioning Matrix
962  NumericVector<T> & x_in, // Solution vector
963  NumericVector<T> & r_in, // Residual vector
964  const double, // Stopping tolerance
965  const unsigned int)
966 {
967  parallel_object_only();
968 
969  LOG_SCOPE("solve()", "PetscNonlinearSolver");
970  this->init ();
971 
972  // Make sure the data passed in are really of Petsc types
973  PetscMatrixBase<T> * pre = cast_ptr<PetscMatrixBase<T> *>(&pre_in);
974  PetscVector<T> * x = cast_ptr<PetscVector<T> *>(&x_in);
975  PetscVector<T> * r = cast_ptr<PetscVector<T> *>(&r_in);
976 
977  PetscInt n_iterations =0;
978  // Should actually be a PetscReal, but I don't know which version of PETSc first introduced PetscReal
979  Real final_residual_norm=0.;
980 
981  // We don't want to do this twice because it resets
982  // SNESSetLagPreconditioner
983  if ((reuse_preconditioner()) && (!_setup_reuse))
984  {
985  _setup_reuse = true;
986  LibmeshPetscCall(SNESSetLagPreconditionerPersists(_snes, PETSC_TRUE));
987  // According to the PETSC 3.16.5 docs -2 is a magic number which
988  // means "recalculate the next time you need it and then not again"
989  LibmeshPetscCall(SNESSetLagPreconditioner(_snes, -2));
990  // Add in our callback which will trigger recalculating
991  // the preconditioner when we hit reuse_preconditioner_max_linear_its
992  LibmeshPetscCall(SNESMonitorSet(_snes, &libmesh_petsc_recalculate_monitor,
993  this,
994  NULL));
995  }
996  else if (!(reuse_preconditioner()))
997  // This covers the case where it was enabled but was then disabled
998  {
999  LibmeshPetscCall(SNESSetLagPreconditionerPersists(_snes, PETSC_FALSE));
1000  if (_setup_reuse)
1001  {
1002  _setup_reuse = false;
1003  LibmeshPetscCall(SNESMonitorCancel(_snes));
1004  // Readd default monitor
1005  setup_default_monitor();
1006  }
1007  }
1008 
1009  LibmeshPetscCall(SNESSetFunction (_snes, r->vec(), libmesh_petsc_snes_residual, this));
1010 
1011  // Only set the jacobian function if we've been provided with something to call.
1012  // This allows a user to set their own jacobian function if they want to
1013  if (this->jacobian || this->jacobian_object || this->residual_and_jacobian_object)
1014  LibmeshPetscCall(SNESSetJacobian (_snes, pre->mat(), pre->mat(), libmesh_petsc_snes_jacobian, this));
1015 
1016  // Have the Krylov subspace method use our good initial guess rather than 0
1017  KSP ksp;
1018  LibmeshPetscCall(SNESGetKSP (_snes, &ksp));
1019 
1020  // Set the tolerances for the iterative solver. Use the user-supplied
1021  // tolerance for the relative residual & leave the others at default values
1022  LibmeshPetscCall(KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
1023  PETSC_DEFAULT, this->max_linear_iterations));
1024 
1025  // Set the tolerances for the non-linear solver.
1026  LibmeshPetscCall(SNESSetTolerances(_snes,
1027  this->absolute_residual_tolerance,
1028  this->relative_residual_tolerance,
1029  this->relative_step_tolerance,
1030  this->max_nonlinear_iterations,
1031  this->max_function_evaluations));
1032 
1033  // Set the divergence tolerance for the non-linear solver
1034 #if !PETSC_VERSION_LESS_THAN(3,8,0)
1035  LibmeshPetscCall(SNESSetDivergenceTolerance(_snes, this->divergence_tolerance));
1036 #endif
1037 
1038  //Pull in command-line options
1039 #if PETSC_VERSION_LESS_THAN(3,7,0)
1040  LibmeshPetscCall(KSPSetFromOptions(ksp));
1041 #endif
1042  LibmeshPetscCall(SNESSetFromOptions(_snes));
1043 
1044 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \
1045  !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE)
1046  {
1047  // Make sure hypre has been initialized
1048  LibmeshPetscCallExternal(HYPRE_Initialize);
1049  PetscScalar * dummyarray;
1050  PetscMemType mtype;
1051  LibmeshPetscCall(VecGetArrayAndMemType(x->vec(), &dummyarray, &mtype));
1052  LibmeshPetscCall(VecRestoreArrayAndMemType(x->vec(), &dummyarray));
1053  if (PetscMemTypeHost(mtype))
1054  LibmeshPetscCallExternal(HYPRE_SetMemoryLocation, HYPRE_MEMORY_HOST);
1055  }
1056 #endif
1057 
1058  if (this->user_presolve)
1059  this->user_presolve(this->system());
1060 
1061  //Set the preconditioning matrix
1062  if (this->_preconditioner)
1063  {
1064  this->_preconditioner->set_matrix(pre_in);
1065  this->_preconditioner->init();
1066  }
1067 
1068  // If the SolverConfiguration object is provided, use it to override
1069  // solver options.
1070  if (this->_solver_configuration)
1071  this->_solver_configuration->configure_solver();
1072 
1073  // In PETSc versions before 3.5.0, it is not possible to call
1074  // SNESSetUp() before the solution and rhs vectors are initialized, as
1075  // this triggers the
1076  //
1077  // "Solution vector cannot be right hand side vector!"
1078  //
1079  // error message. It is also not possible to call SNESSetSolution()
1080  // in those versions of PETSc to work around the problem, since that
1081  // API was removed in 3.0.0 and only restored in 3.6.0. The
1082  // overzealous check was moved out of SNESSetUp in PETSc 3.5.0
1083  // (petsc/petsc@154060b), so this code block should be safe to use
1084  // in 3.5.0 and later.
1085 #if !PETSC_VERSION_LESS_THAN(3,6,0)
1086  LibmeshPetscCall(SNESSetSolution(_snes, x->vec()));
1087 #endif
1088  LibmeshPetscCall(SNESSetUp(_snes));
1089 
1090  Mat J, P;
1091  LibmeshPetscCall(SNESGetJacobian(_snes, &J, &P,
1092  LIBMESH_PETSC_NULLPTR,
1093  LIBMESH_PETSC_NULLPTR));
1094  LibmeshPetscCall(MatMFFDSetFunction(J, libmesh_petsc_snes_mffd_interface, this));
1095 #if !PETSC_VERSION_LESS_THAN(3,8,4)
1096 #ifndef NDEBUG
1097  // If we're in debug mode, do not reuse the nonlinear function evaluation as the base for doing
1098  // matrix-free approximations of the Jacobian action. Instead if the user requested that we reuse
1099  // the base, we'll check the base function evaluation and compare it to the nonlinear residual
1100  // evaluation. If they are different, then we'll error and inform the user that it's unsafe to
1101  // reuse the base
1102  LibmeshPetscCall(MatSNESMFSetReuseBase(J, PETSC_FALSE));
1103 #else
1104  // Resue the residual vector from SNES
1105  LibmeshPetscCall(MatSNESMFSetReuseBase(J, static_cast<PetscBool>(_snesmf_reuse_base)));
1106 #endif
1107 #endif
1108 
1109  // Only set the nullspace if we have a way of computing it and the result is non-empty.
1110  if (this->nullspace || this->nullspace_object)
1111  {
1113  this->build_mat_null_space(this->nullspace_object, this->nullspace, msp.get());
1114  if (msp)
1115  {
1116  LibmeshPetscCall(MatSetNullSpace(J, msp));
1117  if (P != J)
1118  LibmeshPetscCall(MatSetNullSpace(P, msp));
1119  }
1120  }
1121 
1122  // Only set the transpose nullspace if we have a way of computing it and the result is non-empty.
1123  if (this->transpose_nullspace || this->transpose_nullspace_object)
1124  {
1125 #if PETSC_VERSION_LESS_THAN(3,6,0)
1126  libmesh_warning("MatSetTransposeNullSpace is only supported for PETSc >= 3.6, transpose nullspace will be ignored.");
1127 #else
1129  this->build_mat_null_space(this->transpose_nullspace_object, this->transpose_nullspace, msp.get());
1130  if (msp)
1131  {
1132  LibmeshPetscCall(MatSetTransposeNullSpace(J, msp));
1133  if (P != J)
1134  LibmeshPetscCall(MatSetTransposeNullSpace(P, msp));
1135  }
1136 #endif
1137  }
1138 
1139  // Only set the nearnullspace if we have a way of computing it and the result is non-empty.
1140  if (this->nearnullspace || this->nearnullspace_object)
1141  {
1143  this->build_mat_null_space(this->nearnullspace_object, this->nearnullspace, msp.get());
1144 
1145  if (msp)
1146  {
1147  LibmeshPetscCall(MatSetNearNullSpace(J, msp));
1148  if (P != J)
1149  LibmeshPetscCall(MatSetNearNullSpace(P, msp));
1150  }
1151  }
1152 
1153  SNESLineSearch linesearch;
1154  if (linesearch_object)
1155  {
1156  LibmeshPetscCall(SNESGetLineSearch(_snes, &linesearch));
1157  LibmeshPetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHSHELL));
1158 #if PETSC_RELEASE_GREATER_EQUALS(3, 21, 0)
1159  LibmeshPetscCall(SNESLineSearchShellSetApply(linesearch, libmesh_petsc_linesearch_shellfunc, this));
1160 #else
1161  LibmeshPetscCall(SNESLineSearchShellSetUserFunc(linesearch, libmesh_petsc_linesearch_shellfunc, this));
1162 #endif
1163  }
1164 
1165  LibmeshPetscCall(SNESSolve (_snes, LIBMESH_PETSC_NULLPTR, x->vec()));
1166 
1167  LibmeshPetscCall(SNESGetIterationNumber(_snes, &n_iterations));
1168 
1169  LibmeshPetscCall(SNESGetLinearSolveIterations(_snes, &_n_linear_iterations));
1170 
1171  // SNESGetFunction has been around forever and should work on all
1172  // versions of PETSc. This is also now the recommended approach
1173  // according to the documentation for the PETSc 3.5.1 release:
1174  // http://www.mcs.anl.gov/petsc/documentation/changes/35.html
1175  Vec f;
1176  LibmeshPetscCall(SNESGetFunction(_snes, &f, 0, 0));
1177  LibmeshPetscCall(VecNorm(f, NORM_2, pPR(&final_residual_norm)));
1178 
1179  // Get and store the reason for convergence
1180  LibmeshPetscCall(SNESGetConvergedReason(_snes, &_reason));
1181 
1182  //Based on Petsc 2.3.3 documentation all diverged reasons are negative
1183  this->converged = (_reason >= 0);
1184 
1185  // Reset data structure
1186  this->clear();
1187 
1188  // return the # of its. and the final residual norm.
1189  return std::make_pair(n_iterations, final_residual_norm);
1190 }
1191 
1192 
1193 
1194 template <typename T>
1196 {
1197 
1198  libMesh::out << "Nonlinear solver convergence/divergence reason: "
1199  << SNESConvergedReasons[this->get_converged_reason()] << std::endl;
1200 }
1201 
1202 
1203 
1204 template <typename T>
1206 {
1207  if (this->initialized())
1208  LibmeshPetscCall(SNESGetConvergedReason(_snes, &_reason));
1209 
1210  return _reason;
1211 }
1212 
1213 template <typename T>
1215 {
1216  return _n_linear_iterations;
1217 }
1218 
1219 template <typename T>
1221 {
1222  if (_default_monitor)
1223  LibmeshPetscCall(
1224  SNESMonitorSet(_snes, libmesh_petsc_snes_monitor, this, LIBMESH_PETSC_NULLPTR));
1225 }
1226 
1227 template <typename T>
1229 {
1230  return this->_reuse_preconditioner;
1231 }
1232 
1233 template <typename T>
1235 {
1236  return this->_reuse_preconditioner_max_linear_its;
1237 }
1238 
1239 template <typename T>
1241 {
1242  // Easiest way is just to clear everything out
1243  this->_is_initialized = false;
1244  _snes.destroy();
1245  _setup_reuse = false;
1246 }
1247 
1248 //------------------------------------------------------------------
1249 // Explicit instantiations
1250 template class LIBMESH_EXPORT PetscNonlinearSolver<Number>;
1251 
1252 } // namespace libMesh
1253 
1254 
1255 
1256 #endif // #ifdef LIBMESH_HAVE_PETSC
unsigned _current_nonlinear_iteration_number
Stores the current nonlinear iteration number.
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
PetscNonlinearSolver< Number > * solver
SNES snes(const char *name=nullptr)
PetscReal * pPR(T *ptr)
Definition: petsc_macro.h:186
This class provides a nice interface to PETSc&#39;s Vec object.
Definition: petsc_vector.h:73
PetscErrorCode __libmesh_petsc_snes_jacobian(SNES, Vec x, Mat jac, Mat pc, void *ctx)
void(* residual)(const NumericVector< Number > &X, NumericVector< Number > &R, sys_type &S)
Function that computes the residual R(X) of the nonlinear system at the input iterate X...
virtual unsigned int reuse_preconditioner_max_linear_its() const override
Getter for the maximum iterations flag for preconditioner reuse.
NonlinearImplicitSystem::ComputeResidualandJacobian * residual_and_jacobian_object
Object that computes either the residual or the Jacobian of the nonlinear system at the input itera...
unsigned int n_threads()
Definition: libmesh_base.h:96
virtual void residual(const NumericVector< Number > &X, NumericVector< Number > &R, sys_type &S)=0
Residual function.
PetscErrorCode libmesh_petsc_snes_fd_residual(SNES, Vec x, Vec r, void *ctx)
virtual void zero() override
Set all entries to zero.
Definition: petsc_vector.h:912
PetscNonlinearSolver(sys_type &system)
Constructor.
PETSC_EXTERN PetscErrorCode DMlibMeshSetSystem(DM, libMesh::NonlinearImplicitSystem &)
Any functional implementation of the DMlibMesh API must compose the following functions with the DM o...
NonlinearImplicitSystem & sys
PetscErrorCode __libmesh_petsc_snes_monitor(SNES, PetscInt its, PetscReal fnorm, void *)
PetscErrorCode libmesh_petsc_preconditioner_apply(PC, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
const Parallel::Communicator & comm() const
This base class can be inherited from to provide interfaces to nonlinear solvers from different packa...
static PetscMatrixBase< T > * get_context(Mat mat, const TIMPI::Communicator &comm)
PetscErrorCode libmesh_petsc_snes_postcheck(SNESLineSearch, Vec x, Vec y, Vec w, PetscBool *changed_y, PetscBool *changed_w, void *context)
PetscErrorCode __libmesh_petsc_snes_residual(SNES, Vec x, Vec r, void *ctx)
bool _zero_out_residual
true to zero out residual before going into application level call-back, otherwise false ...
The libMesh namespace provides an interface to certain functionality in the library.
NonlinearImplicitSystem::ComputeResidual * residual_object
Object that computes the residual R(X) of the nonlinear system at the input iterate X...
void(* jacobian)(const NumericVector< Number > &X, SparseMatrix< Number > &J, sys_type &S)
Function that computes the Jacobian J(X) of the nonlinear system at the input iterate X...
PetscErrorCode libmesh_petsc_snes_monitor(SNES, PetscInt its, PetscReal fnorm, void *)
PetscErrorCode __libmesh_petsc_snes_mffd_interface(void *ctx, Vec x, Vec r)
virtual void postcheck(const NumericVector< Number > &old_soln, NumericVector< Number > &search_direction, NumericVector< Number > &new_soln, bool &changed_search_direction, bool &changed_new_soln, sys_type &S)=0
This interface, which is inspired by PETSc&#39;s, passes the user: .) A constant reference to the "old" s...
virtual void swap(NumericVector< T > &v) override
Swaps the contents of this with v.
Generic sparse matrix.
Definition: vector_fe_ex5.C:46
PetscErrorCode libmesh_petsc_snes_mffd_residual(SNES snes, Vec x, Vec r, void *ctx)
void enforce_constraints_on_residual(const NonlinearImplicitSystem &system, NumericVector< Number > *rhs, NumericVector< Number > const *solution, bool homogeneous=true) const
Definition: dof_map.h:2359
processor_id_type size() const
const sys_type & system() const
NonlinearImplicitSystem::ComputeJacobian * jacobian_object
Object that computes the Jacobian J(X) of the nonlinear system at the input iterate X...
virtual void zero()=0
Set all entries to 0.
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:257
bool _zero_out_jacobian
true to zero out jacobian before going into application level call-back, otherwise false ...
bool _exact_constraint_enforcement
Whether we should enforce exact constraints globally during a solve.
virtual void jacobian(const NumericVector< Number > &X, SparseMatrix< Number > &J, sys_type &S)=0
Jacobian function.
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
libmesh_assert(ctx)
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and non-linear solv...
ResidualContext(PetscNonlinearSolver< Number > *solver_in, NonlinearImplicitSystem &sys_in)
ResidualContext libmesh_petsc_snes_residual_helper(SNES snes, Vec x, void *ctx)
PetscErrorCode __libmesh_petsc_snes_fd_residual(SNES, Vec x, Vec r, void *ctx)
virtual void close() override
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
PetscErrorCode libmesh_petsc_snes_mffd_interface(void *ctx, Vec x, Vec r)
void attach_dof_map(const DofMap &dof_map)
Set a pointer to the DofMap to use.
Definition: sparse_matrix.C:72
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:510
PetscErrorCode libmesh_petsc_preconditioner_setup(PC)
This function is called by PETSc to initialize the preconditioner.
PetscErrorCode libmesh_petsc_linesearch_shellfunc(SNESLineSearch linesearch, void *ctx)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::unique_ptr< ComputeLineSearchObject > linesearch_object
A callable object that can be used to specify a custom line-search.
NonlinearImplicitSystem::ComputePostCheck * postcheck_object
A callable object that is executed after each nonlinear iteration.
PetscErrorCode libmesh_petsc_snes_jacobian(SNES, Vec x, Mat jac, Mat pc, void *ctx)
PetscErrorCode libmesh_petsc_snes_precheck(SNESLineSearch, Vec X, Vec Y, PetscBool *changed, void *context)
OStreamProxy out
virtual void precheck(const NumericVector< Number > &precheck_soln, NumericVector< Number > &search_direction, bool &changed, sys_type &S)=0
Abstract precheck method that users must override.
NonlinearImplicitSystem::ComputeResidual * mffd_residual_object
Object that computes the residual R(X) of the nonlinear system at the input iterate X for the purpose...
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
bool initialized()
Checks that library initialization has been done.
Definition: libmesh.C:276
void(* postcheck)(const NumericVector< Number > &old_soln, NumericVector< Number > &search_direction, NumericVector< Number > &new_soln, bool &changed_search_direction, bool &changed_new_soln, sys_type &S)
Function that performs a "check" on the Newton search direction and solution after each nonlinear ste...
PetscErrorCode __libmesh_petsc_snes_postcheck(SNESLineSearch, Vec x, Vec y, Vec w, PetscBool *changed_y, PetscBool *changed_w, void *context)
void * ctx
bool on_command_line(std::string arg)
Definition: libmesh.C:987
NonlinearImplicitSystem::ComputePreCheck * precheck_object
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
void set_computing_base_vector(bool computing_base_vector)
Set whether we are computing the base vector for matrix-free finite-differencing. ...
const DofMap & get_dof_map() const
Definition: system.h:2374
const SparseMatrix< Number > & get_system_matrix() const
PetscErrorCode libmesh_petsc_snes_residual(SNES, Vec x, Vec r, void *ctx)
virtual void residual_and_jacobian(const NumericVector< Number > &X, NumericVector< Number > *R, SparseMatrix< Number > *J, sys_type &S)=0
Residual & Jacobian function, calculated simultaneously.
PetscErrorCode libmesh_petsc_recalculate_monitor(SNES snes, PetscInt it, PetscReal norm, void *mctx)
void(* matvec)(const NumericVector< Number > &X, NumericVector< Number > *R, SparseMatrix< Number > *J, sys_type &S)
Function that computes either the residual or the Jacobian of the nonlinear system at the input ite...
NonlinearImplicitSystem::ComputeResidual * fd_residual_object
Object that computes the residual R(X) of the nonlinear system at the input iterate X for the purpose...
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
Callable abstract base class to be used as a callback to provide the solver with a basis for the syst...
void enforce_constraints_on_jacobian(const NonlinearImplicitSystem &system, SparseMatrix< Number > *jac) const
Definition: dof_map.h:2365