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();
393 mooseAssert(
IsNonlinear(),
"Should not be calling this method if our forms are not nonlinear");
395 const mfem::BlockVector block_solution(
const_cast<mfem::Vector &
>(sol),
_block_true_offsets);
403 nlf->AddMult(block_solution.GetBlock(i), block_residual.GetBlock(i));
404 block_residual.GetBlock(i).SyncAliasMemory(block_residual);
421 auto nlf =
_nlfs.
Get(test_var_name);
422 mfem::HypreParMatrix * nlf_jac =
423 dynamic_cast<mfem::HypreParMatrix *
>(&nlf->GetGradient(update_vector.GetBlock(i)));
425 "Jacobian contribution of nonlinear form associated with " + test_var_name +
426 " is not castable into a HypreParMatrix");
447 mooseError(
"MFEM nonlinear solvers that require GetGradient() currently require legacy "
448 "assembly in EquationSystem.");
463 trueX.GetBlock(i).SyncMemory(trueX);
464 _gfuncs->
Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
526 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
528 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
548 auto test_mblfs = std::make_shared<Moose::MFEM::NamedFieldsMap<mfem::ParMixedBilinearForm>>();
556 _kernels_map.Get(test_var_name)->Has(coupled_var_name) &&
557 test_var_name != coupled_var_name)
561 ApplyDomainBLFIntegrators<mfem::ParMixedBilinearForm>(
568 test_mblfs->Register(coupled_var_name, mblf);
572 _mblfs.Register(test_var_name, test_mblfs);
587 const std::string & test_var_name,
588 std::shared_ptr<mfem::ParLinearForm> form,
591 if (kernels_map.Has(test_var_name) && kernels_map.Get(test_var_name)->Has(test_var_name))
593 auto kernels = kernels_map.GetRef(test_var_name).GetRef(test_var_name);
594 for (
auto & kernel : kernels)
596 mfem::LinearFormIntegrator * integ = kernel->createLFIntegrator();
600 kernel->isSubdomainRestricted()
601 ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
602 : form->AddDomainIntegrator(std::move(integ));
610 const std::string & test_var_name,
611 std::shared_ptr<mfem::ParNonlinearForm> form,
613 std::optional<mfem::real_t> scale_factor)
615 if (kernels_map.Has(test_var_name))
616 for (
const auto & [trial_var_name, kernels] : kernels_map.GetRef(test_var_name))
617 for (
auto & kernel : *kernels)
618 if (
auto * integ = kernel->createNLIntegrator())
621 mooseError(
"Support for off-diagonal MFEM nonlinear domain integrators in conjunction "
622 "with a nonlinear solver that requires a gradient is not currently "
623 "implemented. Kernel '",
625 "' contributes to test variable '",
627 "' from trial variable '",
632 if (scale_factor.has_value())
634 kernel->isSubdomainRestricted()
635 ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
636 : form->AddDomainIntegrator(std::move(integ));
642 const std::string & test_var_name,
643 std::shared_ptr<mfem::ParLinearForm> form,
647 if (integrated_bc_map.Has(test_var_name) &&
648 integrated_bc_map.Get(test_var_name)->Has(test_var_name))
650 auto bcs = integrated_bc_map.GetRef(test_var_name).GetRef(test_var_name);
651 for (
auto & bc : bcs)
653 mfem::LinearFormIntegrator * integ = bc->createLFIntegrator();
657 bc->isDGBC() ? bc->isBoundaryRestricted()
658 ? form->AddBdrFaceIntegrator(std::move(integ), bc->getBoundaryMarkers())
659 : form->AddBdrFaceIntegrator(std::move(integ))
660 : bc->isBoundaryRestricted()
661 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
662 : form->AddBoundaryIntegrator(std::move(integ));
670 const std::string & test_var_name,
671 std::shared_ptr<mfem::ParNonlinearForm> form,
674 std::optional<mfem::real_t> scale_factor)
676 if (integrated_bc_map.Has(test_var_name))
677 for (
const auto & [trial_var_name, bcs] : integrated_bc_map.GetRef(test_var_name))
678 for (
auto & bc : *bcs)
679 if (
auto * integ = bc->createNLIntegrator())
683 "Support for Off-diagonal MFEM nonlinear boundary integrators in conjunction with "
684 "a nonlinear solver that requires a gradient is not currently "
685 "implemented. Boundary condition '",
687 "' contributes to test variable '",
689 "' from trial variable '",
694 if (scale_factor.has_value())
696 bc->isBoundaryRestricted()
697 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
698 : form->AddBoundaryIntegrator(std::move(integ));
706 mooseError(
"EquationSystem::GetLinearizationPoint() called before GetGradient().");
710std::shared_ptr<mfem::ParBilinearForm>
712 mfem::ParFiniteElementSpace & fespace,
713 mfem::AssemblyLevel assembly_level)
715 auto blf = std::make_shared<mfem::ParBilinearForm>(&fespace);
716 blf->SetAssemblyLevel(assembly_level);
717 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_integrated_bc_map);
718 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_kernels_map);
724std::shared_ptr<mfem::ParNonlinearForm>
726 mfem::ParFiniteElementSpace & fespace,
727 mfem::AssemblyLevel )
729 auto nlf = std::make_shared<mfem::ParNonlinearForm>(&fespace);
742 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).