libMesh
condensed_eigen_system.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2026 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 #include "libmesh/libmesh_config.h"
19 
20 // Currently, the EigenSystem should only be available
21 // if SLEPc support is enabled.
22 #if defined(LIBMESH_HAVE_SLEPC)
23 
24 #include "libmesh/condensed_eigen_system.h"
25 
26 #include "libmesh/dof_map.h"
27 #include "libmesh/equation_systems.h"
28 #include "libmesh/int_range.h"
29 #include "libmesh/libmesh_logging.h"
30 #include "libmesh/numeric_vector.h"
31 #include "libmesh/parallel.h"
32 
33 namespace libMesh
34 {
35 
37  const std::string & name_in,
38  const unsigned int number_in)
39  : Parent(es, name_in, number_in),
40  _condensed_dofs_initialized(false),
41  _have_condensed_dofs(false),
42  _create_submatrices_in_solve(true)
43 {
44 }
45 
47 
48 void
49 CondensedEigenSystem::initialize_condensed_dofs(const std::set<dof_id_type> & global_dirichlet_dofs_set)
50 {
51  const DofMap & dof_map = this->get_dof_map();
52  if (global_dirichlet_dofs_set.empty() && !dof_map.n_constrained_dofs())
53  {
54  _have_condensed_dofs = false;
56  return;
57  }
58 
59  // First, put all unconstrained local dofs into non_dirichlet_dofs_set
60  std::set<dof_id_type> local_non_condensed_dofs_set;
61  for (auto i : make_range(dof_map.first_dof(), dof_map.end_dof()))
62 #if LIBMESH_ENABLE_CONSTRAINTS
63  if (!dof_map.is_constrained_dof(i))
64 #endif
65  local_non_condensed_dofs_set.insert(i);
66 
67  // Now erase the condensed dofs
68  for (const auto dof : global_dirichlet_dofs_set)
69  if ((dof_map.first_dof() <= dof) && (dof < dof_map.end_dof()))
70  local_non_condensed_dofs_set.erase(dof);
71 
72  // Finally, move local_non_condensed_dofs_set over to a vector for convenience in solve()
73  this->local_non_condensed_dofs_vector.clear();
74 
75  for (const auto dof : local_non_condensed_dofs_set)
76  this->local_non_condensed_dofs_vector.push_back(dof);
77 
78  _have_condensed_dofs = true;
80 }
81 
82 void
84 {
87 }
88 
89 void
91 {
94 
96  return;
97 
98  const auto m = cast_int<numeric_index_type>(this->local_non_condensed_dofs_vector.size());
99  auto M = m;
100  _communicator.sum(M);
101  if (this->has_condensed_matrix_A())
102  {
103  this->get_condensed_matrix_A().init(M, M, m, m);
104  // A bit ludicrously MatCopy requires the matrix being copied to to be assembled
105  this->get_condensed_matrix_A().close();
106  }
107  if (this->has_condensed_matrix_B())
108  {
109  this->get_condensed_matrix_B().init(M, M, m, m);
110  this->get_condensed_matrix_B().close();
111  }
112  if (this->has_condensed_precond_matrix())
113  {
114  this->get_condensed_precond_matrix().init(M, M, m, m);
116  }
117 }
118 
120 {
122  return this->n_dofs();
123  else
124  {
126  cast_int<dof_id_type>(local_non_condensed_dofs_vector.size());
127  this->comm().sum(n_global_non_condensed_dofs);
128 
130  }
131 }
132 
133 void
135 {
136  Parent::clear();
137  _condensed_matrix_A = nullptr;
138  _condensed_matrix_B = nullptr;
139  _condensed_precond_matrix = nullptr;
140 }
141 
142 void
144 {
146 
147  if (!this->use_shell_matrices())
148  {
149  if (!_condensed_matrix_A)
151  if (!_condensed_matrix_B)
153 
154  // When not using shell matrices we use A for P as well so we don't need to add P
155  }
156  // we *are* using shell matrices but we might not be using a shell matrix for P
157  else if (!this->use_shell_precond_matrix())
158  {
161  }
162 }
163 
165 {
166  LOG_SCOPE("solve()", "CondensedEigenSystem");
167 
168  // If we haven't initialized any condensed dofs,
169  // just use the default eigen_system
171  {
172  Parent::solve();
173  return;
174  }
175 
176  // check that necessary parameters have been set
178  this->get_equation_systems().parameters.have_parameter<unsigned int>("eigenpairs"));
180  this->get_equation_systems().parameters.have_parameter<unsigned int>("basis vectors"));
181 
182  if (this->assemble_before_solve)
183  {
184  // Assemble the linear system
185  this->assemble();
186 
187  // And close the assembled matrices; using a non-closed matrix
188  // with create_submatrix() is deprecated.
189  if (matrix_A)
190  matrix_A->close();
191  if (generalized() && matrix_B)
192  matrix_B->close();
193  if (precond_matrix)
195  }
196 
197  // If we reach here, then there should be some non-condensed dofs
199 
201  {
202  if (matrix_A)
205  if (generalized() && matrix_B)
208  if (precond_matrix)
212  }
213 
214  solve_helper(
216 }
217 
219 {
220  LOG_SCOPE("get_eigenpair()", "CondensedEigenSystem");
221 
222  // If we haven't initialized any condensed dofs,
223  // just use the default eigen_system
225  return Parent::get_eigenpair(i);
226 
227  // If we reach here, then there should be some non-condensed dofs
229 
230  // This function assumes that condensed_solve has just been called.
231  // If this is not the case, then we will trip an asset in get_eigenpair
232  std::unique_ptr<NumericVector<Number>> temp = NumericVector<Number>::build(this->comm());
233  const dof_id_type n_local =
234  cast_int<dof_id_type>(local_non_condensed_dofs_vector.size());
235  dof_id_type n = n_local;
236  this->comm().sum(n);
237 
238  temp->init (n, n_local, false, PARALLEL);
239 
240  std::pair<Real, Real> eval = eigen_solver->get_eigenpair (i, *temp);
241 
242  // Now map temp to solution. Loop over local entries of local_non_condensed_dofs_vector
243  libmesh_assert(this->comm().verify(this->solution->closed()));
244  if (!this->solution->closed())
245  this->solution->close();
246  this->solution->zero();
247  for (auto j : make_range(n_local))
248  {
250  solution->set(index,(*temp)(temp->first_local_index()+j));
251  }
252 
253  // Enforcing constraints requires creating a ghosted version of the solution, which requires the
254  // solution be assembled
255  solution->close();
257  this->update();
258 
259  return eval;
260 }
261 
262 
263 
265 {
267  return *_condensed_matrix_A;
268 }
269 
271 {
273  return *_condensed_matrix_B;
274 }
275 
277 {
280 }
281 
282 void
284  NumericVector<Number> & super)
285 {
286  libmesh_assert_equal_to(sub.local_size(), local_non_condensed_dofs_vector.size());
287  libmesh_assert_equal_to(sub.local_size() + this->get_dof_map().n_local_constrained_dofs(),
288  super.local_size());
289  auto super_sub_view = super.get_subvector(local_non_condensed_dofs_vector);
290  *super_sub_view = sub;
291  super.restore_subvector(std::move(super_sub_view), local_non_condensed_dofs_vector);
292 }
293 
294 void
296  NumericVector<Number> & sub)
297 {
298  libmesh_assert_equal_to(sub.local_size(), local_non_condensed_dofs_vector.size());
299  libmesh_assert_equal_to(sub.local_size() + this->get_dof_map().n_local_constrained_dofs(),
300  super.local_size());
301  auto super_sub_view = super.get_subvector(local_non_condensed_dofs_vector);
302  sub = *super_sub_view;
303  super.restore_subvector(std::move(super_sub_view), local_non_condensed_dofs_vector);
304 }
305 
306 void
308  SparseMatrix<Number> & sub)
309 {
310  parallel_object_only();
311 
312  libmesh_assert_equal_to(sub.local_m(), local_non_condensed_dofs_vector.size());
313  libmesh_assert_equal_to(sub.local_m() + this->get_dof_map().n_local_constrained_dofs(),
314  super.local_m());
315  auto super_sub_view = SparseMatrix<Number>::build(super.comm());
316  super.create_submatrix(
318  sub = *super_sub_view;
319 }
320 
321 } // namespace libMesh
322 
323 
324 #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
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
virtual void create_submatrix(SparseMatrix< T > &submatrix, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols) const
This function creates a matrix called "submatrix" which is defined by the row and column indices give...
void initialize_condensed_matrices()
Initializes the condensed matrices.
dof_id_type end_dof(const processor_id_type proc) const
Definition: dof_map_base.h:191
This is the EquationSystems class.
bool _condensed_dofs_initialized
A private flag to indicate whether the condensed dofs have been initialized.
bool have_parameter(std::string_view) const
Definition: parameters.h:420
SparseMatrix< Number > * matrix_B
A second system matrix for generalized eigenvalue problems.
Definition: eigen_system.h:321
SparseMatrix< Number > & get_condensed_precond_matrix()
virtual numeric_index_type local_m() const
Get the number of rows owned by this process.
dof_id_type n_local_constrained_dofs() const
const EquationSystems & get_equation_systems() const
Definition: system.h:767
void sum(T &r) const
virtual void assemble()
Prepares matrix and _dof_map for matrix assembly.
Definition: system.C:554
CondensedEigenSystem(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
Constructor.
const Parallel::Communicator & comm() const
bool use_shell_precond_matrix() const
Definition: eigen_system.h:171
const Parallel::Communicator & _communicator
virtual void clear() override
Clear all the data structures associated with the system.
The libMesh namespace provides an interface to certain functionality in the library.
void copy_super_to_sub(NumericVector< Number > &super, NumericVector< Number > &sub)
Copy a logically super-vector into a sub-vector.
Parameters parameters
Parameters for the system. If a parameter is not provided, it should be retrieved from the EquationSy...
Definition: system.h:1588
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
Builds a SparseMatrix<T> using the linear solver package specified by solver_package.
virtual void solve() override
Override to solve the condensed eigenproblem with the dofs in local_non_condensed_dofs_vector strippe...
dof_id_type n_dofs() const
Definition: system.C:118
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
SparseMatrix< Number > * precond_matrix
A preconditioning matrix.
Definition: eigen_system.h:345
SparseMatrix< Number > & get_condensed_matrix_A()
bool use_shell_matrices() const
Definition: eigen_system.h:161
dof_id_type n_global_non_condensed_dofs() const
void copy_sub_to_super(const NumericVector< Number > &sub, NumericVector< Number > &super)
Copy a logically sub-vector into a super-vector.
bool _have_condensed_dofs
Whether there are any condensed degrees of freedom.
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1655
libmesh_assert(ctx)
bool is_constrained_dof(const dof_id_type dof) const
Definition: dof_map.h:2426
SparseMatrix< Number > * matrix_A
The system matrix for standard eigenvalue problems.
Definition: eigen_system.h:313
void initialize_condensed_dofs(const std::set< dof_id_type > &global_condensed_dofs_set=std::set< dof_id_type >())
Loop over the dofs on each processor to initialize the list of non-condensed dofs.
virtual std::unique_ptr< NumericVector< T > > get_subvector(const std::vector< numeric_index_type > &)
Creates a view into this vector using the indices in rows.
virtual void solve() override
Assembles & solves the eigen system.
Definition: eigen_system.C:287
virtual void add_matrices() override
Adds the necessary matrices and shell matrices.
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:498
virtual void close()=0
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
dof_id_type n_constrained_dofs() const
std::unique_ptr< SparseMatrix< Number > > _condensed_matrix_B
A second (condensed) system matrix for generalized eigenvalue problems.
std::unique_ptr< EigenSolver< Number > > eigen_solver
The EigenSolver, defining which interface, i.e solver package to use.
Definition: eigen_system.h:362
virtual numeric_index_type local_size() const =0
virtual void add_matrices() override
Adds the necessary matrices and shell matrices.
Definition: eigen_system.C:126
virtual std::pair< Real, Real > get_eigenpair(dof_id_type i) override
Override get_eigenpair() to retrieve the eigenpair for the condensed eigensolve.
std::vector< dof_id_type > local_non_condensed_dofs_vector
Vector storing the local dof indices that will not be condensed.
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:176
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
bool _create_submatrices_in_solve
Denotes whether to create the condensed submatrices from the global matrices in the solve...
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
SparseMatrix< Number > & get_condensed_matrix_B()
dof_id_type first_dof(const processor_id_type proc) const
Definition: dof_map_base.h:185
virtual void clear() override
Clear all the data structures associated with the system.
Definition: eigen_system.C:62
Manages consistently variables, degrees of freedom, and coefficient vectors for eigenvalue problems...
Definition: eigen_system.h:55
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:1609
const DofMap & get_dof_map() const
Definition: system.h:2417
std::unique_ptr< SparseMatrix< Number > > _condensed_precond_matrix
The condensed preconditioning matrix.
std::unique_ptr< SparseMatrix< Number > > _condensed_matrix_A
The (condensed) system matrix for standard eigenvalue problems.
uint8_t dof_id_type
Definition: id_types.h:67
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type nnz=30, const numeric_index_type noz=10, const numeric_index_type blocksize=1)=0
Initialize SparseMatrix with the specified sizes.
void enforce_constraints_exactly(const System &system, NumericVector< Number > *v=nullptr, bool homogeneous=false) const
Constrains the numeric vector v, which represents a solution defined on the mesh. ...
Definition: dof_map.h:2518
virtual void restore_subvector(std::unique_ptr< NumericVector< T >>, const std::vector< numeric_index_type > &)
Restores a view into this vector using the indices in rows.