18 #include "libmesh/libmesh_common.h" 20 #ifdef LIBMESH_HAVE_PETSC 24 #include "libmesh/dof_map.h" 25 #include "libmesh/libmesh_logging.h" 26 #include "libmesh/petsc_linear_solver.h" 27 #include "libmesh/shell_matrix.h" 28 #include "libmesh/petsc_matrix.h" 29 #include "libmesh/petsc_preconditioner.h" 30 #include "libmesh/petsc_vector.h" 31 #include "libmesh/enum_to_string.h" 32 #include "libmesh/system.h" 33 #include "libmesh/petsc_auto_fieldsplit.h" 34 #include "libmesh/solver_configuration.h" 35 #include "libmesh/enum_preconditioner_type.h" 36 #include "libmesh/enum_solver_type.h" 37 #include "libmesh/enum_convergence_flags.h" 39 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \ 40 !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE) 41 #include <HYPRE_utilities.h> 61 libmesh_error_msg_if(!preconditioner->
initialized(),
62 "Preconditioner not initialized! Make sure you call init() before solve!");
64 preconditioner->
setup();
80 preconditioner->
apply(x_vec,y_vec);
85 #ifdef LIBMESH_ENABLE_DEPRECATED 104 template <
typename T>
107 _restrict_solve_to_is(nullptr),
108 _restrict_solve_to_is_complement(nullptr),
111 if (this->n_processors() == 1)
119 template <
typename T>
127 if (_restrict_solve_to_is)
128 _restrict_solve_to_is.reset_to_zero();
129 if (_restrict_solve_to_is_complement)
130 _restrict_solve_to_is_complement.reset_to_zero();
137 this->_solver_type =
GMRES;
139 if (!this->_preconditioner)
141 if (this->n_processors() == 1)
151 template <
typename T>
159 LibmeshPetscCall(KSPCreate(this->comm().
get(), _ksp.get()));
162 LibmeshPetscCall(KSPSetOptionsPrefix(_ksp,
name));
165 LibmeshPetscCall(KSPGetPC(_ksp, &_pc));
168 this->set_petsc_solver_type();
172 if (this->_solver_configuration)
174 this->_solver_configuration->set_options_during_init();
183 LibmeshPetscCall(KSPSetFromOptions(_ksp));
190 LibmeshPetscCall(KSPGetType(_ksp, &ksp_type));
192 if (strcmp(ksp_type,
"preonly"))
193 LibmeshPetscCall(KSPSetInitialGuessNonzero(_ksp, PETSC_TRUE));
200 LibmeshPetscCall(KSPSetResidualHistory(_ksp,
201 LIBMESH_PETSC_NULLPTR,
208 if (this->_preconditioner)
210 this->_preconditioner->init();
211 LibmeshPetscCall(PCShellSetContext(_pc,(
void *)this->_preconditioner));
219 template <
typename T>
226 if (this->_preconditioner)
227 this->_preconditioner->set_matrix(*matrix);
232 LibmeshPetscCall(KSPSetOperators(_ksp, matrix->
mat(), matrix->
mat()));
238 template <
typename T>
247 template <
typename T>
258 _subset_solve_mode = subset_solve_mode;
262 PetscInt * petsc_dofs =
nullptr;
263 LibmeshPetscCall(PetscMalloc(dofs->size()*
sizeof(PetscInt), &petsc_dofs));
266 petsc_dofs[i] = (*dofs)[i];
271 LibmeshPetscCall(ISCreateGeneral(this->comm().
get(),
272 cast_int<PetscInt>(dofs->size()),
273 petsc_dofs, PETSC_OWN_POINTER,
274 _restrict_solve_to_is.get()));
280 template <
typename T>
281 std::pair<unsigned int, Real>
286 const std::optional<double> tol,
287 const std::optional<unsigned int> m_its)
289 LOG_SCOPE(
"solve()",
"PetscLinearSolver");
291 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
292 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
294 static_cast<double>(PETSC_DEFAULT));
295 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
297 return this->solve_common(matrix_in, precond_in, solution_in,
298 rhs_in, rel_tol, abs_tol, max_its, KSPSolve);
301 template <
typename T>
302 std::pair<unsigned int, Real>
306 const std::optional<double> tol,
307 const std::optional<unsigned int> m_its)
309 LOG_SCOPE(
"adjoint_solve()",
"PetscLinearSolver");
311 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
312 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
314 static_cast<double>(PETSC_DEFAULT));
315 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
318 return this->solve_common(matrix_in, matrix_in, solution_in,
319 rhs_in, rel_tol, abs_tol, max_its, KSPSolveTranspose);
323 template <
typename T>
324 std::pair<unsigned int, Real>
329 const double rel_tol,
330 const double abs_tol,
331 const unsigned int m_its,
332 ksp_solve_func_type solve_func)
342 if (precond != matrix)
345 auto mat = matrix->
mat();
347 return this->solve_base
348 (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, solve_func);
352 template <
typename T>
353 std::pair<unsigned int, Real>
357 const std::optional<double> tol,
358 const std::optional<unsigned int> m_its)
360 LOG_SCOPE(
"solve()",
"PetscLinearSolver");
362 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
363 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
365 static_cast<double>(PETSC_DEFAULT));
366 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
368 return this->shell_solve_common(shell_matrix,
nullptr, solution_in,
369 rhs_in, rel_tol, abs_tol, max_its);
374 template <
typename T>
375 std::pair<unsigned int, Real>
380 const std::optional<double> tol,
381 const std::optional<unsigned int> m_its)
383 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
384 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
386 static_cast<double>(PETSC_DEFAULT));
387 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
390 const PetscMatrixBase<T> * precond = cast_ptr<const PetscMatrixBase<T> *>(&precond_matrix);
392 return this->shell_solve_common
394 rhs_in, rel_tol, abs_tol, max_its);
399 template <
typename T>
400 std::pair<unsigned int, Real>
405 const double rel_tol,
406 const double abs_tol,
407 const unsigned int m_its)
409 LOG_SCOPE(
"solve()",
"PetscLinearSolver");
418 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
423 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix)),
430 LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
431 LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT_ADD,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult_add)));
432 LibmeshPetscCall(MatShellSetOperation(mat, MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
434 return this->solve_base
435 (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, KSPSolve);
440 template <
typename T>
441 std::pair<unsigned int, Real>
447 const double rel_tol,
448 const double abs_tol,
449 const unsigned int m_its,
450 ksp_solve_func_type solve_func)
453 PetscVector<T> * solution = cast_ptr<PetscVector<T> *>(&solution_in);
460 PetscInt its=0, max_its =
static_cast<PetscInt
>(m_its);
461 PetscReal final_resid=0.;
463 std::unique_ptr<PetscMatrixBase<Number>> subprecond_matrix;
473 if (_restrict_solve_to_is)
475 PetscInt is_local_size = this->restrict_solve_to_is_local_size();
477 LibmeshPetscCall(VecCreate(this->comm().
get(), subrhs.
get()));
478 LibmeshPetscCall(VecSetSizes(subrhs, is_local_size, PETSC_DECIDE));
479 LibmeshPetscCall(VecSetFromOptions(subrhs));
481 LibmeshPetscCall(VecCreate(this->comm().
get(), subsolution.
get()));
482 LibmeshPetscCall(VecSetSizes(subsolution, is_local_size, PETSC_DECIDE));
483 LibmeshPetscCall(VecSetFromOptions(subsolution));
485 LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is, subrhs,
nullptr, scatter.
get()));
487 VecScatterBeginEnd(this->comm(), scatter, rhs->vec(), subrhs, INSERT_VALUES, SCATTER_FORWARD);
488 VecScatterBeginEnd(this->comm(), scatter, solution->
vec(), subsolution, INSERT_VALUES, SCATTER_FORWARD);
490 LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
491 _restrict_solve_to_is,
492 _restrict_solve_to_is,
497 LibmeshPetscCall(LibMeshCreateSubMatrix(
const_cast<PetscMatrixBase<T> *
>(precond)->mat(),
498 _restrict_solve_to_is,
499 _restrict_solve_to_is,
509 this->create_complement_is(rhs_in);
510 PetscInt is_complement_local_size =
511 cast_int<PetscInt>(rhs_in.
local_size()-is_local_size);
514 LibmeshPetscCall(VecCreate(this->comm().
get(), subvec1.get()));
515 LibmeshPetscCall(VecSetSizes(subvec1, is_complement_local_size, PETSC_DECIDE));
516 LibmeshPetscCall(VecSetFromOptions(subvec1));
519 LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is_complement, subvec1,
nullptr, scatter1.
get()));
521 VecScatterBeginEnd(this->comm(), scatter1, _subset_solve_mode==
SUBSET_COPY_RHS ? rhs->vec() : solution->
vec(), subvec1, INSERT_VALUES, SCATTER_FORWARD);
523 LibmeshPetscCall(VecScale(subvec1, -1.0));
526 LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
527 _restrict_solve_to_is,
528 _restrict_solve_to_is_complement,
532 LibmeshPetscCall(MatMultAdd(submat1, subvec1, subrhs, subrhs));
536 LibmeshPetscCall(KSPSetOperators(_ksp, submat, subprecond));
538 LibmeshPetscCall(KSPSetOperators(_ksp, submat, submat));
540 PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
541 LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
543 if (precond && this->_preconditioner)
545 subprecond_matrix = std::make_unique<PetscMatrix<Number>>(subprecond, this->comm());
546 this->_preconditioner->set_matrix(*subprecond_matrix);
547 this->_preconditioner->init();
552 PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
553 LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
556 LibmeshPetscCall(KSPSetOperators(_ksp, mat,
const_cast<PetscMatrixBase<T> *
>(precond)->mat()));
558 LibmeshPetscCall(KSPSetOperators(_ksp, mat, mat));
560 if (this->_preconditioner)
563 this->_preconditioner->set_matrix(*matrix);
567 this->_preconditioner->init();
573 LibmeshPetscCall(KSPSetTolerances(_ksp, rel_tol, abs_tol,
574 PETSC_DEFAULT, max_its));
577 LibmeshPetscCall(KSPSetFromOptions(_ksp));
579 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \ 580 !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE) 583 LibmeshPetscCallExternal(HYPRE_Initialize);
584 PetscScalar * dummyarray;
586 LibmeshPetscCall(VecGetArrayAndMemType(solution->
vec(), &dummyarray, &mtype));
587 LibmeshPetscCall(VecRestoreArrayAndMemType(solution->
vec(), &dummyarray));
588 if (PetscMemTypeHost(mtype))
589 LibmeshPetscCallExternal(HYPRE_SetMemoryLocation, HYPRE_MEMORY_HOST);
595 if (this->_solver_configuration)
597 this->_solver_configuration->configure_solver();
601 if (_restrict_solve_to_is)
602 LibmeshPetscCall(solve_func (_ksp, subrhs, subsolution));
604 LibmeshPetscCall(solve_func (_ksp, rhs->vec(), solution->
vec()));
607 LibmeshPetscCall(KSPGetIterationNumber (_ksp, &its));
610 LibmeshPetscCall(KSPGetResidualNorm (_ksp, &final_resid));
612 if (_restrict_solve_to_is)
614 switch(_subset_solve_mode)
617 LibmeshPetscCall(VecZeroEntries(solution->
vec()));
621 LibmeshPetscCall(VecCopy(rhs->vec(),solution->
vec()));
629 libmesh_error_msg(
"Invalid subset solve mode = " << _subset_solve_mode);
632 VecScatterBeginEnd(this->comm(), scatter, subsolution, solution->
vec(), INSERT_VALUES, SCATTER_REVERSE);
634 if (precond && this->_preconditioner)
639 this->_preconditioner->set_matrix(*matrix);
641 this->_preconditioner->set_matrix(*precond);
643 this->_preconditioner->init();
648 return std::make_pair(its, final_resid);
653 template <
typename T>
660 template <
typename T>
674 #if PETSC_VERSION_LESS_THAN(3,15,0) 680 LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
683 if (its == 0)
return;
689 for (PetscInt i=0; i<its; ++i)
699 template <
typename T>
713 #if PETSC_VERSION_LESS_THAN(3,15,0) 720 LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
725 libMesh::err <<
"No iterations have been performed, returning 0." << std::endl;
736 template <
typename T>
739 #define CaseKSPSetType(SolverType, KSPT) \ 741 LibmeshPetscCall(KSPSetType (_ksp, const_cast<KSPType>(KSPT))); \ 744 switch (this->_solver_type)
746 CaseKSPSetType(
CG, KSPCG)
747 CaseKSPSetType(
CR, KSPCR)
748 CaseKSPSetType(
CGS, KSPCGS)
749 CaseKSPSetType(
BICG, KSPBICG)
750 CaseKSPSetType(
TCQMR, KSPTCQMR)
751 CaseKSPSetType(
TFQMR, KSPTFQMR)
752 CaseKSPSetType(
LSQR, KSPLSQR)
754 CaseKSPSetType(
MINRES, KSPMINRES)
755 CaseKSPSetType(
GMRES, KSPGMRES)
762 <<
"Continuing with PETSC defaults" << std::endl;
768 template <
typename T>
771 KSPConvergedReason reason;
772 LibmeshPetscCall(KSPGetConvergedReason(_ksp, &reason));
781 #if PETSC_VERSION_LESS_THAN(3,19,0) 800 #if !PETSC_VERSION_LESS_THAN(3,7,0) 802 #if PETSC_VERSION_LESS_THAN(3,11,0) && PETSC_VERSION_RELEASE 810 libMesh::err <<
"Unknown convergence flag!" << std::endl;
816 template <
typename T>
823 PetscErrorCode ierr = MatShellGetContext(mat,&
ctx);
827 CHKERRABORT(shell_matrix.
comm().get(), ierr);
841 template <
typename T>
848 PetscErrorCode ierr = MatShellGetContext(mat,&
ctx);
852 CHKERRABORT(shell_matrix.
comm().get(), ierr);
861 arg_global = add_global;
872 template <
typename T>
879 PetscErrorCode ierr = MatShellGetContext(mat,&
ctx);
883 CHKERRABORT(shell_matrix.
comm().get(), ierr);
896 template <
typename T>
901 if (!_restrict_solve_to_is_complement)
902 LibmeshPetscCall(ISComplement(_restrict_solve_to_is,
905 _restrict_solve_to_is_complement.get()));
909 template <
typename T>
916 LibmeshPetscCall(ISGetLocalSize(_restrict_solve_to_is, &s));
930 #endif // #ifdef LIBMESH_HAVE_PETSC std::string name(const ElemQuality q)
This function returns a string containing some name for q.
void petsc_auto_fieldsplit(PC my_pc, const System &sys)
This class provides a nice interface to PETSc's Vec object.
This class provides an interface to the suite of preconditioners available from PETSc.
This class provides a nice interface to the PETSc C-based data structures for parallel, sparse matrices.
PetscErrorCode __libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
virtual numeric_index_type size() const =0
PetscErrorCode libmesh_petsc_preconditioner_apply(PC, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
virtual void apply(const NumericVector< T > &x, NumericVector< T > &y)=0
Computes the preconditioned vector y based on input vector x.
LinearConvergenceReason
Linear solver convergence flags (taken from the PETSc flags).
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
const Parallel::Communicator & comm() const
The libMesh namespace provides an interface to certain functionality in the library.
virtual bool initialized() const
virtual void vector_mult_add(NumericVector< T > &dest, const NumericVector< T > &arg) const =0
Multiplies the matrix with arg and adds the result to dest.
This base class can be inherited from to provide interfaces to linear solvers from different packages...
PetscLinearSolver(const libMesh::Parallel::Communicator &comm_in)
Constructor.
bool _is_initialized
Flag that tells if init() has been called.
Manages consistently variables, degrees of freedom, and coefficient vectors.
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
PetscErrorCode libmesh_petsc_preconditioner_apply(PC pc, Vec x, Vec y)
This function is called by PETSc to actually apply the preconditioner.
PetscErrorCode __libmesh_petsc_preconditioner_setup(PC pc)
This function is called by PETSc to initialize the preconditioner.
virtual void close() override
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
std::string enum_to_string(const T e)
virtual void get_diagonal(NumericVector< T > &dest) const =0
Copies the diagonal part of the matrix into dest.
PetscErrorCode libmesh_petsc_preconditioner_setup(PC pc)
This function is called by PETSc to initialize the preconditioner.
virtual numeric_index_type first_local_index() const =0
LibmeshPetscCallQ(DMShellGetContext(dm, &ctx))
PetscErrorCode libmesh_petsc_preconditioner_setup(PC)
This function is called by PETSc to initialize the preconditioner.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This class provides an interface to PETSc iterative solvers that is compatible with the libMesh Linea...
virtual numeric_index_type local_size() const =0
bool initialized()
Checks that library initialization has been done.
Generic shell matrix, i.e.
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
virtual void setup()
This is called every time the "operator might have changed".
SubsetSolveMode
defines an enum for the question what happens to the dofs outside the given subset when a system is s...
virtual void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const =0
Multiplies the matrix with arg and stores the result in dest.
virtual numeric_index_type last_local_index() const =0
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
virtual void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...