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