https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MFEMProblem.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#ifdef MOOSE_MFEM_ENABLED
11
12#include "MFEMProblem.h"
13#include "MFEMVariable.h"
14#include "MFEMIndicator.h"
15#include "MFEMSubMesh.h"
16#include "MFEMFunctorMaterial.h"
17#include "MFEMExecutedObject.h"
18#include "MFEMVectorUtils.h"
20#include "Postprocessor.h"
21#include "VectorPostprocessor.h"
23#include "DependencyResolver.h"
24#include "MooseUtils.h"
25#include "DataIO.h"
28
29#include "libmesh/string_to_enum.h"
30
31#include <vector>
32#include <algorithm>
33#include <map>
34#include <deque>
35#include <sstream>
36
38
39namespace
40{
41std::vector<MFEMSolverName>
42getMFEMSolverDependencies(const InputParameters & parameters)
43{
44 std::vector<MFEMSolverName> dependencies;
45
46 for (const auto & [param_name, _] : parameters)
47 {
48 if (parameters.isPrivate(param_name))
49 continue;
50
51 if (auto * name = parameters.queryParam<MFEMSolverName>(param_name))
52 dependencies.push_back(*name);
53 else if (auto * names = parameters.queryParam<std::vector<MFEMSolverName>>(param_name))
54 dependencies.insert(dependencies.end(), names->begin(), names->end());
55 }
56
57 return dependencies;
58}
59}
60
63{
65 params.addClassDescription("Problem type for building and solving the finite element problem "
66 "using the MFEM finite element library.");
67 MooseEnum numeric_types("real complex", "real");
68 params.addParam<MooseEnum>("numeric_type", numeric_types, "Number type used for the problem");
69
70 return params;
71}
72
74 : ExternalProblem(params),
75 _num_type{static_cast<int>(getParam<MooseEnum>("numeric_type"))},
76 _solution_state_data(declareRestartableDataWithContext<Moose::MFEM::SolutionState>(
77 "mfem_solution_state", &_problem_data))
78{
79 // Initialise Hypre for all MFEM problems.
80 mfem::Hypre::Init();
81 setMesh();
82}
83
84void
86{
88
89 std::vector<MFEMExecutedObject *> objects;
91 .query()
92 .condition<AttribSystem>("MFEMExecutedObject")
93 .condition<AttribThread>(0)
94 .queryInto(objects);
95 for (auto * const object : objects)
96 object->initialSetup();
97}
98
99void
101{
102 setCurrentExecuteOnFlag(exec_type);
103 executeMFEMObjects(exec_type);
104
105 ExternalProblem::execute(exec_type);
106}
107
108void
110{
111 auto pmesh = mesh().getMFEMParMeshPtr();
112 getProblemData().pmesh = pmesh;
113 getProblemData().comm = pmesh->GetComm();
114 getProblemData().num_procs = pmesh->GetNRanks();
115 getProblemData().myid = pmesh->GetMyRank();
116}
117
118void
119MFEMProblem::addIndicator(const std::string & indicator_type,
120 const std::string & name,
121 InputParameters & parameters)
122{
123 auto estimator = addObject<MFEMIndicator>(indicator_type, name, parameters).front();
124
125 // construct the estimator itself
126 estimator->createEstimator();
127}
128
129void
130MFEMProblem::addMarker(const std::string & marker_type,
131 const std::string & name,
132 InputParameters & parameters)
133{
134 getProblemData().refiner = addObject<MFEMRefinementMarker>(marker_type, name, parameters).front();
135}
136
137void
138MFEMProblem::addMFEMSolver(const std::string & solver_type,
139 const std::string & name,
140 InputParameters & parameters)
141{
142 mooseAssert(!_mfem_solver_definitions.count(name), "Multiple MFEM solvers named '" + name + "'.");
144}
145
146void
148{
149 if (_mfem_solver_definitions.empty())
150 return;
151
153
154 for (auto & [solver_name, definition] : _mfem_solver_definitions)
155 {
156 const auto dependencies = getMFEMSolverDependencies(*definition.parameters);
157 if (dependencies.empty())
158 resolver.addNode(solver_name);
159
160 for (const auto & dependency_name : dependencies)
161 {
162 auto dependency_it = _mfem_solver_definitions.find(dependency_name);
163 if (dependency_it == _mfem_solver_definitions.end())
164 mooseError("MFEM solver '",
165 solver_name,
166 "' references MFEM solver '",
167 dependency_name,
168 "', but no solver with that name was provided in the [Solvers] block.");
169
170 dependency_it->second.referenced = true;
171 resolver.addEdge(dependency_name, solver_name);
172 }
173 }
174
175 const std::vector<std::string> * sorted_solver_names = nullptr;
176 try
177 {
178 sorted_solver_names = &resolver.getSortedValues();
179 }
181 {
182 mooseError("Cyclic MFEM solver dependency detected: ",
183 MooseUtils::join(e.getCyclicDependencies(), " <- "));
184 }
185
186 auto & problem_data = getProblemData();
187 mooseAssert(!problem_data.jacobian_solver, "MFEM linear solver driver already assigned");
188 mooseAssert(!problem_data.nonlinear_solver, "MFEM nonlinear solver driver already assigned");
189
190 for (const auto & solver_name : *sorted_solver_names)
191 {
192 auto & definition = libmesh_map_find(_mfem_solver_definitions, solver_name);
193 auto solver =
194 addObject<Moose::MFEM::SolverBase>(definition.type, solver_name, *definition.parameters)
195 .front();
196
197 if (definition.referenced)
198 continue;
199
200 if (auto lin_solver = std::dynamic_pointer_cast<Moose::MFEM::LinearSolverBase>(solver))
201 {
202 if (problem_data.jacobian_solver)
203 mooseError("Multiple MFEM linear solver drivers provided. '",
204 problem_data.jacobian_solver->name(),
205 "' and '",
206 lin_solver->name(),
207 "' are not referenced by another MFEM solver.");
208 problem_data.jacobian_solver = lin_solver;
209 }
210 else if (auto nonlinear_solver =
211 std::dynamic_pointer_cast<Moose::MFEM::NonlinearSolverBase>(solver);
212 nonlinear_solver)
213 {
214 if (problem_data.nonlinear_solver)
215 mooseError("Multiple MFEM nonlinear solver drivers provided. '",
216 problem_data.nonlinear_solver->name(),
217 "' and '",
218 nonlinear_solver->name(),
219 "' are not referenced by another MFEM solver.");
220 problem_data.nonlinear_solver = nonlinear_solver;
221 }
222 else
223 mooseError("Unsupported MFEM solver object type '",
224 solver->type(),
225 "' for solver '",
226 solver->name(),
227 "'.");
228 }
229
231}
232
233void
234MFEMProblem::addBoundaryCondition(const std::string & bc_name,
235 const std::string & name,
236 InputParameters & parameters)
237{
238 auto bc = addObject<MFEMBoundaryCondition>(bc_name, name, parameters).front();
240}
241
242void
243MFEMProblem::addMaterial(const std::string &, const std::string &, InputParameters &)
244{
246 "MFEM materials must be added through the 'FunctorMaterials' block and not 'Materials'");
247}
248
249void
250MFEMProblem::addFunctorMaterial(const std::string & material_name,
251 const std::string & name,
252 InputParameters & parameters)
253{
254 addObject<MFEMFunctorMaterial>(material_name, name, parameters);
255}
256
257void
258MFEMProblem::addFESpace(const std::string & type,
259 const std::string & name,
260 InputParameters & parameters)
261{
262 if (getProblemData().fespace_hierarchies.Has(name))
263 mooseError("Cannot add FESpace '",
264 name,
265 "': an MFEMFESpaceHierarchy with the same name already exists. "
266 "FESpaces and FESpaceHierarchies share the fespaces namespace.");
267
268 auto & mfem_fespace = *addObject<MFEMFESpace>(type, name, parameters).front();
269
270 // Register fespace and associated fe collection.
271 getProblemData().fecs.Register(name, mfem_fespace.getFEC());
272 getProblemData().fespaces.Register(name, mfem_fespace.getFESpace());
273}
274
275void
276MFEMProblem::addFESpaceHierarchy(const std::string & type,
277 const std::string & name,
278 InputParameters & parameters)
279{
280 if (getProblemData().fespaces.Has(name))
281 mooseError("Cannot add MFEMFESpaceHierarchy '",
282 name,
283 "': a FESpace with the same name already exists. "
284 "FESpaces and FESpaceHierarchies share the fespaces namespace.");
285
286 auto hierarchy_obj = addObject<MFEMFESpaceHierarchy>(type, name, parameters).front();
287 auto hierarchy_shared = hierarchy_obj->getHierarchyShared();
288 // Register the hierarchy for co-ownership by solvers.
289 getProblemData().fespace_hierarchies.Register(name, hierarchy_shared);
290 // Register the finest-level FESpace in fespaces under the hierarchy name so that
291 // variables can say `fespace = <hierarchy_name>` without a separate FESpace definition.
292 // The aliasing shared_ptr keeps the hierarchy alive as long as this entry lives.
293 auto finest = std::shared_ptr<mfem::ParFiniteElementSpace>(
294 hierarchy_shared, &hierarchy_obj->getHierarchy().GetFinestFESpace());
296}
297
298void
299MFEMProblem::validateVariableNumericType(const std::string & var_type,
300 const std::string & var_name) const
301{
302 const bool variable_is_complex = var_type == "MFEMComplexVariable";
303 const bool problem_is_complex = _num_type == NumericType::COMPLEX;
304 if (variable_is_complex != problem_is_complex)
305 paramError("numeric_type",
306 "The problem numeric type does not match primary MFEM variable '",
307 var_name,
308 "', which is ",
309 variable_is_complex ? "complex." : "real.");
310}
311
312void
313MFEMProblem::addVariable(const std::string & var_type,
314 const std::string & var_name,
315 InputParameters & parameters)
316{
317 validateVariableNumericType(var_type, var_name);
318 addGridFunction(var_type, var_name, parameters);
319 // MOOSE variables store DoFs for the trial variable and its time derivatives up to second order;
320 // MFEM GridFunctions store data for only one set of DoFs each, so we must add additional
321 // GridFunctions for time derivatives.
322 if (isTransient())
323 {
324 const auto time_derivative_var_name =
325 getMFEMObject<MFEMVariable>("MooseVariableBase", var_name).getTimeDerivativeName();
327 time_derivative_var_name);
328 addGridFunction(var_type, time_derivative_var_name, parameters);
329 }
330}
331
332void
333MFEMProblem::addGridFunction(const std::string & var_type,
334 const std::string & var_name,
335 InputParameters & parameters)
336{
337
338 if (var_type == "MFEMVariable" || var_type == "MFEMComplexVariable")
339 {
340 // Add MFEM variable directly.
341 if (var_type == "MFEMComplexVariable")
342 addObject<MFEMComplexVariable>(var_type, var_name, parameters);
343 else
344 addObject<MFEMVariable>(var_type, var_name, parameters);
345 }
346 else
347 {
348 // Add MOOSE variable.
349 ExternalProblem::addVariable(var_type, var_name, parameters);
350
351 // Add MFEM variable indirectly ("gridfunction").
353 addObject<MFEMVariable>("MFEMVariable", var_name, mfem_variable_params);
354 }
355
356 // Register gridfunction.
357 if (var_type == "MFEMComplexVariable")
358 {
359 MFEMComplexVariable & mfem_variable =
360 getMFEMObject<MFEMComplexVariable>("MooseVariableBase", var_name);
362 mfem_variable.declareCoefficients();
363 }
364 else // must be real, but may have been set up indirectly from a MOOSE variable
365 {
366 MFEMVariable & mfem_variable = getMFEMObject<MFEMVariable>("MooseVariableBase", var_name);
367 getProblemData().gridfunctions.Register(var_name, mfem_variable.getGridFunction());
368 mfem_variable.declareCoefficients();
369 }
370}
371
372void
373MFEMProblem::addAuxVariable(const std::string & var_type,
374 const std::string & var_name,
375 InputParameters & parameters)
376{
377 // We handle MFEM AuxVariables just like MFEM Variables, except
378 // we do not add additional GridFunctions for time derivatives.
379 addGridFunction(var_type, var_name, parameters);
380}
381
382void
383MFEMProblem::addAuxKernel(const std::string & kernel_name,
384 const std::string & name,
385 InputParameters & parameters)
386{
387 addObject<MFEMExecutedObject>(kernel_name, name, parameters);
388}
389
390void
391MFEMProblem::addKernel(const std::string & kernel_name,
392 const std::string & name,
393 InputParameters & parameters)
394{
395 auto kernel = addObject<MFEMKernel>(kernel_name, name, parameters).front();
397}
398
399void
400MFEMProblem::addRealComponentToKernel(const std::string & kernel_name,
401 const std::string & name,
402 InputParameters & parameters)
403{
404 auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexKernel>(
405 getMFEMObject<MFEMComplexKernel>("Kernel", name).getSharedPtr());
406 parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
407 auto kernel_ptr = addObject<MFEMKernel>(kernel_name, name + "_real", parameters).front();
408 parent_ptr->setRealKernel(kernel_ptr);
409}
410
411void
412MFEMProblem::addImagComponentToKernel(const std::string & kernel_name,
413 const std::string & name,
414 InputParameters & parameters)
415{
416 auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexKernel>(
417 getMFEMObject<MFEMComplexKernel>("Kernel", name).getSharedPtr());
418 parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
419 auto kernel_ptr = addObject<MFEMKernel>(kernel_name, name + "_imag", parameters).front();
420 parent_ptr->setImagKernel(kernel_ptr);
421}
422
423void
424MFEMProblem::addRealComponentToBC(const std::string & kernel_name,
425 const std::string & name,
426 InputParameters & parameters)
427{
428 auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexIntegratedBC>(
429 getMFEMObject<MFEMComplexIntegratedBC>("BoundaryCondition", name).getSharedPtr());
430 parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
431 parameters.set<std::vector<BoundaryName>>("boundary") =
432 parent_ptr->getParam<std::vector<BoundaryName>>("boundary");
433 auto bc_ptr = std::dynamic_pointer_cast<MFEMIntegratedBC>(
434 addObject<MFEMBoundaryCondition>(kernel_name, name + "_real", parameters).front());
435 parent_ptr->setRealBC(bc_ptr);
436}
437
438void
439MFEMProblem::addImagComponentToBC(const std::string & kernel_name,
440 const std::string & name,
441 InputParameters & parameters)
442{
443 auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexIntegratedBC>(
444 getMFEMObject<MFEMComplexIntegratedBC>("BoundaryCondition", name).getSharedPtr());
445 parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
446 parameters.set<std::vector<BoundaryName>>("boundary") =
447 parent_ptr->getParam<std::vector<BoundaryName>>("boundary");
448 auto bc_ptr = std::dynamic_pointer_cast<MFEMIntegratedBC>(
449 addObject<MFEMBoundaryCondition>(kernel_name, name + "_imag", parameters).front());
450 parent_ptr->setImagBC(bc_ptr);
451}
452
453void
454MFEMProblem::addWeakForm(const std::string & weak_form_name,
455 const std::string & name,
456 InputParameters & parameters)
457{
458 addObject<MFEMWeakFormBase>(weak_form_name, name, parameters);
459}
460
461std::shared_ptr<MFEMWeakFormBase>
463{
464 const std::string name("__DefaultWeakForm");
465 std::string type;
466 if (isTransient())
467 type = "MFEMTimeDependentWeakForm";
469 type = "MFEMWeakForm";
471 type = "MFEMComplexWeakForm";
472 else
473 mooseError("Unknown numeric type. "
474 "Please set the Problem numeric type to either 'real' or 'complex'.");
475
477 return addObject<MFEMWeakFormBase>(type, name, parameters).front();
478}
479
480void
482{
483 std::vector<MFEMWeakFormBase *> weak_forms;
484 theWarehouse().query().condition<AttribSystem>("MFEMWeakFormBase").queryInto(weak_forms);
485
486 // Add a default MFEMWeakForm if none has been added by the user.
487 if (weak_forms.empty())
488 weak_forms.push_back(addDefaultWeakForm().get());
489
490 for (auto & weak_form : weak_forms)
491 _problem_data.eqn_systems.Register(weak_form->name(), weak_form->createEquationSystem());
492}
493
494std::shared_ptr<Moose::MFEM::EquationSystem>
495MFEMProblem::getEquationSystem(const std::string & weak_form_name) const
496{
497 const auto & eqn_systems = getProblemData().eqn_systems;
498
499 if (!weak_form_name.empty())
500 return eqn_systems.GetShared(weak_form_name);
501
502 mooseAssert(eqn_systems.size() != 0, "No equation systems have been built for this problem");
503
504 if (eqn_systems.size() > 1)
505 mooseError("This problem has ",
506 eqn_systems.size(),
507 " equation systems, so the one to use cannot be inferred. Set the 'weak_form' "
508 "parameter to name the weak form whose equation system should be used.");
509
510 return eqn_systems.begin()->second;
511}
512
513void
514MFEMProblem::addProblemComposer(const std::string & composer_type,
515 const std::string & name,
516 InputParameters & parameters)
517{
518 _problem_composer = addObject<MFEMProblemComposer>(composer_type, name, parameters).front();
519}
520
521std::shared_ptr<MFEMProblemComposer>
523{
524 const std::string name = "__DefaultWeakFormProblemComposer";
525 std::string type;
526 if (isTransient())
527 type = "MFEMTimeDependentWeakFormProblemComposer";
529 type = "MFEMWeakFormProblemComposer";
531 type = "MFEMComplexWeakFormProblemComposer";
532 else
533 mooseError("Unknown numeric type. "
534 "Please set the Problem numeric type to either 'real' or 'complex'.");
535
537 return addObject<MFEMProblemComposer>(type, name, params).front();
538}
539
540void
542{
543 std::vector<MFEMProblemComposer *> problem_composers;
545 .query()
546 .condition<AttribSystem>("MFEMProblemComposer")
547 .queryInto(problem_composers);
548
549 // Add a default MFEMProblemComposer if none has been added by the user.
550 if (problem_composers.empty())
551 problem_composers.push_back(addDefaultProblemComposer().get());
552
553 for (auto & problem_composer : problem_composers)
554 _problem_operators.push_back(problem_composer->createProblemOperator(*this));
555
556 for (const auto & problem_operator : getProblemOperators())
557 problem_operator->Init();
558}
559
560std::vector<std::shared_ptr<Moose::MFEM::ProblemOperatorBase>> &
565
566int
567vectorFunctionDim(const std::string & type, const InputParameters & parameters)
568{
569 if (parameters.isParamSetByUser("expression_z"))
570 return 3;
571 if (parameters.isParamSetByUser("expression_y") || type == "LevelSetOlssonVortex")
572 return 2;
573 if (parameters.isParamSetByUser("expression_x"))
574 return 1;
575
576 return 3;
577}
578
579const std::vector<std::string> SCALAR_FUNCS = {"Axisymmetric2D3DSolutionFunction",
580 "BicubicSplineFunction",
581 "CoarsenedPiecewiseLinear",
582 "CompositeFunction",
583 "ConstantFunction",
584 "ImageFunction",
585 "ParsedFunction",
586 "ParsedGradFunction",
587 "PeriodicFunction",
588 "PiecewiseBilinear",
589 "PiecewiseConstant",
590 "PiecewiseConstantFromCSV",
591 "PiecewiseLinear",
592 "PiecewiseLinearFromVectorPostprocessor",
593 "PiecewiseMultiInterpolation",
594 "PiecewiseMulticonstant",
595 "SolutionFunction",
596 "SplineFunction",
597 "FunctionSeries",
598 "LevelSetOlssonBubble",
599 "LevelSetOlssonPlane",
600 "NearestReporterCoordinatesFunction",
601 "ParameterMeshFunction",
602 "ParsedOptimizationFunction",
603 "FourierNoise",
604 "MovingPlanarFront",
605 "MultiControlDrumFunction",
606 "Grad2ParsedFunction",
607 "GradParsedFunction",
608 "ScaledAbsDifferenceDRLRewardFunction",
609 "CircularAreaHydraulicDiameterFunction",
610 "CosineHumpFunction",
611 "CosineTransitionFunction",
612 "CubicTransitionFunction",
613 "GeneralizedCircumference",
614 "PiecewiseFunction",
615 "TimeRampFunction"},
616 VECTOR_FUNCS = {"ParsedVectorFunction", "LevelSetOlssonVortex"},
617 MFEM_FUNCS = {"MFEMParsedFunction",
618 "MFEMCoordinateTransformations",
619 "MFEMScalarQuadratureFunction",
620 "MFEMVectorQuadratureFunction"};
621
622void
623MFEMProblem::addFunction(const std::string & type,
624 const std::string & name,
625 InputParameters & parameters)
626{
627 // Add function to the warehouse, while avoiding the threading logic in FEProblemBase::addFunction
628 {
629 parallel_object_only();
630
631 parameters.set<SubProblem *>("_subproblem") = this;
632
633 std::shared_ptr<Function> func = _factory.create<Function>(type, name, parameters);
634 logAdd("Function", name, type, parameters);
635 _functions.addObject(func);
636 }
637
638 auto & func = getFunction(name);
639 // FIXME: Do we want to have optimised versions for when functions
640 // are only of space or only of time.
641 if (std::find(SCALAR_FUNCS.begin(), SCALAR_FUNCS.end(), type) != SCALAR_FUNCS.end())
642 {
643 getCoefficients().declareScalar<mfem::FunctionCoefficient>(
644 name,
645 [&func](const mfem::Vector & p, mfem::real_t t) -> mfem::real_t
646 { return func.value(t, Moose::MFEM::libMeshPointFromMFEMVector(p)); });
647 }
648 else if (std::find(VECTOR_FUNCS.begin(), VECTOR_FUNCS.end(), type) != VECTOR_FUNCS.end())
649 {
651 getCoefficients().declareVector<mfem::VectorFunctionCoefficient>(
652 name,
653 dim,
654 [&func, dim](const mfem::Vector & p, mfem::real_t t, mfem::Vector & u)
655 {
656 libMesh::RealVectorValue vector_value =
657 func.vectorValue(t, Moose::MFEM::libMeshPointFromMFEMVector(p));
658 for (int i = 0; i < dim; i++)
659 {
660 u[i] = vector_value(i);
661 }
662 });
663 }
664 else if (std::find(MFEM_FUNCS.begin(), MFEM_FUNCS.end(), type) != MFEM_FUNCS.end())
665 {
666 }
667 else
668 mooseWarning("Could not identify function ", type, "; no MFEM coefficient object created.");
669}
670
671void
672MFEMProblem::addPostprocessor(const std::string & type,
673 const std::string & name,
674 InputParameters & parameters)
675{
676 if (parameters.getSystemAttributeName() == "MFEMExecutedObject")
677 {
678 checkUserObjectNameCollision(name, "Postprocessor");
679 addObject<MFEMExecutedObject>(type, name, parameters);
680 }
681 else
683
684 // Make the postprocessor value available as a spatially uniform scalar coefficient. This is done
685 // for postprocessors of all types so that values calculated elsewhere and transferred in, such
686 // as from a subapp, may also be used to build coefficients.
688 getCoefficients().declareScalar<mfem::FunctionCoefficient>(
689 name, [&val](const mfem::Vector &) -> mfem::real_t { return val; });
690}
691
692void
693MFEMProblem::addVectorPostprocessor(const std::string & type,
694 const std::string & name,
695 InputParameters & parameters)
696{
697 if (parameters.getSystemAttributeName() == "MFEMExecutedObject")
698 {
699 checkUserObjectNameCollision(name, "VectorPostprocessor");
700 addObject<MFEMExecutedObject>(type, name, parameters);
701 }
702 else
704}
705
708{
709
710 InputParameters fespace_params = _factory.getValidParams("MFEMGenericFESpace");
711 InputParameters variable_params = _factory.getValidParams("MFEMVariable");
712
713 const auto family = Utility::string_to_enum<FEFamily>(parameters.get<MooseEnum>("family"));
714 auto order = static_cast<int>(parameters.get<MooseEnum>("order"));
715 const auto dim = mesh().dimension();
716
717 std::string space;
718 int vdim = 1;
719
720 switch (family)
721 {
722 case FEFamily::LAGRANGE:
723 space = "H1";
724 break;
725 case FEFamily::NEDELEC_ONE:
726 space = "ND";
727 break;
728 case FEFamily::RAVIART_THOMAS:
729 space = "RT";
730 --order;
731 break;
732 case FEFamily::MONOMIAL:
733 case FEFamily::L2_LAGRANGE:
734 space = "L2";
735 break;
736 case FEFamily::LAGRANGE_VEC:
737 space = "H1";
738 vdim = dim;
739 break;
740 case FEFamily::MONOMIAL_VEC:
741 case FEFamily::L2_LAGRANGE_VEC:
742 space = "L2";
743 vdim = dim;
744 break;
745 default:
746 mooseError("Unable to set MFEM FESpace for MOOSE variable");
747 break;
748 }
749
750 // Create fespace name. If this already exists, we will reuse this for
751 // the mfem variable ("gridfunction"). If using AMR, this implies all
752 // variables sharing the fespace are affected.
753 const auto fec_name = space + "_" + std::to_string(dim) + "D_P" + std::to_string(order);
754 const auto fes_name = fec_name + "_X" + std::to_string(vdim);
755
756 // Set all fespace parameters.
757 fespace_params.set<std::string>("fec_name") = fec_name;
758 fespace_params.set<int>("vdim") = vdim;
759
760 if (!hasMFEMObject("MFEMFESpace", fes_name))
761 addFESpace("MFEMGenericFESpace", fes_name, fespace_params);
762
763 variable_params.set<MFEMFESpaceName>("fespace") = fes_name;
764
765 return variable_params;
766}
767
768void
770{
771 // Displace mesh
772 if (mesh().shouldDisplace())
773 {
774 mesh().displace(cast_ref<mfem::GridFunction const &>(getMeshDisplacementGridFunction()));
775 // TODO: update FESpaces GridFunctions etc for transient solves
776 }
777}
778
779const mfem::ParGridFunction &
781{
782 return *getGridFunction(mesh().getMeshDisplacementVariable());
783}
784
785void
786MFEMProblem::rebalanceMesh(mfem::ParMesh & pmesh)
787{
788 if (pmesh.Nonconforming())
789 {
790 pmesh.Rebalance();
793 }
794}
795
796void
798{
799 for (const auto & fe_space_pair : _problem_data.fespaces)
800 fe_space_pair.second->Update();
801}
802
803void
805{
806 for (const auto & gridfunction_pair : _problem_data.gridfunctions)
807 gridfunction_pair.second->Update();
808}
809
810std::vector<VariableName>
815
816MFEMMesh &
818{
819 auto * mfem_mesh = dynamic_cast<MFEMMesh *>(&_mesh);
820 mooseAssert(mfem_mesh,
821 "The mesh for an MFEMProblem must be MFEMFileMesh or MFEMMeshGeneratorMesh.");
822 return *mfem_mesh;
823}
824
825const MFEMMesh &
827{
828 return const_cast<MFEMProblem *>(this)->mesh();
829}
830
831void
832MFEMProblem::addSubMesh(const std::string & var_type,
833 const std::string & var_name,
834 InputParameters & parameters)
835{
836 auto & mfem_submesh = *addObject<MFEMSubMesh>(var_type, var_name, parameters).front();
837 // Register submesh.
838 getProblemData().submeshes.Register(var_name, mfem_submesh.getSubMesh());
839}
840
841void
842MFEMProblem::addTransfer(const std::string & transfer_name,
843 const std::string & name,
844 InputParameters & parameters)
845{
846 if (parameters.getBase() == "MFEMSubMeshTransfer")
847 addObject<MFEMExecutedObject>(transfer_name, name, parameters);
848 else
850}
851
852void
853MFEMProblem::addInitialCondition(const std::string & ic_name,
854 const std::string & name,
855 InputParameters & parameters)
856{
857 addObject<MFEMExecutedObject>(ic_name, name, parameters);
858}
859
860void
862{
863 std::vector<MFEMExecutedObject *> objects;
865 .query()
866 .condition<AttribSystem>("MFEMExecutedObject")
867 .condition<AttribExecOns>(exec_type)
868 .condition<AttribThread>(0)
869 .queryInto(objects);
870
871 std::map<std::string, const MFEMExecutedObject *> suppliers;
872 for (auto * const object : objects)
873 for (const auto & item : object->getSuppliedItems())
874 {
875 const auto [it, inserted] = suppliers.emplace(item, object);
876 if (!inserted && it->second != object)
877 mooseError("MFEM executed-object dependency ambiguity on ",
878 exec_type,
879 ": both '",
880 it->second->name(),
881 "' and '",
882 object->name(),
883 "' supply '",
884 item,
885 "'.");
886 }
887
888 for (auto * const object : objects)
889 {
890 object->initialize();
891 object->execute();
892 object->finalize();
893
894 if (auto * const pp = dynamic_cast<const Postprocessor *>(object))
895 {
896 _reporter_data.finalize(pp->PPName());
897 setPostprocessorValueByName(pp->PPName(), pp->getValue());
898 }
899
900 if (auto * const vpp = dynamic_cast<VectorPostprocessor *>(object))
901 _reporter_data.finalize(vpp->PPName());
902 }
903}
904
905std::string
906MFEMProblem::solverTypeString(const unsigned int libmesh_dbg_var(solver_sys_num))
907{
908 mooseAssert(solver_sys_num == 0, "All mfem systems must use the same solver right now.");
909
910 std::vector<std::string> solvers;
911
912 if (const auto * ns = getProblemData().nonlinear_solver.get())
913 solvers.push_back(MooseUtils::prettyCppType(ns));
914
915 if (const auto * js = getProblemData().jacobian_solver.get())
916 {
917 solvers.push_back(MooseUtils::prettyCppType(js));
918 if (const std::string * pc = js->queryParam<MFEMSolverName>("preconditioner"))
919 solvers.push_back(MooseUtils::prettyCppType(
920 &getMFEMObject<Moose::MFEM::LinearSolverBase>("Moose::MFEM::SolverBase", *pc)));
921 }
922
923 return solvers.empty() ? "None" : MooseUtils::stringJoin(solvers);
924}
925
926bool
927MFEMProblem::hasMFEMObject(const std::string & system, const std::string & name) const
928{
929 std::vector<MooseObject *> objs;
931 .query()
932 .condition<AttribSystem>(system)
933 .condition<AttribThread>(0)
934 .condition<AttribName>(name)
935 .queryInto(objs);
936 return !objs.empty();
937}
938
939#endif
const std::vector< std::string > SCALAR_FUNCS
int vectorFunctionDim(const std::string &type, const InputParameters &parameters)
const std::vector< std::string > MFEM_FUNCS
registerMooseObject("MooseApp", MFEMProblem)
const std::vector< std::string > VECTOR_FUNCS
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
Real PostprocessorValue
various MOOSE typedefs
Definition MooseTypes.h:230
unsigned int dim
void ErrorVector unsigned int
const std::vector< T > & getCyclicDependencies() const
Class that represents the dependecy as a graph.
void addNode(const T &a)
Add a node 'a' to the graph.
const std::vector< T > & getSortedValues()
This function also returns dependency resolved values but with a simpler single vector interface.
void addEdge(const T &a, const T &b)
Add an edge between nodes 'a' and 'b'.
static InputParameters validParams()
ReporterData _reporter_data
virtual const SystemBase & systemBaseAuxiliary() const override
Return the auxiliary system object as a base class reference.
MooseMesh & _mesh
const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name, std::size_t t_index=0) const
Get a read-only reference to the value associated with a Postprocessor that exists.
virtual void addVariable(const std::string &var_type, const std::string &var_name, InputParameters &params)
Canonical method for adding a non-linear variable.
virtual void addTransfer(const std::string &transfer_name, const std::string &name, InputParameters &parameters)
Add a Transfer to the problem.
void checkUserObjectNameCollision(const std::string &name, const std::string &type) const
Check for name collision between different user objects.
virtual void addVectorPostprocessor(const std::string &pp_name, const std::string &name, InputParameters &parameters)
virtual void addPostprocessor(const std::string &pp_name, const std::string &name, InputParameters &parameters)
void logAdd(const std::string &system, const std::string &name, const std::string &type, const InputParameters &params) const
Output information about the object just added to the problem.
void setPostprocessorValueByName(const PostprocessorName &name, const PostprocessorValue &value, std::size_t t_index=0)
Set the value of a PostprocessorValue.
void setCurrentExecuteOnFlag(const ExecFlagType &)
virtual void execute(const ExecFlagType &exec_type)
Convenience function for performing execution of MOOSE systems.
TheWarehouse & theWarehouse() const
virtual bool isTransient() const override
virtual Function & getFunction(const std::string &name, const THREAD_ID tid=0)
MooseObjectWarehouse< Function > _functions
functions
void initialSetup() override
std::shared_ptr< MooseObject > create(const std::string &obj_name, const std::string &name, const InputParameters &parameters, THREAD_ID tid=0, bool print_deprecated=true)
Definition Factory.C:142
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Definition Factory.C:68
Base class for function objects.
Definition Function.h:30
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
bool isPrivate(const std::string &name) const
Returns a Boolean indicating whether the specified parameter is private or not.
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
const std::string & getSystemAttributeName() const
Get the system attribute name if it was registered.
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
const std::string & getBase() const
const T * queryParam(const std::string &name) const
Query a parameter.
Constructs and stores an mfem::ParComplexGridFunction object.
std::shared_ptr< mfem::ParComplexGridFunction > getComplexGridFunction() const
Returns a shared pointer to the constructed gridfunction.
Abstract MooseMesh base for all MFEM-backed mesh types (MFEMFileMesh, MFEMMeshGeneratorMesh).
Definition MFEMMesh.h:24
unsigned int dimension() const override
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition MFEMMesh.h:65
std::shared_ptr< mfem::ParMesh > getMFEMParMeshPtr()
Copy a shared_ptr to the mfem::ParMesh object.
Definition MFEMMesh.h:39
void displace(mfem::GridFunction const &displacement)
Displace the nodes of the mesh by the given displacement.
Definition MFEMMesh.C:136
virtual std::vector< VariableName > getAuxVariableNames()
Returns all the variable names from the auxiliary system base.
std::shared_ptr< MFEMProblemComposer > _problem_composer
The problem operator builders for this mfem problem.
void addPostprocessor(const std::string &type, const std::string &name, InputParameters &parameters) override
Override of ExternalProblem::addPostprocessor.
virtual MFEMMesh & mesh() override
Overwritten mesh() method from base MooseMesh to retrieve the correct mesh type, in this case MFEMMes...
void addWeakForm(const std::string &weak_form_name, const std::string &name, InputParameters &parameters)
Add an MFEM WeakForm to the problem.
void addFESpace(const std::string &type, const std::string &name, InputParameters &parameters)
Add an MFEM FESpace to the problem.
void addMarker(const std::string &type, const std::string &name, InputParameters &parameters) override
Override of FEProblemBase::addMarker.
void addFESpaceHierarchy(const std::string &type, const std::string &name, InputParameters &parameters)
Add an MFEMFESpaceHierarchy to the problem.
void setProblemOperators()
Set all MFEM ProblemOperators to solve in this problem.
virtual void addMFEMSolver(const std::string &user_object_name, const std::string &name, InputParameters &parameters)
Method called in AddMFEMSolverAction which records a solver for later dependency-ordered construction...
Moose::MFEM::CoefficientManager & getCoefficients()
Method to get the PropertyManager object for storing material properties and converting them to MFEM ...
std::string solverTypeString(unsigned int solver_sys_num) override
Return solver type as a human readable string.
std::vector< std::shared_ptr< Moose::MFEM::ProblemOperatorBase > > _problem_operators
Vector of MFEM problem operators executed in this problem.
bool hasMFEMObject(const std::string &system, const std::string &name) const
Determine whether an MFEM object with the supplied system and name exists.
std::shared_ptr< mfem::ParGridFunction > getGridFunction(const std::string &name)
std::vector< std::shared_ptr< Moose::MFEM::ProblemOperatorBase > > & getProblemOperators()
Get vector of all ProblemOperators added to this problem.
MFEMProblemData & getProblemData()
Method to get the current MFEMProblemData object storing the current data specifying the FE problem.
void updateFESpaces()
Calls Update() on all FE spaces.
void addIndicator(const std::string &type, const std::string &name, InputParameters &parameters) override
Override of FEProblemBase::addIndicator.
void setEquationSystems()
Set all MFEM EquationSystems for this problem.
void rebalanceMesh(mfem::ParMesh &pmesh)
Rebalance the (necessarily nonconforming) mesh.
void addVectorPostprocessor(const std::string &type, const std::string &name, InputParameters &parameters) override
Add a vector postprocessor and register its vectors with the MFEM execution system.
void addAuxKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters) override
Override of ExternalProblem::addAuxKernel.
void addMaterial(const std::string &material_name, const std::string &name, InputParameters &parameters) override
void addProblemComposer(const std::string &composer_type, const std::string &name, InputParameters &parameters)
Method called in AddMFEMProblemComposerAction which will create the problem composer.
void addSubMesh(const std::string &type, const std::string &name, InputParameters &parameters)
Add an MFEM SubMesh to the problem.
void validateVariableNumericType(const std::string &var_type, const std::string &var_name) const
Verify that a primary variable's numeric type matches the problem's equation system.
void addInitialCondition(const std::string &ic_name, const std::string &name, InputParameters &parameters) override
Add an MFEM initial condition to the problem.
static InputParameters validParams()
Return the input parameters used to construct an MFEM problem.
Definition MFEMProblem.C:62
void setMesh()
Set the mesh used by MFEM.
void addKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters) override
Override of ExternalProblem::addKernel.
virtual std::shared_ptr< MFEMWeakFormBase > addDefaultWeakForm()
Add default weak form if none has been added by the user.
virtual void addVariable(const std::string &var_type, const std::string &var_name, InputParameters &parameters) override
Override of ExternalProblem::addVariable.
NumericType getNumericType() const
Retrieve the numeric type of the problem.
void updateGridFunctions()
Calls Update() on all gridfunctions.
void addRealComponentToKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a real component kernel to the parent MFEMComplexKernel.
MFEMProblemData _problem_data
Aggregated MFEM-side state for meshes, spaces, variables, coefficients, and solvers.
void addRealComponentToBC(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds a real component BC to the parent MFEMComplexIntegratedBC.
void addFunction(const std::string &type, const std::string &name, InputParameters &parameters) override
Override of ExternalProblem::addFunction.
std::shared_ptr< Moose::MFEM::EquationSystem > getEquationSystem(const std::string &weak_form_name="") const
Return the EquationSystem built by the weak form named weak_form_name.
InputParameters addMFEMFESpaceFromMOOSEVariable(InputParameters &moosevar_params)
Method used to get an mfem FEC depending on the variable family specified in the input file.
void addGridFunction(const std::string &var_type, const std::string &var_name, InputParameters &parameters)
Adds one MFEM GridFunction to be used in the MFEM solve.
void addTransfer(const std::string &transfer_name, const std::string &name, InputParameters &parameters) override
Add transfers between MultiApps and/or MFEM SubMeshes.
void displaceMesh()
Displace the mesh, if mesh displacement is enabled.
void addBoundaryCondition(const std::string &bc_name, const std::string &name, InputParameters &parameters) override
virtual void execute(const ExecFlagType &exec_type) override
Convenience function for performing execution of MOOSE systems.
NumericType _num_type
The numeric representation currently active for this problem.
const mfem::ParGridFunction & getMeshDisplacementGridFunction()
Returns reference to the displacement GridFunction to apply to nodes.
void addImagComponentToBC(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds an imaginary component BC to the parent MFEMComplexIntegratedBC.
virtual std::shared_ptr< MFEMProblemComposer > addDefaultProblemComposer()
Add default problem composer if none has been added by the user.
void executeMFEMObjects(const ExecFlagType &exec_type)
Execute MFEM executed objects scheduled on the supplied execute flag.
MFEMProblem(const InputParameters &params)
Construct an MFEM problem from the supplied parameters.
Definition MFEMProblem.C:73
std::map< std::string, MFEMSolverDefinition > _mfem_solver_definitions
Solver definitions recorded by AddMFEMSolverAction before the dependency resolver constructs them.
void addAuxVariable(const std::string &var_type, const std::string &var_name, InputParameters &parameters) override
Override of ExternalProblem::addAuxVariable.
virtual void resolveMFEMSolvers()
Construct recorded MFEM solvers in dependency order and select the problem driver solver(s).
void addFunctorMaterial(const std::string &material_name, const std::string &name, InputParameters &parameters) override
void addImagComponentToKernel(const std::string &kernel_name, const std::string &name, InputParameters &parameters)
Adds an imaginary component kernel to the parent MFEMComplexKernel.
virtual void initialSetup() override
Definition MFEMProblem.C:85
Constructs and stores an mfem::ParGridFunction object.
std::shared_ptr< mfem::ParGridFunction > getGridFunction() const
Returns a shared pointer to the constructed gridfunction.
void declareCoefficients()
Declare default coefficients associated with this gridfunction.
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & type() const
Get the type of this class.
Definition MooseBase.h:93
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
Class for containing MooseEnum item information.
const std::string & name() const
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
virtual void addObject(std::shared_ptr< T > object, THREAD_ID tid=0, bool recurse=true) override
Adds an object to the storage structure.
std::shared_ptr< MooseObject > getSharedPtr()
Get another shared pointer to this object that has the same ownership group.
Definition MooseObject.C:70
mfem::Coefficient & declareScalar(const std::string &name, const std::string &existing_or_literal)
Declare an alias to an existing scalar coefficient or, if it does not exist, try interpreting the nam...
mfem::VectorCoefficient & declareVector(const std::string &name, const std::string &existing_or_literal)
Declare an alias to an existing vector coefficientor or, if it does not exist, try interpreting the n...
void Register(const std::string &field_name, FieldArgs &&... args)
Construct new field with name field_name and register.
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.
void addTimeDerivativeAssociation(const std::string &var_name, const std::string &time_derivative_var_name)
Base class for all Postprocessors.
void finalize(const std::string &object_name)
Helper function for performing post calculation actions via the ReporterContext objects.
Generic class for solving transient nonlinear problems.
Definition SubProblem.h:79
Factory & _factory
The Factory for building objects.
const std::vector< VariableName > & getVariableNames() const
Definition SystemBase.h:893
QueryCache & condition(Args &&... args)
Adds a new condition to the query.
Query query()
query creates and returns an initialized a query object for querying objects from the warehouse.
Base class for Postprocessors that produce a vector of values.
std::string prettyCppType(const std::string &cpp_type)
std::string stringJoin(const std::vector< std::string > &values, const std::string &separator=" ")
Concatenates value into a single string separated by separator.
libMesh::Point libMeshPointFromMFEMVector(const mfem::Vector &vec)
Convert an MFEM position vector to a libMesh::Point.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
Moose::MFEM::FESpaces fespaces
Moose::MFEM::SubMeshes submeshes
Moose::MFEM::BoundaryConditions bcs
Moose::MFEM::TimeDerivativeMap time_derivative_map
Moose::MFEM::Kernels kernels
Moose::MFEM::ComplexGridFunctions cmplx_gridfunctions
Moose::MFEM::EquationSystems eqn_systems
std::shared_ptr< MFEMRefinementMarker > refiner
Moose::MFEM::FECollections fecs
std::shared_ptr< mfem::ParMesh > pmesh
Moose::MFEM::GridFunctions gridfunctions
Moose::MFEM::FESpaceHierarchies fespace_hierarchies