https://mooseframework.inl.gov
Loading...
Searching...
No Matches
EigenproblemEquationSystem.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#ifdef MOOSE_MFEM_ENABLED
11
13#include "MFEMEigensolverBase.h"
14#include "libmesh/int_range.h"
15
16namespace Moose::MFEM
17{
18
19void
21{
22 _ess_tdof_lists.resize(1);
23 _ess_markers.resize(1);
24 mfem::ParGridFunction & trial_gf = *(_var_ess_constraints.at(0));
25 trial_gf.Update();
26 trial_gf = _gfuncs->GetRef(_trial_var_names.at(0));
27 // A mesh without boundary elements, such as a periodic one, has no boundary attributes
28 const auto & bdr_attributes = trial_gf.ParFESpace()->GetParMesh()->bdr_attributes;
29 _ess_markers.at(0).SetSize(bdr_attributes.Size() ? bdr_attributes.Max() : 0, 0);
30 // Set constrained DoF values on user-declared essential boundaries and collect their markers
31 ApplyEssentialBC(_trial_var_names.at(0), trial_gf, _ess_markers.at(0));
32 trial_gf.FESpace()->GetEssentialTrueDofs(_ess_markers.at(0), _ess_tdof_lists.at(0));
34}
35
36void
38{
39 // Reject nonzero Dirichlet BCs.
40 mfem::ParGridFunction & trial_gf = *(_var_ess_constraints.at(0));
41 mfem::Vector ess_values;
42 trial_gf.GetTrueDofs(ess_values);
43 ess_values.SetSubVectorComplement(_ess_tdof_lists.at(0), 0.0);
44 mfem::real_t max_ess_value =
45 mfem::GlobalLpNorm(mfem::infinity(), ess_values.Normlinf(), trial_gf.ParFESpace()->GetComm());
46 // Roundoff guard. Zero coefficients project to exactly zero.
47 if (max_ess_value > 10 * std::numeric_limits<mfem::real_t>::epsilon())
48 mooseError("Essential boundary conditions on variable '",
49 _trial_var_names.at(0),
50 "' prescribe a nonzero value. "
51 "An eigenproblem is homogeneous so only zero-valued essential boundary conditions "
52 "are meaningful. Set the boundary coefficient to zero.");
53}
54
55void
57{
58 auto & test_var_name = _test_var_names.at(0);
59 auto blf = _blfs.Get(test_var_name);
60
61 blf->EliminateEssentialBCDiag(_ess_markers.at(0), 1.0);
62 blf->Finalize();
63 _jacobian.Reset(blf->ParallelAssemble());
64}
65
66void
68{
69 mfem::ParFiniteElementSpace * fespace = _test_pfespaces.at(0);
70 std::unique_ptr<mfem::ParBilinearForm> m = std::make_unique<mfem::ParBilinearForm>(fespace);
71
72 if (fespace->GetTypicalFE()->GetRangeType() == mfem::FiniteElement::SCALAR)
73 {
74 // VectorMassIntegrator reads vdim x vdim entries of the evaluated matrix without bounds checks.
75 if (std::holds_alternative<mfem::MatrixCoefficient *>(rhs_coefficient))
76 {
77 const auto & mat_coef = *std::get<mfem::MatrixCoefficient *>(rhs_coefficient);
78 if (mat_coef.GetHeight() != fespace->GetVDim() || mat_coef.GetWidth() != fespace->GetVDim())
79 mooseError("A matrix rhs_coefficient on an H1 or L2 finite element space must be ",
80 fespace->GetVDim(),
81 "x",
82 fespace->GetVDim(),
83 " to match the number of components of the space, but it is ",
84 mat_coef.GetHeight(),
85 "x",
86 mat_coef.GetWidth(),
87 ".");
88 }
89 auto * const integ = std::visit(
90 [](auto * coef) { return new mfem::VectorMassIntegrator(*coef); }, rhs_coefficient);
91 // Otherwise, for scalar coefficients, VectorMassIntegrator defaults to the space dimension.
92 integ->SetVDim(fespace->GetVDim());
93 m->AddDomainIntegrator(integ);
94 }
95 else
96 m->AddDomainIntegrator(std::visit(
97 [](auto * coef) { return new mfem::VectorFEMassIntegrator(*coef); }, rhs_coefficient));
98
99 m->Assemble();
100 // Shift the eigenvalue corresponding to eliminated dofs to a large value. The BC DoFs on the
101 // stiffness matrix are set to 1 and the mass matrix BC DoFs are set to a small value eps, such
102 // that the eigenvalues associate with these DOFs are ~1/eps.
103 m->EliminateEssentialBCDiag(_ess_markers.at(0), std::numeric_limits<mfem::real_t>::epsilon());
104 m->Finalize();
105 _mass_rhs.Reset(m->ParallelAssemble());
106}
107
108void
110 EigenRHSCoefficient rhs_coefficient)
111{
112 mooseAssert(_test_var_names.size() == 1 && (_test_var_names.size() == _trial_var_names.size()) &&
113 (_test_var_names.at(0) == _trial_var_names.at(0)),
114 "Eigensolve is only supported for single-variable, square systems");
115
116 height = trueX.Size();
117 width = trueX.Size();
120 FormMassMatrix(rhs_coefficient);
121}
122
123void
129
130} // namespace Moose::MFEM
131
132#endif
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
virtual void ApplyEssentialBCs() override
Mark external boundaries as essential for eigenproblem BC elimination.
void FormMassMatrix(EigenRHSCoefficient rhs_coefficient)
Form mass matrix for the eigensolver with Dirichlet BC elimination.
virtual void CheckProblemIsHomogeneous()
Verify that the problem is homogeneous (all Dirichlet BCs are zero)
mfem::OperatorHandle _mass_rhs
The mass operator (e.g. the RHS operator for a generalized eigenproblem)
void PrepareEigensolver(EigensolverBase &solver)
Prepare the provided eigensolver.
void BuildEigenproblemJacobian(mfem::BlockVector &trueX, EigenRHSCoefficient rhs_coefficient)
Build eigenproblem system, with essential boundary conditions accounted for.
void FormEigenproblemMatrix()
Form HypreParMatrix matrix operator for the eigensolver with Dirichlet BC elimination.
Base class for eigensolvers.
virtual void SetMassMatrix(mfem::Operator &mass)=0
Sets the mass matrix for the eigensolver in derived classes.
std::vector< mfem::ParFiniteElementSpace * > _test_pfespaces
Pointers to finite element spaces associated with test variables.
virtual void ApplyEssentialBC(const std::string &var_name, mfem::ParGridFunction &trial_gf, mfem::Array< int > &global_ess_markers)
Apply essential BC(s) associated with var_name to set true DoFs of trial_gf and update markers of all...
std::vector< std::string > _test_var_names
Names of all test variables corresponding to linear forms in this equation system.
std::vector< mfem::Array< int > > _ess_tdof_lists
NamedFieldsMap< mfem::ParBilinearForm > _blfs
mfem::OperatorHandle _jacobian
std::vector< std::string > _trial_var_names
Subset of _coupled_var_names of all variables corresponding to gridfunctions with degrees of freedom ...
std::vector< std::unique_ptr< mfem::ParGridFunction > > _var_ess_constraints
Gridfunctions holding essential constraints from Dirichlet BCs.
std::vector< mfem::Array< int > > _ess_markers
Moose::MFEM::GridFunctions * _gfuncs
virtual void SetOperator(const mfem::Operator &op) override
Updates the solver and any associated weak form context at the operator level.
T * Get(const std::string &field_name) const
Returns a non-owning pointer to the field. This is guaranteed to return a non-null pointer.
T & GetRef(const std::string &field_name) const
Returns a reference to a field.
Utilities for converting between vector(s) of libMesh Points and MFEM Vector(s).
std::variant< mfem::Coefficient *, mfem::MatrixCoefficient * > EigenRHSCoefficient
Scalar or matrix coefficient scaling the eigenproblem right-hand side.