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
55{
56 // Register linear forms
57 for (const auto i : index_range(_test_var_names))
58 {
59 auto test_var_name = _test_var_names.at(i);
60 _clfs.Register(test_var_name,
61 std::make_shared<mfem::ParComplexLinearForm>(_test_pfespaces.at(i)));
62 _clfs.GetRef(test_var_name) = 0.0;
63 }
64
65 for (auto & test_var_name : _test_var_names)
66 {
67 // Apply kernels
68 auto clf = _clfs.GetShared(test_var_name);
71 clf->Assemble();
72 }
73
74 // Apply boundary conditions
76
77 // Eliminate trivially eliminated variables by subtracting contributions from linear forms
79}
80
81void
83{
84 // Register bilinear forms
85 for (const auto i : index_range(_test_var_names))
86 {
87 auto test_var_name = _test_var_names.at(i);
88 _slfs.Register(test_var_name,
89 std::make_shared<mfem::ParSesquilinearForm>(_test_pfespaces.at(i)));
90
91 // Apply kernels
92 auto slf = _slfs.GetShared(test_var_name);
93 slf->SetAssemblyLevel(_assembly_level);
94 ApplyBoundaryBLFIntegrators<mfem::ParSesquilinearForm>(
95 test_var_name, test_var_name, slf, _cmplx_integrated_bc_map);
96 ApplyDomainBLFIntegrators<mfem::ParSesquilinearForm>(
97 test_var_name, test_var_name, slf, _cmplx_kernels_map);
98 // Assemble
99 slf->Assemble();
100 }
101}
102
103void
105{
106 // Register mixed sesquilinear forms. Note that not all combinations may
107 // have a kernel.
108
109 // Create mslf for each test/coupled variable pair with an added kernel.
110 // Mixed sesquilinear forms with coupled variables that are not trial variables are
111 // associated with contributions from eliminated variables.
112 for (const auto i : index_range(_test_var_names))
113 {
114 auto test_var_name = _test_var_names.at(i);
115 auto test_mslfs =
116 std::make_shared<Moose::MFEM::NamedFieldsMap<mfem::ParMixedSesquilinearForm>>();
117 for (const auto j : index_range(_coupled_var_names))
118 {
119 const auto & coupled_var_name = _coupled_var_names.at(j);
120 auto mslf = std::make_shared<mfem::ParMixedSesquilinearForm>(_coupled_pfespaces.at(j),
121 _test_pfespaces.at(i));
122 // Register MixedSesquilinearForm if kernels exist for it, and assemble
123 // kernels
124 if (_cmplx_kernels_map.Has(test_var_name) &&
125 _cmplx_kernels_map.Get(test_var_name)->Has(coupled_var_name) &&
126 test_var_name != coupled_var_name)
127 {
128 mslf->SetAssemblyLevel(_assembly_level);
129 // Apply all mixed kernels with this test/trial pair
130 ApplyDomainBLFIntegrators<mfem::ParMixedSesquilinearForm>(
131 coupled_var_name, test_var_name, mslf, _cmplx_kernels_map);
132 // Assemble mixed bilinear forms
133 mslf->Assemble();
134 // Register mixed bilinear forms associated with a single trial variable
135 // for the current test variable
136 test_mslfs->Register(coupled_var_name, mslf);
137 }
138 }
139 // Register all mixed bilinear form sets associated with a single test
140 // variable
141 _mslfs.Register(test_var_name, test_mslfs);
142 }
143}
144
145void
147 mfem::ParComplexGridFunction & trial_gf,
148 mfem::Array<int> & global_ess_markers)
149{
150 if (_cmplx_essential_bc_map.Has(var_name))
151 for (auto & bc : _cmplx_essential_bc_map.GetRef(var_name))
152 {
153 // Set constrained DoFs values on essential boundaries
154 bc->ApplyBC(trial_gf);
155 // Fetch marker array labelling essential boundaries of current BC
156 mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
157 // Add these boundary markers to the set of markers labelling all essential boundaries
158 for (const auto i : make_range(ess_bdrs.Size()))
159 global_ess_markers[i] |= ess_bdrs[i];
160 }
161}
162
163void
165{
166 _ess_tdof_lists.resize(_trial_var_names.size());
167 _ess_markers.resize(_trial_var_names.size());
168 for (const auto i : index_range(_trial_var_names))
169 {
170 const auto & trial_var_name = _trial_var_names.at(i);
171 mfem::ParComplexGridFunction & trial_gf = *_cmplx_var_ess_constraints.at(i);
172
173 // Make sure we update the size, if this mesh has changed recently for instance
174 trial_gf.Update();
175
176 // Initial guess for iterative solvers (initial condition or the previous time step solution)
177 cast_ref<mfem::Vector &>(trial_gf) = _complex_gfuncs->GetRef(trial_var_name);
178
179 _ess_markers.at(i).SetSize(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max(), 0);
180 // Set strongly constrained DoFs of trial_gf on essential boundaries and add markers for all
181 // essential boundaries to the _ess_markers array
182 ApplyComplexEssentialBC(trial_var_name, trial_gf, _ess_markers.at(i));
183 trial_gf.ParFESpace()->GetEssentialTrueDofs(_ess_markers.at(i), _ess_tdof_lists.at(i));
184 }
185}
186
187void
188ComplexEquationSystem::AddComplexKernel(std::shared_ptr<MFEMComplexKernel> kernel)
189{
190 const auto & trial_var_name = kernel->getTrialVariableName();
191 const auto & test_var_name = kernel->getTestVariableName();
192 AddCoupledVariableNameIfMissing(trial_var_name);
193 AddTestVariableNameIfMissing(test_var_name);
194 // Register new complex kernels map if not present for the test variable
195 if (!_cmplx_kernels_map.Has(test_var_name))
196 {
197 auto kernel_field_map =
198 std::make_shared<NamedFieldsMap<std::vector<std::shared_ptr<MFEMComplexKernel>>>>();
199 _cmplx_kernels_map.Register(test_var_name, std::move(kernel_field_map));
200 }
201 // Register new complex kernels map if not present for the test/trial variable pair
202 if (!_cmplx_kernels_map.Get(test_var_name)->Has(trial_var_name))
203 {
204 auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMComplexKernel>>>();
205 _cmplx_kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
206 }
207 _cmplx_kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
208}
209
210void
211ComplexEquationSystem::AddComplexIntegratedBC(std::shared_ptr<MFEMComplexIntegratedBC> bc)
212{
213 const auto & trial_var_name = bc->getTrialVariableName();
214 const auto & test_var_name = bc->getTestVariableName();
215 AddCoupledVariableNameIfMissing(trial_var_name);
216 AddTestVariableNameIfMissing(test_var_name);
217 // Register new complex integrated bc map if not present for the test variable
218 if (!_cmplx_integrated_bc_map.Has(test_var_name))
219 {
220 auto integrated_bc_field_map =
221 std::make_shared<NamedFieldsMap<std::vector<std::shared_ptr<MFEMComplexIntegratedBC>>>>();
222 _cmplx_integrated_bc_map.Register(test_var_name, std::move(integrated_bc_field_map));
223 }
224 // Register new complex integrated bc map if not present for the test/trial variable pair
225 if (!_cmplx_integrated_bc_map.Get(test_var_name)->Has(trial_var_name))
226 {
227 auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMComplexIntegratedBC>>>();
228 _cmplx_integrated_bc_map.Get(test_var_name)->Register(trial_var_name, std::move(bcs));
229 }
230 _cmplx_integrated_bc_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(bc));
231}
232
233void
234ComplexEquationSystem::AddComplexEssentialBCs(std::shared_ptr<MFEMComplexEssentialBC> bc)
235{
236 const auto & test_var_name = bc->getTestVariableName();
237 AddTestVariableNameIfMissing(test_var_name);
238 // Register new complex essential bc map if not present for the test variable
239 if (!_cmplx_essential_bc_map.Has(test_var_name))
240 {
241 auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMComplexEssentialBC>>>();
242 _cmplx_essential_bc_map.Register(test_var_name, std::move(bcs));
243 }
244 _cmplx_essential_bc_map.GetRef(test_var_name).push_back(std::move(bc));
245}
246
247void
249{
250 for (const auto & test_var_name : _test_var_names)
251 for (const auto & eliminated_var_name : _eliminated_var_names)
252 if (_mslfs.Has(test_var_name) && _mslfs.Get(test_var_name)->Has(eliminated_var_name) &&
253 !VectorContainsName(_test_var_names, eliminated_var_name))
254 {
255 auto & mslf = *_mslfs.Get(test_var_name)->Get(eliminated_var_name);
256 auto & clf = *_clfs.Get(test_var_name);
257 const mfem::real_t scale = -1.0;
258 const mfem::real_t conv =
259 (mslf.GetConvention() == mfem::ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
260
261 // y += scale * (A_r + i * A_i) * (x_r + i * x_i)
262 // and take the complex conjugate of the result if convention is BLOCK_SYMMETRIC
263 mslf.real().AddMult(
264 _cmplx_eliminated_variables.Get(eliminated_var_name)->real(), clf.real(), scale);
265 mslf.real().AddMult(
266 _cmplx_eliminated_variables.Get(eliminated_var_name)->imag(), clf.imag(), conv * scale);
267 mslf.imag().AddMult(
268 _cmplx_eliminated_variables.Get(eliminated_var_name)->imag(), clf.real(), -scale);
269 mslf.imag().AddMult(
270 _cmplx_eliminated_variables.Get(eliminated_var_name)->real(), clf.imag(), conv * scale);
271 clf.SyncAlias();
272 }
273}
274
275void
277 mfem::BlockVector & trueX,
278 mfem::BlockVector & trueRHS)
279{
280 auto & test_var_name = _test_var_names.at(0);
281 mfem::Vector aux_x, aux_rhs;
282 mfem::OperatorPtr aux_a;
283
284 auto slf = _slfs.Get(test_var_name);
285 slf->FormLinearSystem(_ess_tdof_lists.at(0),
287 *_clfs.Get(test_var_name),
288 aux_a,
289 aux_x,
290 aux_rhs,
291 /*copy_interior=*/true);
292
293 trueX.GetBlock(0) = aux_x;
294 trueRHS.GetBlock(0) = aux_rhs;
295 trueX.SyncFromBlocks();
296 trueRHS.SyncFromBlocks();
297
298 op.Reset(aux_a.Ptr());
299 aux_a.SetOperatorOwner(false);
300}
301
302void
304 mfem::BlockVector & trueX,
305 mfem::BlockVector & trueRHS)
306{
307
308 // Allocate block operator
310 _h_blocks.SetSize(_test_var_names.size(), _trial_var_names.size());
311 _h_blocks = nullptr;
312 // Zero out RHS and sync memory
313 trueRHS = 0.0;
314 trueRHS.SyncToBlocks();
315
316 for (const auto i : index_range(_test_var_names))
317 {
318 auto test_var_name = _test_var_names.at(i);
319 for (const auto j : index_range(_trial_var_names))
320 {
321 auto trial_var_name = _trial_var_names.at(j);
322
323 mfem::Vector aux_x, aux_rhs;
324 mfem::ParComplexLinearForm aux_lf(_test_pfespaces.at(i));
325 std::unique_ptr<mfem::OperatorHandle> aux_a = std::make_unique<mfem::OperatorHandle>();
326 aux_lf = 0.0;
327 if (test_var_name == trial_var_name)
328 {
329 mooseAssert(i == j, "Trial and test variables must have the same ordering.");
330 auto slf = _slfs.Get(test_var_name);
331 auto clf = _clfs.Get(test_var_name);
332 slf->FormLinearSystem(_ess_tdof_lists.at(j),
334 *clf,
335 *aux_a,
336 aux_x,
337 aux_rhs,
338 /*copy_interior=*/true);
339 trueX.GetBlock(i) = aux_x;
340 }
341 else if (_mslfs.Has(test_var_name) && _mslfs.Get(test_var_name)->Has(trial_var_name))
342 {
343 auto mslf = _mslfs.Get(test_var_name)->Get(trial_var_name);
344 mslf->FormRectangularLinearSystem(_ess_tdof_lists.at(j),
345 _ess_tdof_lists.at(i),
347 aux_lf,
348 *aux_a,
349 aux_x,
350 aux_rhs);
351 }
352 else
353 continue;
354
355 trueRHS.GetBlock(i) += aux_rhs;
356 _h_blocks(i, j) = aux_a->As<mfem::ComplexHypreParMatrix>()->GetSystemMatrix();
357 }
358 }
359
360 // Sync memory
361 trueX.SyncFromBlocks();
362 trueRHS.SyncFromBlocks();
363
364 // Create monolithic matrix
365 op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
366}
367
368// Equation system Mult
369void
370ComplexEquationSystem::Mult(const mfem::Vector & x, mfem::Vector & residual) const
371{
372 _linear_operator->Mult(x, residual);
373 x.HostRead();
374 residual.HostRead();
375}
376
377void
379{
380 for (const auto i : index_range(_trial_var_names))
381 {
382 auto & trial_var_name = _trial_var_names.at(i);
383 trueX.GetBlock(i).SyncMemory(trueX);
384 _complex_gfuncs->Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
385 }
386 // Solution variables changed: stored projections of solution-dependent coefficients are stale.
389}
390}
391
392#endif
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
Real scale
Definition MortarUtils.C:62
void markSolutionChanged()
Notify quadrature function coefficients that solution variables have changed, marking the stored valu...
void EliminateCoupledVariables() override
Perform trivial eliminations of coupled variables lacking corresponding test variables.
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 BuildMixedBilinearForms() override
Build mixed bilinear forms (off-diagonal Jacobian contributions)
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)
Applies complex BCs to a single trial variable.
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
NamedFieldsMap< NamedFieldsMap< mfem::ParMixedSesquilinearForm > > _mslfs
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 ComplexEquationSystem.
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.
bool VectorContainsName(const std::vector< std::string > &the_vector, const std::string &name) const
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).