10#ifdef MOOSE_MFEM_ENABLED
24 iterative_mode =
false;
38 _owner.BuildMultigrid(op);
44 mooseAssert(
_mg,
"MGProxy: GeometricMultigrid not yet built");
53 "Geometric (p-)multigrid preconditioner backed by mfem::GeometricMultigrid. "
54 "Requires a linear equation system, an MFEMFESpaceHierarchy, and per-level smoother "
58 "Name of the trial variable this preconditioner acts on.");
61 "Names of LinearSolverBase objects used as smoothers on levels 1 to N-1, one per level, "
62 "ordered coarse-to-fine. Each level needs its own solver object, distinct from the "
65 "coarse_solver",
"Name of the LinearSolverBase used on the coarsest level.");
66 params.
addParam<std::vector<std::string>>(
69 "Assembly level for each level in the hierarchy. Valid values: 'legacy', 'full', "
70 "'element', 'partial', 'none'. May have length 1 (used on all N levels) or N.");
83 mooseError(
"GeometricMultigridSolver '",
name(),
"': requires a real, non-eigen eq. system");
88 _hierarchy = problem.getProblemData().fespace_hierarchies.GetShared(*hierarchy_name);
90 paramError(
"variable",
"must be associated with an MFEMFESpaceHierarchy.");
94 mooseAssert(N,
"Malformed MFEMFESpaceHierarchy w/ no levels");
95 const auto & asm_strs = getParam<std::vector<std::string>>(
"assembly_levels");
96 const int n_asm = asm_strs.size();
97 if (n_asm != 1 && n_asm != N)
99 "assembly_levels",
"must have length 1 or N = ", N,
" (total levels), got ", n_asm,
".");
102 for (
const auto i : make_range(N))
107 if (n_smooth != N - 1)
109 "must have one entry per level above the coarsest (N-1 = ",
113 ", because each level needs its own solver object.");
116 if (!level_solver_names.insert(smoother_name).second)
120 "' for more than one level, but each level needs its own solver object.");
133 auto proxy = std::make_unique<MGProxy>(*
this);
141 static MooseEnum assembly_levels(
"legacy full element partial none",
"legacy");
142 return (assembly_levels = s).getEnum<mfem::AssemblyLevel>();
157 mooseError(
"GeometricMultigridSolver '",
name(),
"': requires a univariate, linear eq. system");
160 const int finest_level =
_hierarchy->GetFinestLevelIndex();
171 auto & finest_fespace =
172 cast_ref<mfem::ParFiniteElementSpace &>(
_hierarchy->GetFESpaceAtLevel(finest_level));
173 const int finest_size = finest_fespace.GetTrueVSize();
174 if (op.Height() != finest_size || op.Width() != finest_size)
177 "': incoming fine operator has size ",
181 ", but the finest hierarchy space has true size ",
186 std::vector<std::shared_ptr<mfem::ParBilinearForm>> new_blfs;
187 std::vector<std::unique_ptr<mfem::OperatorHandle>> new_level_ops;
188 new_level_ops.reserve(N - 1);
189 std::vector<std::unique_ptr<mfem::Array<int>>> new_level_tdofs;
191 auto mg = std::make_unique<mfem::GeometricMultigrid>(*
_hierarchy, ess_bdr);
192 auto * mg_ptr = mg.get();
194 for (
const auto level : make_range(N))
196 auto & level_fespace =
197 cast_ref<mfem::ParFiniteElementSpace &>(
_hierarchy->GetFESpaceAtLevel(level));
200 mfem::Operator * level_op =
nullptr;
202 if (level == finest_level)
203 level_op =
const_cast<mfem::Operator *
>(&op);
212 auto level_tdofs = std::make_unique<mfem::Array<int>>();
213 level_fespace.GetEssentialTrueDofs(ess_bdr, *level_tdofs);
215 auto level_op_handle = std::make_unique<mfem::OperatorHandle>();
216 blf->FormSystemMatrix(*level_tdofs, *level_op_handle);
217 level_op = level_op_handle->Ptr();
218 new_level_ops.push_back(std::move(level_op_handle));
219 new_level_tdofs.push_back(std::move(level_tdofs));
220 new_blfs.push_back(std::move(blf));
225 auto & level_smoother = get_smoother(level);
226 level_smoother.SetOperator(*level_op);
229 level_op, &level_smoother.GetSolver(),
false,
false);
registerMooseObject("MooseApp", MFEMGeometricMultigridSolver)
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
void SetOperator(const mfem::Operator &op) override
Rebuilds the owner's multigrid hierarchy for the new outer-solver operator.
void SetMG(mfem::GeometricMultigrid &mg)
Updates the concrete MFEM multigrid object used by Mult().
void Mult(const mfem::Vector &x, mfem::Vector &y) const override
Applies the current concrete MFEM multigrid preconditioner.
MGProxy(MFEMGeometricMultigridSolver &owner)
Constructs a proxy that delegates multigrid rebuilding to the owning MOOSE solver.
P-multigrid / geometric multigrid preconditioner backed by mfem::GeometricMultigrid.
std::unique_ptr< mfem::GeometricMultigrid > _mg
Concrete MFEM multigrid preconditioner rebuilt on each SetOperator() call.
const std::string _var_name
Trial variable whose operator is preconditioned by this solver.
std::shared_ptr< mfem::ParFiniteElementSpaceHierarchy > _hierarchy
Finite element space hierarchy defining the multigrid levels.
MFEMGeometricMultigridSolver(const InputParameters ¶meters)
mfem::AssemblyLevel ParseAssemblyLevel(const std::string &s) const
Map assembly-level string ("legacy", "full", "element", "partial", "none") to the corresponding mfem:...
void ConstructSolver() override
Creates a stable proxy solver; the real multigrid is built when the proxy gets an operator.
std::vector< mfem::AssemblyLevel > _assembly_levels
Assembly level requested for each multigrid level after optional single-value expansion.
static InputParameters validParams()
void SetOperatorImpl(const mfem::Operator &op) override
Rebuilds the multigrid hierarchy for the supplied finest-level operator.
std::vector< std::shared_ptr< mfem::ParBilinearForm > > _level_blfs
Rediscretized bilinear forms kept alive for the active linear coarse-level operators.
MGProxy * _mg_proxy
Non-owning pointer to the proxy solver stored in _solver.
void BuildMultigrid(const mfem::Operator &op)
Rebuild the multigrid object and per-level operators for the supplied finest-level operator.
std::vector< std::unique_ptr< mfem::Array< int > > > _level_tdofs
Essential true DoFs of the coarse levels, which their constrained operators reference.
const std::vector< MFEMSolverName > _smoother_names
Names of solvers used as smoothers on interior multigrid levels.
const MFEMSolverName _coarse_solver_name
Name of the solver used on the coarsest multigrid level.
std::vector< std::unique_ptr< mfem::OperatorHandle > > _level_ops
Constrained linear coarse-level operators; destroyed before the forms that own their data.
MFEMProblem & getMFEMProblem()
Return the owning MFEM problem.
Constructs and stores an mfem::ParGridFunction object.
const InputParameters & parameters() const
Get the parameters of the object.
const std::string & name() const
Get the name of the class.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
const T * queryParam(const std::string &name) const
Query a parameter for the object.
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Base class for linear MFEM solvers and preconditioners.
std::shared_ptr< EquationSystem > _equation_system
Pointer to EquationSystem used for problem-specific solver setup.
static InputParameters validParams()
LinearSolverBase(const InputParameters ¶meters)
std::unique_ptr< mfem::Solver > _solver
Solver to be used for the problem.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...