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 }
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 //---------------------------------------------------------------
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();
203 }
204 }
205
206 else
207 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
208
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());
213
214 X_global.swap(X_sys);
215 rc.sys.update();
216 X_global.swap(X_sys);
217
218 R.close();
219
221 {
222 rc.sys.get_dof_map().enforce_constraints_on_residual(rc.sys, &R, rc.sys.current_local_solution.get(), /*homogeneous=*/false);
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
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 {
267 rc.sys.get_dof_map().enforce_constraints_on_residual(rc.sys, &R, rc.sys.current_local_solution.get(), /*homogeneous=*/false);
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!");
301
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 {
314 rc.sys.get_dof_map().enforce_constraints_on_residual(rc.sys, &R, rc.sys.current_local_solution.get(), /*homogeneous=*/false);
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;
329 // No way to safety-check this cast, since we got a void *...
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 // The check requires an exact match, so skip it for MPI-parallel or threaded runs, or when the
341 // application reports that its residual is not reproducible
342 if (solver->snes_mf_reuse_base() && solver->reproducible_residual() &&
343 (solver->comm().size() == 1) && (libMesh::n_threads() == 1))
344 {
345 SNES snes = solver->snes();
346
347 KSP ksp;
348 LibmeshPetscCall2(solver->comm(), SNESGetKSP(snes, &ksp));
349
350 PetscInt ksp_it;
351 LibmeshPetscCall2(solver->comm(), KSPGetIterationNumber(ksp, &ksp_it));
352
353 SNESType snes_type;
354 LibmeshPetscCall2(solver->comm(), SNESGetType(snes, &snes_type));
355
356 libmesh_assert_msg(snes_type, "We're being called from SNES; snes_type should be non-null");
357
358 Mat J;
359 LibmeshPetscCall2(solver->comm(), SNESGetJacobian(snes, &J, NULL, NULL, NULL));
360 libmesh_assert_msg(J, "We're being called from SNES; J should be non-null");
361
362 MatType mat_type;
363 LibmeshPetscCall2(solver->comm(), MatGetType(J, &mat_type));
364 libmesh_assert_msg(mat_type, "We're being called from SNES; mat_type should be non-null");
365
366 bool is_operator_mffd = strcmp(mat_type, MATMFFD) == 0;
367
368 if ((ksp_it == PetscInt(0)) && is_operator_mffd)
369 {
370 bool computing_base_vector = solver->computing_base_vector();
371
372 if (computing_base_vector)
373 {
374 Vec nonlinear_residual;
375
376 LibmeshPetscCall2(solver->comm(), SNESGetFunction(snes, &nonlinear_residual, NULL, NULL));
377
378 PetscBool vecs_equal;
379 LibmeshPetscCall2(solver->comm(), VecEqual(r, nonlinear_residual, &vecs_equal));
380
381 libmesh_error_msg_if(!(vecs_equal == PETSC_TRUE),
382 "You requested to reuse the nonlinear residual vector as the base vector for "
383 "computing the action of the matrix-free Jacobian, but the vectors are not "
384 "the same. Your physics must have states; either remove the states "
385 "from your code or make sure that you set_mf_reuse_base(false)");
386 }
387
388 // There are always exactly two function evaluations for the zeroth ksp iteration when doing
389 // matrix-free approximation of the Jacobian action: one corresponding to the evaluation of
390 // the base vector, and the other corresponding to evaluation of the perturbed vector. So we
391 // toggle back and forth between states
392 solver->set_computing_base_vector(!computing_base_vector);
393 }
394 }
395#endif
396#endif
397
398 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
399 }
400
401 //---------------------------------------------------------------
402 // this function is called by PETSc to evaluate the Jacobian at X
403 PetscErrorCode
404 libmesh_petsc_snes_jacobian(SNES snes, Vec x, Mat jac, Mat pc, void * ctx)
405 {
406 PetscFunctionBegin;
407
408 LOG_SCOPE("jacobian()", "PetscNonlinearSolver");
409
411
412 // No way to safety-check this cast, since we got a void *...
414 static_cast<PetscNonlinearSolver<Number> *> (ctx);
415
416 libmesh_parallel_only(solver->comm());
417
418 // Get the current iteration number from the snes object,
419 // store it in the PetscNonlinearSolver object for possible use
420 // by the user's Jacobian function.
421 {
422 PetscInt n_iterations = 0;
423 LibmeshPetscCall2(solver->comm(), SNESGetIterationNumber(snes, &n_iterations));
424 solver->_current_nonlinear_iteration_number = cast_int<unsigned>(n_iterations);
425 }
426
427 //-----------------------------------------------------------------------------
428 // if the user has provided both function pointers and objects only the pointer
429 // will be used, so catch that as an error
430 libmesh_error_msg_if(solver->jacobian && solver->jacobian_object,
431 "ERROR: cannot specify both a function and object to compute the Jacobian!");
432
433 libmesh_error_msg_if(solver->matvec && solver->residual_and_jacobian_object,
434 "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
435
436 NonlinearImplicitSystem & sys = solver->system();
437
438 PetscMatrixBase<Number> * const PC = pc ? PetscMatrixBase<Number>::get_context(pc, sys.comm()) : nullptr;
439 PetscMatrixBase<Number> * Jac = jac ? PetscMatrixBase<Number>::get_context(jac, sys.comm()) : nullptr;
440 PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
441 PetscVector<Number> X_global(x, sys.comm());
442
443 PetscMFFDMatrix<Number> mffd_jac(sys.comm());
444 PetscBool p_is_shell = PETSC_FALSE;
445 PetscBool j_is_mffd = PETSC_FALSE;
446 PetscBool j_is_shell = PETSC_FALSE;
447 if (pc)
448 LibmeshPetscCall2(sys.comm(), PetscObjectTypeCompare((PetscObject)pc, MATSHELL, &p_is_shell));
449 libmesh_assert(jac);
450 LibmeshPetscCall2(sys.comm(), PetscObjectTypeCompare((PetscObject)jac, MATMFFD, &j_is_mffd));
451 LibmeshPetscCall2(sys.comm(), PetscObjectTypeCompare((PetscObject)jac, MATSHELL, &j_is_shell));
452 if (j_is_mffd == PETSC_TRUE)
453 {
454 libmesh_assert(!Jac);
455 Jac = &mffd_jac;
456 // mffd_jac is function-local, so don't attach a context to jac here -- it would
457 // dangle once mffd_jac is destroyed at the end of this call.
458 mffd_jac.assign(jac, /*set_context=*/false);
459 }
460
461 // We already computed the Jacobian during the residual evaluation
463 {
464 // We could be doing matrix-free in which case we cannot rely on closing of explicit matrices
465 // that occurs during the PETSc residual callback
466 if ((j_is_shell == PETSC_TRUE) || (j_is_mffd == PETSC_TRUE))
467 Jac->close();
468
469 if (pc && (p_is_shell == PETSC_TRUE))
470 PC->close();
471
472 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
473 }
474
475 // Set the dof maps
476 PC->attach_dof_map(sys.get_dof_map());
477 Jac->attach_dof_map(sys.get_dof_map());
478
479 // Use the systems update() to get a good local version of the parallel solution
480 X_global.swap(X_sys);
481 sys.update();
482 X_global.swap(X_sys);
483
484 // Enforce constraints (if any) exactly on the
485 // current_local_solution. This is the solution vector that is
486 // actually used in the computation of the residual below, and is
487 // not locked by debug-enabled PETSc the way that "x" is.
490
491 if (solver->_zero_out_jacobian)
492 PC->zero();
493
494
495 if (solver->jacobian != nullptr)
496 solver->jacobian(*sys.current_local_solution.get(), *PC, sys);
497
498 else if (solver->jacobian_object != nullptr)
499 solver->jacobian_object->jacobian(*sys.current_local_solution.get(), *PC, sys);
500
501 else if (solver->matvec != nullptr)
502 solver->matvec(*sys.current_local_solution.get(), nullptr, PC, sys);
503
504 else
505 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
506
507 PC->close();
509 {
511 PC->close();
512 }
513
514 if (Jac != PC)
515 {
516 // Assume that shells know what they're doing
517 libmesh_assert(!solver->_exact_constraint_enforcement || (j_is_mffd == PETSC_TRUE) ||
518 (j_is_shell == PETSC_TRUE));
519 Jac->close();
520 }
521
522 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
523 }
524
525 // This function gets called by PETSc in place of the standard Petsc line searches
526 // if a linesearch object is supplied to the PetscNonlinearSolver class. It wraps
527 // the linesearch algorithm implemented on the linesearch object.
528 // * "linesearch" is an object that can be used to access the non-linear and linear solution
529 // vectors as well as the residual and SNES object
530 // * "ctx" is the PetscNonlinearSolver context
531 PetscErrorCode libmesh_petsc_linesearch_shellfunc (SNESLineSearch linesearch, void * ctx)
532 {
533 PetscFunctionBegin;
534
535 // No way to safety-check this cast, since we got a void *...
537 static_cast<PetscNonlinearSolver<Number> *> (ctx);
538
539 libmesh_parallel_only(solver->comm());
540
541 solver->linesearch_object->linesearch(linesearch);
542 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
543 }
544
545 // This function gets called by PETSc after the SNES linesearch is
546 // complete. We use it to exactly enforce any constraints on the
547 // solution which may have drifted during the linear solve. In the
548 // PETSc nomenclature:
549 // * "x" is the old solution vector,
550 // * "y" is the search direction (Newton step) vector,
551 // * "w" is the candidate solution vector, and
552 // the user is responsible for setting changed_y and changed_w
553 // appropriately, depending on whether or not the search
554 // direction or solution vector was changed, respectively.
555 PetscErrorCode libmesh_petsc_snes_postcheck(SNESLineSearch, Vec x, Vec y, Vec w, PetscBool * changed_y, PetscBool * changed_w, void * context)
556 {
557 PetscFunctionBegin;
558
559 LOG_SCOPE("postcheck()", "PetscNonlinearSolver");
560
561 // PETSc almost certainly initializes these to false already, but
562 // it doesn't hurt to be explicit.
563 *changed_w = PETSC_FALSE;
564 *changed_y = PETSC_FALSE;
565
566 libmesh_assert(context);
567
568 // Cast the context to a NonlinearSolver object.
570 static_cast<PetscNonlinearSolver<Number> *> (context);
571
572 libmesh_parallel_only(solver->comm());
573
574 // If the user has provided both postcheck function pointer and
575 // object, this is ambiguous, so throw an error.
576 libmesh_error_msg_if(solver->postcheck && solver->postcheck_object,
577 "ERROR: cannot specify both a function and object for performing the solve postcheck!");
578
579 // It's also possible that we don't need to do anything at all, in
580 // that case return early...
581 NonlinearImplicitSystem & sys = solver->system();
582
583 if (!solver->postcheck && !solver->postcheck_object)
584 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
585
586 // We definitely need to wrap at least "w"
587 PetscVector<Number> petsc_w(w, sys.comm());
588
589 // The user sets these flags in his/her postcheck function to
590 // indicate whether they changed something.
591 bool
592 changed_search_direction = false,
593 changed_new_soln = false;
594
595 if (solver->postcheck || solver->postcheck_object)
596 {
597 PetscVector<Number> petsc_x(x, sys.comm());
598 PetscVector<Number> petsc_y(y, sys.comm());
599
600 if (solver->postcheck)
601 solver->postcheck(petsc_x,
602 petsc_y,
603 petsc_w,
604 changed_search_direction,
605 changed_new_soln,
606 sys);
607
608 else if (solver->postcheck_object)
609 solver->postcheck_object->postcheck(petsc_x,
610 petsc_y,
611 petsc_w,
612 changed_search_direction,
613 changed_new_soln,
614 sys);
615 }
616
617 // Record whether the user changed the solution or the search direction.
618 if (changed_search_direction)
619 *changed_y = PETSC_TRUE;
620
621 if (changed_new_soln)
622 *changed_w = PETSC_TRUE;
623
624 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
625 }
626
627 PetscErrorCode libmesh_petsc_snes_precheck(SNESLineSearch, Vec X, Vec Y, PetscBool * changed, void * context)
628 {
629 PetscFunctionBegin;
630
631 LOG_SCOPE("precheck()", "PetscNonlinearSolver");
632
633 // PETSc almost certainly initializes these to false already, but
634 // it doesn't hurt to be explicit.
635 *changed = PETSC_FALSE;
636
637 libmesh_assert(context);
638
639 // Cast the context to a NonlinearSolver object.
641 static_cast<PetscNonlinearSolver<Number> *> (context);
642
643 libmesh_parallel_only(solver->comm());
644
645 // It's possible that we don't need to do anything at all, in
646 // that case return early...
647 if (!solver->precheck_object)
648 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
649
650 // The user sets these flags in his/her postcheck function to
651 // indicate whether they changed something.
652 bool
653 petsc_changed = false;
654
655 auto & sys = solver->system();
656 auto & x_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
657 PetscVector<Number> petsc_x(X, sys.comm());
658 PetscVector<Number> petsc_y(Y, sys.comm());
659
660 // Use the systems update() to get a good local version of the parallel solution
661 petsc_x.swap(x_sys);
662 sys.update();
663 petsc_x.swap(x_sys);
664
665 // Enforce constraints (if any) exactly on the
666 // current_local_solution. This is the solution vector that is
667 // actually used in the computation of residuals and Jacobians, and is
668 // not locked by debug-enabled PETSc the way that "x" is.
670 auto & local_soln = *sys.current_local_solution.get();
672 sys.get_dof_map().enforce_constraints_exactly(sys, &local_soln);
673
674 solver->precheck_object->precheck(local_soln,
675 petsc_y,
676 petsc_changed,
677 sys);
678
679 // Record whether the user changed the solution or the search direction.
680 if (petsc_changed)
681 *changed = PETSC_TRUE;
682
683 PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
684 }
685
686} // end extern "C"
687
688
689
690//---------------------------------------------------------------------
691// PetscNonlinearSolver<> methods
692template <typename T>
694 NonlinearSolver<T>(system_in),
695 linesearch_object(nullptr),
696 _reason(SNES_CONVERGED_ITERATING/*==0*/), // Arbitrary initial value...
697 _n_linear_iterations(0),
698 _current_nonlinear_iteration_number(0),
699 _zero_out_residual(true),
700 _zero_out_jacobian(true),
701 _default_monitor(true),
702 _snesmf_reuse_base(true),
703 _reproducible_residual(true),
704 _computing_base_vector(true),
705 _setup_reuse(false)
706{
707}
708
709
710
711template <typename T>
713
714
715
716template <typename T>
718{
719 if (this->initialized())
720 {
721 this->_is_initialized = false;
722
723 // If we don't need the preconditioner next time
724 // retain the original behavior of clearing the data
725 // between solves.
726 if (!(reuse_preconditioner()))
727 {
728 // SNESReset really ought to work but replacing destroy() with
729 // SNESReset causes a very slight change in behavior that
730 // manifests as two failed MOOSE tests...
731 _snes.destroy();
732 }
733
734 // Reset the nonlinear iteration counter. This information is only relevant
735 // *during* the solve(). After the solve is completed it should return to
736 // the default value of 0.
737 _current_nonlinear_iteration_number = 0;
738 }
739}
740
741template <typename T>
742void PetscNonlinearSolver<T>::init (const char * name)
743{
744 parallel_object_only();
745
746 // Initialize the data structures if not done so already.
747 if (!this->initialized())
748 {
749 this->_is_initialized = true;
750
751 // Make only if we don't already have a retained snes
752 // hanging around from the last solve
753 if (!_snes)
754 LibmeshPetscCall(SNESCreate(this->comm().get(), _snes.get()));
755
756 // I believe all of the following can be safely repeated
757 // even on an old snes instance from the last solve
758
759 if (name)
760 {
761 libmesh_assert(std::string(name).front() != '-');
762 libmesh_assert(std::string(name).back() == '_');
763 LibmeshPetscCall(SNESSetOptionsPrefix(_snes, name));
764 }
765
766 // Attaching a DM to SNES.
767#if defined(LIBMESH_ENABLE_AMR) && defined(LIBMESH_HAVE_METAPHYSICL)
768 bool use_petsc_dm = libMesh::on_command_line(
769 "--" + (name ? std::string(name) : std::string("")) + "use_petsc_dm");
770
771 // This needs to be called before SNESSetFromOptions
772 if (use_petsc_dm)
773 this->_dm_wrapper.init_and_attach_petscdm(this->system(), _snes);
774 else
775#endif
776 {
778 LibmeshPetscCall(DMCreate(this->comm().get(), dm.get()));
779 LibmeshPetscCall(DMSetType(dm, DMLIBMESH));
780 LibmeshPetscCall(DMlibMeshSetSystem(dm, this->system()));
781
782 if (name)
783 LibmeshPetscCall(DMSetOptionsPrefix(dm, name));
784
785 LibmeshPetscCall(DMSetFromOptions(dm));
786 LibmeshPetscCall(DMSetUp(dm));
787 LibmeshPetscCall(SNESSetDM(_snes, dm));
788 // SNES now owns the reference to dm.
789 }
790
791 setup_default_monitor();
792
793 // If the SolverConfiguration object is provided, use it to set
794 // options during solver initialization.
795 if (this->_solver_configuration)
796 {
797 this->_solver_configuration->set_options_during_init();
798 }
799
800 if (this->_preconditioner)
801 {
802 KSP ksp;
803 LibmeshPetscCall(SNESGetKSP (_snes, &ksp));
804 PC pc;
805 LibmeshPetscCall(KSPGetPC(ksp,&pc));
806
807 this->_preconditioner->init();
808
809 LibmeshPetscCall(PCSetType(pc, PCSHELL));
810 LibmeshPetscCall(PCShellSetContext(pc,(void *)this->_preconditioner));
811
812 //Re-Use the shell functions from petsc_linear_solver
813 LibmeshPetscCall(PCShellSetSetUp(pc,libmesh_petsc_preconditioner_setup));
814 LibmeshPetscCall(PCShellSetApply(pc,libmesh_petsc_preconditioner_apply));
815 }
816 }
817
818
819 // Tell PETSc about our linesearch "post-check" function, but only
820 // if the user has provided one. There seem to be extra,
821 // unnecessary residual calculations if a postcheck function is
822 // attached for no reason.
823 if (this->postcheck || this->postcheck_object)
824 {
825 SNESLineSearch linesearch;
826 LibmeshPetscCall(SNESGetLineSearch(_snes, &linesearch));
827
828 LibmeshPetscCall(SNESLineSearchSetPostCheck(linesearch, libmesh_petsc_snes_postcheck, this));
829 }
830
831 if (this->precheck_object)
832 {
833 SNESLineSearch linesearch;
834 LibmeshPetscCall(SNESGetLineSearch(_snes, &linesearch));
835
836 LibmeshPetscCall(SNESLineSearchSetPreCheck(linesearch, libmesh_petsc_snes_precheck, this));
837 }
838}
839
840
841template <typename T>
842SNES PetscNonlinearSolver<T>::snes(const char * name)
843{
844 this->init(name);
845 return _snes;
846}
847
848
849
850template <typename T>
851void
853 void (*computeSubspace)(std::vector<NumericVector<Number> *> &, sys_type &),
854 MatNullSpace * msp)
855{
856 parallel_object_only();
857
858 std::vector<NumericVector<Number> *> sp;
859 if (computeSubspaceObject)
860 (*computeSubspaceObject)(sp, this->system());
861 else
862 (*computeSubspace)(sp, this->system());
863
864 *msp = LIBMESH_PETSC_NULLPTR;
865 if (sp.size())
866 {
867 PetscInt nmodes = cast_int<PetscInt>(sp.size());
868
869 std::vector<Vec> modes(nmodes);
870 std::vector<PetscScalar> dots(nmodes);
871
872 for (PetscInt i=0; i<nmodes; ++i)
873 {
874 auto pv = cast_ptr<PetscVector<T> *>(sp[i]);
875
876 LibmeshPetscCall(VecDuplicate(pv->vec(), &modes[i]));
877
878 LibmeshPetscCall(VecCopy(pv->vec(), modes[i]));
879 }
880
881 // Normalize.
882 LibmeshPetscCall(VecNormalize(modes[0], LIBMESH_PETSC_NULLPTR));
883
884 for (PetscInt i=1; i<nmodes; i++)
885 {
886 // Orthonormalize vec[i] against vec[0:i-1]
887 LibmeshPetscCall(VecMDot(modes[i], i, modes.data(), dots.data()));
888
889 for (PetscInt j=0; j<i; j++)
890 dots[j] *= -1.;
891
892 LibmeshPetscCall(VecMAXPY(modes[i], i, dots.data(), modes.data()));
893
894 LibmeshPetscCall(VecNormalize(modes[i], LIBMESH_PETSC_NULLPTR));
895 }
896
897 LibmeshPetscCall(MatNullSpaceCreate(this->comm().get(), PETSC_FALSE, nmodes, modes.data(), msp));
898
899 for (PetscInt i=0; i<nmodes; ++i)
900 LibmeshPetscCall(VecDestroy(&modes[i]));
901 }
902}
903
904template <typename T>
905std::pair<unsigned int, Real>
906PetscNonlinearSolver<T>::solve (SparseMatrix<T> & pre_in, // System Preconditioning Matrix
907 NumericVector<T> & x_in, // Solution vector
908 NumericVector<T> & r_in, // Residual vector
909 const double tol, // Stopping tolerance
910 const unsigned int m_its)
911{
912 return this->solve(pre_in, pre_in, x_in, r_in, tol, m_its);
913}
914
915template <typename T>
916std::pair<unsigned int, Real>
917PetscNonlinearSolver<T>::solve (SparseMatrix<T> & jac_in, // Jacobian operator matrix (Amat)
918 SparseMatrix<T> & pre_in, // Preconditioning matrix (Pmat)
919 NumericVector<T> & x_in, // Solution vector
920 NumericVector<T> & r_in, // Residual vector
921 const double, // Stopping tolerance
922 const unsigned int)
923{
924 parallel_object_only();
925
926 LOG_SCOPE("solve()", "PetscNonlinearSolver");
927 this->init ();
928
929 // Make sure the data passed in are really of Petsc types
930 PetscMatrixBase<T> * jac = cast_ptr<PetscMatrixBase<T> *>(&jac_in);
931 PetscMatrixBase<T> * pre = cast_ptr<PetscMatrixBase<T> *>(&pre_in);
932 PetscVector<T> * x = cast_ptr<PetscVector<T> *>(&x_in);
933 PetscVector<T> * r = cast_ptr<PetscVector<T> *>(&r_in);
934
935 PetscInt n_iterations =0;
936 // Should actually be a PetscReal, but I don't know which version of PETSc first introduced PetscReal
937 Real final_residual_norm=0.;
938
939 // We don't want to do this twice because it resets
940 // SNESSetLagPreconditioner
941 if ((reuse_preconditioner()) && (!_setup_reuse))
942 {
943 _setup_reuse = true;
944 LibmeshPetscCall(SNESSetLagPreconditionerPersists(_snes, PETSC_TRUE));
945 // According to the PETSC 3.16.5 docs -2 is a magic number which
946 // means "recalculate the next time you need it and then not again"
947 LibmeshPetscCall(SNESSetLagPreconditioner(_snes, -2));
948 // Add in our callback which will trigger recalculating
949 // the preconditioner when we hit reuse_preconditioner_max_linear_its
950 LibmeshPetscCall(SNESMonitorSet(_snes, &libmesh_petsc_recalculate_monitor,
951 this,
952 NULL));
953 }
954 else if (!(reuse_preconditioner()))
955 // This covers the case where it was enabled but was then disabled
956 {
957 LibmeshPetscCall(SNESSetLagPreconditionerPersists(_snes, PETSC_FALSE));
958 if (_setup_reuse)
959 {
960 _setup_reuse = false;
961 LibmeshPetscCall(SNESMonitorCancel(_snes));
962 // Readd default monitor
963 setup_default_monitor();
964 }
965 }
966
967 LibmeshPetscCall(SNESSetFunction (_snes, r->vec(), libmesh_petsc_snes_residual, this));
968
969 // Only set the jacobian function if we've been provided with something to call.
970 // This allows a user to set their own jacobian function if they want to
971 if (this->jacobian || this->jacobian_object || this->residual_and_jacobian_object)
972 LibmeshPetscCall(SNESSetJacobian (_snes, jac->mat(), pre->mat(), libmesh_petsc_snes_jacobian, this));
973
974 // Have the Krylov subspace method use our good initial guess rather than 0
975 KSP ksp;
976 LibmeshPetscCall(SNESGetKSP (_snes, &ksp));
977
978 // Set the tolerances for the iterative solver. Use the user-supplied
979 // tolerance for the relative residual & leave the others at default values
980 LibmeshPetscCall(KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
981 PETSC_DEFAULT, this->max_linear_iterations));
982
983 // Set the tolerances for the non-linear solver.
984 LibmeshPetscCall(SNESSetTolerances(_snes,
985 this->absolute_residual_tolerance,
986 this->relative_residual_tolerance,
987 this->relative_step_tolerance,
988 this->max_nonlinear_iterations,
989 this->max_function_evaluations));
990
991 // Not supported by PETSc
992 if (this->absolute_step_tolerance != 0) // 0 is default value, both in MOOSE and libMesh
993 libmesh_warning("Setting the absolute step tolerance is not supported with the PETSc nonlinear solver.");
994
995 // Set the divergence tolerance for the non-linear solver
996#if !PETSC_VERSION_LESS_THAN(3,8,0)
997 LibmeshPetscCall(SNESSetDivergenceTolerance(_snes, this->divergence_tolerance));
998#endif
999
1000 //Pull in command-line options
1001#if PETSC_VERSION_LESS_THAN(3,7,0)
1002 LibmeshPetscCall(KSPSetFromOptions(ksp));
1003#endif
1004 LibmeshPetscCall(SNESSetFromOptions(_snes));
1005
1006 PC pc;
1007 LibmeshPetscCall(KSPGetPC(ksp, &pc));
1009
1010#if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \
1011 !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE)
1012 {
1013 // Make sure hypre has been initialized
1014 LibmeshPetscCallExternal(HYPRE_Initialize);
1015 PetscScalar * dummyarray;
1016 PetscMemType mtype;
1017 LibmeshPetscCall(VecGetArrayAndMemType(x->vec(), &dummyarray, &mtype));
1018 LibmeshPetscCall(VecRestoreArrayAndMemType(x->vec(), &dummyarray));
1019 if (PetscMemTypeHost(mtype))
1020 LibmeshPetscCallExternal(HYPRE_SetMemoryLocation, HYPRE_MEMORY_HOST);
1021 }
1022#endif
1023
1024 if (this->user_presolve)
1025 this->user_presolve(this->system());
1026
1027 //Set the preconditioning matrix
1028 if (this->_preconditioner)
1029 {
1030 this->_preconditioner->set_matrix(pre_in);
1031 this->_preconditioner->init();
1032 }
1033
1034 // If the SolverConfiguration object is provided, use it to override
1035 // solver options.
1036 if (this->_solver_configuration)
1037 this->_solver_configuration->configure_solver();
1038
1039 // In PETSc versions before 3.5.0, it is not possible to call
1040 // SNESSetUp() before the solution and rhs vectors are initialized, as
1041 // this triggers the
1042 //
1043 // "Solution vector cannot be right hand side vector!"
1044 //
1045 // error message. It is also not possible to call SNESSetSolution()
1046 // in those versions of PETSc to work around the problem, since that
1047 // API was removed in 3.0.0 and only restored in 3.6.0. The
1048 // overzealous check was moved out of SNESSetUp in PETSc 3.5.0
1049 // (petsc/petsc@154060b), so this code block should be safe to use
1050 // in 3.5.0 and later.
1051#if !PETSC_VERSION_LESS_THAN(3,6,0)
1052 LibmeshPetscCall(SNESSetSolution(_snes, x->vec()));
1053#endif
1054 LibmeshPetscCall(SNESSetUp(_snes));
1055
1056 Mat J, P;
1057 LibmeshPetscCall(SNESGetJacobian(_snes, &J, &P,
1058 LIBMESH_PETSC_NULLPTR,
1059 LIBMESH_PETSC_NULLPTR));
1060 LibmeshPetscCall(MatMFFDSetFunction(J, libmesh_petsc_snes_mffd_interface, this));
1061#if !PETSC_VERSION_LESS_THAN(3,8,4)
1062#ifndef NDEBUG
1063 // If we're in debug mode, do not reuse the nonlinear function evaluation as the base for doing
1064 // matrix-free approximations of the Jacobian action. Instead if the user requested that we reuse
1065 // the base, we'll check the base function evaluation and compare it to the nonlinear residual
1066 // evaluation. If they are different, then we'll error and inform the user that it's unsafe to
1067 // reuse the base
1068 LibmeshPetscCall(MatSNESMFSetReuseBase(J, PETSC_FALSE));
1069#else
1070 // Resue the residual vector from SNES
1071 LibmeshPetscCall(MatSNESMFSetReuseBase(J, static_cast<PetscBool>(_snesmf_reuse_base)));
1072#endif
1073#endif
1074
1075 // Only set the nullspace if we have a way of computing it and the result is non-empty.
1076 if (this->nullspace || this->nullspace_object)
1077 {
1079 this->build_mat_null_space(this->nullspace_object, this->nullspace, msp.get());
1080 if (msp)
1081 {
1082 LibmeshPetscCall(MatSetNullSpace(J, msp));
1083 if (P != J)
1084 LibmeshPetscCall(MatSetNullSpace(P, msp));
1085 }
1086 }
1087
1088 // Only set the transpose nullspace if we have a way of computing it and the result is non-empty.
1089 if (this->transpose_nullspace || this->transpose_nullspace_object)
1090 {
1091#if PETSC_VERSION_LESS_THAN(3,6,0)
1092 libmesh_warning("MatSetTransposeNullSpace is only supported for PETSc >= 3.6, transpose nullspace will be ignored.");
1093#else
1095 this->build_mat_null_space(this->transpose_nullspace_object, this->transpose_nullspace, msp.get());
1096 if (msp)
1097 {
1098 LibmeshPetscCall(MatSetTransposeNullSpace(J, msp));
1099 if (P != J)
1100 LibmeshPetscCall(MatSetTransposeNullSpace(P, msp));
1101 }
1102#endif
1103 }
1104
1105 // Only set the nearnullspace if we have a way of computing it and the result is non-empty.
1106 if (this->nearnullspace || this->nearnullspace_object)
1107 {
1109 this->build_mat_null_space(this->nearnullspace_object, this->nearnullspace, msp.get());
1110
1111 if (msp)
1112 {
1113 LibmeshPetscCall(MatSetNearNullSpace(J, msp));
1114 if (P != J)
1115 LibmeshPetscCall(MatSetNearNullSpace(P, msp));
1116 }
1117 }
1118
1119 SNESLineSearch linesearch;
1120 if (linesearch_object)
1121 {
1122 LibmeshPetscCall(SNESGetLineSearch(_snes, &linesearch));
1123 LibmeshPetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHSHELL));
1124#if PETSC_RELEASE_GREATER_EQUALS(3, 21, 0)
1125 LibmeshPetscCall(SNESLineSearchShellSetApply(linesearch, libmesh_petsc_linesearch_shellfunc, this));
1126#else
1127 LibmeshPetscCall(SNESLineSearchShellSetUserFunc(linesearch, libmesh_petsc_linesearch_shellfunc, this));
1128#endif
1129 }
1130
1131 LibmeshPetscCall(SNESSolve (_snes, LIBMESH_PETSC_NULLPTR, x->vec()));
1132
1133 LibmeshPetscCall(SNESGetIterationNumber(_snes, &n_iterations));
1134
1135 LibmeshPetscCall(SNESGetLinearSolveIterations(_snes, &_n_linear_iterations));
1136
1137 // SNESGetFunction has been around forever and should work on all
1138 // versions of PETSc. This is also now the recommended approach
1139 // according to the documentation for the PETSc 3.5.1 release:
1140 // http://www.mcs.anl.gov/petsc/documentation/changes/35.html
1141 Vec f;
1142 LibmeshPetscCall(SNESGetFunction(_snes, &f, 0, 0));
1143 LibmeshPetscCall(VecNorm(f, NORM_2, pPR(&final_residual_norm)));
1144
1145 // Get and store the reason for convergence
1146 LibmeshPetscCall(SNESGetConvergedReason(_snes, &_reason));
1147
1148 //Based on Petsc 2.3.3 documentation all diverged reasons are negative
1149 this->converged = (_reason >= 0);
1150
1151 // Reset data structure
1152 this->clear();
1153
1154 // return the # of its. and the final residual norm.
1155 return std::make_pair(n_iterations, final_residual_norm);
1156}
1157
1158
1159
1160template <typename T>
1162{
1163
1164 libMesh::out << "Nonlinear solver convergence/divergence reason: "
1165 << SNESConvergedReasons[this->get_converged_reason()] << std::endl;
1166}
1167
1168
1169
1170template <typename T>
1172{
1173 if (this->initialized())
1174 LibmeshPetscCall(SNESGetConvergedReason(_snes, &_reason));
1175
1176 return _reason;
1177}
1178
1179template <typename T>
1181{
1182 return _n_linear_iterations;
1183}
1184
1185template <typename T>
1187{
1188 if (_default_monitor)
1189 LibmeshPetscCall(
1190 SNESMonitorSet(_snes, libmesh_petsc_snes_monitor, this, LIBMESH_PETSC_NULLPTR));
1191}
1192
1193template <typename T>
1195{
1196 return this->_reuse_preconditioner;
1197}
1198
1199template <typename T>
1201{
1202 return this->_reuse_preconditioner_max_linear_its;
1203}
1204
1205template <typename T>
1207{
1208 // Easiest way is just to clear everything out
1209 this->_is_initialized = false;
1210 _snes.destroy();
1211 _setup_reuse = false;
1212}
1213
1214//------------------------------------------------------------------
1215// Explicit instantiations
1216template class LIBMESH_EXPORT PetscNonlinearSolver<Number>;
1217
1218} // namespace libMesh
1219
1220
1221
1222#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:2540
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:2531
void enforce_constraints_on_jacobian(const NonlinearImplicitSystem &system, SparseMatrix< Number > *jac) const
Definition dof_map.h:2546
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.
void assign(Mat m, bool set_context)
Adopt an existing, externally-owned Mat, without destroying it when this object goes out of scope.
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 > &pre_in, NumericVector< T > &, NumericVector< T > &, const double, const unsigned int) override
Call the Petsc solver, using the same matrix for the system and preconditioner matrices.
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...