Multi Sample Action System

This system allows any object to be turned into an action that generates _N_ copies of the object using a simple registration macro like so


#include "MultiSampleAction.h"
#include "ThermalBaseTest.h"

registerMultiSampleAction("BisonTestApp", ThermalBaseTest, "add_material");

This generates a MultiSampleThermalBaseTest object. It can be registered to MOOSE syntax with another macro in the registerAll function of the app. E.g.


registerMultiSampleSyntax(ThermalBaseTest);

This will enable the following syntax

[MultiSample<<<{"href": "index.html"}>>>]
  [GeneratedMeshGenerator<<<{"href": "GeneratedMeshGenerator/index.html"}>>>]
    [mymesh]
      multi_sample_number_params<<<{"description": "List of Real value parameters to set for the generated objects"}>>> = 'xmin xmax'
      multi_sample_number_values<<<{"description": "List of Real or Integer value vectors for each parameter, multi_sample_size entries each"}>>> = "0 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9;
                            1 2.1 3.2 4.3 5.4 6.5 7.6 8.7 9.8 10.9"
      dim<<<{"description": "The dimension of the mesh to be generated"}>>> = 2
      nx<<<{"description": "Number of elements in the X direction"}>>> = 3
      ny<<<{"description": "Number of elements in the Y direction"}>>> = 3
    []
  []

  [MultiSampleMeshCombiner<<<{"href": "MultiSampleMeshCombiner/index.html"}>>>]
    [mymesh]
    []
  []

  [DirichletBC<<<{"href": "DirichletBC/index.html"}>>>]
    [leftbc]
      multi_sample_number_params<<<{"description": "List of Real value parameters to set for the generated objects"}>>> = value
      multi_sample_number_values<<<{"description": "List of Real or Integer value vectors for each parameter, multi_sample_size entries each"}>>> = '1 2 3 4 5 6 7 8 9 10'
      value<<<{"description": "Value of the BC"}>>> = 0
      boundary<<<{"description": "The list of boundary IDs from the mesh where this object applies"}>>> = left
      variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = u
    []
    [rightbc]
      multi_sample_number_params<<<{"description": "List of Real value parameters to set for the generated objects"}>>> = value
      multi_sample_number_values<<<{"description": "List of Real or Integer value vectors for each parameter, multi_sample_size entries each"}>>> = '-1 -2 -3 -4 -5 -6 -7 -8 -9 -10'
      value<<<{"description": "Value of the BC"}>>> = 0
      boundary<<<{"description": "The list of boundary IDs from the mesh where this object applies"}>>> = right
      variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = u
    []
  []
[]
(test/tests/multi_sample_action/test.i)

The example above will create 10 3x3 element meshes side by side, with the boundary_name_prefix set to mesh and the sample number, resulting in boundary names of the form mesh2_left, mesh6_bottom , etc. Using the MultiSampleMeshCombiner the results from those mesh generators are combined into a single simulation mesh.

Using the MultiSample/DirichletBC different boundary conditions are applied to each sample. Note that this action prefixes the boundary parameter in the same manner as the MultiSample/GeneratedMeshGenerator.

If several Real (or integer) valued parameters are specified in multi_sample_number_params multiple value vectors (separated by ;) must be provided in multi_sample_number_values.

Modifying object parameters programmatically

If parameters need to be modified that are not of type Real (such as the block restriction of the generated object) a functor like object can be created to programmatically assign parameter values. The MSABlockEnumerator object sets separate block restrictions for each generated object:

class MSABlockEnumerator : public MultiSampleParameterModifier
{
  // This operator sets a different block number for each generated instance.
public:
  static void modify(unsigned int i, InputParameters & params)
  {
    params.set<std::vector<SubdomainName>>("block") = {Moose::stringify(i)};
  }
};
(src/actions/MultiSampleAction.C)

you can explicitly provide this object, using the advanced registerMultiSampleActionCustom macro.

commentnote

Setting the block restriction is required for MultiSample Material classes to avoid duplicate material property declaration on the same block!

Instead of MSABlockEnumerator a custom class, derived from MultiSampleParameterModifier can be provided to set parameters of arbitrary types based on the index of the generated object.

class MultiSampleParameterModifier
{
public:
  static void modify(unsigned int /*sample_index*/, InputParameters & /*params*/){};
  static void valid(InputParameters & /*params*/){};
};
(src/actions/MultiSampleAction.C)
  • void modify(unsigned int /*sample_index*/, InputParameters & /*params*/)

    The modify function can be used to change any parameter value that will passed to the object created for sample sample_index. It can be used to prefix name parameters with the sample index, compute parameter values based on the sample index.

  • valid(InputParameters & /*params*/)

    The valid function can be used to modify the set of valid input parameters returned by the underlying object's validParams function. See below for an example.

Required parameters

The MOOSE parser will complain, if the underlying objects created by a MultiSample action have required parameters that are not explicitly specified, for example because they are set using the multi_sample_number_params/multi_sample_number_values parameters. In this case the MultiSampleParameterModifier::valid(InputParameters &) interface can be used to make parameters as not required, as shown in MSASubdomainID:

class MSASubdomainID : public MultiSampleParameterModifier
{
public:
  static void modify(unsigned int i, InputParameters & params)
  {
    params.set<MeshGeneratorName>("input") += "_" + Moose::stringify(i);
    params.set<SubdomainID>("subdomain_id") = i;
  }
  static void valid(InputParameters & params)
  {
    params.makeParamNotRequired<SubdomainID>("subdomain_id");
  };
};
(src/actions/MultiSampleAction.C)

registerMultiSampleActionCustom("BisonTestApp", ThermalBaseTest, "add_material", MSABlockEnumerator)

Extending support for more systems

This is the compile error if an object from a yet unsupported system is registered as a MultiSampleAction:


bison/build/header_symlinks/MultiSampleAction.h:132:11: error: static assertion failed:
 =====================================================================================
 An object from an unsupported MOOSE system was supplied in registerMultiSampleAction.
 Add another if constexpr clause to MultiSampleAction<T, ParameterModifier>::act()
 with the corresponding add* call to FEProblem.
 =====================================================================================

  132 |           always_false_v<T>,
      |           ^~~~~~~~~~~~~~~~~

Should you encounter this error edit the if constexpr block in MultiSampleAction<T, ParameterModifier>::act() and add the correct FEProblemBase::add*() method for the new system you want to support.

    // add object to problem (add new systems here as needed)
    if constexpr (std::is_base_of_v<Kernel, T>)
      _problem->addKernel(type, obj_name, params);
    else if constexpr (std::is_base_of_v<AuxKernel, T>)
      _problem->addAuxKernel(type, obj_name, params);
    else if constexpr (std::is_base_of_v<BoundaryCondition, T>)
      _problem->addBoundaryCondition(type, obj_name, params);
    else if constexpr (std::is_base_of_v<Postprocessor, T>)
      _problem->addPostprocessor(type, obj_name, params);
    else if constexpr (std::is_base_of_v<Material, T>)
      _problem->addMaterial(type, obj_name, params);
    else if constexpr (std::is_base_of_v<MeshGenerator, T>)
      _app.addMeshGenerator(type, obj_name, params);
    else if constexpr (std::is_base_of_v<Action, T>)
    {
      auto action = MooseSharedNamespace::static_pointer_cast<MooseObjectAction>(
          _action_factory.create(type, obj_name, params));
      _awh.addActionBlock(action);
    }
    else
      static_assert(
          always_false_v<T>,
          "\n "
          "=====================================================================================\n "
          "An object from an unsupported MOOSE system was supplied in registerMultiSampleAction.\n "
          "Add another if constexpr clause to MultiSampleAction<T, ParameterModifier>::act()\n "
          "with the corresponding add* call to FEProblem.\n "
          "====================================================================================="
          "\n");
(include/actions/MultiSampleAction.h)