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