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

Generated by: LCOV version 1.14