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];
238 const auto & bdr_attributes = trial_gf.ParFESpace()->GetParMesh()->bdr_attributes;
239 _ess_markers.at(i).SetSize(bdr_attributes.Size() ? bdr_attributes.Max() : 0, 0);
252 if (
_mblfs.Has(test_var_name) &&
_mblfs.Get(test_var_name)->Has(eliminated_var_name) &&
255 auto & mblf = *
_mblfs.Get(test_var_name)->Get(eliminated_var_name);
262 mfem::BlockVector & trueX,
263 mfem::BlockVector & trueRHS)
266 "Number of test and trial variables must be the same for block matrix assembly.");
276 mfem::BlockVector & trueX,
277 mfem::BlockVector & trueRHS)
280 "Non-legacy assembly is only supported for single test and trial variable systems");
283 mfem::Vector aux_x, aux_rhs;
284 mfem::OperatorPtr aux_a;
286 auto blf =
_blfs.
Get(test_var_name);
295 trueX.GetBlock(0) = aux_x;
296 trueRHS.GetBlock(0) = aux_rhs;
297 trueX.SyncFromBlocks();
298 trueRHS.SyncFromBlocks();
300 op.Reset(aux_a.Ptr());
301 aux_a.SetOperatorOwner(
false);
306 mfem::BlockVector & trueX,
307 mfem::BlockVector & trueRHS)
315 trueRHS.SyncToBlocks();
325 mfem::Vector aux_x, aux_rhs;
327 mfem::HypreParMatrix * aux_a =
new mfem::HypreParMatrix;
329 if (test_var_name == trial_var_name)
331 mooseAssert(i == j,
"Trial and test variables must have the same ordering.");
332 auto blf =
_blfs.
Get(test_var_name);
340 trueX.GetBlock(j) = aux_x;
342 else if (
_mblfs.Has(test_var_name) &&
_mblfs.Get(test_var_name)->Has(trial_var_name))
344 auto mblf =
_mblfs.Get(test_var_name)->Get(trial_var_name);
356 trueRHS.GetBlock(i) += aux_rhs;
361 trueX.SyncFromBlocks();
362 trueRHS.SyncFromBlocks();
365 op.Reset(mfem::HypreParMatrixFromBlocks(
_h_blocks));
372 height = trueX.Size();
373 width = trueRHS.Size();
395 mooseAssert(
IsNonlinear(),
"Should not be calling this method if our forms are not nonlinear");
397 const mfem::BlockVector block_solution(
const_cast<mfem::Vector &
>(sol),
_block_true_offsets);
405 nlf->AddMult(block_solution.GetBlock(i), block_residual.GetBlock(i));
406 block_residual.GetBlock(i).SyncAliasMemory(block_residual);
423 auto nlf =
_nlfs.
Get(test_var_name);
424 mfem::HypreParMatrix * nlf_jac =
425 dynamic_cast<mfem::HypreParMatrix *
>(&nlf->GetGradient(update_vector.GetBlock(i)));
427 "Jacobian contribution of nonlinear form associated with " + test_var_name +
428 " is not castable into a HypreParMatrix");
449 mooseError(
"MFEM nonlinear solvers that require GetGradient() currently require legacy "
450 "assembly in EquationSystem.");
465 trueX.GetBlock(i).SyncMemory(trueX);
466 _gfuncs->
Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
528 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
530 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
550 auto test_mblfs = std::make_shared<Moose::MFEM::NamedFieldsMap<mfem::ParMixedBilinearForm>>();
558 _kernels_map.Get(test_var_name)->Has(coupled_var_name) &&
559 test_var_name != coupled_var_name)
563 ApplyDomainBLFIntegrators<mfem::ParMixedBilinearForm>(
570 test_mblfs->Register(coupled_var_name, mblf);
574 _mblfs.Register(test_var_name, test_mblfs);
589 const std::string & test_var_name,
590 std::shared_ptr<mfem::ParLinearForm> form,
593 if (kernels_map.Has(test_var_name) && kernels_map.Get(test_var_name)->Has(test_var_name))
595 auto kernels = kernels_map.GetRef(test_var_name).GetRef(test_var_name);
596 for (
auto & kernel : kernels)
598 mfem::LinearFormIntegrator * integ = kernel->createLFIntegrator();
602 kernel->isSubdomainRestricted()
603 ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
604 : form->AddDomainIntegrator(std::move(integ));
612 const std::string & test_var_name,
613 std::shared_ptr<mfem::ParNonlinearForm> form,
615 std::optional<mfem::real_t> scale_factor)
617 if (kernels_map.Has(test_var_name))
618 for (
const auto & [trial_var_name, kernels] : kernels_map.GetRef(test_var_name))
619 for (
auto & kernel : *kernels)
620 if (
auto * integ = kernel->createNLIntegrator())
623 mooseError(
"Support for off-diagonal MFEM nonlinear domain integrators in conjunction "
624 "with a nonlinear solver that requires a gradient is not currently "
625 "implemented. Kernel '",
627 "' contributes to test variable '",
629 "' from trial variable '",
634 if (scale_factor.has_value())
636 kernel->isSubdomainRestricted()
637 ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
638 : form->AddDomainIntegrator(std::move(integ));
644 const std::string & test_var_name,
645 std::shared_ptr<mfem::ParLinearForm> form,
649 if (integrated_bc_map.Has(test_var_name) &&
650 integrated_bc_map.Get(test_var_name)->Has(test_var_name))
652 auto bcs = integrated_bc_map.GetRef(test_var_name).GetRef(test_var_name);
653 for (
auto & bc : bcs)
655 mfem::LinearFormIntegrator * integ = bc->createLFIntegrator();
659 bc->isDGBC() ? bc->isBoundaryRestricted()
660 ? form->AddBdrFaceIntegrator(std::move(integ), bc->getBoundaryMarkers())
661 : form->AddBdrFaceIntegrator(std::move(integ))
662 : bc->isBoundaryRestricted()
663 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
664 : form->AddBoundaryIntegrator(std::move(integ));
672 const std::string & test_var_name,
673 std::shared_ptr<mfem::ParNonlinearForm> form,
676 std::optional<mfem::real_t> scale_factor)
678 if (integrated_bc_map.Has(test_var_name))
679 for (
const auto & [trial_var_name, bcs] : integrated_bc_map.GetRef(test_var_name))
680 for (
auto & bc : *bcs)
681 if (
auto * integ = bc->createNLIntegrator())
685 "Support for Off-diagonal MFEM nonlinear boundary integrators in conjunction with "
686 "a nonlinear solver that requires a gradient is not currently "
687 "implemented. Boundary condition '",
689 "' contributes to test variable '",
691 "' from trial variable '",
696 if (scale_factor.has_value())
698 bc->isBoundaryRestricted()
699 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
700 : form->AddBoundaryIntegrator(std::move(integ));
708 mooseError(
"EquationSystem::GetLinearizationPoint() called before GetGradient().");
712std::shared_ptr<mfem::ParBilinearForm>
714 mfem::ParFiniteElementSpace & fespace,
715 mfem::AssemblyLevel assembly_level)
717 auto blf = std::make_shared<mfem::ParBilinearForm>(&fespace);
718 blf->SetAssemblyLevel(assembly_level);
719 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_integrated_bc_map);
720 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_kernels_map);
726std::shared_ptr<mfem::ParNonlinearForm>
728 mfem::ParFiniteElementSpace & fespace,
729 mfem::AssemblyLevel )
731 auto nlf = std::make_shared<mfem::ParNonlinearForm>(&fespace);
744 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).