libMesh
slepc_eigen_solver.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 #include "libmesh/libmesh_common.h"
21 
22 #if defined(LIBMESH_HAVE_SLEPC) && defined(LIBMESH_HAVE_PETSC)
23 
24 // Local Includes
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"
34 
35 // PETSc 3.15 includes a non-release SLEPc 3.14.2 that has already
36 // deprecated STPrecondSetMatForPC but that hasn't upgraded its
37 // version number to let us switch to the non-deprecated version. If
38 // we're in that situation we need to ignore the deprecated warning.
39 #if SLEPC_VERSION_LESS_THAN(3,15,0) && !SLEPC_VERSION_LESS_THAN(3,14,2)
40 #include "libmesh/ignore_warnings.h"
41 #endif
42 
43 namespace libMesh
44 {
45 
46 
47 
48 template <typename T>
50  EigenSolver<T>(comm_in),
51  _initial_space(nullptr)
52 {
53  this->_eigen_solver_type = ARNOLDI;
54  this->_eigen_problem_type = NHEP;
55 }
56 
57 
58 
59 template <typename T>
61 {
62  this->SlepcEigenSolver::clear ();
63 }
64 
65 
66 
67 template <typename T>
69 {
70  if (this->initialized())
71  {
72  this->_is_initialized = false;
73 
74  PetscErrorCode ierr = LibMeshEPSDestroy(&_eps);
75  if (ierr)
76  libmesh_warning("Warning: EPSDestroy returned a non-zero error code which we ignored.");
77 
78  // SLEPc default eigenproblem solver
79  this->_eigen_solver_type = KRYLOVSCHUR;
80  }
81 }
82 
83 
84 
85 template <typename T>
87 {
88  // Initialize the data structures if not done so already.
89  if (!this->initialized())
90  {
91  this->_is_initialized = true;
92 
93  // Create the eigenproblem solver context
94  LibmeshPetscCall(EPSCreate (this->comm().get(), &_eps));
95 
96  // Set user-specified solver
97  set_slepc_solver_type();
98  }
99 }
100 
101 
102 
103 template <typename T>
104 std::pair<unsigned int, unsigned int>
106  int nev, // number of requested eigenpairs
107  int ncv, // number of basis vectors
108  const double tol, // solver tolerance
109  const unsigned int m_its) // maximum number of iterations
110 {
111  LOG_SCOPE("solve_standard()", "SlepcEigenSolver");
112 
113  this->clear ();
114 
115  this->init ();
116 
117  // Make sure the SparseMatrix passed in is really a PetscMatrix
118  auto * const matrix_A = cast_ptr<PetscMatrixBase<T> *>(&matrix_A_in);
119 
120  libmesh_error_msg_if(!matrix_A, "Error: input matrix to solve_standard() must be a PetscMatrixBase.");
121 
122  // Close the matrix and vectors in case this wasn't already done.
123  if (this->_close_matrix_before_solve)
124  matrix_A->close ();
125 
126  return _solve_standard_helper(matrix_A->mat(), nullptr, nev, ncv, tol, m_its);
127 }
128 
129 
130 template <typename T>
131 std::pair<unsigned int, unsigned int>
133  int nev, // number of requested eigenpairs
134  int ncv, // number of basis vectors
135  const double tol, // solver tolerance
136  const unsigned int m_its) // maximum number of iterations
137 {
138  this->clear ();
139 
140  this->init ();
141 
142  // Prepare the matrix. Note that the const_cast is only necessary
143  // because PETSc does not accept a const void *. Inside the member
144  // function _petsc_shell_matrix() below, the pointer is casted back
145  // to a const ShellMatrix<T> *.
146  Mat mat;
147  LibmeshPetscCall(MatCreateShell(this->comm().get(),
148  shell_matrix.m(), // Specify the number of local rows
149  shell_matrix.n(), // Specify the number of local columns
150  PETSC_DETERMINE,
151  PETSC_DETERMINE,
152  const_cast<void *>(static_cast<const void *>(&shell_matrix)),
153  &mat));
154 
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)));
157 
158  return _solve_standard_helper(mat, nullptr, nev, ncv, tol, m_its);
159 }
160 
161 template <typename T>
162 std::pair<unsigned int, unsigned int>
164  SparseMatrix<T> & precond_in,
165  int nev, // number of requested eigenpairs
166  int ncv, // number of basis vectors
167  const double tol, // solver tolerance
168  const unsigned int m_its) // maximum number of iterations
169 {
170  this->clear ();
171 
172  this->init ();
173 
174  // Make sure the SparseMatrix passed in is really a PetscMatrix
175  auto * const precond = cast_ptr<PetscMatrixBase<T> *>(&precond_in);
176 
177  libmesh_error_msg_if(!precond, "Error: input preconditioning matrix to solve_standard() must be a PetscMatrixBase.");
178 
179  auto * const matrix = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix);
180 
181  libmesh_error_msg_if(!matrix, "Error: input operator matrix to solve_standard() must be a PetscShellMatrix.");
182 
183  return _solve_standard_helper(matrix->mat(), precond->mat(), nev, ncv, tol, m_its);
184 }
185 
186 template <typename T>
187 std::pair<unsigned int, unsigned int>
189  ShellMatrix<T> & precond_in,
190  int nev, // number of requested eigenpairs
191  int ncv, // number of basis vectors
192  const double tol, // solver tolerance
193  const unsigned int m_its) // maximum number of iterations
194 {
195  this->clear ();
196 
197  this->init ();
198 
199  // Make sure the SparseMatrix passed in is really a PetscMatrix
200  auto * const precond = cast_ptr<PetscShellMatrix<T> *>(&precond_in);
201 
202  libmesh_error_msg_if(!precond, "Error: input preconditioning matrix to solve_standard() must be a PetscShellMatrix.");
203 
204  auto * const matrix = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix);
205 
206  libmesh_error_msg_if(!matrix, "Error: input operator matrix to solve_standard() must be a PetscShellMatrix.");
207 
208  return _solve_standard_helper(matrix->mat(), precond->mat(), nev, ncv, tol, m_its);
209 }
210 
211 
212 
213 template <typename T>
214 std::pair<unsigned int, unsigned int>
216  Mat precond,
217  int nev, // number of requested eigenpairs
218  int ncv, // number of basis vectors
219  const double tol, // solver tolerance
220  const unsigned int m_its) // maximum number of iterations
221 {
222  LOG_SCOPE("solve_standard()", "SlepcEigenSolver");
223 
224  // Set operators.
225  LibmeshPetscCall(EPSSetOperators (_eps, mat, LIBMESH_PETSC_NULLPTR));
226 
227  return this->_solve_helper(precond, nev, ncv, tol, m_its);
228 }
229 
230 
231 
232 template <typename T>
233 std::pair<unsigned int, unsigned int>
235  SparseMatrix<T> & matrix_B_in,
236  int nev, // number of requested eigenpairs
237  int ncv, // number of basis vectors
238  const double tol, // solver tolerance
239  const unsigned int m_its) // maximum number of iterations
240 {
241  this->clear ();
242 
243  this->init ();
244 
245  // Make sure the data passed in are really of Petsc types
246  auto * const matrix_A = cast_ptr<PetscMatrixBase<T> *>(&matrix_A_in);
247  auto * const matrix_B = cast_ptr<PetscMatrixBase<T> *>(&matrix_B_in);
248 
249  libmesh_error_msg_if(!matrix_A || !matrix_B,
250  "Error: inputs to solve_generalized() must be of type PetscMatrixBase.");
251 
252  // Close the matrix and vectors in case this wasn't already done.
253  if (this->_close_matrix_before_solve)
254  {
255  matrix_A->close ();
256  matrix_B->close ();
257  }
258 
259  return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(), nullptr, nev, ncv, tol, m_its);
260 }
261 
262 template <typename T>
263 std::pair<unsigned int, unsigned int>
265  SparseMatrix<T> & matrix_B_in,
266  int nev, // number of requested eigenpairs
267  int ncv, // number of basis vectors
268  const double tol, // solver tolerance
269  const unsigned int m_its) // maximum number of iterations
270 {
271  this->clear();
272 
273  this->init ();
274 
275  // Prepare the matrix. Note that the const_cast is only necessary
276  // because PETSc does not accept a const void *. Inside the member
277  // function _petsc_shell_matrix() below, the pointer is casted back
278  // to a const ShellMatrix<T> *.
279  Mat mat_A;
280  LibmeshPetscCall(MatCreateShell(this->comm().get(),
281  shell_matrix_A.m(), // Specify the number of local rows
282  shell_matrix_A.n(), // Specify the number of local columns
283  PETSC_DETERMINE,
284  PETSC_DETERMINE,
285  const_cast<void *>(static_cast<const void *>(&shell_matrix_A)),
286  &mat_A));
287 
288  auto * const matrix_B = cast_ptr<PetscMatrixBase<T> *>(&matrix_B_in);
289 
290  libmesh_error_msg_if(!matrix_B, "Error: inputs to solve_generalized() must be of type PetscMatrixBase.");
291 
292  // Close the matrix and vectors in case this wasn't already done.
293  if (this->_close_matrix_before_solve)
294  matrix_B->close ();
295 
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)));
298 
299  return _solve_generalized_helper (mat_A, matrix_B->mat(), nullptr, nev, ncv, tol, m_its);
300 }
301 
302 template <typename T>
303 std::pair<unsigned int, unsigned int>
305  ShellMatrix<T> & shell_matrix_B,
306  int nev, // number of requested eigenpairs
307  int ncv, // number of basis vectors
308  const double tol, // solver tolerance
309  const unsigned int m_its) // maximum number of iterations
310 {
311  this->clear();
312 
313  this->init ();
314 
315  auto * const matrix_A = cast_ptr<PetscMatrixBase<T> *>(&matrix_A_in);
316 
317  libmesh_error_msg_if(!matrix_A, "Error: inputs to solve_generalized() must be of type PetscMatrixBase.");
318 
319  // Close the matrix and vectors in case this wasn't already done.
320  if (this->_close_matrix_before_solve)
321  matrix_A->close ();
322 
323  // Prepare the matrix. Note that the const_cast is only necessary
324  // because PETSc does not accept a const void *. Inside the member
325  // function _petsc_shell_matrix() below, the pointer is casted back
326  // to a const ShellMatrix<T> *.
327  Mat mat_B;
328  LibmeshPetscCall(MatCreateShell(this->comm().get(),
329  shell_matrix_B.m(), // Specify the number of local rows
330  shell_matrix_B.n(), // Specify the number of local columns
331  PETSC_DETERMINE,
332  PETSC_DETERMINE,
333  const_cast<void *>(static_cast<const void *>(&shell_matrix_B)),
334  &mat_B));
335 
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)));
338 
339  return _solve_generalized_helper (matrix_A->mat(), mat_B, nullptr, nev, ncv, tol, m_its);
340 }
341 
342 template <typename T>
343 std::pair<unsigned int, unsigned int>
345  ShellMatrix<T> & shell_matrix_B,
346  int nev, // number of requested eigenpairs
347  int ncv, // number of basis vectors
348  const double tol, // solver tolerance
349  const unsigned int m_its) // maximum number of iterations
350 {
351  this->clear();
352 
353  this->init ();
354 
355  // Prepare the matrices. Note that the const_casts are only
356  // necessary because PETSc does not accept a const void *. Inside
357  // the member function _petsc_shell_matrix() below, the pointer is
358  // casted back to a const ShellMatrix<T> *.
359  Mat mat_A;
360  LibmeshPetscCall(MatCreateShell(this->comm().get(),
361  shell_matrix_A.m(), // Specify the number of local rows
362  shell_matrix_A.n(), // Specify the number of local columns
363  PETSC_DETERMINE,
364  PETSC_DETERMINE,
365  const_cast<void *>(static_cast<const void *>(&shell_matrix_A)),
366  &mat_A));
367 
368  Mat mat_B;
369  LibmeshPetscCall(MatCreateShell(this->comm().get(),
370  shell_matrix_B.m(), // Specify the number of local rows
371  shell_matrix_B.n(), // Specify the number of local columns
372  PETSC_DETERMINE,
373  PETSC_DETERMINE,
374  const_cast<void *>(static_cast<const void *>(&shell_matrix_B)),
375  &mat_B));
376 
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)));
379 
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)));
382 
383  return _solve_generalized_helper (mat_A, mat_B, nullptr, nev, ncv, tol, m_its);
384 }
385 
386 template <typename T>
387 std::pair<unsigned int, unsigned int>
389  ShellMatrix<T> & shell_matrix_B,
390  SparseMatrix<T> & precond_in,
391  int nev, // number of requested eigenpairs
392  int ncv, // number of basis vectors
393  const double tol, // solver tolerance
394  const unsigned int m_its) // maximum number of iterations
395 {
396  this->clear();
397 
398  this->init ();
399 
400  // Make sure the SparseMatrix passed in is really a PetscMatrix
401  auto * const precond = cast_ptr<PetscMatrixBase<T> *>(&precond_in);
402 
403  libmesh_error_msg_if(!precond, "Error: input preconditioning matrix to solve_generalized() must be of type PetscMatrixBase.");
404 
405  auto * const matrix_A = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_A);
406 
407  libmesh_error_msg_if(!matrix_A, "Error: input operator A to solve_generalized() must be of type PetscShellMatrix.");
408 
409  auto * const matrix_B = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_B);
410 
411  libmesh_error_msg_if(!matrix_B, "Error: input operator B to solve_generalized() must be of type PetscShellMatrix.");
412 
413  return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(), precond->mat(), nev, ncv, tol, m_its);
414 }
415 
416 template <typename T>
417 std::pair<unsigned int, unsigned int>
419  ShellMatrix<T> & shell_matrix_B,
420  ShellMatrix<T> & precond_in,
421  int nev, // number of requested eigenpairs
422  int ncv, // number of basis vectors
423  const double tol, // solver tolerance
424  const unsigned int m_its) // maximum number of iterations
425 {
426  this->clear();
427 
428  this->init ();
429 
430  // Make sure the ShellMatrix passed in is really a PetscShellMatrix
431  auto * const precond = cast_ptr<PetscShellMatrix<T> *>(&precond_in);
432 
433  libmesh_error_msg_if(!precond, "Error: input preconditioning matrix to solve_generalized() must be of type PetscShellMatrix.");
434 
435  auto * const matrix_A = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_A);
436 
437  libmesh_error_msg_if(!matrix_A, "Error: input operator A to solve_generalized() must be of type PetscShellMatrix.");
438 
439  auto * const matrix_B = cast_ptr<PetscShellMatrix<T> *> (&shell_matrix_B);
440 
441  libmesh_error_msg_if(!matrix_B, "Error: input operator B to solve_generalized() must be of type PetscShellMatrix.");
442 
443  return _solve_generalized_helper (matrix_A->mat(), matrix_B->mat(), precond->mat(), nev, ncv, tol, m_its);
444 }
445 
446 template <typename T>
447 std::pair<unsigned int, unsigned int>
449  Mat mat_B,
450  Mat precond,
451  int nev, // number of requested eigenpairs
452  int ncv, // number of basis vectors
453  const double tol, // solver tolerance
454  const unsigned int m_its) // maximum number of iterations
455 {
456  LOG_SCOPE("solve_generalized()", "SlepcEigenSolver");
457 
458  // Set operators.
459  LibmeshPetscCall(EPSSetOperators (_eps, mat_A, mat_B));
460 
461  return this->_solve_helper(precond, nev, ncv, tol, m_its);
462 }
463 
464 
465 
466 template <typename T>
467 std::pair<unsigned int, unsigned int>
469  int nev, // number of requested eigenpairs
470  int ncv, // number of basis vectors
471  const double tol, // solver tolerance
472  const unsigned int m_its) // maximum number of iterations
473 {
474  // converged eigen pairs and number of iterations
475  PetscInt nconv=0;
476  PetscInt its=0;
477  ST st=nullptr;
478 
479  //set the problem type and the position of the spectrum
480  set_slepc_problem_type();
481  set_slepc_position_of_spectrum();
482 
483  // Set eigenvalues to be computed.
484 #if SLEPC_VERSION_LESS_THAN(3,0,0)
485  LibmeshPetscCall(EPSSetDimensions (_eps, nev, ncv));
486 #else
487  LibmeshPetscCall(EPSSetDimensions (_eps, nev, ncv, PETSC_DECIDE));
488 #endif
489  // Set the tolerance and maximum iterations.
490  LibmeshPetscCall(EPSSetTolerances (_eps, tol, m_its));
491 
492  // Set runtime options, e.g.,
493  // -eps_type <type>, -eps_nev <nev>, -eps_ncv <ncv>
494  // Similar to PETSc, these options will override those specified
495  // above as long as EPSSetFromOptions() is called _after_ any
496  // other customization routines.
497  LibmeshPetscCall(EPSSetFromOptions (_eps));
498 
499  // Set a preconditioning matrix to ST
500  if (precond) {
501  LibmeshPetscCall(EPSGetST(_eps,&st));
502 #if SLEPC_VERSION_LESS_THAN(3,15,0)
503  LibmeshPetscCall(STPrecondSetMatForPC(st, precond));
504 #else
505  LibmeshPetscCall(STSetPreconditionerMat(st, precond));
506 #endif
507  }
508 
509  // If the SolverConfiguration object is provided, use it to override
510  // solver options.
511  if (this->_solver_configuration)
512  {
513  this->_solver_configuration->configure_solver();
514  }
515 
516  // If an initial space is provided, let us attach it to EPS
517  if (_initial_space) {
518  // Get a handle for the underlying Vec.
519  Vec initial_vector = _initial_space->vec();
520 
521  LibmeshPetscCall(EPSSetInitialSpace(_eps, 1, &initial_vector));
522  }
523 
524  // Solve the eigenproblem.
525  LibmeshPetscCall(EPSSolve (_eps));
526 
527  // Get the number of iterations.
528  LibmeshPetscCall(EPSGetIterationNumber (_eps, &its));
529 
530  // Get number of converged eigenpairs.
531  LibmeshPetscCall(EPSGetConverged(_eps,&nconv));
532 
533  // return the number of converged eigenpairs
534  // and the number of iterations
535  return std::make_pair(nconv, its);
536 }
537 
538 
539 template <typename T>
541 {
542  // converged eigen pairs and number of iterations
543  PetscInt nconv=0;
544 
545  // The relative error.
546  PetscReal error, re, im;
547 
548  // Pointer to vectors of the real parts, imaginary parts.
549  PetscScalar kr, ki;
550 
551  // Get number of converged eigenpairs.
552  LibmeshPetscCall(EPSGetConverged(_eps,&nconv));
553 
554  // Display eigenvalues and relative errors.
555  LibmeshPetscCall(PetscPrintf(this->comm().get(),
556  " k ||Ax-kx||/|kx|\n"
557  " ----------------- -----------------\n" ));
558 
559  for (PetscInt i=0; i<nconv; i++ )
560  {
561  LibmeshPetscCall(EPSGetEigenpair(_eps, i, &kr, &ki, LIBMESH_PETSC_NULLPTR,
562  LIBMESH_PETSC_NULLPTR));
563 
564 #if SLEPC_VERSION_LESS_THAN(3,6,0)
565  LibmeshPetscCall(EPSComputeRelativeError(_eps, i, &error));
566 #else
567  LibmeshPetscCall(EPSComputeError(_eps, i, EPS_ERROR_RELATIVE, &error));
568 #endif
569 
570 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
571  re = PetscRealPart(kr);
572  im = PetscImaginaryPart(kr);
573 #else
574  re = kr;
575  im = ki;
576 #endif
577 
578  if (im != .0)
579  LibmeshPetscCall(PetscPrintf(this->comm().get()," %9f%+9f i %12f\n", double(re), double(im), double(error)));
580  else
581  LibmeshPetscCall(PetscPrintf(this->comm().get()," %12f %12f\n", double(re), double(error)));
582  }
583 
584  LibmeshPetscCall(PetscPrintf(this->comm().get(),"\n" ));
585 }
586 
587 
588 template <typename T>
590 {
591  switch (this->_eigen_solver_type)
592  {
593  case POWER:
594  LibmeshPetscCall(EPSSetType (_eps, EPSPOWER)); return;
595  case SUBSPACE:
596  LibmeshPetscCall(EPSSetType (_eps, EPSSUBSPACE)); return;
597  case LAPACK:
598  LibmeshPetscCall(EPSSetType (_eps, EPSLAPACK)); return;
599  case ARNOLDI:
600  LibmeshPetscCall(EPSSetType (_eps, EPSARNOLDI)); return;
601  case LANCZOS:
602  LibmeshPetscCall(EPSSetType (_eps, EPSLANCZOS)); return;
603  case KRYLOVSCHUR:
604  LibmeshPetscCall(EPSSetType (_eps, EPSKRYLOVSCHUR)); return;
605  // case ARPACK:
606  // LibmeshPetscCall(EPSSetType (_eps, (char *) EPSARPACK)); return;
607 
608  default:
609  libMesh::err << "ERROR: Unsupported SLEPc Eigen Solver: "
610  << Utility::enum_to_string(this->_eigen_solver_type) << std::endl
611  << "Continuing with SLEPc defaults" << std::endl;
612  }
613 }
614 
615 
616 
617 
618 template <typename T>
620 {
621  switch (this->_eigen_problem_type)
622  {
623  case NHEP:
624  LibmeshPetscCall(EPSSetProblemType (_eps, EPS_NHEP)); return;
625  case GNHEP:
626  LibmeshPetscCall(EPSSetProblemType (_eps, EPS_GNHEP)); return;
627  case HEP:
628  LibmeshPetscCall(EPSSetProblemType (_eps, EPS_HEP)); return;
629  case GHEP:
630  LibmeshPetscCall(EPSSetProblemType (_eps, EPS_GHEP)); return;
631 #if !SLEPC_VERSION_LESS_THAN(3,3,0)
632  // EPS_GHIEP added in 3.3.0
633  case GHIEP:
634  LibmeshPetscCall(EPSSetProblemType (_eps, EPS_GHIEP)); return;
635 #endif
636 
637  default:
638  libMesh::err << "ERROR: Unsupported SLEPc Eigen Problem: "
639  << this->_eigen_problem_type << std::endl
640  << "Continuing with SLEPc defaults" << std::endl;
641  }
642 }
643 
644 
645 
646 template <typename T>
648 {
649  switch (this->_position_of_spectrum)
650  {
651  case LARGEST_MAGNITUDE:
652  {
653  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_LARGEST_MAGNITUDE));
654  return;
655  }
656  case SMALLEST_MAGNITUDE:
657  {
658  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_MAGNITUDE));
659  return;
660  }
661  case LARGEST_REAL:
662  {
663  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_LARGEST_REAL));
664  return;
665  }
666  case SMALLEST_REAL:
667  {
668  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_REAL));
669  return;
670  }
671  case LARGEST_IMAGINARY:
672  {
673  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_LARGEST_IMAGINARY));
674  return;
675  }
676  case SMALLEST_IMAGINARY:
677  {
678  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_SMALLEST_IMAGINARY));
679  return;
680  }
681 
682  // The EPS_TARGET_XXX enums were added in SLEPc 3.1
683 #if !SLEPC_VERSION_LESS_THAN(3,1,0)
684  case TARGET_MAGNITUDE:
685  {
686  LibmeshPetscCall(EPSSetTarget(_eps, PS(this->_target_val)));
687  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_TARGET_MAGNITUDE));
688  return;
689  }
690  case TARGET_REAL:
691  {
692  LibmeshPetscCall(EPSSetTarget(_eps, PS(this->_target_val)));
693  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_TARGET_REAL));
694  return;
695  }
696  case TARGET_IMAGINARY:
697  {
698  LibmeshPetscCall(EPSSetTarget(_eps, PS(this->_target_val)));
699  LibmeshPetscCall(EPSSetWhichEigenpairs (_eps, EPS_TARGET_IMAGINARY));
700  return;
701  }
702 #endif
703 
704  default:
705  libmesh_error_msg("ERROR: Unsupported SLEPc position of spectrum: " << this->_position_of_spectrum);
706  }
707 }
708 
709 
710 
711 
712 
713 
714 template <typename T>
716  NumericVector<T> & solution_in)
717 {
718  PetscReal re, im;
719 
720  // Make sure the NumericVector passed in is really a PetscVector
721  PetscVector<T> * solution = dynamic_cast<PetscVector<T> *>(&solution_in);
722 
723  libmesh_error_msg_if(!solution, "Error getting eigenvector: input vector must be a PetscVector.");
724 
725  // real and imaginary part of the ith eigenvalue.
726  PetscScalar kr, ki;
727 
728  solution->close();
729 
730  LibmeshPetscCall(EPSGetEigenpair(_eps, i, &kr, &ki, solution->vec(),
731  LIBMESH_PETSC_NULLPTR));
732 
733 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
734  re = PetscRealPart(kr);
735  im = PetscImaginaryPart(kr);
736 #else
737  re = kr;
738  im = ki;
739 #endif
740 
741  return std::make_pair(re, im);
742 }
743 
744 
745 template <typename T>
747 {
748  PetscReal re, im;
749 
750  // real and imaginary part of the ith eigenvalue.
751  PetscScalar kr, ki;
752 
753  LibmeshPetscCall(EPSGetEigenvalue(_eps, i, &kr, &ki));
754 
755 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
756  re = PetscRealPart(kr);
757  im = PetscImaginaryPart(kr);
758 #else
759  re = kr;
760  im = ki;
761 #endif
762 
763  return std::make_pair(re, im);
764 }
765 
766 
767 template <typename T>
769 {
770  PetscReal error;
771 
772 #if SLEPC_VERSION_LESS_THAN(3,6,0)
773  LibmeshPetscCall(EPSComputeRelativeError(_eps, i, &error));
774 #else
775  LibmeshPetscCall(EPSComputeError(_eps, i, EPS_ERROR_RELATIVE, &error));
776 #endif
777 
778  return error;
779 }
780 
781 
782 template <typename T>
784 {
785  this->init();
786 
787  // Make sure the input vector is actually a PetscVector
788  PetscVector<T> * deflation_vector_petsc_vec =
789  dynamic_cast<PetscVector<T> *>(&deflation_vector_in);
790 
791  libmesh_error_msg_if(!deflation_vector_petsc_vec, "Error attaching deflation space: input vector must be a PetscVector.");
792 
793  // Get a handle for the underlying Vec.
794  Vec deflation_vector = deflation_vector_petsc_vec->vec();
795 
796 #if SLEPC_VERSION_LESS_THAN(3,1,0)
797  LibmeshPetscCall(EPSAttachDeflationSpace(_eps, 1, &deflation_vector, PETSC_FALSE));
798 #else
799  LibmeshPetscCall(EPSSetDeflationSpace(_eps, 1, &deflation_vector));
800 #endif
801 }
802 
803 template <typename T>
805 {
806 #if SLEPC_VERSION_LESS_THAN(3,1,0)
807  libmesh_error_msg("SLEPc 3.1 is required to call EigenSolver::set_initial_space()");
808 #else
809  // Make sure the input vector (which is still owned by caller) is
810  // actually a PetscVector
811  _initial_space = cast_ptr<PetscVector<T> *>(&initial_space_in);
812 #endif
813 }
814 
815 template <typename T>
816 PetscErrorCode SlepcEigenSolver<T>::_petsc_shell_matrix_mult(Mat mat, Vec arg, Vec dest)
817 {
818  PetscFunctionBegin;
819 
820  // Get the matrix context.
821  void * ctx;
822  LibmeshPetscCallQ(MatShellGetContext(mat,&ctx));
823 
824  // Get user shell matrix object.
825  const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
826 
827  // Make \p NumericVector instances around the vectors.
828  PetscVector<T> arg_global(arg, shell_matrix.comm());
829  PetscVector<T> dest_global(dest, shell_matrix.comm());
830 
831  // Call the user function.
832  shell_matrix.vector_mult(dest_global,arg_global);
833 
834  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
835 }
836 
837 template <typename T>
839 {
840  PetscFunctionBegin;
841 
842  // Get the matrix context.
843  void * ctx;
844  LibmeshPetscCallQ(MatShellGetContext(mat,&ctx));
845 
846  // Get user shell matrix object.
847  const ShellMatrix<T> & shell_matrix = *static_cast<const ShellMatrix<T> *>(ctx);
848 
849  // Make \p NumericVector instances around the vector.
850  PetscVector<T> dest_global(dest, shell_matrix.comm());
851 
852  // Call the user function.
853  shell_matrix.get_diagonal(dest_global);
854 
855  PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
856 }
857 
858 //------------------------------------------------------------------
859 // Explicit instantiations
860 template class LIBMESH_EXPORT SlepcEigenSolver<Number>;
861 
862 } // namespace libMesh
863 
864 
865 // In case we do unity builds someday
866 #if SLEPC_VERSION_LESS_THAN(3,15,0) && !SLEPC_VERSION_LESS_THAN(3,14,2)
867 #include "libmesh/restore_warnings.h"
868 #endif
869 
870 
871 #endif // #ifdef LIBMESH_HAVE_SLEPC
OStreamProxy err
This class provides a nice interface to PETSc&#39;s Vec object.
Definition: petsc_vector.h:73
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...
Definition: vector_fe_ex5.C:44
const Parallel::Communicator & comm() const
The libMesh namespace provides an interface to certain functionality in the library.
virtual numeric_index_type m() const =0
Generic sparse matrix.
Definition: vector_fe_ex5.C:46
PetscScalar PS(T val)
Definition: petsc_macro.h:168
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:257
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.
Definition: libmesh.C:276
void * ctx
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&#39;s internal assembly routines, ensuring that the values are consistent across ...
Definition: petsc_vector.h:869
uint8_t dof_id_type
Definition: id_types.h:67
This class provides an interface to solvers for eigenvalue problems.
Definition: eigen_solver.h:58