• The UserObject system provides data and calculation results to other MOOSE objects.
  • All Postprocessors are UserObjects that compute a single scalar value.
  • Therefore, a UserObject can be thought of as a more generic Postprocessor with more functionality.
  • UserObjects define their own interface, which other MOOSE objects can call to retrieve data.
  • Just like Postprocessors, there are 4 types of UserObjects:
    • ElementUserObject - perform evaluations on each element.
    • NodalUserObject - perform evaluations on each node.
    • SideUserObject - perform evaluations on each side.
    • GeneralUserObject - a generic object that can do "anything" while providing a common interface for use by other MOOSE objects.
  • For example, a GeneralUserObject might read in a large data set, hold it in memory, and provide an interface for Material classes to access the data.

UserObject Anatomy

All UserObjects must override the following functions:

virtual void initialize();
  • Called just one time before beginning the UserObject calculation.
  • Useful for resetting data structures.
virtual void execute();
  • Called once on each geometric object (element, node or side) or just one time per calculation for a GeneralUserObject.
  • This is where you actually do your calculation, read data, etc.

virtual void threadJoin(const UserObject & y);
  • During threaded execution this function is used to "join" together calculations generated on different threads.
  • In general you need to cast y to a const reference of your type of UserObject, then extract data from - y} and add it to the data in "this" object.
  • Note, this is not required for a GeneralUserObject because it is not threaded.
virtual void finalize();
  • The very last function called after all calculations have been completed.
  • In this function, the user must take all of the small calculations performed in execute() and do some last operation to get the final values.
  • Be careful to do parallel communication where necessary to ensure all processors compute the same values.

  • A UserObject defines its own interface by defining const accessor functions.
  • When another MOOSE object uses a UserObject, they do so by calling these accessor functions.
  • For example, if a UserObject is computing the average value of a variable on every block in the mesh, it might provide a function like:
Real averageValue(SubdomainID block) const;
  • Another MOOSE object using this UserObject would then call averageValue() to get the result of the calculation.
  • Take special note of the const at the end of the function declaration!
  • This means the function cannot modify any member variables of the object, and is required for UserObject accessors functions.

Using a UserObject

  • Any MOOSE object can retrieve a UserObject in a manner similar to retrieving a Function.
  • Generally, it is a good idea to take the name of the UserObject to use from the input file:
template<>
InputParameters validParams<BlockAverageDiffusionMaterial>()
{
  InputParameters params = validParams<Material>();
  params.addRequiredParam<UserObjectName>("block_average_userobject", "Doc");
  return params;
}

A UserObject comes through as a const reference of the UserObject type. So, in your object:

const BlockAverageValue & _block_average_value;

The reference is set in the initialization list of your object by calling the templated getUserObject() method:

BlockAverageDiffusionMaterial::BlockAverageDiffusionMaterial(const InputParameters & parameters) :
    Material(parameters),
    _block_average_value(getUserObject<BlockAverageValue>("block_average_userobject"))
{}

Use the reference by calling some of the interface functions defined by the UserObject:

_diffusivity[_qp] = 0.5 * _block_average_value.averageValue(_current_elem->subdomain_id());

Example 20

Built-in UserObjects