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);
91 _restrict_solve_to_is(nullptr),
92 _restrict_solve_to_is_complement(nullptr),
95 if (this->n_processors() == 1)
103 template <
typename T>
111 if (_restrict_solve_to_is)
112 _restrict_solve_to_is.reset_to_zero();
113 if (_restrict_solve_to_is_complement)
114 _restrict_solve_to_is_complement.reset_to_zero();
121 this->_solver_type =
GMRES;
123 if (!this->_preconditioner)
125 if (this->n_processors() == 1)
135 template <
typename T>
143 LibmeshPetscCall(KSPCreate(this->comm().
get(), _ksp.get()));
146 LibmeshPetscCall(KSPSetOptionsPrefix(_ksp,
name));
149 LibmeshPetscCall(KSPGetPC(_ksp, &_pc));
152 this->set_petsc_solver_type();
156 if (this->_solver_configuration)
158 this->_solver_configuration->set_options_during_init();
167 LibmeshPetscCall(KSPSetFromOptions(_ksp));
174 LibmeshPetscCall(KSPGetType(_ksp, &ksp_type));
176 if (strcmp(ksp_type,
"preonly"))
177 LibmeshPetscCall(KSPSetInitialGuessNonzero(_ksp, PETSC_TRUE));
184 LibmeshPetscCall(KSPSetResidualHistory(_ksp,
185 LIBMESH_PETSC_NULLPTR,
192 if (this->_preconditioner)
194 this->_preconditioner->init();
195 LibmeshPetscCall(PCShellSetContext(_pc,(
void *)this->_preconditioner));
203 template <
typename T>
210 if (this->_preconditioner)
211 this->_preconditioner->set_matrix(*matrix);
216 LibmeshPetscCall(KSPSetOperators(_ksp, matrix->
mat(), matrix->
mat()));
222 template <
typename T>
232 template <
typename T>
243 _subset_solve_mode = subset_solve_mode;
247 PetscInt * petsc_dofs =
nullptr;
248 LibmeshPetscCall(PetscMalloc(dofs->size()*
sizeof(PetscInt), &petsc_dofs));
251 petsc_dofs[i] = (*dofs)[i];
256 LibmeshPetscCall(ISCreateGeneral(this->comm().
get(),
257 cast_int<PetscInt>(dofs->size()),
258 petsc_dofs, PETSC_OWN_POINTER,
259 _restrict_solve_to_is.get()));
265 template <
typename T>
266 std::pair<unsigned int, Real>
271 const std::optional<double> tol,
272 const std::optional<unsigned int> m_its)
274 LOG_SCOPE(
"solve()",
"PetscLinearSolver");
276 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
277 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
279 static_cast<double>(PETSC_DEFAULT));
280 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
282 return this->solve_common(matrix_in, precond_in, solution_in,
283 rhs_in, rel_tol, abs_tol, max_its, KSPSolve);
286 template <
typename T>
287 std::pair<unsigned int, Real>
291 const std::optional<double> tol,
292 const std::optional<unsigned int> m_its)
294 LOG_SCOPE(
"adjoint_solve()",
"PetscLinearSolver");
296 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
297 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
299 static_cast<double>(PETSC_DEFAULT));
300 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
303 return this->solve_common(matrix_in, matrix_in, solution_in,
304 rhs_in, rel_tol, abs_tol, max_its, KSPSolveTranspose);
308 template <
typename T>
309 std::pair<unsigned int, Real>
314 const double rel_tol,
315 const double abs_tol,
316 const unsigned int m_its,
317 ksp_solve_func_type solve_func)
327 if (precond != matrix)
330 auto mat = matrix->
mat();
332 return this->solve_base
333 (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, solve_func);
337 template <
typename T>
338 std::pair<unsigned int, Real>
342 const std::optional<double> tol,
343 const std::optional<unsigned int> m_its)
345 LOG_SCOPE(
"solve()",
"PetscLinearSolver");
347 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
348 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
350 static_cast<double>(PETSC_DEFAULT));
351 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
353 return this->shell_solve_common(shell_matrix,
nullptr, solution_in,
354 rhs_in, rel_tol, abs_tol, max_its);
359 template <
typename T>
360 std::pair<unsigned int, Real>
365 const std::optional<double> tol,
366 const std::optional<unsigned int> m_its)
368 const double rel_tol = this->get_real_solver_setting(
"rel_tol", tol);
369 const double abs_tol = this->get_real_solver_setting(
"abs_tol",
371 static_cast<double>(PETSC_DEFAULT));
372 const double max_its = this->get_int_solver_setting(
"max_its", m_its);
375 const PetscMatrixBase<T> * precond = cast_ptr<const PetscMatrixBase<T> *>(&precond_matrix);
377 return this->shell_solve_common
379 rhs_in, rel_tol, abs_tol, max_its);
384 template <
typename T>
385 std::pair<unsigned int, Real>
390 const double rel_tol,
391 const double abs_tol,
392 const unsigned int m_its)
394 LOG_SCOPE(
"solve()",
"PetscLinearSolver");
403 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
408 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix)),
415 LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
416 LibmeshPetscCall(MatShellSetOperation(mat, MATOP_MULT_ADD,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult_add)));
417 LibmeshPetscCall(MatShellSetOperation(mat, MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
419 return this->solve_base
420 (matrix, precond, mat, solution_in, rhs_in, rel_tol, abs_tol, m_its, KSPSolve);
425 template <
typename T>
426 std::pair<unsigned int, Real>
432 const double rel_tol,
433 const double abs_tol,
434 const unsigned int m_its,
435 ksp_solve_func_type solve_func)
438 PetscVector<T> * solution = cast_ptr<PetscVector<T> *>(&solution_in);
445 PetscInt its=0, max_its =
static_cast<PetscInt
>(m_its);
446 PetscReal final_resid=0.;
448 std::unique_ptr<PetscMatrixBase<Number>> subprecond_matrix;
458 if (_restrict_solve_to_is)
460 PetscInt is_local_size = this->restrict_solve_to_is_local_size();
462 LibmeshPetscCall(VecCreate(this->comm().
get(), subrhs.
get()));
463 LibmeshPetscCall(VecSetSizes(subrhs, is_local_size, PETSC_DECIDE));
464 LibmeshPetscCall(VecSetFromOptions(subrhs));
466 LibmeshPetscCall(VecCreate(this->comm().
get(), subsolution.
get()));
467 LibmeshPetscCall(VecSetSizes(subsolution, is_local_size, PETSC_DECIDE));
468 LibmeshPetscCall(VecSetFromOptions(subsolution));
470 LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is, subrhs,
nullptr, scatter.
get()));
472 VecScatterBeginEnd(this->comm(), scatter, rhs->vec(), subrhs, INSERT_VALUES, SCATTER_FORWARD);
473 VecScatterBeginEnd(this->comm(), scatter, solution->
vec(), subsolution, INSERT_VALUES, SCATTER_FORWARD);
475 LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
476 _restrict_solve_to_is,
477 _restrict_solve_to_is,
482 LibmeshPetscCall(LibMeshCreateSubMatrix(
const_cast<PetscMatrixBase<T> *
>(precond)->mat(),
483 _restrict_solve_to_is,
484 _restrict_solve_to_is,
494 this->create_complement_is(rhs_in);
495 PetscInt is_complement_local_size =
496 cast_int<PetscInt>(rhs_in.
local_size()-is_local_size);
499 LibmeshPetscCall(VecCreate(this->comm().
get(), subvec1.get()));
500 LibmeshPetscCall(VecSetSizes(subvec1, is_complement_local_size, PETSC_DECIDE));
501 LibmeshPetscCall(VecSetFromOptions(subvec1));
504 LibmeshPetscCall(VecScatterCreate(rhs->vec(), _restrict_solve_to_is_complement, subvec1,
nullptr, scatter1.
get()));
506 VecScatterBeginEnd(this->comm(), scatter1, _subset_solve_mode==
SUBSET_COPY_RHS ? rhs->vec() : solution->
vec(), subvec1, INSERT_VALUES, SCATTER_FORWARD);
508 LibmeshPetscCall(VecScale(subvec1, -1.0));
511 LibmeshPetscCall(LibMeshCreateSubMatrix(mat,
512 _restrict_solve_to_is,
513 _restrict_solve_to_is_complement,
517 LibmeshPetscCall(MatMultAdd(submat1, subvec1, subrhs, subrhs));
521 LibmeshPetscCall(KSPSetOperators(_ksp, submat, subprecond));
523 LibmeshPetscCall(KSPSetOperators(_ksp, submat, submat));
525 PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
526 LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
528 if (precond && this->_preconditioner)
530 subprecond_matrix = std::make_unique<PetscMatrix<Number>>(subprecond, this->comm());
531 this->_preconditioner->set_matrix(*subprecond_matrix);
532 this->_preconditioner->init();
537 PetscBool ksp_reuse_preconditioner = this->same_preconditioner ? PETSC_TRUE : PETSC_FALSE;
538 LibmeshPetscCall(KSPSetReusePreconditioner(_ksp, ksp_reuse_preconditioner));
541 LibmeshPetscCall(KSPSetOperators(_ksp, mat,
const_cast<PetscMatrixBase<T> *
>(precond)->mat()));
543 LibmeshPetscCall(KSPSetOperators(_ksp, mat, mat));
545 if (this->_preconditioner)
548 this->_preconditioner->set_matrix(*matrix);
552 this->_preconditioner->init();
558 LibmeshPetscCall(KSPSetTolerances(_ksp, rel_tol, abs_tol,
559 PETSC_DEFAULT, max_its));
562 LibmeshPetscCall(KSPSetFromOptions(_ksp));
564 #if defined(LIBMESH_HAVE_PETSC_HYPRE) && PETSC_VERSION_LESS_THAN(3, 23, 0) && \ 565 !PETSC_VERSION_LESS_THAN(3, 12, 0) && defined(PETSC_HAVE_HYPRE_DEVICE) 568 LibmeshPetscCallExternal(HYPRE_Initialize);
569 PetscScalar * dummyarray;
571 LibmeshPetscCall(VecGetArrayAndMemType(solution->
vec(), &dummyarray, &mtype));
572 LibmeshPetscCall(VecRestoreArrayAndMemType(solution->
vec(), &dummyarray));
573 if (PetscMemTypeHost(mtype))
574 LibmeshPetscCallExternal(HYPRE_SetMemoryLocation, HYPRE_MEMORY_HOST);
580 if (this->_solver_configuration)
582 this->_solver_configuration->configure_solver();
586 if (_restrict_solve_to_is)
587 LibmeshPetscCall(solve_func (_ksp, subrhs, subsolution));
589 LibmeshPetscCall(solve_func (_ksp, rhs->vec(), solution->
vec()));
592 LibmeshPetscCall(KSPGetIterationNumber (_ksp, &its));
595 LibmeshPetscCall(KSPGetResidualNorm (_ksp, &final_resid));
597 if (_restrict_solve_to_is)
599 switch(_subset_solve_mode)
602 LibmeshPetscCall(VecZeroEntries(solution->
vec()));
606 LibmeshPetscCall(VecCopy(rhs->vec(),solution->
vec()));
614 libmesh_error_msg(
"Invalid subset solve mode = " << _subset_solve_mode);
617 VecScatterBeginEnd(this->comm(), scatter, subsolution, solution->
vec(), INSERT_VALUES, SCATTER_REVERSE);
619 if (precond && this->_preconditioner)
624 this->_preconditioner->set_matrix(*matrix);
626 this->_preconditioner->set_matrix(*precond);
628 this->_preconditioner->init();
633 return std::make_pair(its, final_resid);
638 template <
typename T>
645 template <
typename T>
659 #if PETSC_VERSION_LESS_THAN(3,15,0) 665 LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
668 if (its == 0)
return;
674 for (PetscInt i=0; i<its; ++i)
684 template <
typename T>
698 #if PETSC_VERSION_LESS_THAN(3,15,0) 705 LibmeshPetscCall(KSPGetResidualHistory(_ksp, &p, &its));
710 libMesh::err <<
"No iterations have been performed, returning 0." << std::endl;
721 template <
typename T>
724 #define CaseKSPSetType(SolverType, KSPT) \ 726 LibmeshPetscCall(KSPSetType (_ksp, const_cast<KSPType>(KSPT))); \ 729 switch (this->_solver_type)
731 CaseKSPSetType(
CG, KSPCG)
732 CaseKSPSetType(
CR, KSPCR)
733 CaseKSPSetType(
CGS, KSPCGS)
734 CaseKSPSetType(
BICG, KSPBICG)
735 CaseKSPSetType(
TCQMR, KSPTCQMR)
736 CaseKSPSetType(
TFQMR, KSPTFQMR)
737 CaseKSPSetType(
LSQR, KSPLSQR)
739 CaseKSPSetType(
MINRES, KSPMINRES)
740 CaseKSPSetType(
GMRES, KSPGMRES)
747 <<
"Continuing with PETSC defaults" << std::endl;
753 template <
typename T>
756 KSPConvergedReason reason;
757 LibmeshPetscCall(KSPGetConvergedReason(_ksp, &reason));
761 #if PETSC_VERSION_LESS_THAN(3,24,0) 771 #if PETSC_VERSION_LESS_THAN(3,19,0) 790 #if !PETSC_VERSION_LESS_THAN(3,7,0) 792 #if PETSC_VERSION_LESS_THAN(3,11,0) && PETSC_VERSION_RELEASE 800 libMesh::err <<
"Unknown convergence flag!" << std::endl;
806 template <
typename T>
813 PetscErrorCode ierr = MatShellGetContext(mat,&
ctx);
817 CHKERRABORT(shell_matrix.
comm().get(), ierr);
831 template <
typename T>
838 PetscErrorCode ierr = MatShellGetContext(mat,&
ctx);
842 CHKERRABORT(shell_matrix.
comm().get(), ierr);
851 arg_global = add_global;
862 template <
typename T>
869 PetscErrorCode ierr = MatShellGetContext(mat,&
ctx);
873 CHKERRABORT(shell_matrix.
comm().get(), ierr);
886 template <
typename T>
891 if (!_restrict_solve_to_is_complement)
892 LibmeshPetscCall(ISComplement(_restrict_solve_to_is,
895 _restrict_solve_to_is_complement.get()));
899 template <
typename T>
906 LibmeshPetscCall(ISGetLocalSize(_restrict_solve_to_is, &s));
920 #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.
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.
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 ...