Reference documentation for deal.II version 8.4.2
slepc_solver.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2009 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/lac/slepc_solver.h>
17 
18 #ifdef DEAL_II_WITH_SLEPC
19 
20 # include <deal.II/lac/petsc_matrix_base.h>
21 # include <deal.II/lac/petsc_vector_base.h>
22 # include <deal.II/lac/petsc_vector.h>
23 # include <deal.II/lac/slepc_spectral_transformation.h>
24 
25 # include <cmath>
26 # include <vector>
27 
28 # include <petscversion.h>
29 # include <slepcversion.h>
30 
31 DEAL_II_NAMESPACE_OPEN
32 
33 namespace SLEPcWrappers
34 {
35 
37  const MPI_Comm &mpi_communicator)
38  :
39  solver_control (cn),
40  mpi_communicator (mpi_communicator)
41  {
42  // create eigensolver context
43  int ierr = EPSCreate (mpi_communicator, &eps);
44  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
45 
46  // hand over the absolute tolerance and the maximum number of
47  // iteration steps to the SLEPc convergence criterion.
48  ierr = EPSSetTolerances(eps, this->solver_control.tolerance(),
49  this->solver_control.max_steps());
50  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
51 
52  // default values:
53  set_which_eigenpairs(EPS_LARGEST_MAGNITUDE);
54  set_problem_type(EPS_GNHEP);
55 
56  // TODO:
57  // By default, EPS initializes the starting vector or the initial subspace randomly.
58  }
59 
61  {
62  if (eps != NULL)
63  {
64  // Destroy the solver object.
65 #if DEAL_II_PETSC_VERSION_LT(3,2,0)
66  int ierr = EPSDestroy (eps);
67 #else
68  int ierr = EPSDestroy (&eps);
69 #endif
70  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
71  }
72  }
73 
74  void
76  {
77  // standard eigenspectrum problem
78  int ierr = EPSSetOperators (eps, A, PETSC_NULL);
79  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
80  }
81 
82  void
85  {
86  // generalized eigenspectrum problem
87  int ierr = EPSSetOperators (eps, A, B);
88  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
89  }
90 
91  void
93  {
94  // set transformation type if any
95  // STSetShift is called inside
96  int ierr = EPSSetST(eps,transformation.st);
97  AssertThrow (ierr == 0, SolverBase::ExcSLEPcError(ierr));
98  }
99 
100  void
102  {
103  Assert(this_initial_vector.l2_norm()>0.0,
104  ExcMessage("Initial vector should be nonzero."));
105 
106  int ierr;
107  Vec vec = this_initial_vector;
108 #if DEAL_II_PETSC_VERSION_LT(3,1,0)
109  ierr = EPSSetInitialVector (eps, &vec);
110 #else
111  ierr = EPSSetInitialSpace (eps, 1, &vec);
112 #endif
113  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
114  }
115 
116  void
117  SolverBase::set_target_eigenvalue (const PetscScalar &this_target)
118  {
119  // set target eigenvalues to solve for
120  // in all transformation except STSHIFT there is a direct connection between
121  // the target and the shift, read more on p41 of SLEPc manual.
122  int ierr = EPSSetTarget (eps, this_target );
123  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
124  }
125 
126  void
127  SolverBase::set_which_eigenpairs (const EPSWhich eps_which)
128  {
129  // set which portion of the eigenspectrum to solve for
130  int ierr = EPSSetWhichEigenpairs (eps, eps_which);
131  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
132  }
133 
134  void
135  SolverBase::set_problem_type (const EPSProblemType eps_problem)
136  {
137  int ierr = EPSSetProblemType (eps, eps_problem);
138  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
139  }
140 
141  void
142  SolverBase::solve (const unsigned int n_eigenpairs,
143  unsigned int *n_converged)
144  {
145  int ierr;
146 
147  // set number of eigenvectors to compute
148  ierr = EPSSetDimensions (eps, n_eigenpairs,
149  PETSC_DECIDE, PETSC_DECIDE);
150  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
151 
152  // set the solve options to the eigenvalue problem solver context
153  ierr = EPSSetFromOptions (eps);
154  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
155 
156  // TODO breaks @ref step_36 "step-36"
157  // force Krylov solver to use true residual instead of an estimate.
158  //EPSSetTrueResidual(solver_data->eps, PETSC_TRUE);
159  //AssertThrow (ierr == 0, ExcSLEPcError(ierr));
160 
161  // Set convergence test to be absolute
162  ierr = EPSSetConvergenceTest (eps, EPS_CONV_ABS);
163  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
164 
165  // TODO Set the convergence test function
166  // ierr = EPSSetConvergenceTestFunction (solver_data->eps, &convergence_test,
167  // reinterpret_cast<void *>(&solver_control));
168  // AssertThrow (ierr == 0, ExcSLEPcError(ierr));
169 
170  // solve the eigensystem
171  ierr = EPSSolve (eps);
172  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
173 
174  // get number of converged eigenstates
175  ierr = EPSGetConverged (eps,
176  reinterpret_cast<PetscInt *>(n_converged));
177  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
178 
179  PetscInt n_iterations = 0;
180  PetscReal residual_norm = 0;
181 
182  // @todo Investigate elaborating on some of this to act on the
183  // complete eigenspectrum
184  {
185  // get the number of solver iterations
186  ierr = EPSGetIterationNumber (eps, &n_iterations);
187  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
188 
189  // get the maximum of residual norm among converged eigenvectors.
190  for (unsigned int i = 0; i < *n_converged; i++)
191  {
192  double residual_norm_i = 0.0;
193  // EPSComputeResidualNorm is L2-norm and is not consistent with the stopping criteria
194  // used during the solution process.
195  // Yet, this is the norm which gives error bounds (Saad, 1992, ch3):
196  // | \lambda - \widehat\lambda | <= ||r||_2
197  ierr = EPSComputeResidualNorm (eps, i, &residual_norm_i);
198 
199  // EPSComputeRelativeError may not be consistent with the stopping criteria
200  // used during the solution process. Given EPS_CONV_ABS set above,
201  // this can be either the l2 norm or the mass-matrix induced norm
202  // when EPS_GHEP is set.
203  // ierr = EPSComputeRelativeError (solver_data->eps, i, &residual_norm_i);
204 
205  // EPSGetErrorEstimate is consistent with the residual norm
206  // used during the solution process. However, it is not guaranteed to
207  // be derived from the residual even when EPSSetTrueResidual is set.
208  // ierr = EPSGetErrorEstimate (solver_data->eps, i, &residual_norm_i);
209 
210  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
211  residual_norm = std::max (residual_norm, residual_norm_i);
212  }
213 
214  // check the solver state
215  const SolverControl::State state
216  = solver_control.check (n_iterations, residual_norm);
217 
218  // get the solver state according to SLEPc
219  get_solver_state (state);
220 
221  // as SLEPc uses different stopping criteria, we have to omit this step.
222  // This can be checked only in conjunction with EPSGetErrorEstimate.
223  // and in case of failure: throw exception
224  // if (solver_control.last_check () != SolverControl::success)
225  // AssertThrow(false, SolverControl::NoConvergence (solver_control.last_step(),
226  // solver_control.last_value()));
227  }
228  }
229 
230  void
231  SolverBase::get_eigenpair (const unsigned int index,
232  PetscScalar &eigenvalues,
233  PETScWrappers::VectorBase &eigenvectors)
234  {
235  // get converged eigenpair
236  int ierr = EPSGetEigenpair (eps, index,
237  &eigenvalues, PETSC_NULL,
238  eigenvectors, PETSC_NULL);
239  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
240  }
241 
242 
243  void
244  SolverBase::get_eigenpair (const unsigned int index,
245  double &real_eigenvalues,
246  double &imag_eigenvalues,
247  PETScWrappers::VectorBase &real_eigenvectors,
248  PETScWrappers::VectorBase &imag_eigenvectors)
249  {
250 #ifndef PETSC_USE_COMPLEX
251  // get converged eigenpair
252  int ierr = EPSGetEigenpair (eps, index,
253  &real_eigenvalues, &imag_eigenvalues,
254  real_eigenvectors, imag_eigenvectors);
255  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
256 #else
257  Assert ((false),
258  ExcMessage ("Your PETSc/SLEPc installation was configured with scalar-type complex "
259  "but this function is not defined for complex types."));
260 #endif
261  }
262 
263  void
265  {
266  switch (state)
267  {
268  case ::SolverControl::iterate:
269  reason = EPS_CONVERGED_ITERATING;
270  break;
271 
272  case ::SolverControl::success:
273  reason = static_cast<EPSConvergedReason>(1);
274  break;
275 
276  case ::SolverControl::failure:
278  reason = EPS_DIVERGED_ITS;
279  else
280  reason = EPS_DIVERGED_BREAKDOWN;
281  break;
282 
283  default:
284  Assert (false, ExcNotImplemented());
285  }
286  }
287 
288  /* ---------------------- SolverControls ----------------------- */
289  SolverControl &
291  {
292  return solver_control;
293  }
294 
295  int
297  PetscScalar /*real_eigenvalue */,
298  PetscScalar /*imag_eigenvalue */,
299  PetscReal /*residual norm associated to the eigenpair */,
300  PetscReal */*(output) computed error estimate */,
301  void */*solver_control_x*/)
302  {
303  // If the error estimate returned by the convergence test function is less
304  // than the tolerance, then the eigenvalue is accepted as converged.
305  // This function is undefined (future reference only).
306 
307  // return without failure.
308  return 0;
309  }
310 
311  /* ---------------------- SolverKrylovSchur ------------------------ */
313  const MPI_Comm &mpi_communicator,
314  const AdditionalData &data)
315  :
316  SolverBase (cn, mpi_communicator),
317  additional_data (data)
318  {
319  int ierr = EPSSetType (eps, const_cast<char *>(EPSKRYLOVSCHUR));
320  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
321  }
322 
323  /* ---------------------- SolverArnoldi ------------------------ */
325  AdditionalData (const bool delayed_reorthogonalization)
326  :
327  delayed_reorthogonalization (delayed_reorthogonalization)
328  {}
329 
331  const MPI_Comm &mpi_communicator,
332  const AdditionalData &data)
333  :
334  SolverBase (cn, mpi_communicator),
335  additional_data (data)
336  {
337  int ierr = EPSSetType (eps, const_cast<char *>(EPSARNOLDI));
338  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
339 
340  // if requested, set delayed reorthogonalization in the Arnoldi
341  // iteration.
343  {
344  ierr = EPSArnoldiSetDelayed (eps, PETSC_TRUE);
345  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
346  }
347  }
348 
349 
350  /* ---------------------- Lanczos ------------------------ */
352  AdditionalData(const EPSLanczosReorthogType r)
353  : reorthog(r)
354  {}
355 
357  const MPI_Comm &mpi_communicator,
358  const AdditionalData &data)
359  :
360  SolverBase (cn, mpi_communicator),
361  additional_data (data)
362  {
363  int ierr = EPSSetType (eps, const_cast<char *>(EPSLANCZOS));
364  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
365 
366  ierr = EPSLanczosSetReorthog(eps,additional_data.reorthog);
367  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
368  }
369 
370  /* ----------------------- Power ------------------------- */
372  const MPI_Comm &mpi_communicator,
373  const AdditionalData &data)
374  :
375  SolverBase (cn, mpi_communicator),
376  additional_data (data)
377  {
378  int ierr = EPSSetType (eps, const_cast<char *>(EPSPOWER));
379  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
380  }
381 
382  /* ---------------- Generalized Davidson ----------------- */
384  AdditionalData(bool double_expansion)
385  : double_expansion(double_expansion)
386  {}
387 
389  const MPI_Comm &mpi_communicator,
390  const AdditionalData &data)
391  :
392  SolverBase (cn, mpi_communicator),
393  additional_data (data)
394  {
395 #if DEAL_II_PETSC_VERSION_GTE(3,1,0)
396  int ierr = EPSSetType (eps, const_cast<char *>(EPSGD));
397  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
398 
400  {
401  ierr = EPSGDSetDoubleExpansion (eps, PETSC_TRUE);
402  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
403  }
404 #else
405  // PETSc/SLEPc version must be > 3.1.0.
406  Assert ((false),
407  ExcMessage ("Your SLEPc installation does not include a copy of the "
408  "Generalized Davidson solver. A SLEPc version > 3.1.0 is required."));
409 #endif
410  }
411 
412  /* ------------------ Jacobi Davidson -------------------- */
414  const MPI_Comm &mpi_communicator,
415  const AdditionalData &data)
416  :
417  SolverBase (cn, mpi_communicator),
418  additional_data (data)
419  {
420 #if DEAL_II_PETSC_VERSION_GTE(3,1,0)
421  int ierr;
422  ierr = EPSSetType (eps, const_cast<char *>(EPSJD));
423  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
424 #else
425  // PETSc/SLEPc version must be > 3.1.0.
426  Assert ((false),
427  ExcMessage ("Your SLEPc installation does not include a copy of the "
428  "Jacobi-Davidson solver. A SLEPc version > 3.1.0 is required."));
429 #endif
430  }
431 
432  /* ---------------------- LAPACK ------------------------- */
434  const MPI_Comm &mpi_communicator,
435  const AdditionalData &data)
436  :
437  SolverBase (cn, mpi_communicator),
438  additional_data (data)
439  {
440  // 'Tis overwhelmingly likely that PETSc/SLEPc *always* has
441  // BLAS/LAPACK, but let's be defensive.
442 #if PETSC_HAVE_BLASLAPACK
443  int ierr;
444  ierr = EPSSetType (eps, const_cast<char *>(EPSLAPACK));
445  AssertThrow (ierr == 0, ExcSLEPcError(ierr));
446 #else
447  Assert ((false),
448  ExcMessage ("Your PETSc/SLEPc installation was not configured with BLAS/LAPACK "
449  "but this is needed to use the LAPACK solver."));
450 #endif
451  }
452 }
453 
454 DEAL_II_NAMESPACE_CLOSE
455 
456 #endif // DEAL_II_WITH_SLEPC
457 
virtual State check(const unsigned int step, const double check_value)
void set_initial_vector(const PETScWrappers::VectorBase &this_initial_vector) DEAL_II_DEPRECATED
SolverJacobiDavidson(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
SolverPower(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
void solve(const PETScWrappers::MatrixBase &A, std::vector< PetscScalar > &eigenvalues, std::vector< OutputVector > &eigenvectors, const unsigned int n_eigenpairs=1)
Definition: slepc_solver.h:672
const MPI_Comm mpi_communicator
Definition: slepc_solver.h:304
SolverKrylovSchur(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
SolverBase(SolverControl &cn, const MPI_Comm &mpi_communicator)
Definition: slepc_solver.cc:36
AdditionalData(const bool delayed_reorthogonalization=false)
void set_problem_type(EPSProblemType set_problem)
void set_target_eigenvalue(const PetscScalar &this_target)
void set_matrices(const PETScWrappers::MatrixBase &A)
Definition: slepc_solver.cc:75
void set_which_eigenpairs(EPSWhich set_which)
#define Assert(cond, exc)
Definition: exceptions.h:294
SolverGeneralizedDavidson(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
EPSConvergedReason reason
Definition: slepc_solver.h:364
const AdditionalData additional_data
Definition: slepc_solver.h:508
void get_eigenpair(const unsigned int index, PetscScalar &eigenvalues, PETScWrappers::VectorBase &eigenvectors)
static int convergence_test(EPS eps, PetscScalar real_eigenvalue, PetscScalar imag_eigenvalue, PetscReal residual_norm, PetscReal *estimated_error, void *solver_control)
SolverLanczos(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
double tolerance() const
unsigned int last_step() const
unsigned int max_steps() const
SolverLAPACK(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
const AdditionalData additional_data
Definition: slepc_solver.h:623
AdditionalData(const EPSLanczosReorthogType r=EPS_LANCZOS_REORTHOG_FULL)
const AdditionalData additional_data
Definition: slepc_solver.h:462
void set_transformation(SLEPcWrappers::TransformationBase &this_transformation)
Definition: slepc_solver.cc:92
SolverControl & solver_control
Definition: slepc_solver.h:299
SolverArnoldi(SolverControl &cn, const MPI_Comm &mpi_communicator=PETSC_COMM_SELF, const AdditionalData &data=AdditionalData())
SolverControl & control() const
void get_solver_state(const SolverControl::State state)