10#ifdef MOOSE_MFEM_ENABLED
15#include "libmesh/int_range.h"
29 for (
const auto i : make_range(
_h_blocks.NumRows()))
30 for (
const auto j : make_range(
_h_blocks.NumCols()))
51 const std::string & name)
const
53 return std::find(the_vector.begin(), the_vector.end(), name) != the_vector.end();
95 const auto & trial_var_name = kernel->getTrialVariableName();
96 const auto & test_var_name = kernel->getTestVariableName();
102 auto kernel_field_map =
103 std::make_shared<Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>>();
104 _kernels_map.Register(test_var_name, std::move(kernel_field_map));
107 if (!
_kernels_map.Get(test_var_name)->Has(trial_var_name))
109 auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMKernel>>>();
110 _kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
112 _kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
118 const auto & trial_var_name = bc->getTrialVariableName();
119 const auto & test_var_name = bc->getTestVariableName();
125 auto integrated_bc_field_map = std::make_shared<
132 auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMIntegratedBC>>>();
135 _integrated_bc_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(bc));
141 const auto & test_var_name = bc->getTestVariableName();
146 auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMEssentialBC>>>();
155 mfem::AssemblyLevel assembly_level)
164 if (!gridfunctions.
Has(test_var_name))
168 " requested by equation system during initialization was "
169 "not found in gridfunctions");
177 if (!gridfunctions.
Has(trial_var_name))
181 " requested by equation system during initialization was "
182 "not found in gridfunctions");
186 std::make_unique<mfem::ParGridFunction>(gridfunctions.
Get(trial_var_name)->ParFESpace()));
197 gridfunctions.
GetShared(eliminated_var_name));
205 mfem::ParGridFunction & trial_gf,
206 mfem::Array<int> & global_ess_markers)
212 bc->ApplyBC(trial_gf);
214 mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
216 for (
const auto i : make_range(ess_bdrs.Size()))
217 global_ess_markers[i] |= ess_bdrs[i];
237 _ess_markers.at(i).SetSize(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max(), 0);
250 if (
_mblfs.Has(test_var_name) &&
_mblfs.Get(test_var_name)->Has(eliminated_var_name) &&
253 auto & mblf = *
_mblfs.Get(test_var_name)->Get(eliminated_var_name);
260 mfem::BlockVector & trueX,
261 mfem::BlockVector & trueRHS)
264 "Number of test and trial variables must be the same for block matrix assembly.");
274 mfem::BlockVector & trueX,
275 mfem::BlockVector & trueRHS)
278 "Non-legacy assembly is only supported for single test and trial variable systems");
281 mfem::Vector aux_x, aux_rhs;
282 mfem::OperatorPtr aux_a;
284 auto blf =
_blfs.
Get(test_var_name);
293 trueX.GetBlock(0) = aux_x;
294 trueRHS.GetBlock(0) = aux_rhs;
295 trueX.SyncFromBlocks();
296 trueRHS.SyncFromBlocks();
298 op.Reset(aux_a.Ptr());
299 aux_a.SetOperatorOwner(
false);
304 mfem::BlockVector & trueX,
305 mfem::BlockVector & trueRHS)
313 trueRHS.SyncToBlocks();
323 mfem::Vector aux_x, aux_rhs;
325 mfem::HypreParMatrix * aux_a =
new mfem::HypreParMatrix;
327 if (test_var_name == trial_var_name)
329 mooseAssert(i == j,
"Trial and test variables must have the same ordering.");
330 auto blf =
_blfs.
Get(test_var_name);
338 trueX.GetBlock(j) = aux_x;
340 else if (
_mblfs.Has(test_var_name) &&
_mblfs.Get(test_var_name)->Has(trial_var_name))
342 auto mblf =
_mblfs.Get(test_var_name)->Get(trial_var_name);
354 trueRHS.GetBlock(i) += aux_rhs;
359 trueX.SyncFromBlocks();
360 trueRHS.SyncFromBlocks();
363 op.Reset(mfem::HypreParMatrixFromBlocks(
_h_blocks));
370 height = trueX.Size();
371 width = trueRHS.Size();
402 mooseAssert(
_non_linear,
"Should not be calling this method if our forms are not nonlinear");
405 const mfem::BlockVector block_solution(
const_cast<mfem::Vector &
>(sol),
_block_true_offsets);
413 nlf->Mult(block_solution.GetBlock(i), block_residual.GetBlock(i));
414 block_residual.GetBlock(i).SyncAliasMemory(block_residual);
431 auto nlf =
_nlfs.
Get(test_var_name);
432 mfem::HypreParMatrix * nlf_jac =
433 dynamic_cast<mfem::HypreParMatrix *
>(&nlf->GetGradient(update_vector.GetBlock(i)));
435 "Jacobian contribution of nonlinear form associated with " + test_var_name +
436 " is not castable into a HypreParMatrix");
457 mooseError(
"MFEM nonlinear solvers that require GetGradient() currently require legacy "
458 "assembly in EquationSystem.");
473 trueX.GetBlock(i).SyncMemory(trueX);
474 _gfuncs->
Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
536 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
538 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
557 auto test_mblfs = std::make_shared<Moose::MFEM::NamedFieldsMap<mfem::ParMixedBilinearForm>>();
565 _kernels_map.Get(test_var_name)->Has(coupled_var_name) &&
566 test_var_name != coupled_var_name)
570 ApplyDomainBLFIntegrators<mfem::ParMixedBilinearForm>(
576 test_mblfs->Register(coupled_var_name, mblf);
580 _mblfs.Register(test_var_name, test_mblfs);
595 const std::string & test_var_name,
596 std::shared_ptr<mfem::ParLinearForm> form,
599 if (kernels_map.Has(test_var_name) && kernels_map.Get(test_var_name)->Has(test_var_name))
601 auto kernels = kernels_map.GetRef(test_var_name).GetRef(test_var_name);
602 for (
auto & kernel : kernels)
604 mfem::LinearFormIntegrator * integ = kernel->createLFIntegrator();
608 kernel->isSubdomainRestricted()
609 ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
610 : form->AddDomainIntegrator(std::move(integ));
618 const std::string & test_var_name,
619 std::shared_ptr<mfem::ParNonlinearForm> form,
621 std::optional<mfem::real_t> scale_factor)
623 if (kernels_map.Has(test_var_name))
624 for (
const auto & [trial_var_name, kernels] : kernels_map.GetRef(test_var_name))
625 for (
auto & kernel : *kernels)
626 if (
auto * integ = kernel->createNLIntegrator())
629 mooseError(
"Support for off-diagonal MFEM nonlinear domain integrators in conjunction "
630 "with a nonlinear solver that requires a gradient is not currently "
631 "implemented. Kernel '",
633 "' contributes to test variable '",
635 "' from trial variable '",
640 if (scale_factor.has_value())
642 kernel->isSubdomainRestricted()
643 ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
644 : form->AddDomainIntegrator(std::move(integ));
650 const std::string & test_var_name,
651 std::shared_ptr<mfem::ParLinearForm> form,
655 if (integrated_bc_map.Has(test_var_name) &&
656 integrated_bc_map.Get(test_var_name)->Has(test_var_name))
658 auto bcs = integrated_bc_map.GetRef(test_var_name).GetRef(test_var_name);
659 for (
auto & bc : bcs)
661 mfem::LinearFormIntegrator * integ = bc->createLFIntegrator();
665 bc->isDGBC() ? bc->isBoundaryRestricted()
666 ? form->AddBdrFaceIntegrator(std::move(integ), bc->getBoundaryMarkers())
667 : form->AddBdrFaceIntegrator(std::move(integ))
668 : bc->isBoundaryRestricted()
669 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
670 : form->AddBoundaryIntegrator(std::move(integ));
678 const std::string & test_var_name,
679 std::shared_ptr<mfem::ParNonlinearForm> form,
682 std::optional<mfem::real_t> scale_factor)
684 if (integrated_bc_map.Has(test_var_name))
685 for (
const auto & [trial_var_name, bcs] : integrated_bc_map.GetRef(test_var_name))
686 for (
auto & bc : *bcs)
687 if (
auto * integ = bc->createNLIntegrator())
691 "Support for Off-diagonal MFEM nonlinear boundary integrators in conjunction with "
692 "a nonlinear solver that requires a gradient is not currently "
693 "implemented. Boundary condition '",
695 "' contributes to test variable '",
697 "' from trial variable '",
702 if (scale_factor.has_value())
704 bc->isBoundaryRestricted()
705 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
706 : form->AddBoundaryIntegrator(std::move(integ));
714 mooseError(
"EquationSystem::GetLinearizationPoint() called before GetGradient().");
718std::shared_ptr<mfem::ParBilinearForm>
720 mfem::ParFiniteElementSpace & fespace,
721 mfem::AssemblyLevel assembly_level)
723 auto blf = std::make_shared<mfem::ParBilinearForm>(&fespace);
724 blf->SetAssemblyLevel(assembly_level);
725 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_integrated_bc_map);
726 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_kernels_map);
731std::shared_ptr<mfem::ParNonlinearForm>
733 mfem::ParFiniteElementSpace & fespace,
734 mfem::AssemblyLevel )
736 auto nlf = std::make_shared<mfem::ParNonlinearForm>(&fespace);
749 mooseError(
"No essential boundary markers found for variable '", var_name,
"'.");
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
void markSolutionChanged()
Notify quadrature function coefficients that solution variables have changed, marking the stored valu...
Owns the weak-form mathematics of a MOOSE MFEM problem.
virtual void AddTestVariableNameIfMissing(const std::string &test_var_name)
Add test variable to EquationSystem.
std::shared_ptr< mfem::ParBilinearForm > BuildBilinearFormForFESpace(const std::string &var_name, mfem::ParFiniteElementSpace &fespace, mfem::AssemblyLevel assembly_level)
Build a fresh ParBilinearForm on the given FESpace using the same kernels as the main system's biline...
virtual void BuildBilinearForms()
Build bilinear forms (diagonal Jacobian contributions)
virtual void BuildNonlinearForms()
Build non-linear action forms.
std::vector< std::string > _coupled_var_names
Names of all trial variables of kernels and boundary conditions added to this EquationSystem.
virtual void ApplyEssentialBCs()
Update all essentially constrained true DoF markers and values on boundaries.
std::vector< mfem::ParFiniteElementSpace * > _test_pfespaces
Pointers to finite element spaces associated with test variables.
mfem::Array< int > _block_true_offsets
void FormSystem(mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Build all weak-form components via BuildEquationSystem(), form the constrained linear part of the sys...
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMKernel > > > > _kernels_map
Arrays to store kernels to act on each component of weak form.
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
void ApplyDomainNLFIntegrators(const std::string &test_var_name, std::shared_ptr< mfem::ParNonlinearForm > form, NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMKernel > > > > &kernels_map, std::optional< mfem::real_t > scale_factor=std::nullopt)
Apply domain NonlinearFormIntegrators from kernels to the nonlinear form associated with the supplied...
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...
virtual void EliminateCoupledVariables()
Perform trivial eliminations of coupled variables lacking corresponding test variables.
virtual void BuildEquationSystem()
Build all forms comprising this EquationSystem.
mfem::Operator & GetGradient(const mfem::Vector &u) const override
Get Jacobian at the provided vector of true DoFs of trial variables.
virtual void BuildMixedBilinearForms()
Build mixed bilinear forms (off-diagonal Jacobian contributions)
mfem::Array2D< const mfem::HypreParMatrix * > _h_blocks
void ApplyBoundaryLFIntegrators(const std::string &test_var_name, std::shared_ptr< mfem::ParLinearForm > form, NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMIntegratedBC > > > > &integrated_bc_map)
Apply boundary LinearFormIntegrators from integrated boundary conditions to the linear form associate...
std::vector< std::string > _test_var_names
Names of all test variables corresponding to linear forms in this equation system.
void FormJacobianMatrix(const mfem::Vector &u)
Compute Jacobian matrix at the provided vector of true DoFs of trial variables.
virtual void FormSystemOperator(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Form matrix-free representation of linear components of system operator.
~EquationSystem() override
mfem::Array< int > & GetEssentialBoundaryMarkers(const std::string &var_name)
Return the essential boundary attribute marker array for a given trial variable.
void ApplyBoundaryNLFIntegrators(const std::string &test_var_name, std::shared_ptr< mfem::ParNonlinearForm > form, NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMIntegratedBC > > > > &integrated_bc_map, std::optional< mfem::real_t > scale_factor=std::nullopt)
Apply boundary NonlinearFormIntegrators from integrated boundary conditions to the nonlinear form ass...
mfem::OperatorHandle _linear_operator
const mfem::Vector * _linearization_point
std::shared_ptr< mfem::ParNonlinearForm > BuildNonlinearFormForFESpace(const std::string &var_name, mfem::ParFiniteElementSpace &fespace, mfem::AssemblyLevel assembly_level)
Build a fresh ParNonlinearForm on the given FESpace using the same kernels as the main system's nonli...
NamedFieldsMap< mfem::ParLinearForm > _lfs
virtual void AddIntegratedBC(std::shared_ptr< MFEMIntegratedBC > kernel)
mfem::AssemblyLevel _assembly_level
virtual void AddKernel(std::shared_ptr< MFEMKernel > kernel)
Add kernels.
virtual void SetTrialVariableNames()
Set trial variable names from subset of coupled variables that have an associated test variable.
mfem::Array2D< const mfem::HypreParMatrix * > _jacobian_blocks
virtual void FormSystemMatrix(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Form matrix representation of linear components of system operator as a HypreParMatrix.
std::vector< mfem::Array< int > > _ess_tdof_lists
CoefficientManager * _coefficient_manager
virtual void SetTrialVariablesFromTrueVectors(const mfem::BlockVector &trueX) const
Update variable from solution vector after solve.
virtual void AddEssentialBC(std::shared_ptr< MFEMEssentialBC > bc)
Add BC associated with essentially constrained DoFs on boundaries.
NamedFieldsMap< mfem::ParBilinearForm > _blfs
void DeleteHBlocks()
Deletes the HypreParMatrix associated with any pointer stored in _h_blocks, and then proceeds to dele...
virtual void ComputeNonlinearResidual(const mfem::Vector &u, mfem::Vector &residual) const
Compute the contribution to the residual from nonlinear forms only.
mfem::OperatorHandle _jacobian
virtual void FormLinearSystem(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Form linear components of system based on on- and off-diagonal bilinear form contributions,...
NamedFieldsMap< std::vector< std::shared_ptr< MFEMEssentialBC > > > _essential_bc_map
Arrays to store essential BCs to act on each component of weak form.
virtual void Init(GridFunctions &gridfunctions, ComplexGridFunctions &cmplx_gridfunctions, mfem::AssemblyLevel assembly_level)
Initialise.
std::vector< std::string > _trial_var_names
Subset of _coupled_var_names of all variables corresponding to gridfunctions with degrees of freedom ...
NamedFieldsMap< NamedFieldsMap< mfem::ParMixedBilinearForm > > _mblfs
std::vector< std::unique_ptr< mfem::ParGridFunction > > _var_ess_constraints
Gridfunctions holding essential constraints from Dirichlet BCs.
void DeleteJacobianBlocks()
Deletes the HypreParMatrix associated with any pointer stored in _jacobian_blocks,...
void ApplyDomainLFIntegrators(const std::string &test_var_name, std::shared_ptr< mfem::ParLinearForm > form, NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMKernel > > > > &kernels_map)
Apply domain LinearFormIntegrators from kernels to the linear form associated with the supplied test ...
virtual void AddEliminatedVariableNameIfMissing(const std::string &eliminated_var_name)
Add eliminated variable to EquationSystem.
void Mult(const mfem::Vector &u, mfem::Vector &residual) const override
Compute residual y = Mu.
NamedFieldsMap< mfem::ParNonlinearForm > _nlfs
Moose::MFEM::GridFunctions _eliminated_variables
Pointers to coupled variables not part of the reduced EquationSystem.
const mfem::Vector & GetLinearizationPoint() const
The true-DoF vector used for the most recent Jacobian linearization.
std::vector< mfem::Array< int > > _ess_markers
std::vector< std::string > _eliminated_var_names
Names of all coupled variables without a corresponding test variable.
Moose::MFEM::GridFunctions * _gfuncs
virtual void BuildLinearForms()
Build linear forms and eliminate constrained DoFs.
virtual void AddCoupledVariableNameIfMissing(const std::string &coupled_var_name)
Add coupled variable to EquationSystem.
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMIntegratedBC > > > > _integrated_bc_map
Arrays to store integrated BCs to act on each component of weak form.
NonlinearFormIntegrator which scales its results by a constant value.
Lightweight adaptor over an std::map from strings to pointer to T.
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.
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).