https://mooseframework.inl.gov
ComplexEquationSystem.C
Go to the documentation of this file.
1 #ifdef MOOSE_MFEM_ENABLED
2 
4 #include "CoefficientManager.h"
5 #include "libmesh/int_range.h"
6 
7 namespace Moose::MFEM
8 {
9 
10 void
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 
53 void
55 {
58 }
59 
60 void
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);
78  ApplyDomainLFIntegrators(test_var_name, clf, _cmplx_kernels_map);
80  clf->Assemble();
81  }
82 }
83 
84 void
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 
106 void
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 
124 void
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 
148 void
149 ComplexEquationSystem::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 
171 void
172 ComplexEquationSystem::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 
194 void
195 ComplexEquationSystem::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 
208 void
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 
235 void
236 ComplexEquationSystem::FormSystemMatrix(mfem::OperatorHandle & op,
237  mfem::BlockVector & trueX,
238  mfem::BlockVector & trueRHS)
239 {
240 
241  // Allocate block operator
242  DeleteHBlocks();
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
278 void
279 ComplexEquationSystem::Mult(const mfem::Vector & x, mfem::Vector & residual) const
280 {
281  _linear_operator->Mult(x, residual);
282  x.HostRead();
283  residual.HostRead();
284 }
285 
286 void
287 ComplexEquationSystem::SetTrialVariablesFromTrueVectors(const mfem::BlockVector & trueX) const
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
virtual void Mult(const mfem::Vector &x, mfem::Vector &y) const override
Nonlinear Mult (Used by Newton-solver not necessarily nonlinear)
virtual void SetTrialVariablesFromTrueVectors(const mfem::BlockVector &trueX) const override
Update variable from solution vector after solve.
std::vector< std::unique_ptr< mfem::ParComplexGridFunction > > _cmplx_var_ess_constraints
Complex Gridfunctions holding essential constraints from Dirichlet BCs.
virtual void AddTestVariableNameIfMissing(const std::string &test_var_name)
Add test variable to EquationSystem.
bool Has(const std::string &field_name) const
Predicate to check if a field is registered with name field_name.
std::vector< mfem::ParFiniteElementSpace * > _coupled_pfespaces
Pointers to finite element spaces associated with coupled variables.
virtual void BuildLinearForms() override
Build linear forms and eliminate constrained DoFs.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
NamedFieldsMap< mfem::ParComplexLinearForm > _clfs
virtual void FormSystemOperator(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS) override
Form matrix-free representation of system operator.
std::vector< std::string > _eliminated_var_names
Names of all coupled variables without a corresponding test variable.
ComplexGridFunctions _cmplx_eliminated_variables
Pointers to coupled variables not part of the reduced EquationSystem.
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...
std::vector< mfem::Array< int > > _ess_tdof_lists
CoefficientManager * _coefficient_manager
mfem::AssemblyLevel _assembly_level
std::vector< mfem::ParFiniteElementSpace * > _test_pfespaces
Pointers to finite element spaces associated with test variables.
void AddComplexEssentialBCs(std::shared_ptr< MFEMComplexEssentialBC > bc)
Add complex essential BCs.
virtual void ApplyEssentialBCs() override
Update all essentially constrained true DoF markers and values on boundaries.
std::vector< std::string > _trial_var_names
Subset of _coupled_var_names of all variables corresponding to gridfunctions with degrees of freedom ...
NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexEssentialBC > > > _cmplx_essential_bc_map
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...
virtual void BuildEquationSystem() override
Build all forms comprising this EquationSystem.
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...
virtual void FormSystemMatrix(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS) override
Form matrix representation of system operator as a HypreParMatrix.
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexKernel > > > > _cmplx_kernels_map
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.
virtual void BuildBilinearForms() override
Build bilinear forms (diagonal Jacobian contributions)
std::vector< std::string > _test_var_names
Names of all test variables corresponding to linear forms in this equation system.
void AddComplexIntegratedBC(std::shared_ptr< MFEMComplexIntegratedBC > bc)
Add complex integrated BCs.
std::vector< mfem::Array< int > > _ess_markers
mfem::Array2D< const mfem::HypreParMatrix * > _h_blocks
virtual void SetTrialVariableNames()
Set trial variable names from subset of coupled variables that have an associated test variable...
virtual void AddCoupledVariableNameIfMissing(const std::string &coupled_var_name)
Add coupled variable to EquationSystem.
void DeleteHBlocks()
Deletes the HypreParMatrix associated with any pointer stored in _h_blocks, and then proceeds to dele...
std::vector< std::string > _coupled_var_names
Names of all trial variables of kernels and boundary conditions added to this EquationSystem.
void Register(const std::string &field_name, FieldArgs &&... args)
Construct new field with name field_name and register.
void markSolutionChanged()
Notify quadrature function coefficients that solution variables have changed, marking the stored valu...
virtual void Init(GridFunctions &gridfunctions, ComplexGridFunctions &cmplx_gridfunctions, mfem::AssemblyLevel assembly_level) override
Initialise.
NamedFieldsMap< mfem::ParSesquilinearForm > _slfs
Moose::MFEM::ComplexGridFunctions * _complex_gfuncs
IntRange< T > make_range(T beg, T end)
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.
int size()
Returns the number of elements in the map.
Utilities for converting between vector(s) of libMesh Points and MFEM Vector(s).
mfem::OperatorHandle _linear_operator
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMComplexIntegratedBC > > > > _cmplx_integrated_bc_map
T & GetRef(const std::string &field_name) const
Returns a reference to a field.
auto index_range(const T &sizable)
void AddComplexKernel(std::shared_ptr< MFEMComplexKernel > kernel)
Add complex kernels.