20 #include "libmesh/libmesh_common.h" 22 #if defined(LIBMESH_HAVE_SLEPC) && defined(LIBMESH_HAVE_PETSC) 25 #include "libmesh/libmesh_logging.h" 26 #include "libmesh/petsc_matrix_base.h" 27 #include "libmesh/petsc_vector.h" 28 #include "libmesh/slepc_eigen_solver.h" 29 #include "libmesh/shell_matrix.h" 30 #include "libmesh/enum_to_string.h" 31 #include "libmesh/solver_configuration.h" 32 #include "libmesh/enum_eigen_solver_type.h" 33 #include "libmesh/petsc_shell_matrix.h" 39 #if SLEPC_VERSION_LESS_THAN(3,15,0) && !SLEPC_VERSION_LESS_THAN(3,14,2) 40 #include "libmesh/ignore_warnings.h" 51 _initial_space(nullptr)
53 this->_eigen_solver_type =
ARNOLDI;
54 this->_eigen_problem_type =
NHEP;
62 this->SlepcEigenSolver::clear ();
74 PetscErrorCode ierr = LibMeshEPSDestroy(&_eps);
76 libmesh_warning(
"Warning: EPSDestroy returned a non-zero error code which we ignored.");
94 LibmeshPetscCall(EPSCreate (this->comm().
get(), &_eps));
97 set_slepc_solver_type();
103 template <
typename T>
104 std::pair<unsigned int, unsigned int>
109 const unsigned int m_its)
111 LOG_SCOPE(
"solve_standard()",
"SlepcEigenSolver");
118 auto *
const matrix_A = cast_ptr<PetscMatrixBase<T> *>(&matrix_A_in);
120 libmesh_error_msg_if(!matrix_A,
"Error: input matrix to solve_standard() must be a PetscMatrixBase.");
123 if (this->_close_matrix_before_solve)
126 return _solve_standard_helper(matrix_A->mat(),
nullptr, nev, ncv, tol, m_its);
130 template <
typename T>
131 std::pair<unsigned int, unsigned int>
136 const unsigned int m_its)
147 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
152 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix)),
155 LibmeshPetscCall(MatShellSetOperation(mat,MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
156 LibmeshPetscCall(MatShellSetOperation(mat,MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
158 return _solve_standard_helper(mat,
nullptr, nev, ncv, tol, m_its);
161 template <
typename T>
162 std::pair<unsigned int, unsigned int>
168 const unsigned int m_its)
175 auto *
const precond = cast_ptr<PetscMatrixBase<T> *>(&precond_in);
177 libmesh_error_msg_if(!precond,
"Error: input preconditioning matrix to solve_standard() must be a PetscMatrixBase.");
179 auto *
const matrix = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix);
181 libmesh_error_msg_if(!matrix,
"Error: input operator matrix to solve_standard() must be a PetscShellMatrix.");
183 return _solve_standard_helper(matrix->mat(), precond->mat(), nev, ncv, tol, m_its);
186 template <
typename T>
187 std::pair<unsigned int, unsigned int>
193 const unsigned int m_its)
200 auto *
const precond = cast_ptr<PetscShellMatrix<T> *>(&precond_in);
202 libmesh_error_msg_if(!precond,
"Error: input preconditioning matrix to solve_standard() must be a PetscShellMatrix.");
204 auto *
const matrix = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix);
206 libmesh_error_msg_if(!matrix,
"Error: input operator matrix to solve_standard() must be a PetscShellMatrix.");
208 return _solve_standard_helper(matrix->mat(), precond->mat(), nev, ncv, tol, m_its);
213 template <
typename T>
214 std::pair<unsigned int, unsigned int>
220 const unsigned int m_its)
222 LOG_SCOPE(
"solve_standard()",
"SlepcEigenSolver");
225 LibmeshPetscCall(EPSSetOperators (_eps, mat, LIBMESH_PETSC_NULLPTR));
227 return this->_solve_helper(precond, nev, ncv, tol, m_its);
232 template <
typename T>
233 std::pair<unsigned int, unsigned int>
239 const unsigned int m_its)
246 auto *
const matrix_A = cast_ptr<PetscMatrixBase<T> *>(&matrix_A_in);
247 auto *
const matrix_B = cast_ptr<PetscMatrixBase<T> *>(&matrix_B_in);
249 libmesh_error_msg_if(!matrix_A || !matrix_B,
250 "Error: inputs to solve_generalized() must be of type PetscMatrixBase.");
253 if (this->_close_matrix_before_solve)
259 return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(),
nullptr, nev, ncv, tol, m_its);
262 template <
typename T>
263 std::pair<unsigned int, unsigned int>
269 const unsigned int m_its)
280 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
285 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix_A)),
288 auto *
const matrix_B = cast_ptr<PetscMatrixBase<T> *>(&matrix_B_in);
290 libmesh_error_msg_if(!matrix_B,
"Error: inputs to solve_generalized() must be of type PetscMatrixBase.");
293 if (this->_close_matrix_before_solve)
296 LibmeshPetscCall(MatShellSetOperation(mat_A,MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
297 LibmeshPetscCall(MatShellSetOperation(mat_A,MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
299 return _solve_generalized_helper (mat_A, matrix_B->mat(),
nullptr, nev, ncv, tol, m_its);
302 template <
typename T>
303 std::pair<unsigned int, unsigned int>
309 const unsigned int m_its)
315 auto *
const matrix_A = cast_ptr<PetscMatrixBase<T> *>(&matrix_A_in);
317 libmesh_error_msg_if(!matrix_A,
"Error: inputs to solve_generalized() must be of type PetscMatrixBase.");
320 if (this->_close_matrix_before_solve)
328 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
333 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix_B)),
336 LibmeshPetscCall(MatShellSetOperation(mat_B,MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
337 LibmeshPetscCall(MatShellSetOperation(mat_B,MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
339 return _solve_generalized_helper (matrix_A->mat(), mat_B,
nullptr, nev, ncv, tol, m_its);
342 template <
typename T>
343 std::pair<unsigned int, unsigned int>
349 const unsigned int m_its)
360 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
365 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix_A)),
369 LibmeshPetscCall(MatCreateShell(this->comm().
get(),
374 const_cast<void *
>(
static_cast<const void *
>(&shell_matrix_B)),
377 LibmeshPetscCall(MatShellSetOperation(mat_A,MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
378 LibmeshPetscCall(MatShellSetOperation(mat_A,MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
380 LibmeshPetscCall(MatShellSetOperation(mat_B,MATOP_MULT,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_mult)));
381 LibmeshPetscCall(MatShellSetOperation(mat_B,MATOP_GET_DIAGONAL,
reinterpret_cast<void(*)(
void)
>(_petsc_shell_matrix_get_diagonal)));
383 return _solve_generalized_helper (mat_A, mat_B,
nullptr, nev, ncv, tol, m_its);
386 template <
typename T>
387 std::pair<unsigned int, unsigned int>
394 const unsigned int m_its)
401 auto *
const precond = cast_ptr<PetscMatrixBase<T> *>(&precond_in);
403 libmesh_error_msg_if(!precond,
"Error: input preconditioning matrix to solve_generalized() must be of type PetscMatrixBase.");
405 auto *
const matrix_A = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_A);
407 libmesh_error_msg_if(!matrix_A,
"Error: input operator A to solve_generalized() must be of type PetscShellMatrix.");
409 auto *
const matrix_B = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_B);
411 libmesh_error_msg_if(!matrix_B,
"Error: input operator B to solve_generalized() must be of type PetscShellMatrix.");
413 return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(), precond->mat(), nev, ncv, tol, m_its);
416 template <
typename T>
417 std::pair<unsigned int, unsigned int>
424 const unsigned int m_its)
431 auto *
const precond = cast_ptr<PetscShellMatrix<T> *>(&precond_in);
433 libmesh_error_msg_if(!precond,
"Error: input preconditioning matrix to solve_generalized() must be of type PetscShellMatrix.");
435 auto *
const matrix_A = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_A);
437 libmesh_error_msg_if(!matrix_A,
"Error: input operator A to solve_generalized() must be of type PetscShellMatrix.");
439 auto *
const matrix_B = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_B);
441 libmesh_error_msg_if(!matrix_B,
"Error: input operator B to solve_generalized() must be of type PetscShellMatrix.");
443 return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(), precond->mat(), nev, ncv, tol, m_its);
446 template <
typename T>
447 std::pair<unsigned int, unsigned int>
454 const unsigned int m_its)
456 LOG_SCOPE(
"solve_generalized()",
"SlepcEigenSolver");
459 LibmeshPetscCall(EPSSetOperators (_eps, mat_A, mat_B));
461 return this->_solve_helper(precond, nev, ncv, tol, m_its);
466 template <
typename T>
467 std::pair<unsigned int, unsigned int>
472 const unsigned int m_its)
480 set_slepc_problem_type();
481 set_slepc_position_of_spectrum();
484 #if SLEPC_VERSION_LESS_THAN(3,0,0) 485 LibmeshPetscCall(EPSSetDimensions (_eps, nev, ncv));
487 LibmeshPetscCall(EPSSetDimensions (_eps, nev, ncv, PETSC_DECIDE));
490 LibmeshPetscCall(EPSSetTolerances (_eps, tol, m_its));
497 LibmeshPetscCall(EPSSetFromOptions (_eps));
501 LibmeshPetscCall(EPSGetST(_eps,&st));
502 #if SLEPC_VERSION_LESS_THAN(3,15,0) 503 LibmeshPetscCall(STPrecondSetMatForPC(st, precond));
505 LibmeshPetscCall(STSetPreconditionerMat(st, precond));
511 if (this->_solver_configuration)
513 this->_solver_configuration->configure_solver();
517 if (_initial_space) {
519 Vec initial_vector = _initial_space->vec();
521 LibmeshPetscCall(EPSSetInitialSpace(_eps, 1, &initial_vector));
525 LibmeshPetscCall(EPSSolve (_eps));
528 LibmeshPetscCall(EPSGetIterationNumber (_eps, &its));
531 LibmeshPetscCall(EPSGetConverged(_eps,&nconv));
535 return std::make_pair(nconv, its);
539 template <
typename T>
546 PetscReal error, re, im;
552 LibmeshPetscCall(EPSGetConverged(_eps,&nconv));
555 LibmeshPetscCall(PetscPrintf(this->comm().
get(),
556 " k ||Ax-kx||/|kx|\n" 557 " ----------------- -----------------\n" ));
559 for (PetscInt i=0; i<nconv; i++ )
561 LibmeshPetscCall(EPSGetEigenpair(_eps, i, &kr, &ki, LIBMESH_PETSC_NULLPTR,
562 LIBMESH_PETSC_NULLPTR));
564 #if SLEPC_VERSION_LESS_THAN(3,6,0) 565 LibmeshPetscCall(EPSComputeRelativeError(_eps, i, &error));
567 LibmeshPetscCall(EPSComputeError(_eps, i, EPS_ERROR_RELATIVE, &error));
570 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 571 re = PetscRealPart(kr);
572 im = PetscImaginaryPart(kr);
579 LibmeshPetscCall(PetscPrintf(this->comm().
get(),
" %9f%+9f i %12f\n",
double(re),
double(im),
double(error)));
581 LibmeshPetscCall(PetscPrintf(this->comm().
get(),
" %12f %12f\n",
double(re),
double(error)));
584 LibmeshPetscCall(PetscPrintf(this->comm().
get(),
"\n" ));
588 template <
typename T>
591 switch (this->_eigen_solver_type)
594 LibmeshPetscCall(EPSSetType (_eps, EPSPOWER));
return;
596 LibmeshPetscCall(EPSSetType (_eps, EPSSUBSPACE));
return;
598 LibmeshPetscCall(EPSSetType (_eps, EPSLAPACK));
return;
600 LibmeshPetscCall(EPSSetType (_eps, EPSARNOLDI));
return;
602 LibmeshPetscCall(EPSSetType (_eps, EPSLANCZOS));
return;
604 LibmeshPetscCall(EPSSetType (_eps, EPSKRYLOVSCHUR));
return;
609 libMesh::err <<
"ERROR: Unsupported SLEPc Eigen Solver: " 611 <<
"Continuing with SLEPc defaults" << std::endl;
618 template <
typename T>
621 switch (this->_eigen_problem_type)
624 LibmeshPetscCall(EPSSetProblemType (_eps, EPS_NHEP));
return;
626 LibmeshPetscCall(EPSSetProblemType (_eps, EPS_GNHEP));
return;
628 LibmeshPetscCall(EPSSetProblemType (_eps, EPS_HEP));
return;
630 LibmeshPetscCall(EPSSetProblemType (_eps, EPS_GHEP));
return;
631 #if !SLEPC_VERSION_LESS_THAN(3,3,0) 634 LibmeshPetscCall(EPSSetProblemType (_eps, EPS_GHIEP));
return;
638 libMesh::err <<
"ERROR: Unsupported SLEPc Eigen Problem: " 639 << this->_eigen_problem_type << std::endl
640 <<
"Continuing with SLEPc defaults" << std::endl;
646 template <
typename T>
649 switch (this->_position_of_spectrum)
653 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_LARGEST_MAGNITUDE));
658 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_MAGNITUDE));
663 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_LARGEST_REAL));
668 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_REAL));
673 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_LARGEST_IMAGINARY));
678 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_IMAGINARY));
683 #if !SLEPC_VERSION_LESS_THAN(3,1,0) 686 LibmeshPetscCall(EPSSetTarget(_eps,
PS(this->_target_val)));
687 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_TARGET_MAGNITUDE));
692 LibmeshPetscCall(EPSSetTarget(_eps,
PS(this->_target_val)));
693 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_TARGET_REAL));
698 LibmeshPetscCall(EPSSetTarget(_eps,
PS(this->_target_val)));
699 LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_TARGET_IMAGINARY));
705 libmesh_error_msg(
"ERROR: Unsupported SLEPc position of spectrum: " << this->_position_of_spectrum);
714 template <
typename T>
723 libmesh_error_msg_if(!solution,
"Error getting eigenvector: input vector must be a PetscVector.");
730 LibmeshPetscCall(EPSGetEigenpair(_eps, i, &kr, &ki, solution->
vec(),
731 LIBMESH_PETSC_NULLPTR));
733 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 734 re = PetscRealPart(kr);
735 im = PetscImaginaryPart(kr);
741 return std::make_pair(re, im);
745 template <
typename T>
753 LibmeshPetscCall(EPSGetEigenvalue(_eps, i, &kr, &ki));
755 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 756 re = PetscRealPart(kr);
757 im = PetscImaginaryPart(kr);
763 return std::make_pair(re, im);
767 template <
typename T>
772 #if SLEPC_VERSION_LESS_THAN(3,6,0) 773 LibmeshPetscCall(EPSComputeRelativeError(_eps, i, &error));
775 LibmeshPetscCall(EPSComputeError(_eps, i, EPS_ERROR_RELATIVE, &error));
782 template <
typename T>
791 libmesh_error_msg_if(!deflation_vector_petsc_vec,
"Error attaching deflation space: input vector must be a PetscVector.");
794 Vec deflation_vector = deflation_vector_petsc_vec->
vec();
796 #if SLEPC_VERSION_LESS_THAN(3,1,0) 797 LibmeshPetscCall(EPSAttachDeflationSpace(_eps, 1, &deflation_vector, PETSC_FALSE));
799 LibmeshPetscCall(EPSSetDeflationSpace(_eps, 1, &deflation_vector));
803 template <
typename T>
806 #if SLEPC_VERSION_LESS_THAN(3,1,0) 807 libmesh_error_msg(
"SLEPc 3.1 is required to call EigenSolver::set_initial_space()");
811 _initial_space = cast_ptr<PetscVector<T> *>(&initial_space_in);
815 template <
typename T>
837 template <
typename T>
866 #if SLEPC_VERSION_LESS_THAN(3,15,0) && !SLEPC_VERSION_LESS_THAN(3,14,2) 867 #include "libmesh/restore_warnings.h" 871 #endif // #ifdef LIBMESH_HAVE_SLEPC
This class provides a nice interface to PETSc's Vec object.
This class provides an interface to the SLEPc eigenvalue solver library from http://slepc.upv.es/.
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 numeric_index_type m() const =0
bool _is_initialized
Flag that tells if init() has been called.
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
virtual numeric_index_type n() const =0
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.
LibmeshPetscCallQ(DMShellGetContext(dm, &ctx))
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool initialized()
Checks that library initialization has been done.
SlepcEigenSolver(const Parallel::Communicator &comm_in)
Constructor.
Generic shell matrix, i.e.
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
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 void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
This class provides an interface to solvers for eigenvalue problems.