20 #include "libmesh/libmesh_common.h"
22 #ifdef LIBMESH_HAVE_PETSC
27 #include "libmesh/libmesh_logging.h"
28 #include "libmesh/nonlinear_implicit_system.h"
29 #include "libmesh/petsc_nonlinear_solver.h"
30 #include "libmesh/petsc_linear_solver.h"
31 #include "libmesh/petsc_vector.h"
32 #include "libmesh/petsc_matrix.h"
33 #include "libmesh/dof_map.h"
34 #include "libmesh/preconditioner.h"
35 #include "libmesh/solver_configuration.h"
38 #include "libmesh/petscdmlibmesh.h"
41 #if PETSC_VERSION_LESS_THAN(3,4,0)
42 # define SNESGETLINESEARCH SNESGetSNESLineSearch
44 # define SNESGETLINESEARCH SNESGetLineSearch
53 PetscErrorCode ierr_in) :
67 LOG_SCOPE(
"residual()",
"PetscNonlinearSolver");
69 PetscErrorCode
ierr = 0;
82 PetscInt n_iterations = 0;
83 ierr = SNESGetIterationNumber(snes, &n_iterations);
84 CHKERRABORT(solver->
comm().get(),
ierr);
100 X_global.swap(X_sys);
129 << std::setw(2) << its
131 <<
", |residual|_2 = " << fnorm
138 #ifdef LIBMESH_ENABLE_DEPRECATED
142 libmesh_deprecated();
165 libmesh_error_msg(
"ERROR: cannot specify both a function and object to compute the Residual!");
168 libmesh_error_msg(
"ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
183 libmesh_error_msg(
"Error! Unable to compute residual and/or Jacobian!");
194 #ifdef LIBMESH_ENABLE_DEPRECATED
198 libmesh_deprecated();
223 libmesh_error_msg(
"Error! Unable to compute residual for forming finite difference Jacobian!");
234 #ifdef LIBMESH_ENABLE_DEPRECATED
238 libmesh_deprecated();
264 libmesh_error_msg(
"Error! Unable to compute residual for forming finite differenced"
265 "Jacobian-vector products!");
289 #ifdef LIBMESH_ENABLE_DEPRECATED
293 libmesh_deprecated();
302 #
if PETSC_RELEASE_LESS_THAN(3,5,0)
303 SNES snes, Vec x, Mat * jac, Mat * pc, MatStructure * msflag,
void *
ctx
305 SNES snes, Vec x, Mat jac, Mat pc,
void *
ctx
309 LOG_SCOPE(
"jacobian()",
"PetscNonlinearSolver");
311 PetscErrorCode
ierr=0;
323 PetscInt n_iterations = 0;
324 ierr = SNESGetIterationNumber(snes, &n_iterations);
325 CHKERRABORT(solver->
comm().get(),
ierr);
330 #if PETSC_RELEASE_LESS_THAN(3,5,0)
345 X_global.
swap(X_sys);
347 X_global.swap(X_sys);
362 libmesh_error_msg(
"ERROR: cannot specify both a function and object to compute the Jacobian!");
365 libmesh_error_msg(
"ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
373 else if (solver->
matvec !=
nullptr)
380 libmesh_error_msg(
"Error! Unable to compute residual and/or Jacobian!");
387 #if PETSC_RELEASE_LESS_THAN(3,5,0)
388 *msflag = SAME_NONZERO_PATTERN;
410 #ifdef LIBMESH_ENABLE_DEPRECATED
413 #
if PETSC_RELEASE_LESS_THAN(3,5,0)
414 SNES snes, Vec x, Mat * jac, Mat * pc, MatStructure * msflag,
void *
ctx
416 SNES snes, Vec x, Mat jac, Mat pc,
void *
ctx
420 libmesh_deprecated();
422 #
if PETSC_RELEASE_LESS_THAN(3,5,0)
423 snes, x, jac, pc, msflag,
ctx
425 snes, x, jac, pc,
ctx
442 #
if PETSC_VERSION_LESS_THAN(3,3,0)
443 SNES, Vec x, Vec y, Vec w,
void * context,
PetscBool * changed_y,
PetscBool * changed_w
445 SNESLineSearch, Vec x, Vec y, Vec w,
PetscBool * changed_y,
PetscBool * changed_w,
void * context
449 LOG_SCOPE(
"postcheck()",
"PetscNonlinearSolver");
451 PetscErrorCode
ierr = 0;
455 *changed_w = PETSC_FALSE;
456 *changed_y = PETSC_FALSE;
467 libmesh_error_msg(
"ERROR: cannot specify both a function and object for performing the solve postcheck!");
482 changed_search_direction =
false,
483 changed_new_soln =
false;
494 changed_search_direction,
502 changed_search_direction,
508 if (changed_search_direction)
509 *changed_y = PETSC_TRUE;
511 if (changed_new_soln)
512 *changed_w = PETSC_TRUE;
517 #ifdef LIBMESH_ENABLE_DEPRECATED
519 #
if PETSC_VERSION_LESS_THAN(3,3,0)
520 SNES, Vec x, Vec y, Vec w,
void * context,
PetscBool * changed_y,
PetscBool * changed_w
522 SNESLineSearch, Vec x, Vec y, Vec w,
PetscBool * changed_y,
PetscBool * changed_w,
void * context
526 libmesh_deprecated();
528 #
if PETSC_VERSION_LESS_THAN(3,3,0)
529 nullptr, x, y, w, context, changed_y, changed_w
531 nullptr, x, y, w, changed_y, changed_w, context
542 template <
typename T>
545 linesearch_object(nullptr),
546 _reason(SNES_CONVERGED_ITERATING),
547 _n_linear_iterations(0),
548 _current_nonlinear_iteration_number(0),
549 _zero_out_residual(true),
550 _zero_out_jacobian(true),
551 _default_monitor(true),
552 _snesmf_reuse_base(true)
558 template <
typename T>
566 template <
typename T>
573 PetscErrorCode
ierr=0;
575 ierr = LibMeshSNESDestroy(&_snes);
576 LIBMESH_CHKERR(
ierr);
581 _current_nonlinear_iteration_number = 0;
587 template <
typename T>
595 PetscErrorCode
ierr=0;
597 ierr = SNESCreate(this->comm().
get(),&_snes);
598 LIBMESH_CHKERR(
ierr);
602 ierr = SNESSetOptionsPrefix(_snes,
name);
603 LIBMESH_CHKERR(
ierr);
606 #if !PETSC_RELEASE_LESS_THAN(3,3,0)
609 ierr = DMCreate(this->comm().
get(), &dm);LIBMESH_CHKERR(
ierr);
610 ierr = DMSetType(dm,DMLIBMESH);LIBMESH_CHKERR(
ierr);
614 ierr = DMSetOptionsPrefix(dm,
name); LIBMESH_CHKERR(
ierr);
616 ierr = DMSetFromOptions(dm); LIBMESH_CHKERR(
ierr);
617 ierr = DMSetUp(dm); LIBMESH_CHKERR(
ierr);
618 ierr = SNESSetDM(this->_snes, dm); LIBMESH_CHKERR(
ierr);
620 ierr = DMDestroy(&dm); LIBMESH_CHKERR(
ierr);
624 if (_default_monitor)
628 LIBMESH_CHKERR(
ierr);
633 if (this->_solver_configuration)
635 this->_solver_configuration->set_options_during_init();
638 #if PETSC_VERSION_LESS_THAN(3,1,0)
641 ierr = SNESSetFromOptions(_snes);
642 LIBMESH_CHKERR(
ierr);
645 if (this->_preconditioner)
648 ierr = SNESGetKSP (_snes, &ksp);
649 LIBMESH_CHKERR(
ierr);
651 ierr = KSPGetPC(ksp,&pc);
652 LIBMESH_CHKERR(
ierr);
654 this->_preconditioner->init();
656 PCSetType(pc, PCSHELL);
657 PCShellSetContext(pc,(
void *)this->_preconditioner);
670 if (this->postcheck || this->postcheck_object)
672 #if PETSC_VERSION_LESS_THAN(3,3,0)
674 LIBMESH_CHKERR(
ierr);
677 SNESLineSearch linesearch;
678 PetscErrorCode
ierr = SNESGETLINESEARCH(_snes, &linesearch);
679 LIBMESH_CHKERR(
ierr);
682 LIBMESH_CHKERR(
ierr);
687 #if !PETSC_VERSION_LESS_THAN(3,3,0)
688 template <
typename T>
695 std::vector<NumericVector<Number> *> sp;
696 if (computeSubspaceObject)
697 (*computeSubspaceObject)(sp, this->system());
699 (*computeSubspace)(sp, this->system());
706 PetscInt nmodes = cast_int<PetscInt>(sp.size());
708 #if PETSC_RELEASE_LESS_THAN(3,5,0)
709 ierr = PetscMalloc2(nmodes,Vec,&modes,nmodes,PetscScalar,&dots);
711 ierr = PetscMalloc2(nmodes,&modes,nmodes,&dots);
713 LIBMESH_CHKERR(
ierr);
715 for (PetscInt i=0; i<nmodes; ++i)
720 ierr = VecDuplicate(v, modes+i);
721 LIBMESH_CHKERR(
ierr);
723 ierr = VecCopy(v,modes[i]);
724 LIBMESH_CHKERR(
ierr);
728 ierr = VecNormalize(modes[0],PETSC_NULL);
729 LIBMESH_CHKERR(
ierr);
731 for (PetscInt i=1; i<nmodes; i++)
734 ierr = VecMDot(modes[i],i,modes,dots);
735 LIBMESH_CHKERR(
ierr);
737 for (PetscInt j=0; j<i; j++)
740 ierr = VecMAXPY(modes[i],i,dots,modes);
741 LIBMESH_CHKERR(
ierr);
743 ierr = VecNormalize(modes[i],PETSC_NULL);
744 LIBMESH_CHKERR(
ierr);
747 ierr = MatNullSpaceCreate(this->comm().
get(), PETSC_FALSE, nmodes, modes, msp);
748 LIBMESH_CHKERR(
ierr);
750 for (PetscInt i=0; i<nmodes; ++i)
752 ierr = VecDestroy(modes+i);
753 LIBMESH_CHKERR(
ierr);
756 ierr = PetscFree2(modes,dots);
757 LIBMESH_CHKERR(
ierr);
762 template <
typename T>
763 std::pair<unsigned int, Real>
770 LOG_SCOPE(
"solve()",
"PetscNonlinearSolver");
778 PetscErrorCode
ierr=0;
779 PetscInt n_iterations =0;
781 Real final_residual_norm=0.;
784 LIBMESH_CHKERR(
ierr);
788 if (this->jacobian || this->jacobian_object || this->residual_and_jacobian_object)
791 LIBMESH_CHKERR(
ierr);
795 #if !PETSC_VERSION_LESS_THAN(3,3,0)
797 if (this->nullspace || this->nullspace_object)
800 this->build_mat_null_space(this->nullspace_object, this->nullspace, &msp);
803 ierr = MatSetNullSpace(pre->
mat(), msp);
804 LIBMESH_CHKERR(
ierr);
805 ierr = MatNullSpaceDestroy(&msp);
806 LIBMESH_CHKERR(
ierr);
811 if (this->transpose_nullspace || this->transpose_nullspace_object)
813 #if PETSC_VERSION_LESS_THAN(3,6,0)
814 libmesh_warning(
"MatSetTransposeNullSpace is only supported for PETSc >= 3.6, transpose nullspace will be ignored.");
816 MatNullSpace msp = PETSC_NULL;
817 this->build_mat_null_space(this->transpose_nullspace_object, this->transpose_nullspace, &msp);
820 ierr = MatSetTransposeNullSpace(pre->
mat(), msp);
821 LIBMESH_CHKERR(
ierr);
822 ierr = MatNullSpaceDestroy(&msp);
823 LIBMESH_CHKERR(
ierr);
829 if (this->nearnullspace || this->nearnullspace_object)
831 MatNullSpace msp = PETSC_NULL;
832 this->build_mat_null_space(this->nearnullspace_object, this->nearnullspace, &msp);
836 ierr = MatSetNearNullSpace(pre->
mat(), msp);
837 LIBMESH_CHKERR(
ierr);
838 ierr = MatNullSpaceDestroy(&msp);
839 LIBMESH_CHKERR(
ierr);
846 ierr = SNESGetKSP (_snes, &ksp);
847 LIBMESH_CHKERR(
ierr);
851 ierr = KSPSetTolerances (ksp, this->initial_linear_tolerance, PETSC_DEFAULT,
852 PETSC_DEFAULT, this->max_linear_iterations);
853 LIBMESH_CHKERR(
ierr);
856 ierr = SNESSetTolerances(_snes, this->absolute_residual_tolerance, this->relative_residual_tolerance,
857 this->relative_step_tolerance, this->max_nonlinear_iterations, this->max_function_evaluations);
858 LIBMESH_CHKERR(
ierr);
861 #if !PETSC_VERSION_LESS_THAN(3,8,0)
862 ierr = SNESSetDivergenceTolerance(_snes, this->divergence_tolerance);
863 LIBMESH_CHKERR(
ierr);
867 #if PETSC_VERSION_LESS_THAN(3,7,0)
868 KSPSetFromOptions(ksp);
870 SNESSetFromOptions(_snes);
872 if (this->user_presolve)
873 this->user_presolve(this->system());
876 if (this->_preconditioner)
878 this->_preconditioner->set_matrix(pre_in);
879 this->_preconditioner->init();
884 if (this->_solver_configuration)
886 this->_solver_configuration->configure_solver();
901 #if !PETSC_VERSION_LESS_THAN(3,5,0)
902 #if !PETSC_VERSION_LESS_THAN(3,6,0)
903 ierr = SNESSetSolution(_snes, x->vec());
904 LIBMESH_CHKERR(
ierr);
906 ierr = SNESSetUp(_snes);
907 LIBMESH_CHKERR(
ierr);
910 ierr = SNESGetJacobian(_snes,&J,PETSC_NULL,PETSC_NULL,PETSC_NULL);
911 LIBMESH_CHKERR(
ierr);
913 LIBMESH_CHKERR(
ierr);
914 #if !PETSC_VERSION_LESS_THAN(3, 8, 4)
916 ierr = MatSNESMFSetReuseBase(J, static_cast<PetscBool>(_snesmf_reuse_base));
917 LIBMESH_CHKERR(
ierr);
921 #if PETSC_VERSION_LESS_THAN(3, 3, 0)
922 if (linesearch_object)
923 libmesh_error_msg(
"Line search setter interface introduced in petsc version 3.3!");
925 SNESLineSearch linesearch;
926 if (linesearch_object)
928 ierr = SNESGETLINESEARCH(_snes, &linesearch);
929 LIBMESH_CHKERR(
ierr);
930 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHSHELL);
931 LIBMESH_CHKERR(
ierr);
933 LIBMESH_CHKERR(
ierr);
937 ierr = SNESSolve (_snes, PETSC_NULL, x->vec());
938 LIBMESH_CHKERR(
ierr);
940 ierr = SNESGetIterationNumber(_snes,&n_iterations);
941 LIBMESH_CHKERR(
ierr);
943 ierr = SNESGetLinearSolveIterations(_snes, &_n_linear_iterations);
944 LIBMESH_CHKERR(
ierr);
951 ierr = SNESGetFunction(_snes, &f, 0, 0);
952 LIBMESH_CHKERR(
ierr);
953 ierr = VecNorm(f, NORM_2,
pPR(&final_residual_norm));
954 LIBMESH_CHKERR(
ierr);
957 SNESGetConvergedReason(_snes, &_reason);
960 this->converged = (_reason >= 0);
965 return std::make_pair(n_iterations, final_residual_norm);
970 template <
typename T>
974 libMesh::out <<
"Nonlinear solver convergence/divergence reason: "
975 << SNESConvergedReasons[this->get_converged_reason()] << std::endl;
980 template <
typename T>
983 PetscErrorCode
ierr=0;
987 ierr = SNESGetConvergedReason(_snes, &_reason);
988 LIBMESH_CHKERR(
ierr);
994 template <
typename T>
997 return _n_linear_iterations;
1009 #endif // #ifdef LIBMESH_HAVE_PETSC