LCOV - code coverage report
Current view: top level - src/mfem/problem - MFEMProblem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: fa5e60 Lines: 307 351 87.5 %
Date: 2026-06-24 08:03:36 Functions: 39 44 88.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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"
      19             : #include "libmesh/string_to_enum.h"
      20             : 
      21             : #include <vector>
      22             : #include <algorithm>
      23             : #include <map>
      24             : #include <set>
      25             : #include <deque>
      26             : #include <sstream>
      27             : 
      28             : registerMooseObject("MooseApp", MFEMProblem);
      29             : 
      30             : InputParameters
      31        7850 : MFEMProblem::validParams()
      32             : {
      33        7850 :   InputParameters params = ExternalProblem::validParams();
      34       15700 :   params.addClassDescription("Problem type for building and solving the finite element problem "
      35             :                              "using the MFEM finite element library.");
      36       31400 :   MooseEnum numeric_types("real complex", "real");
      37       23550 :   params.addParam<MooseEnum>("numeric_type", numeric_types, "Number type used for the problem");
      38             : 
      39       15700 :   return params;
      40        7850 : }
      41             : 
      42        1827 : MFEMProblem::MFEMProblem(const InputParameters & params)
      43        3654 :   : ExternalProblem(params), _num_type{static_cast<int>(getParam<MooseEnum>("numeric_type"))}
      44             : {
      45             :   // Initialise Hypre for all MFEM problems.
      46        1827 :   mfem::Hypre::Init();
      47             :   // Disable multithreading for all MFEM problems (including any libMesh or MFEM subapps).
      48        1827 :   libMesh::libMeshPrivateData::_n_threads = 1;
      49             : #ifdef LIBMESH_HAVE_OPENMP
      50        1827 :   omp_set_num_threads(1);
      51             : #endif
      52        1827 :   setMesh();
      53        1827 : }
      54             : 
      55             : void
      56        1479 : MFEMProblem::initialSetup()
      57             : {
      58        1479 :   ExternalProblem::initialSetup();
      59             : 
      60             :   // MFEM indicators create their estimators during addIndicator(); markers still need an explicit
      61             :   // setup pass because they are no longer initialized through the libMesh/MOOSE user-object path.
      62        1479 :   std::vector<MFEMRefinementMarker *> markers;
      63        1479 :   theWarehouse().query().condition<AttribSystem>("Marker").queryInto(markers);
      64        1505 :   for (auto marker : markers)
      65          26 :     marker->initialSetup();
      66        1479 : }
      67             : 
      68             : void
      69        9987 : MFEMProblem::execute(const ExecFlagType & exec_type)
      70             : {
      71        9987 :   setCurrentExecuteOnFlag(exec_type);
      72        9987 :   executeMFEMObjects(exec_type);
      73             : 
      74        9987 :   ExternalProblem::execute(exec_type);
      75        9987 : }
      76             : 
      77             : void
      78        1827 : MFEMProblem::setMesh()
      79             : {
      80        1827 :   auto pmesh = mesh().getMFEMParMeshPtr();
      81        1827 :   getProblemData().pmesh = pmesh;
      82        1827 :   getProblemData().comm = pmesh->GetComm();
      83        1827 :   getProblemData().num_procs = pmesh->GetNRanks();
      84        1827 :   getProblemData().myid = pmesh->GetMyRank();
      85        1827 : }
      86             : 
      87             : void
      88        1128 : MFEMProblem::addMFEMPreconditioner(const std::string & user_object_name,
      89             :                                    const std::string & name,
      90             :                                    InputParameters & parameters)
      91             : {
      92        2256 :   addObject<Moose::MFEM::SolverBase>(user_object_name, name, parameters);
      93        1128 : }
      94             : 
      95             : void
      96          26 : MFEMProblem::addIndicator(const std::string & user_object_name,
      97             :                           const std::string & name,
      98             :                           InputParameters & parameters)
      99             : {
     100          52 :   auto estimator = addObject<MFEMIndicator>(user_object_name, name, parameters).front();
     101             : 
     102             :   // construct the estimator itself
     103          26 :   estimator->createEstimator();
     104          26 : }
     105             : 
     106             : void
     107          26 : MFEMProblem::addMarker(const std::string & user_object_name,
     108             :                        const std::string & name,
     109             :                        InputParameters & parameters)
     110             : {
     111          26 :   getProblemData().refiner =
     112          78 :       addObject<MFEMRefinementMarker>(user_object_name, name, parameters).front();
     113          26 : }
     114             : 
     115             : void
     116         995 : MFEMProblem::addMFEMSolver(const std::string & user_object_name,
     117             :                            const std::string & name,
     118             :                            InputParameters & parameters)
     119             : {
     120        1990 :   auto object = addObject<Moose::MFEM::SolverBase>(user_object_name, name, parameters).front();
     121         995 :   auto & problem_data = getProblemData();
     122             : 
     123         995 :   if (auto lin_solver = std::dynamic_pointer_cast<Moose::MFEM::LinearSolverBase>(object))
     124             :   {
     125         953 :     if (problem_data.jacobian_solver)
     126           0 :       mooseError("Multiple linear solvers provided. '",
     127           0 :                  problem_data.jacobian_solver->name(),
     128             :                  "' and '",
     129           0 :                  lin_solver->name(),
     130             :                  "'");
     131         953 :     problem_data.jacobian_solver = lin_solver;
     132             :   }
     133          42 :   else if (auto nonlinear_solver =
     134          42 :                std::dynamic_pointer_cast<Moose::MFEM::NonlinearSolverBase>(object);
     135          42 :            nonlinear_solver)
     136             :   {
     137          42 :     if (problem_data.nonlinear_solver)
     138           0 :       mooseError("Multiple nonlinear solvers provided. '",
     139           0 :                  problem_data.nonlinear_solver->name(),
     140             :                  "' and '",
     141           0 :                  nonlinear_solver->name(),
     142             :                  "'");
     143          42 :     problem_data.nonlinear_solver = nonlinear_solver;
     144             :   }
     145             :   else
     146           0 :     mooseError(
     147        1037 :         "Unsupported MFEM solver object type '", user_object_name, "' for solver '", name, "'.");
     148         995 : }
     149             : 
     150             : void
     151        1332 : MFEMProblem::addBoundaryCondition(const std::string & bc_name,
     152             :                                   const std::string & name,
     153             :                                   InputParameters & parameters)
     154             : {
     155        2664 :   auto bc = addObject<MFEMBoundaryCondition>(bc_name, name, parameters).front();
     156        1332 :   const auto & mfem_bc = *bc;
     157             : 
     158        1332 :   if (dynamic_cast<const MFEMIntegratedBC *>(&mfem_bc))
     159             :   {
     160          56 :     auto integrated_bc = std::dynamic_pointer_cast<MFEMIntegratedBC>(bc);
     161             :     auto eqsys =
     162          56 :         std::dynamic_pointer_cast<Moose::MFEM::EquationSystem>(getProblemData().eqn_system);
     163          56 :     if (eqsys)
     164          56 :       eqsys->AddIntegratedBC(std::move(integrated_bc));
     165             :     else
     166           0 :       mooseError("Cannot add integrated BC with name '" + name +
     167             :                  "' because there is no corresponding equation system.");
     168          56 :   }
     169        1276 :   else if (dynamic_cast<const MFEMComplexIntegratedBC *>(&mfem_bc))
     170             :   {
     171          14 :     auto integrated_bc = std::dynamic_pointer_cast<MFEMComplexIntegratedBC>(bc);
     172             :     auto eqsys =
     173          14 :         std::dynamic_pointer_cast<Moose::MFEM::ComplexEquationSystem>(getProblemData().eqn_system);
     174          14 :     if (eqsys)
     175          14 :       eqsys->AddComplexIntegratedBC(std::move(integrated_bc));
     176             :     else
     177           0 :       mooseError("Cannot add complex integrated BC with name '" + name +
     178             :                  "' because there is no corresponding equation system.");
     179          14 :   }
     180        1262 :   else if (dynamic_cast<const MFEMComplexEssentialBC *>(&mfem_bc))
     181             :   {
     182          63 :     auto essential_bc = std::dynamic_pointer_cast<MFEMComplexEssentialBC>(bc);
     183             :     auto eqsys =
     184          63 :         std::dynamic_pointer_cast<Moose::MFEM::ComplexEquationSystem>(getProblemData().eqn_system);
     185          63 :     if (eqsys)
     186          63 :       eqsys->AddComplexEssentialBCs(std::move(essential_bc));
     187             :     else
     188           0 :       mooseError("Cannot add boundary condition with name '" + name +
     189             :                  "' because there is no corresponding equation system.");
     190          63 :   }
     191        1199 :   else if (dynamic_cast<const MFEMEssentialBC *>(&mfem_bc))
     192             :   {
     193        1199 :     auto essential_bc = std::dynamic_pointer_cast<MFEMEssentialBC>(bc);
     194             :     auto eqsys =
     195        1199 :         std::dynamic_pointer_cast<Moose::MFEM::EquationSystem>(getProblemData().eqn_system);
     196        1199 :     if (eqsys)
     197        1199 :       eqsys->AddEssentialBC(std::move(essential_bc));
     198             :     else
     199           0 :       mooseError("Cannot add boundary condition with name '" + name +
     200             :                  "' because there is no corresponding equation system.");
     201        1199 :   }
     202             :   else
     203             :   {
     204           0 :     mooseError("Unsupported bc of type '", bc_name, "' and name '", name, "' detected.");
     205             :   }
     206        1332 : }
     207             : 
     208             : void
     209           0 : MFEMProblem::addMaterial(const std::string &, const std::string &, InputParameters &)
     210             : {
     211           0 :   mooseError(
     212             :       "MFEM materials must be added through the 'FunctorMaterials' block and not 'Materials'");
     213             : }
     214             : 
     215             : void
     216         272 : MFEMProblem::addFunctorMaterial(const std::string & material_name,
     217             :                                 const std::string & name,
     218             :                                 InputParameters & parameters)
     219             : {
     220         560 :   addObject<MFEMFunctorMaterial>(material_name, name, parameters);
     221         256 : }
     222             : 
     223             : void
     224        2564 : MFEMProblem::addFESpace(const std::string & type,
     225             :                         const std::string & name,
     226             :                         InputParameters & parameters)
     227             : {
     228        5128 :   auto & mfem_fespace = *addObject<MFEMFESpace>(type, name, parameters).front();
     229             : 
     230             :   // Register fespace and associated fe collection.
     231        2564 :   getProblemData().fecs.Register(name, mfem_fespace.getFEC());
     232        2564 :   getProblemData().fespaces.Register(name, mfem_fespace.getFESpace());
     233        2564 : }
     234             : 
     235             : void
     236        1748 : MFEMProblem::addVariable(const std::string & var_type,
     237             :                          const std::string & var_name,
     238             :                          InputParameters & parameters)
     239             : {
     240        1748 :   addGridFunction(var_type, var_name, parameters);
     241             :   // MOOSE variables store DoFs for the trial variable and its time derivatives up to second order;
     242             :   // MFEM GridFunctions store data for only one set of DoFs each, so we must add additional
     243             :   // GridFunctions for time derivatives.
     244        1748 :   if (isTransient())
     245             :   {
     246             :     const auto time_derivative_var_name =
     247         217 :         getMFEMObject<MFEMVariable>("MooseVariableBase", var_name).getTimeDerivativeName();
     248         217 :     getProblemData().time_derivative_map.addTimeDerivativeAssociation(var_name,
     249             :                                                                       time_derivative_var_name);
     250         217 :     addGridFunction(var_type, time_derivative_var_name, parameters);
     251         217 :   }
     252        1748 : }
     253             : 
     254             : void
     255        3676 : MFEMProblem::addGridFunction(const std::string & var_type,
     256             :                              const std::string & var_name,
     257             :                              InputParameters & parameters)
     258             : {
     259             : 
     260        3676 :   if (var_type == "MFEMVariable" || var_type == "MFEMComplexVariable")
     261             :   {
     262             :     // Add MFEM variable directly.
     263        3571 :     if (var_type == "MFEMComplexVariable")
     264         189 :       addObject<MFEMComplexVariable>(var_type, var_name, parameters);
     265             :     else
     266       10524 :       addObject<MFEMVariable>(var_type, var_name, parameters);
     267             :   }
     268             :   else
     269             :   {
     270             :     // Add MOOSE variable.
     271         105 :     ExternalProblem::addVariable(var_type, var_name, parameters);
     272             : 
     273             :     // Add MFEM variable indirectly ("gridfunction").
     274         105 :     InputParameters mfem_variable_params = addMFEMFESpaceFromMOOSEVariable(parameters);
     275         420 :     addObject<MFEMVariable>("MFEMVariable", var_name, mfem_variable_params);
     276         105 :   }
     277             : 
     278             :   // Register gridfunction.
     279        3676 :   if (var_type == "MFEMComplexVariable")
     280             :   {
     281             :     MFEMComplexVariable & mfem_variable =
     282          63 :         getMFEMObject<MFEMComplexVariable>("MooseVariableBase", var_name);
     283          63 :     getProblemData().cmplx_gridfunctions.Register(var_name, mfem_variable.getComplexGridFunction());
     284          63 :     mfem_variable.declareCoefficients();
     285             :   }
     286             :   else // must be real, but may have been set up indirectly from a MOOSE variable
     287             :   {
     288        3613 :     MFEMVariable & mfem_variable = getMFEMObject<MFEMVariable>("MooseVariableBase", var_name);
     289        3613 :     getProblemData().gridfunctions.Register(var_name, mfem_variable.getGridFunction());
     290        3613 :     mfem_variable.declareCoefficients();
     291             :   }
     292        3676 : }
     293             : 
     294             : void
     295        1555 : MFEMProblem::addAuxVariable(const std::string & var_type,
     296             :                             const std::string & var_name,
     297             :                             InputParameters & parameters)
     298             : {
     299             :   // We handle MFEM AuxVariables just like MFEM Variables, except
     300             :   // we do not add additional GridFunctions for time derivatives.
     301        1555 :   addGridFunction(var_type, var_name, parameters);
     302        1555 : }
     303             : 
     304             : void
     305         477 : MFEMProblem::addAuxKernel(const std::string & kernel_name,
     306             :                           const std::string & name,
     307             :                           InputParameters & parameters)
     308             : {
     309         954 :   addObject<MFEMExecutedObject>(kernel_name, name, parameters);
     310         477 : }
     311             : 
     312             : void
     313        1816 : MFEMProblem::addKernel(const std::string & kernel_name,
     314             :                        const std::string & name,
     315             :                        InputParameters & parameters)
     316             : {
     317        3632 :   auto kernel = addObject<MFEMKernel>(kernel_name, name, parameters).front();
     318        1816 :   const auto & kernel_object = *kernel;
     319             : 
     320        1816 :   if (dynamic_cast<const MFEMComplexKernel *>(&kernel_object))
     321             :   {
     322          63 :     auto complex_kernel = std::dynamic_pointer_cast<MFEMComplexKernel>(kernel);
     323             :     auto eqsys =
     324          63 :         std::dynamic_pointer_cast<Moose::MFEM::ComplexEquationSystem>(getProblemData().eqn_system);
     325          63 :     if (eqsys)
     326          63 :       eqsys->AddComplexKernel(std::move(complex_kernel));
     327             :     else
     328           0 :       mooseError("Cannot add complex kernel with name '" + name +
     329             :                  "' because there is no corresponding equation system.");
     330          63 :   }
     331             :   else
     332             :   {
     333             :     auto eqsys =
     334        1753 :         std::dynamic_pointer_cast<Moose::MFEM::EquationSystem>(getProblemData().eqn_system);
     335        1753 :     if (eqsys)
     336        1753 :       eqsys->AddKernel(std::move(kernel));
     337             :     else
     338           0 :       mooseError("Cannot add kernel with name '" + name +
     339             :                  "' because there is no corresponding equation system.");
     340        1753 :   }
     341        1816 : }
     342             : 
     343             : void
     344          63 : MFEMProblem::addRealComponentToKernel(const std::string & kernel_name,
     345             :                                       const std::string & name,
     346             :                                       InputParameters & parameters)
     347             : {
     348             :   auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexKernel>(
     349          63 :       getMFEMObject<MFEMComplexKernel>("Kernel", name).getSharedPtr());
     350         252 :   parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
     351         126 :   auto kernel_ptr = addObject<MFEMKernel>(kernel_name, name + "_real", parameters).front();
     352          63 :   parent_ptr->setRealKernel(kernel_ptr);
     353          63 : }
     354             : 
     355             : void
     356          56 : MFEMProblem::addImagComponentToKernel(const std::string & kernel_name,
     357             :                                       const std::string & name,
     358             :                                       InputParameters & parameters)
     359             : {
     360             :   auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexKernel>(
     361          56 :       getMFEMObject<MFEMComplexKernel>("Kernel", name).getSharedPtr());
     362         224 :   parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
     363         112 :   auto kernel_ptr = addObject<MFEMKernel>(kernel_name, name + "_imag", parameters).front();
     364          56 :   parent_ptr->setImagKernel(kernel_ptr);
     365          56 : }
     366             : 
     367             : void
     368           0 : MFEMProblem::addRealComponentToBC(const std::string & kernel_name,
     369             :                                   const std::string & name,
     370             :                                   InputParameters & parameters)
     371             : {
     372             :   auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexIntegratedBC>(
     373           0 :       getMFEMObject<MFEMComplexIntegratedBC>("BoundaryCondition", name).getSharedPtr());
     374           0 :   parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
     375           0 :   parameters.set<std::vector<BoundaryName>>("boundary") =
     376           0 :       parent_ptr->getParam<std::vector<BoundaryName>>("boundary");
     377             :   auto bc_ptr = std::dynamic_pointer_cast<MFEMIntegratedBC>(
     378           0 :       addObject<MFEMBoundaryCondition>(kernel_name, name + "_real", parameters).front());
     379           0 :   parent_ptr->setRealBC(bc_ptr);
     380           0 : }
     381             : 
     382             : void
     383           0 : MFEMProblem::addImagComponentToBC(const std::string & kernel_name,
     384             :                                   const std::string & name,
     385             :                                   InputParameters & parameters)
     386             : {
     387             :   auto parent_ptr = std::dynamic_pointer_cast<MFEMComplexIntegratedBC>(
     388           0 :       getMFEMObject<MFEMComplexIntegratedBC>("BoundaryCondition", name).getSharedPtr());
     389           0 :   parameters.set<VariableName>("variable") = parent_ptr->getParam<VariableName>("variable");
     390           0 :   parameters.set<std::vector<BoundaryName>>("boundary") =
     391           0 :       parent_ptr->getParam<std::vector<BoundaryName>>("boundary");
     392             :   auto bc_ptr = std::dynamic_pointer_cast<MFEMIntegratedBC>(
     393           0 :       addObject<MFEMBoundaryCondition>(kernel_name, name + "_imag", parameters).front());
     394           0 :   parent_ptr->setImagBC(bc_ptr);
     395           0 : }
     396             : 
     397             : int
     398         325 : vectorFunctionDim(const std::string & type, const InputParameters & parameters)
     399             : {
     400         650 :   if (parameters.isParamSetByUser("expression_z"))
     401         295 :     return 3;
     402          90 :   if (parameters.isParamSetByUser("expression_y") || type == "LevelSetOlssonVortex")
     403          28 :     return 2;
     404           4 :   if (parameters.isParamSetByUser("expression_x"))
     405           2 :     return 1;
     406             : 
     407           0 :   return 3;
     408             : }
     409             : 
     410             : const std::vector<std::string> SCALAR_FUNCS = {"Axisymmetric2D3DSolutionFunction",
     411             :                                                "BicubicSplineFunction",
     412             :                                                "CoarsenedPiecewiseLinear",
     413             :                                                "CompositeFunction",
     414             :                                                "ConstantFunction",
     415             :                                                "ImageFunction",
     416             :                                                "ParsedFunction",
     417             :                                                "ParsedGradFunction",
     418             :                                                "PeriodicFunction",
     419             :                                                "PiecewiseBilinear",
     420             :                                                "PiecewiseConstant",
     421             :                                                "PiecewiseConstantFromCSV",
     422             :                                                "PiecewiseLinear",
     423             :                                                "PiecewiseLinearFromVectorPostprocessor",
     424             :                                                "PiecewiseMultiInterpolation",
     425             :                                                "PiecewiseMulticonstant",
     426             :                                                "SolutionFunction",
     427             :                                                "SplineFunction",
     428             :                                                "FunctionSeries",
     429             :                                                "LevelSetOlssonBubble",
     430             :                                                "LevelSetOlssonPlane",
     431             :                                                "NearestReporterCoordinatesFunction",
     432             :                                                "ParameterMeshFunction",
     433             :                                                "ParsedOptimizationFunction",
     434             :                                                "FourierNoise",
     435             :                                                "MovingPlanarFront",
     436             :                                                "MultiControlDrumFunction",
     437             :                                                "Grad2ParsedFunction",
     438             :                                                "GradParsedFunction",
     439             :                                                "ScaledAbsDifferenceDRLRewardFunction",
     440             :                                                "CircularAreaHydraulicDiameterFunction",
     441             :                                                "CosineHumpFunction",
     442             :                                                "CosineTransitionFunction",
     443             :                                                "CubicTransitionFunction",
     444             :                                                "GeneralizedCircumference",
     445             :                                                "PiecewiseFunction",
     446             :                                                "TimeRampFunction"},
     447             :                                VECTOR_FUNCS = {"ParsedVectorFunction", "LevelSetOlssonVortex"};
     448             : 
     449             : void
     450        1430 : MFEMProblem::addFunction(const std::string & type,
     451             :                          const std::string & name,
     452             :                          InputParameters & parameters)
     453             : {
     454        1430 :   ExternalProblem::addFunction(type, name, parameters);
     455        1430 :   auto & func = getFunction(name);
     456             :   // FIXME: Do we want to have optimised versions for when functions
     457             :   // are only of space or only of time.
     458        1430 :   if (std::find(SCALAR_FUNCS.begin(), SCALAR_FUNCS.end(), type) != SCALAR_FUNCS.end())
     459             :   {
     460        1011 :     getCoefficients().declareScalar<mfem::FunctionCoefficient>(
     461             :         name,
     462        1011 :         [&func](const mfem::Vector & p, mfem::real_t t) -> mfem::real_t
     463     1935562 :         { return func.value(t, Moose::MFEM::libMeshPointFromMFEMVector(p)); });
     464             :   }
     465         419 :   else if (std::find(VECTOR_FUNCS.begin(), VECTOR_FUNCS.end(), type) != VECTOR_FUNCS.end())
     466             :   {
     467         325 :     int dim = vectorFunctionDim(type, parameters);
     468         325 :     getCoefficients().declareVector<mfem::VectorFunctionCoefficient>(
     469             :         name,
     470             :         dim,
     471         325 :         [&func, dim](const mfem::Vector & p, mfem::real_t t, mfem::Vector & u)
     472             :         {
     473             :           libMesh::RealVectorValue vector_value =
     474     1189598 :               func.vectorValue(t, Moose::MFEM::libMeshPointFromMFEMVector(p));
     475     4440146 :           for (int i = 0; i < dim; i++)
     476             :           {
     477     3250548 :             u[i] = vector_value(i);
     478             :           }
     479     1189598 :         });
     480             :   }
     481          94 :   else if ("MFEMParsedFunction" != type)
     482             :   {
     483           2 :     mooseWarning("Could not identify whether function ",
     484             :                  type,
     485             :                  " is scalar or vector; no MFEM coefficient object created.");
     486             :   }
     487        1428 : }
     488             : 
     489             : void
     490         740 : MFEMProblem::addPostprocessor(const std::string & type,
     491             :                               const std::string & name,
     492             :                               InputParameters & parameters)
     493             : {
     494         740 :   if (parameters.getSystemAttributeName() == "MFEMExecutedObject")
     495             :   {
     496        1288 :     checkUserObjectNameCollision(name, "Postprocessor");
     497        1288 :     addObject<MFEMExecutedObject>(type, name, parameters);
     498         644 :     const PostprocessorValue & val = getPostprocessorValueByName(name);
     499         644 :     getCoefficients().declareScalar<mfem::FunctionCoefficient>(
     500         646 :         name, [&val](const mfem::Vector &) -> mfem::real_t { return val; });
     501             :   }
     502             :   else
     503          96 :     ExternalProblem::addPostprocessor(type, name, parameters);
     504         740 : }
     505             : 
     506             : void
     507         328 : MFEMProblem::addVectorPostprocessor(const std::string & type,
     508             :                                     const std::string & name,
     509             :                                     InputParameters & parameters)
     510             : {
     511         328 :   if (parameters.getSystemAttributeName() == "MFEMExecutedObject")
     512             :   {
     513         656 :     checkUserObjectNameCollision(name, "VectorPostprocessor");
     514         984 :     addObject<MFEMExecutedObject>(type, name, parameters);
     515             :   }
     516             :   else
     517           0 :     ExternalProblem::addVectorPostprocessor(type, name, parameters);
     518         328 : }
     519             : 
     520             : InputParameters
     521         105 : MFEMProblem::addMFEMFESpaceFromMOOSEVariable(InputParameters & parameters)
     522             : {
     523             : 
     524         210 :   InputParameters fespace_params = _factory.getValidParams("MFEMGenericFESpace");
     525         210 :   InputParameters variable_params = _factory.getValidParams("MFEMVariable");
     526             : 
     527         105 :   const auto family = Utility::string_to_enum<FEFamily>(parameters.get<MooseEnum>("family"));
     528         105 :   auto order = static_cast<int>(parameters.get<MooseEnum>("order"));
     529         105 :   const auto dim = mesh().dimension();
     530             : 
     531         105 :   std::string space;
     532         105 :   int vdim = 1;
     533             : 
     534         105 :   switch (family)
     535             :   {
     536          19 :     case FEFamily::LAGRANGE:
     537          19 :       space = "H1";
     538          19 :       break;
     539          19 :     case FEFamily::NEDELEC_ONE:
     540          19 :       space = "ND";
     541          19 :       break;
     542          19 :     case FEFamily::RAVIART_THOMAS:
     543          19 :       space = "RT";
     544          19 :       --order;
     545          19 :       break;
     546          18 :     case FEFamily::MONOMIAL:
     547             :     case FEFamily::L2_LAGRANGE:
     548          18 :       space = "L2";
     549          18 :       break;
     550          12 :     case FEFamily::LAGRANGE_VEC:
     551          12 :       space = "H1";
     552          12 :       vdim = dim;
     553          12 :       break;
     554          18 :     case FEFamily::MONOMIAL_VEC:
     555             :     case FEFamily::L2_LAGRANGE_VEC:
     556          18 :       space = "L2";
     557          18 :       vdim = dim;
     558          18 :       break;
     559           0 :     default:
     560           0 :       mooseError("Unable to set MFEM FESpace for MOOSE variable");
     561             :       break;
     562             :   }
     563             : 
     564             :   // Create fespace name. If this already exists, we will reuse this for
     565             :   // the mfem variable ("gridfunction"). If using AMR, this implies all
     566             :   // variables sharing the fespace are affected.
     567         105 :   const auto fec_name = space + "_" + std::to_string(dim) + "D_P" + std::to_string(order);
     568         105 :   const auto fes_name = fec_name + "_X" + std::to_string(vdim);
     569             : 
     570             :   // Set all fespace parameters.
     571         105 :   fespace_params.set<std::string>("fec_name") = fec_name;
     572         315 :   fespace_params.set<int>("vdim") = vdim;
     573             : 
     574         210 :   if (!hasMFEMObject("MFEMFESpace", fes_name))
     575         138 :     addFESpace("MFEMGenericFESpace", fes_name, fespace_params);
     576             : 
     577         315 :   variable_params.set<MFEMFESpaceName>("fespace") = fes_name;
     578             : 
     579         210 :   return variable_params;
     580         105 : }
     581             : 
     582             : void
     583        2691 : MFEMProblem::displaceMesh()
     584             : {
     585             :   // Displace mesh
     586        2691 :   if (mesh().shouldDisplace())
     587             :   {
     588          11 :     mesh().displace(static_cast<mfem::GridFunction const &>(*getMeshDisplacementGridFunction()));
     589             :     // TODO: update FESpaces GridFunctions etc for transient solves
     590             :   }
     591        2691 : }
     592             : 
     593             : std::optional<std::reference_wrapper<mfem::ParGridFunction const>>
     594        1490 : MFEMProblem::getMeshDisplacementGridFunction()
     595             : {
     596             :   // If C++23 transform were available this would be easier
     597        1490 :   auto const displacement_variable = mesh().getMeshDisplacementVariable();
     598        1490 :   if (displacement_variable)
     599             :   {
     600          22 :     return *_problem_data.gridfunctions.Get(displacement_variable.value());
     601             :   }
     602             :   else
     603             :   {
     604        1468 :     return std::nullopt;
     605             :   }
     606             : }
     607             : 
     608             : void
     609           0 : MFEMProblem::rebalanceMesh(mfem::ParMesh & pmesh)
     610             : {
     611           0 :   if (pmesh.Nonconforming())
     612             :   {
     613           0 :     pmesh.Rebalance();
     614           0 :     updateFESpaces();
     615           0 :     updateGridFunctions();
     616             :   }
     617           0 : }
     618             : 
     619             : void
     620          13 : MFEMProblem::updateFESpaces()
     621             : {
     622          39 :   for (const auto & fe_space_pair : _problem_data.fespaces)
     623          26 :     fe_space_pair.second->Update();
     624          13 : }
     625             : 
     626             : void
     627          26 : MFEMProblem::updateGridFunctions()
     628             : {
     629          78 :   for (const auto & gridfunction_pair : _problem_data.gridfunctions)
     630          52 :     gridfunction_pair.second->Update();
     631          26 : }
     632             : 
     633             : std::vector<VariableName>
     634           0 : MFEMProblem::getAuxVariableNames()
     635             : {
     636           0 :   return systemBaseAuxiliary().getVariableNames();
     637             : }
     638             : 
     639             : MFEMMesh &
     640       65840 : MFEMProblem::mesh()
     641             : {
     642             :   mooseAssert(ExternalProblem::mesh().type() == "MFEMMesh",
     643             :               "Please choose the MFEMMesh mesh type for an MFEMProblem\n");
     644       65840 :   return static_cast<MFEMMesh &>(_mesh);
     645             : }
     646             : 
     647             : const MFEMMesh &
     648        3049 : MFEMProblem::mesh() const
     649             : {
     650        3049 :   return const_cast<MFEMProblem *>(this)->mesh();
     651             : }
     652             : 
     653             : void
     654         187 : MFEMProblem::addSubMesh(const std::string & var_type,
     655             :                         const std::string & var_name,
     656             :                         InputParameters & parameters)
     657             : {
     658         374 :   auto & mfem_submesh = *addObject<MFEMSubMesh>(var_type, var_name, parameters).front();
     659             :   // Register submesh.
     660         187 :   getProblemData().submeshes.Register(var_name, mfem_submesh.getSubMesh());
     661         187 : }
     662             : 
     663             : void
     664         664 : MFEMProblem::addTransfer(const std::string & transfer_name,
     665             :                          const std::string & name,
     666             :                          InputParameters & parameters)
     667             : {
     668         664 :   if (parameters.getBase() == "MFEMSubMeshTransfer")
     669         687 :     addObject<MFEMExecutedObject>(transfer_name, name, parameters);
     670             :   else
     671         435 :     ExternalProblem::addTransfer(transfer_name, name, parameters);
     672         664 : }
     673             : 
     674             : void
     675        1086 : MFEMProblem::addInitialCondition(const std::string & ic_name,
     676             :                                  const std::string & name,
     677             :                                  InputParameters & parameters)
     678             : {
     679        2172 :   addObject<MFEMExecutedObject>(ic_name, name, parameters);
     680        1086 : }
     681             : 
     682             : void
     683        9993 : MFEMProblem::executeMFEMObjects(const ExecFlagType & exec_type)
     684             : {
     685        9993 :   std::vector<MFEMExecutedObject *> objects;
     686        9993 :   theWarehouse()
     687        9993 :       .query()
     688        9993 :       .condition<AttribSystem>("MFEMExecutedObject")
     689        9993 :       .condition<AttribExecOns>(exec_type)
     690       19986 :       .condition<AttribThread>(0)
     691        9993 :       .queryInto(objects);
     692             : 
     693        9993 :   std::map<std::string, const MFEMExecutedObject *> suppliers;
     694       13745 :   for (auto * const object : objects)
     695        7506 :     for (const auto & item : object->getSuppliedItems())
     696             :     {
     697        3754 :       const auto [it, inserted] = suppliers.emplace(item, object);
     698        3754 :       if (!inserted && it->second != object)
     699           2 :         mooseError("MFEM executed-object dependency ambiguity on ",
     700             :                    exec_type,
     701             :                    ": both '",
     702           2 :                    it->second->name(),
     703             :                    "' and '",
     704           2 :                    object->name(),
     705             :                    "' supply '",
     706             :                    item,
     707             :                    "'.");
     708             :     }
     709             : 
     710       13741 :   for (auto * const object : objects)
     711             :   {
     712        3750 :     object->initialize();
     713        3750 :     object->execute();
     714        3750 :     object->finalize();
     715             : 
     716        3750 :     if (auto * const pp = dynamic_cast<const Postprocessor *>(object))
     717             :     {
     718        1170 :       _reporter_data.finalize(pp->PPName());
     719        1170 :       setPostprocessorValueByName(pp->PPName(), pp->getValue());
     720             :     }
     721             : 
     722        3750 :     if (auto * const vpp = dynamic_cast<VectorPostprocessor *>(object))
     723         646 :       _reporter_data.finalize(vpp->PPName());
     724             :   }
     725        9995 : }
     726             : 
     727             : std::string
     728        1461 : MFEMProblem::solverTypeString(const unsigned int libmesh_dbg_var(solver_sys_num))
     729             : {
     730             :   mooseAssert(solver_sys_num == 0, "No support for multi-system with MFEM right now");
     731             : 
     732        1461 :   std::vector<std::string> solvers;
     733             : 
     734        1461 :   if (getProblemData().nonlinear_solver)
     735          42 :     solvers.push_back(MooseUtils::prettyCppType(getProblemData().nonlinear_solver.get()));
     736             : 
     737        1461 :   if (getProblemData().jacobian_solver)
     738             :   {
     739         979 :     solvers.push_back(MooseUtils::prettyCppType(getProblemData().jacobian_solver.get()));
     740         979 :     if (const auto * prec = getProblemData().jacobian_solver->GetPreconditioner())
     741         867 :       solvers.push_back(MooseUtils::prettyCppType(prec));
     742             :   }
     743             : 
     744        5369 :   return solvers.empty() ? "None" : MooseUtils::stringJoin(solvers);
     745        1461 : }
     746             : 
     747             : bool
     748         105 : MFEMProblem::hasMFEMObject(const std::string & system, const std::string & name) const
     749             : {
     750         105 :   std::vector<MooseObject *> objs;
     751         105 :   theWarehouse()
     752         105 :       .query()
     753         105 :       .condition<AttribSystem>(system)
     754         210 :       .condition<AttribThread>(0)
     755         105 :       .condition<AttribName>(name)
     756         105 :       .queryInto(objs);
     757         210 :   return !objs.empty();
     758         105 : }
     759             : 
     760             : #endif

Generated by: LCOV version 1.14