libMesh
eigen_system.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 #include "libmesh/libmesh_config.h"
20 
21 // Currently, the EigenSystem should only be available
22 // if SLEPc support is enabled.
23 #if defined(LIBMESH_HAVE_SLEPC)
24 
25 // Local includes
26 #include "libmesh/eigen_system.h"
27 #include "libmesh/equation_systems.h"
28 #include "libmesh/sparse_matrix.h"
29 #include "libmesh/shell_matrix.h"
30 #include "libmesh/eigen_solver.h"
31 #include "libmesh/dof_map.h"
32 #include "libmesh/mesh_base.h"
33 #include "libmesh/enum_eigen_solver_type.h"
34 
35 namespace libMesh
36 {
37 
38 
40  const std::string & name_in,
41  const unsigned int number_in
42  ) :
43  Parent (es, name_in, number_in),
44  matrix_A (nullptr),
45  matrix_B (nullptr),
46  precond_matrix (nullptr),
47  eigen_solver (EigenSolver<Number>::build(es.comm())),
48  _n_converged_eigenpairs (0),
49  _n_iterations (0),
50  _eigen_problem_type (NHEP),
51  _use_shell_matrices (false),
52  _use_shell_precond_matrix(false)
53 {
54 }
55 
56 
57 
58 EigenSystem::~EigenSystem () = default;
59 
60 
61 
63 {
64  // Clear the parent data
65  Parent::clear();
66 
67  // The SparseMatrices are contained in _matrices
68  // and are cleared with the above call
69  matrix_A = nullptr;
70  matrix_B = nullptr;
71  precond_matrix = nullptr;
72 
73  // Operators
74  shell_matrix_A.reset();
75  shell_matrix_B.reset();
76 
77  // Preconditioning matrices
78  shell_precond_matrix.reset();
79 
80  // clear the solver
81  eigen_solver->clear();
82 }
83 
84 
86 {
87  if (!can_add_matrices())
88  libmesh_error_msg("ERROR: Cannot change eigen problem type after system initialization");
89 
90  _eigen_problem_type = ept;
91 
92  eigen_solver->set_eigenproblem_type(ept);
93 
94  // libMesh::out << "The Problem type is set to be: " << std::endl;
95 
96  switch (_eigen_problem_type)
97  {
98  case HEP:
99  // libMesh::out << "Hermitian" << std::endl;
100  break;
101 
102  case NHEP:
103  // libMesh::out << "Non-Hermitian" << std::endl;
104  break;
105 
106  case GHEP:
107  // libMesh::out << "Generalized Hermitian" << std::endl;
108  break;
109 
110  case GNHEP:
111  // libMesh::out << "Generalized Non-Hermitian" << std::endl;
112  break;
113 
114  case GHIEP:
115  // libMesh::out << "Generalized indefinite Hermitian" << std::endl;
116  break;
117 
118  default:
119  // libMesh::out << "not properly specified" << std::endl;
120  libmesh_error_msg("Unrecognized _eigen_problem_type = " << _eigen_problem_type);
121  }
122 }
123 
124 
125 
127 {
129 
131  {
132  if (!shell_matrix_A)
134 
135  if (generalized() && !shell_matrix_B)
137 
139  {
142  }
143  else if (!precond_matrix)
144  precond_matrix = &(this->add_matrix("Eigen Preconditioner"));
145  }
146  else
147  {
148  if (!matrix_A)
149  matrix_A = &(this->add_matrix("Eigen Matrix A"));
150 
151  if (generalized() && !matrix_B)
152  matrix_B = &(this->add_matrix("Eigen Matrix B"));
153  }
154 }
155 
156 
157 
159 {
161 
162  const bool condense_constraints = condense_constrained_dofs();
163  if (shell_matrix_A)
164  {
165  shell_matrix_A->attach_dof_map(this->get_dof_map());
166  if (condense_constraints)
167  shell_matrix_A->omit_constrained_dofs();
168  shell_matrix_A->init();
169  }
170 
171  if (shell_matrix_B)
172  {
173  shell_matrix_B->attach_dof_map(this->get_dof_map());
174  if (condense_constraints)
175  shell_matrix_B->omit_constrained_dofs();
176  shell_matrix_B->init();
177  }
178 
180  {
181  shell_precond_matrix->attach_dof_map(this->get_dof_map());
182  if (condense_constraints)
183  shell_precond_matrix->omit_constrained_dofs();
184  shell_precond_matrix->init();
185  }
186 }
187 
188 
190 {
191  // initialize parent data
192  // this calls reinit on matrix_A, matrix_B, and precond_matrix (if any)
193  Parent::reinit();
194 
195  if (shell_matrix_A)
196  {
197  shell_matrix_A->clear();
198  shell_matrix_A->init();
199  }
200 
201  if (shell_matrix_B)
202  {
203  shell_matrix_B->clear();
204  shell_matrix_B->init();
205  }
206 
208  {
209  shell_precond_matrix->clear();
210  shell_precond_matrix->init();
211  }
212 }
213 
214 void
216  SparseMatrix<Number> * const B,
217  SparseMatrix<Number> * const P)
218 {
219  // A reference to the EquationSystems
220  EquationSystems & es = this->get_equation_systems();
221 
222  // Get the tolerance for the solver and the maximum
223  // number of iterations. Here, we simply adopt the linear solver
224  // specific parameters.
225  const double tol = parameters.have_parameter<Real>("linear solver tolerance") ?
226  double(parameters.get<Real>("linear solver tolerance")) :
227  double(es.parameters.get<Real>("linear solver tolerance"));
228 
229  const unsigned int maxits = parameters.have_parameter<unsigned int>("linear solver maximum iterations") ?
230  parameters.get<unsigned int>("linear solver maximum iterations") :
231  es.parameters.get<unsigned int>("linear solver maximum iterations");
232 
233  const unsigned int nev = parameters.have_parameter<unsigned int>("eigenpairs") ?
234  parameters.get<unsigned int>("eigenpairs") :
235  es.parameters.get<unsigned int>("eigenpairs");
236 
237  const unsigned int ncv = parameters.have_parameter<unsigned int>("basis vectors") ?
238  parameters.get<unsigned int>("basis vectors") :
239  es.parameters.get<unsigned int>("basis vectors");
240 
241  std::pair<unsigned int, unsigned int> solve_data;
242 
243  // call the solver depending on the type of eigenproblem
244 
246  {
247  // Generalized eigenproblem
248  if (generalized())
249  // Shell preconditioning matrix
251  solve_data = eigen_solver->solve_generalized(
252  *shell_matrix_A, *shell_matrix_B, *shell_precond_matrix, nev, ncv, tol, maxits);
253  else
254  solve_data = eigen_solver->solve_generalized(
255  *shell_matrix_A, *shell_matrix_B, *P, nev, ncv, tol, maxits);
256 
257  // Standard eigenproblem
258  else
259  {
261  // Shell preconditioning matrix
263  solve_data = eigen_solver->solve_standard(
264  *shell_matrix_A, *shell_precond_matrix, nev, ncv, tol, maxits);
265  else
266  solve_data = eigen_solver->solve_standard(*shell_matrix_A, *P, nev, ncv, tol, maxits);
267  }
268  }
269  else
270  {
271  // Generalized eigenproblem
272  if (generalized())
273  solve_data = eigen_solver->solve_generalized(*A, *B, nev, ncv, tol, maxits);
274 
275  // Standard eigenproblem
276  else
277  {
279  solve_data = eigen_solver->solve_standard(*A, nev, ncv, tol, maxits);
280  }
281  }
282 
283  this->_n_converged_eigenpairs = solve_data.first;
284  this->_n_iterations = solve_data.second;
285 }
286 
288 {
290  libmesh_warning("EigenSystem does not have first-class support for constrained degrees of "
291  "freedom. You may see spurious effects of the constrained degrees of freedom "
292  "in a given eigenvector. If you wish to perform a reliable solve on a system "
293  "with constraints, please use the CondensedEigenSystem class instead");
294 
295  // check that necessary parameters have been set
297  this->get_equation_systems().parameters.have_parameter<unsigned int>("eigenpairs"));
299  this->get_equation_systems().parameters.have_parameter<unsigned int>("basis vectors"));
300 
301  if (this->assemble_before_solve)
302  // Assemble the linear system
303  this->assemble ();
304 
306 }
307 
308 std::pair<Real, Real> EigenSystem::get_eigenpair (dof_id_type i)
309 {
310  // call the eigen_solver get_eigenpair method
311  return eigen_solver->get_eigenpair (i, *solution);
312 }
313 
314 std::pair<Real, Real> EigenSystem::get_eigenvalue (dof_id_type i)
315 {
316  return eigen_solver->get_eigenvalue (i);
317 }
318 
320 {
321  eigen_solver->set_initial_space (initial_space_in);
322 }
323 
324 
326 {
327  return _eigen_problem_type == GNHEP ||
330 }
331 
332 
334 {
338  return *matrix_A;
339 }
340 
341 
343 {
347  return *matrix_A;
348 }
349 
350 
352 {
357  return *matrix_B;
358 }
359 
360 
362 {
367  return *matrix_B;
368 }
369 
370 
372 {
377  return *precond_matrix;
378 }
379 
380 
382 {
387  return *precond_matrix;
388 }
389 
390 
392 {
395  return *shell_matrix_A;
396 }
397 
398 
400 {
403  return *shell_matrix_A;
404 }
405 
406 
408 {
412  return *shell_matrix_B;
413 }
414 
415 
417 {
421  return *shell_matrix_B;
422 }
423 
424 
426 {
430  return *shell_precond_matrix;
431 }
432 
433 
435 {
439  return *shell_precond_matrix;
440 }
441 
442 
444 {
445  libmesh_assert_equal_to(request_matrix("Eigen Matrix A"), matrix_A);
446  return matrix_A;
447 }
448 
449 
451 {
452  libmesh_assert_equal_to(request_matrix("Eigen Matrix B"), matrix_B);
453  return matrix_B;
454 }
455 
456 
458 {
459  libmesh_assert_equal_to(request_matrix("Eigen Preconditioner"), precond_matrix);
460  return precond_matrix;
461 }
462 
463 
465 {
466  return shell_matrix_A.get();
467 }
468 
469 
471 {
472  return shell_matrix_B.get();
473 }
474 
475 
477 {
478  return shell_precond_matrix.get();
479 }
480 
481 
483 {
485  return *eigen_solver;
486 }
487 
488 
490 {
492  return *eigen_solver;
493 }
494 
495 
496 } // namespace libMesh
497 
498 #endif // LIBMESH_HAVE_SLEPC
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
Definition: eigen_system.C:189
virtual std::pair< Real, Real > get_eigenpair(dof_id_type i)
Definition: eigen_system.C:308
bool can_add_matrices() const
Definition: system.h:1975
void solve_helper(SparseMatrix< Number > *const A, SparseMatrix< Number > *const B, SparseMatrix< Number > *const P)
Definition: eigen_system.C:215
bool generalized() const
Definition: eigen_system.C:325
const SparseMatrix< Number > & get_precond_matrix() const
Definition: eigen_system.C:371
This is the EquationSystems class.
virtual void clear()
Clear all the data structures associated with the system.
Definition: system.C:176
bool have_parameter(std::string_view) const
Definition: parameters.h:395
SparseMatrix< Number > * matrix_B
A second system matrix for generalized eigenvalue problems.
Definition: eigen_system.h:321
unsigned int _n_converged_eigenpairs
The number of converged eigenpairs.
Definition: eigen_system.h:399
virtual void init_matrices()
Initializes the matrices associated with this system.
Definition: system.C:323
const SparseMatrix< Number > & get_matrix_A() const
Definition: eigen_system.C:333
virtual bool condense_constrained_dofs() const
Whether this object should condense out constrained degrees of freedom.
Definition: system.h:2013
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition: system.C:454
std::unique_ptr< ShellMatrix< Number > > shell_precond_matrix
A preconditioning shell matrix.
Definition: eigen_system.h:353
const SparseMatrix< Number > & get_matrix_B() const
Definition: eigen_system.C:351
bool has_matrix_A() const
Definition: eigen_system.C:443
const EquationSystems & get_equation_systems() const
Definition: system.h:721
virtual void assemble()
Prepares matrix and _dof_map for matrix assembly.
Definition: system.C:566
static std::unique_ptr< ShellMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package())
Builds a ShellMatrix<T> using the linear solver package specified by solver_package.
Definition: shell_matrix.C:31
bool has_shell_matrix_A() const
Definition: eigen_system.C:464
const Parallel::Communicator & comm() const
EigenProblemType
Defines an enum for eigenproblem types.
virtual void init_matrices() override
Initializes the matrices associated with the system.
Definition: eigen_system.C:158
void set_initial_space(NumericVector< Number > &initial_space_in)
Sets an initial eigen vector.
Definition: eigen_system.C:319
The libMesh namespace provides an interface to certain functionality in the library.
const EigenSolver< Number > & get_eigen_solver() const
Definition: eigen_system.C:482
const SparseMatrix< Number > * request_matrix(std::string_view mat_name) const
Definition: system.C:1100
Parameters parameters
Parameters for the system. If a parameter is not provided, it should be retrieved from the EquationSy...
Definition: system.h:1526
const ShellMatrix< Number > & get_shell_matrix_A() const
Definition: eigen_system.C:391
unsigned int _n_iterations
The number of iterations of the eigen solver algorithm.
Definition: eigen_system.h:404
Definition: assembly.h:38
std::unique_ptr< ShellMatrix< Number > > shell_matrix_A
The system shell matrix for standard eigenvalue problems.
Definition: eigen_system.h:329
SparseMatrix< Number > * precond_matrix
A preconditioning matrix.
Definition: eigen_system.h:345
const T & get(std::string_view) const
Definition: parameters.h:426
bool has_matrix_B() const
Definition: eigen_system.C:450
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
bool has_precond_matrix() const
Definition: eigen_system.C:457
bool _use_shell_precond_matrix
A boolean flag to indicate whether or not to use a shell preconditioning matrix.
Definition: eigen_system.h:419
virtual void add_matrices()
Insertion point for adding matrices in derived classes before init_matrices() is called.
Definition: system.h:1964
std::unique_ptr< ShellMatrix< Number > > shell_matrix_B
A second system shell matrix for generalized eigenvalue problems.
Definition: eigen_system.h:337
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
libmesh_assert(ctx)
SparseMatrix< Number > * matrix_A
The system matrix for standard eigenvalue problems.
Definition: eigen_system.h:313
bool has_shell_matrix_B() const
Definition: eigen_system.C:470
const ShellMatrix< Number > & get_shell_precond_matrix() const
Definition: eigen_system.C:425
bool has_shell_precond_matrix() const
Definition: eigen_system.C:476
virtual std::pair< Real, Real > get_eigenvalue(dof_id_type i)
Definition: eigen_system.C:314
virtual void solve() override
Assembles & solves the eigen system.
Definition: eigen_system.C:287
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
EigenSystem(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
Constructor.
Definition: eigen_system.C:39
bool _use_shell_matrices
A boolean flag to indicate whether or not to use shell matrices.
Definition: eigen_system.h:414
std::unique_ptr< EigenSolver< Number > > eigen_solver
The EigenSolver, defining which interface, i.e solver package to use.
Definition: eigen_system.h:362
const ShellMatrix< Number > & get_shell_matrix_B() const
Definition: eigen_system.C:407
virtual void add_matrices() override
Adds the necessary matrices and shell matrices.
Definition: eigen_system.C:126
EigenProblemType _eigen_problem_type
The type of the eigenvalue problem.
Definition: eigen_system.h:409
Parameters parameters
Data structure holding arbitrary parameters.
void set_eigenproblem_type(EigenProblemType ept)
Sets the type of the current eigen problem.
Definition: eigen_system.C:85
virtual void clear() override
Clear all the data structures associated with the system.
Definition: eigen_system.C:62
bool assemble_before_solve
Flag which tells the system to whether or not to call the user assembly function during each call to ...
Definition: system.h:1547
SparseMatrix< Number > & add_matrix(std::string_view mat_name, ParallelType type=PARALLEL, MatrixBuildType mat_build_type=MatrixBuildType::AUTOMATIC)
Adds the additional matrix mat_name to this system.
Definition: system.C:1010
const DofMap & get_dof_map() const
Definition: system.h:2374
dof_id_type n_constrained_dofs() const
Definition: system.C:128
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