MOOSE Newsletter (February 2023)

MOOSE Improvements

New MultiApp general field transfers

General field transfers have been added to the framework. They are a re-implementation of existing transfers with additional functionalities, based on libMesh's generic projector. The documentation for the base class explains all the features (siblings transfers, spatial restrictions, higher order variables, etc.) which are supported. The specific instances implemented are:

Two additional execution flags (execute_on) have been added to MOOSE: MULTIAPP_FIXED_POINT_BEGIN and MULTIAPP_FIXED_POINT_END. These execution schedules are executed once at the beginning and the end of the fixed point iterations between MultiApps, respectively, and are related to the fixed point iterations between the current app and its subapps, not between the current app and its parent app. A few notable uses for these flags include:

  • limiting the transfer of one field to once per time step during a fixed point iteration. The field will not be part of the tight coupling and will effectively be lagged during the fixed point iterations

  • performing fixed point iterations with one app and not the other. The MultiApp executed on MULTIAPP_FIXED_POINT_BEGIN/END will only be executed once, while the other MultiApp will be executed on each fixed point iteration.

New parameter: transform a MultiApp frame of reference

A new parameter has been added to all MultiApps to execute them in a transformed frame of reference: "run_in_position". This will apply the coordinate transformation (rotations and scaling defined in the MultiApp [Mesh] block, and translation from the "positions" parameter) to the MultiApps' mesh. Unless a coordinate transformation is also specified in the parent app's [Mesh] block, this parameter makes the child and parent app execute in the same frame of reference.

Ability to rename parameters in derived objects and new deprecation APIs

We have added the ability to rename a parameter, using the renameParam/renameCoupledVar APIs on an InputParameters object. This is meant to be used by derived classes in validParams to give more specificity than that granted by more general base class parameter names. The APIs take three arguments, the first being the old/base-class parameter name, the second being the new/derived-class parameter name, and the third being the new documentation string for the renamed parameter.

New deprecation APIs have also been added to InputParameters that use the same underlying machinery that the renameParam/renameCoupledVar APIs use. The new deprecation APIs are deprecateParam and deprecateCoupledVar. These APIs also take three arguments, with the difference from the rename* APIs being that the third argument is a string corresponding to the removal_date instead of a documentation string.

An example of use of the new deprecation APIs is in ParsedAux::validParams:


  params.addRequiredCustomTypeParam<std::string>(
      "function", "FunctionExpression", "Parsed function expression to compute");
  params.deprecateParam("function", "expression", "02/07/2024");
  params.addCoupledVar("args", "Vector of coupled variable names");
  params.deprecateCoupledVar("args", "coupled_variables", "02/07/2024");

When the deprecation period is over the code-block can be simplified by simply swapping the new name into the deprecated name and removing the deprecation calls:


  params.addRequiredCustomTypeParam<std::string>(
      "expression", "FunctionExpression", "Parsed function expression to compute");
  params.addCoupledVar("coupled_variables", "Vector of coupled variable names");

The machinery underlying the new rename and deprecate APIs allows object code to simply use the new names as opposed to checking for both deprecated/base-class and new/blessed parameters. For instance this code in the ParsedAux constructor


  if (isCoupled("args"))
    for (std::size_t i = 0; i < _nargs; ++i)
    {
      auto * const field_var = getFieldVar("args", i);
      variables += (i == 0 ? "" : ",") + field_var->name();
    }
  else
    for (std::size_t i = 0; i < _nargs; ++i)
    {
      auto * const field_var = getFieldVar("coupled_variables", i);
      variables += (i == 0 ? "" : ",") + field_var->name();
    }

has now simplified to


  for (std::size_t i = 0; i < _nargs; ++i)
    variables += (i == 0 ? "" : ",") + getFieldVar("coupled_variables", i)->name();

As a final note, deprecation messages printed to the screen should be improved. The location of the use of the deprecated parameter in the file is now printed, and we no longer print the stack trace. The latter finished in frames related to the Parser class, which is of no use to the user in resolving their deprecated parameter use.

Post-processor added to query solid properties

ThermalSolidPropertiesPostprocessor was added to the solid properties module, which allows users to query a given property from a ThermalSolidProperties object at a temperature given by a post-processor value.

Improved the ability to mark the converged solution invalid

We have improved the recently-added capability that allows a user to mark a solution as "invalid". Once marked invalid, the system allows output of which object triggered the invalidity as well as how many times the warning occurs. An invalid solution means that the solution somehow does not satisfy requirements, such as a value being out of the bounds of a correlation. Solutions are allowed to be invalid during the nonlinear solve - but are not allowed to be invalid once it converges. A "converged" solution that is marked as invalid will cause MOOSE to behave as if the solution did NOT converge - including cutting back timesteps, etc. A macro, flagInvalidSolution, is provided to declare a solution as "invalid". The macro allows for a user-defined short description of the object (optional) and a message to describe the invalidity.

Performance Improvements for Navier-Stokes Finite Volume Simulations

The automatic porosity jump handling feature introduced in the last newsletter slowed down Navier-Stokes finite volume simulations. A representative example was the mixing length channel test in the incompressible finite volume test suite, which went from a run-time of ~100 seconds to ~121 seconds on a twice-refined mesh. To combat this slowing, we introduced several optimizations including:

  • Building a boundary ID to Dirichlet boundary condition map during the simulation's initial setup as opposed to querying for boundary conditions every time a new face is visited

  • Disabling pre-initialized data computation when only the on-the-fly functor system is used

  • Caching the degree of freedom indices and re-using them when the same element is repeatedly visited

With these changes, the same mixing length test (twice refined) reduced its run-time to ~83 seconds, a 20% improvement over the pre-porosity-jump treatment behavior, and a 45% improvement over the post-porosity-jump treatment behavior.

Bug Fixes and Minor Enhancements

  • SimpleFluidProperties has been further developed to better support the (specific volume, specific energy) variable set used in the thermal_hydraulics module.

  • The HFEM flavor using Lagrange multipliers on lower-dimensional elements now supports distributed meshes.

  • The Bounds system was extended from supporting only first order Lagrange variables to also supporting constant monomial variables, including support for finite volume variables.