10 #ifdef MOOSE_MFEM_ENABLED 15 #include "libmesh/int_range.h" 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->isBoundaryRestricted()
666 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
667 : form->AddBoundaryIntegrator(std::move(integ));
675 const std::string & test_var_name,
676 std::shared_ptr<mfem::ParNonlinearForm> form,
679 std::optional<mfem::real_t> scale_factor)
681 if (integrated_bc_map.Has(test_var_name))
682 for (
const auto & [trial_var_name, bcs] : integrated_bc_map.GetRef(test_var_name))
683 for (
auto & bc : *bcs)
684 if (
auto * integ = bc->createNLIntegrator())
688 "Support for Off-diagonal MFEM nonlinear boundary integrators in conjunction with " 689 "a nonlinear solver that requires a gradient is not currently " 690 "implemented. Boundary condition '",
692 "' contributes to test variable '",
694 "' from trial variable '",
699 if (scale_factor.has_value())
701 bc->isBoundaryRestricted()
702 ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
703 : form->AddBoundaryIntegrator(std::move(integ));
711 mooseError(
"EquationSystem::GetLinearizationPoint() called before GetGradient().");
715 std::shared_ptr<mfem::ParBilinearForm>
717 mfem::ParFiniteElementSpace & fespace,
718 mfem::AssemblyLevel assembly_level)
720 auto blf = std::make_shared<mfem::ParBilinearForm>(&fespace);
721 blf->SetAssemblyLevel(assembly_level);
722 ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_integrated_bc_map);
723 ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(var_name, var_name, blf,
_kernels_map);
728 std::shared_ptr<mfem::ParNonlinearForm>
730 mfem::ParFiniteElementSpace & fespace,
731 mfem::AssemblyLevel )
733 auto nlf = std::make_shared<mfem::ParNonlinearForm>(&fespace);
746 mooseError(
"No essential boundary markers found for variable '", var_name,
"'.");
std::string name(const ElemQuality q)
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...
NamedFieldsMap< mfem::ParBilinearForm > _blfs
virtual void EliminateCoupledVariables()
Perform trivial eliminations of coupled variables lacking corresponding test variables.
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
NamedFieldsMap< NamedFieldsMap< mfem::ParMixedBilinearForm > > _mblfs
virtual void AddTestVariableNameIfMissing(const std::string &test_var_name)
Add test variable to EquationSystem.
virtual void AddKernel(std::shared_ptr< MFEMKernel > kernel)
Add kernels.
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...
virtual void BuildBilinearForms()
Build bilinear forms (diagonal Jacobian contributions)
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.
const mfem::Vector & GetLinearizationPoint() const
The true-DoF vector used for the most recent Jacobian linearization.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
virtual void SetTrialVariablesFromTrueVectors(const mfem::BlockVector &trueX) const
Update variable from solution vector after solve.
void DeleteJacobianBlocks()
Deletes the HypreParMatrix associated with any pointer stored in _jacobian_blocks, and then proceeds to delete all dynamically allocated memory for _jacobian_blocks itself, resetting all dimensions to zero.
bool VectorContainsName(const std::vector< std::string > &the_vector, const std::string &name) const
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMIntegratedBC > > > > _integrated_bc_map
Arrays to store integrated BCs to act on each component of weak form.
std::vector< std::string > _eliminated_var_names
Names of all coupled variables without a corresponding test variable.
void FormJacobianMatrix(const mfem::Vector &u)
Compute Jacobian matrix at the provided vector of true DoFs of trial variables.
~EquationSystem() override
NamedFieldsMap< mfem::ParNonlinearForm > _nlfs
Owns the weak-form mathematics of a MOOSE MFEM problem.
Moose::MFEM::GridFunctions _eliminated_variables
Pointers to coupled variables not part of the reduced EquationSystem.
virtual void AddEssentialBC(std::shared_ptr< MFEMEssentialBC > bc)
Add BC associated with essentially constrained DoFs on boundaries.
NonlinearFormIntegrator which scales its results by a constant value.
std::vector< mfem::Array< int > > _ess_tdof_lists
CoefficientManager * _coefficient_manager
Lightweight adaptor over an std::map from strings to pointer to T.
mfem::AssemblyLevel _assembly_level
mfem::Array< int > & GetEssentialBoundaryMarkers(const std::string &var_name)
Return the essential boundary attribute marker array for a given trial variable.
std::vector< mfem::ParFiniteElementSpace * > _test_pfespaces
Pointers to finite element spaces associated with test variables.
void FormSystem(mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Build all weak-form components via BuildEquationSystem(), form the constrained linear part of the sys...
void Mult(const mfem::Vector &u, mfem::Vector &residual) const override
Compute residual y = Mu.
mfem::Array< int > _block_true_offsets
std::vector< std::string > _trial_var_names
Subset of _coupled_var_names of all variables corresponding to gridfunctions with degrees of freedom ...
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...
NamedFieldsMap< std::vector< std::shared_ptr< MFEMEssentialBC > > > _essential_bc_map
Arrays to store essential BCs to act on each component of weak form.
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...
mfem::OperatorHandle _jacobian
NamedFieldsMap< NamedFieldsMap< std::vector< std::shared_ptr< MFEMKernel > > > > _kernels_map
Arrays to store kernels to act on each component of weak form.
std::vector< std::string > _test_var_names
Names of all test variables corresponding to linear forms in this equation system.
virtual void BuildEquationSystem()
Build all forms comprising this EquationSystem.
std::vector< std::unique_ptr< mfem::ParGridFunction > > _var_ess_constraints
Gridfunctions holding essential constraints from Dirichlet BCs.
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...
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...
virtual void BuildMixedBilinearForms()
Build mixed bilinear forms (off-diagonal Jacobian contributions)
std::vector< mfem::Array< int > > _ess_markers
virtual void FormSystemOperator(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Form matrix-free representation of linear components of system operator.
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 FormSystemMatrix(mfem::OperatorHandle &op, mfem::BlockVector &trueX, mfem::BlockVector &trueRHS)
Form matrix representation of linear components of system operator as a HypreParMatrix.
virtual void AddCoupledVariableNameIfMissing(const std::string &coupled_var_name)
Add coupled variable to EquationSystem.
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, populate solution and RHS vectors of true DoFs, and apply constraints.
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 BuildNonlinearForms()
Build non-linear action forms.
NamedFieldsMap< mfem::ParLinearForm > _lfs
virtual void BuildLinearForms()
Build linear forms and eliminate constrained DoFs.
IntRange< T > make_range(T beg, T end)
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...
virtual void ApplyEssentialBCs()
Update all essentially constrained true DoF markers and values on boundaries.
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 ...
Utilities for converting between vector(s) of libMesh Points and MFEM Vector(s).
mfem::OperatorHandle _linear_operator
virtual void AddEliminatedVariableNameIfMissing(const std::string &eliminated_var_name)
Add eliminated variable to EquationSystem.
virtual void Init(GridFunctions &gridfunctions, ComplexGridFunctions &cmplx_gridfunctions, mfem::AssemblyLevel assembly_level)
Initialise.
const mfem::Vector * _linearization_point
T & GetRef(const std::string &field_name) const
Returns a reference to a field.
mfem::Operator & GetGradient(const mfem::Vector &u) const override
Get Jacobian at the provided vector of true DoFs of trial variables.
virtual void ComputeNonlinearResidual(const mfem::Vector &u, mfem::Vector &residual) const
Compute the contribution to the residual from nonlinear forms only.
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 AddIntegratedBC(std::shared_ptr< MFEMIntegratedBC > kernel)
auto index_range(const T &sizable)
mfem::Array2D< const mfem::HypreParMatrix * > _jacobian_blocks
Moose::MFEM::GridFunctions * _gfuncs