https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ComplexEquationSystem.C
Go to the documentation of this file.
1#ifdef MOOSE_MFEM_ENABLED
2
5#include "libmesh/int_range.h"
6
7namespace Moose::MFEM
8{
9
10void
12 ComplexGridFunctions & cmplx_gridfunctions,
13 mfem::AssemblyLevel assembly_level)
14{
15 _assembly_level = assembly_level;
16
17 if (gridfunctions.size())
18 mooseError("Mixing real and complex variables is currently not supported.");
19
20 for (auto & test_var_name : _test_var_names)
21 {
22 if (!cmplx_gridfunctions.Has(test_var_name))
23 {
24 mooseError("MFEM complex variable ",
25 test_var_name,
26 " requested by equation system during initialization was "
27 "not found in gridfunctions");
28 }
29 // Store pointers to test FESpaces
30 _test_pfespaces.push_back(cmplx_gridfunctions.Get(test_var_name)->ParFESpace());
31 // Create auxiliary gridfunctions for storing essential constraints from Dirichlet conditions
32 _cmplx_var_ess_constraints.emplace_back(std::make_unique<mfem::ParComplexGridFunction>(
33 cmplx_gridfunctions.Get(test_var_name)->ParFESpace()));
34 }
35
36 // Store pointers to FESpaces of all coupled variables
37 for (auto & coupled_var_name : _coupled_var_names)
38 _coupled_pfespaces.push_back(cmplx_gridfunctions.Get(coupled_var_name)->ParFESpace());
39
40 // Extract which coupled variables are to be trivially eliminated and which are trial variables
42
43 // Store pointers to coupled variable ComplexGridFunctions that are to be eliminated prior to
44 // forming the jacobian
45 for (auto & eliminated_var_name : _eliminated_var_names)
46 _cmplx_eliminated_variables.Register(eliminated_var_name,
47 cmplx_gridfunctions.GetShared(eliminated_var_name));
48
49 // Get a reference to the complex GridFunctions
50 _complex_gfuncs = &cmplx_gridfunctions;
51}
52
53void
59
60void
62{
63 // Register linear forms
64 for (const auto i : index_range(_test_var_names))
65 {
66 auto test_var_name = _test_var_names.at(i);
67 _clfs.Register(test_var_name,
68 std::make_shared<mfem::ParComplexLinearForm>(_test_pfespaces.at(i)));
69 _clfs.GetRef(test_var_name) = 0.0;
70 }
71 // Apply boundary conditions
73
74 for (auto & test_var_name : _test_var_names)
75 {
76 // Apply kernels
77 auto clf = _clfs.GetShared(test_var_name);
80 clf->Assemble();
81 }
82}
83
84void
86{
87 // Register bilinear forms
88 for (const auto i : index_range(_test_var_names))
89 {
90 auto test_var_name = _test_var_names.at(i);
91 _slfs.Register(test_var_name,
92 std::make_shared<mfem::ParSesquilinearForm>(_test_pfespaces.at(i)));
93
94 // Apply kernels
95 auto slf = _slfs.GetShared(test_var_name);
96 slf->SetAssemblyLevel(_assembly_level);
97 ApplyBoundaryBLFIntegrators<mfem::ParSesquilinearForm>(
98 test_var_name, test_var_name, slf, _cmplx_integrated_bc_map);
99 ApplyDomainBLFIntegrators<mfem::ParSesquilinearForm>(
100 test_var_name, test_var_name, slf, _cmplx_kernels_map);
101 // Assemble
102 slf->Assemble();
103 }
104}
105
106void
108 mfem::ParComplexGridFunction & trial_gf,
109 mfem::Array<int> & global_ess_markers)
110{
111 if (_cmplx_essential_bc_map.Has(var_name))
112 for (auto & bc : _cmplx_essential_bc_map.GetRef(var_name))
113 {
114 // Set constrained DoFs values on essential boundaries
115 bc->ApplyBC(trial_gf);
116 // Fetch marker array labelling essential boundaries of current BC
117 mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
118 // Add these boundary markers to the set of markers labelling all essential boundaries
119 for (const auto i : make_range(ess_bdrs.Size()))
120 global_ess_markers[i] |= ess_bdrs[i];
121 }
122}
123
124void
126{
127 _ess_tdof_lists.resize(_trial_var_names.size());
128 _ess_markers.resize(_trial_var_names.size());
129 for (const auto i : index_range(_trial_var_names))
130 {
131 const auto & trial_var_name = _trial_var_names.at(i);
132 mfem::ParComplexGridFunction & trial_gf = *_cmplx_var_ess_constraints.at(i);
133
134 // Make sure we update the size, if this mesh has changed recently for instance
135 trial_gf.Update();
136
137 // Initial guess for iterative solvers (initial condition or the previous time step solution)
138 static_cast<mfem::Vector &>(trial_gf) = _complex_gfuncs->GetRef(trial_var_name);
139
140 _ess_markers.at(i).SetSize(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max(), 0);
141 // Set strongly constrained DoFs of trial_gf on essential boundaries and add markers for all
142 // essential boundaries to the _ess_markers array
143 ApplyComplexEssentialBC(trial_var_name, trial_gf, _ess_markers.at(i));
144 trial_gf.ParFESpace()->GetEssentialTrueDofs(_ess_markers.at(i), _ess_tdof_lists.at(i));
145 }
146}
147
148void
149ComplexEquationSystem::AddComplexKernel(std::shared_ptr<MFEMComplexKernel> kernel)
150{
151 const auto & trial_var_name = kernel->getTrialVariableName();
152 const auto & test_var_name = kernel->getTestVariableName();
153 AddCoupledVariableNameIfMissing(trial_var_name);
154 AddTestVariableNameIfMissing(test_var_name);
155 // Register new complex kernels map if not present for the test variable
156 if (!_cmplx_kernels_map.Has(test_var_name))
157 {
158 auto kernel_field_map =
159 std::make_shared<NamedFieldsMap<std::vector<std::shared_ptr<MFEMComplexKernel>>>>();
160 _cmplx_kernels_map.Register(test_var_name, std::move(kernel_field_map));
161 }
162 // Register new complex kernels map if not present for the test/trial variable pair
163 if (!_cmplx_kernels_map.Get(test_var_name)->Has(trial_var_name))
164 {
165 auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMComplexKernel>>>();
166 _cmplx_kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
167 }
168 _cmplx_kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
169}
170
171void
172ComplexEquationSystem::AddComplexIntegratedBC(std::shared_ptr<MFEMComplexIntegratedBC> bc)
173{
174 const auto & trial_var_name = bc->getTrialVariableName();
175 const auto & test_var_name = bc->getTestVariableName();
176 AddCoupledVariableNameIfMissing(trial_var_name);
177 AddTestVariableNameIfMissing(test_var_name);
178 // Register new complex integrated bc map if not present for the test variable
179 if (!_cmplx_integrated_bc_map.Has(test_var_name))
180 {
181 auto integrated_bc_field_map =
182 std::make_shared<NamedFieldsMap<std::vector<std::shared_ptr<MFEMComplexIntegratedBC>>>>();
183 _cmplx_integrated_bc_map.Register(test_var_name, std::move(integrated_bc_field_map));
184 }
185 // Register new complex integrated bc map if not present for the test/trial variable pair
186 if (!_cmplx_integrated_bc_map.Get(test_var_name)->Has(trial_var_name))
187 {
188 auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMComplexIntegratedBC>>>();
189 _cmplx_integrated_bc_map.Get(test_var_name)->Register(trial_var_name, std::move(bcs));
190 }
191 _cmplx_integrated_bc_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(bc));
192}
193
194void
195ComplexEquationSystem::AddComplexEssentialBCs(std::shared_ptr<MFEMComplexEssentialBC> bc)
196{
197 const auto & test_var_name = bc->getTestVariableName();
198 AddTestVariableNameIfMissing(test_var_name);
199 // Register new complex essential bc map if not present for the test variable
200 if (!_cmplx_essential_bc_map.Has(test_var_name))
201 {
202 auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMComplexEssentialBC>>>();
203 _cmplx_essential_bc_map.Register(test_var_name, std::move(bcs));
204 }
205 _cmplx_essential_bc_map.GetRef(test_var_name).push_back(std::move(bc));
206}
207
208void
210 mfem::BlockVector & trueX,
211 mfem::BlockVector & trueRHS)
212{
213 auto & test_var_name = _test_var_names.at(0);
214 mfem::Vector aux_x, aux_rhs;
215 mfem::OperatorPtr aux_a;
216
217 auto slf = _slfs.Get(test_var_name);
218 slf->FormLinearSystem(_ess_tdof_lists.at(0),
220 *_clfs.Get(test_var_name),
221 aux_a,
222 aux_x,
223 aux_rhs,
224 /*copy_interior=*/true);
225
226 trueX.GetBlock(0) = aux_x;
227 trueRHS.GetBlock(0) = aux_rhs;
228 trueX.SyncFromBlocks();
229 trueRHS.SyncFromBlocks();
230
231 op.Reset(aux_a.Ptr());
232 aux_a.SetOperatorOwner(false);
233}
234
235void
237 mfem::BlockVector & trueX,
238 mfem::BlockVector & trueRHS)
239{
240
241 // Allocate block operator
243 _h_blocks.SetSize(_test_var_names.size(), _trial_var_names.size());
244 _h_blocks = nullptr;
245 // Zero out RHS and sync memory
246 trueRHS = 0.0;
247 trueRHS.SyncToBlocks();
248
249 // Form diagonal blocks.
250 for (const auto i : index_range(_test_var_names))
251 {
252 auto & test_var_name = _test_var_names.at(i);
253
254 mfem::Vector aux_x, aux_rhs;
255 mfem::OperatorHandle aux_a;
256
257 auto slf = _slfs.Get(test_var_name);
258 slf->FormLinearSystem(_ess_tdof_lists.at(i),
260 *_clfs.Get(test_var_name),
261 aux_a,
262 aux_x,
263 aux_rhs,
264 /*copy_interior=*/true);
265 trueX.GetBlock(i) = aux_x;
266 trueRHS.GetBlock(i) = aux_rhs;
267 _h_blocks(i, i) = aux_a.As<mfem::ComplexHypreParMatrix>()->GetSystemMatrix();
268 }
269 // Sync memory
270 trueX.SyncFromBlocks();
271 trueRHS.SyncFromBlocks();
272
273 // Create monolithic matrix
274 op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
275}
276
277// Equation system Mult
278void
279ComplexEquationSystem::Mult(const mfem::Vector & x, mfem::Vector & residual) const
280{
281 _linear_operator->Mult(x, residual);
282 x.HostRead();
283 residual.HostRead();
284}
285
286void
288{
289 for (const auto i : index_range(_trial_var_names))
290 {
291 auto & trial_var_name = _trial_var_names.at(i);
292 trueX.GetBlock(i).SyncMemory(trueX);
293 _complex_gfuncs->Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
294 }
295 // Solution variables changed: stored projections of solution-dependent coefficients are stale.
298}
299}
300
301#endif
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
void markSolutionChanged()
Notify quadrature function coefficients that solution variables have changed, marking the stored valu...
virtual void BuildEquationSystem() override
Build all forms comprising this EquationSystem.
virtual void BuildLinearForms() override
Build linear forms and eliminate constrained DoFs.
std::vector< std::unique_ptr< mfem::ParComplexGridFunction > > _cmplx_var_ess_constraints
Complex Gridfunctions holding essential constraints from Dirichlet BCs.
Moose::MFEM::ComplexGridFunctions * _complex_gfuncs
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexKernel > > > > _cmplx_kernels_map
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const override
Nonlinear Mult (Used by Newton-solver not necessarily nonlinear)
virtual void FormSystemOperator(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS) override
Form matrix-free representation of system operator.
virtual void SetTrialVariablesFromTrueVectors(const mfem::BlockVector &trueX) const override
Update variable from solution vector after solve.
NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexEssentialBC > > > _cmplx_essential_bc_map
NamedFieldsMap< mfem::ParSesquilinearForm > _slfs
virtual void BuildBilinearForms() override
Build bilinear forms (diagonal Jacobian contributions)
virtual void Init(GridFunctions &gridfunctions, ComplexGridFunctions &cmplx_gridfunctions, mfem::AssemblyLevel assembly_level) override
Initialise.
void ApplyBoundaryLFIntegrators(const std::string &test_var_name, std::shared_ptr< mfem::ParComplexLinearForm > form, NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexIntegratedBC > > > > &integrated_bc_map)
Method for applying LinearFormIntegrators on boundaries from kernels to a ParComplexLinearForm.
void AddComplexKernel(std::shared_ptr< MFEMComplexKernel > kernel)
Add complex kernels.
virtual void ApplyComplexEssentialBC(const std::string &var_name, mfem::ParComplexGridFunction &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...
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexIntegratedBC > > > > _cmplx_integrated_bc_map
virtual void ApplyEssentialBCs() override
Update all essentially constrained true DoF markers and values on boundaries.
void ApplyDomainLFIntegrators(const std::string &test_var_name, std::shared_ptr< mfem::ParComplexLinearForm > form, NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexKernel > > > > &kernels_map)
Method for applying LinearFormIntegrators on domains from kernels to a ParComplexLinearForm.
NamedFieldsMap< mfem::ParComplexLinearForm > _clfs
virtual void FormSystemMatrix(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS) override
Form matrix representation of system operator as a HypreParMatrix.
void AddComplexIntegratedBC(std::shared_ptr< MFEMComplexIntegratedBC > bc)
Add complex integrated BCs.
ComplexGridFunctions _cmplx_eliminated_variables
Pointers to coupled variables not part of the reduced EquationSystem.
void AddComplexEssentialBCs(std::shared_ptr< MFEMComplexEssentialBC > bc)
Add complex essential BCs.
virtual void AddTestVariableNameIfMissing(const std::string &test_var_name)
Add test variable to EquationSystem.
std::vector< std::string > _coupled_var_names
Names of all trial variables of kernels and boundary conditions added to this EquationSystem.
std::vector< mfem::ParFiniteElementSpace * > _test_pfespaces
Pointers to finite element spaces associated with test variables.
std::vector< mfem::ParFiniteElementSpace * > _coupled_pfespaces
Pointers to finite element spaces associated with coupled variables.
mfem::Array2D< const mfem::HypreParMatrix * > _h_blocks
std::vector< std::string > _test_var_names
Names of all test variables corresponding to linear forms in this equation system.
mfem::OperatorHandle _linear_operator
mfem::AssemblyLevel _assembly_level
virtual void SetTrialVariableNames()
Set trial variable names from subset of coupled variables that have an associated test variable.
std::vector< mfem::Array< int > > _ess_tdof_lists
CoefficientManager * _coefficient_manager
void DeleteHBlocks()
Deletes the HypreParMatrix associated with any pointer stored in _h_blocks, and then proceeds to dele...
std::vector< std::string > _trial_var_names
Subset of _coupled_var_names of all variables corresponding to gridfunctions with degrees of freedom ...
std::vector< mfem::Array< int > > _ess_markers
std::vector< std::string > _eliminated_var_names
Names of all coupled variables without a corresponding test variable.
virtual void AddCoupledVariableNameIfMissing(const std::string &coupled_var_name)
Add coupled variable to EquationSystem.
void Register(const std::string &field_name, FieldArgs &&... args)
Construct new field with name field_name and register.
bool Has(const std::string &field_name) const
Predicate to check if a field is registered with name field_name.
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.
std::shared_ptr< T > GetShared(const std::string &field_name) const
Returns a shared pointer to the field. This is guaranteed to return a non-null shared pointer.
int size()
Returns the number of elements in the map.
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).