Example 8 : Material Properties

MOOSE includes built-in support for creating and sharing material properties thorughout your simulation calculations. Material property calculations are run/updated by MOOSE automatically for every quadrature point. Kernels, Postprocessors, and other objects all have convenient access to these properties. This example demonstrates a convection-diffusion problem with kernels that utilize custom non-linear material properties.

Problem Statement

This problem considers the same coupled system from Example 3:

(1)

but with slightly different boundary conditions: on the bottom boundary and and on the top boundary. The remaining boundaries taking the natural boundary condition. is a diffusivity coefficient and is a convection coefficient derived from the coupled diffusion equation.

Creating Material Objects

You create custom material properties by writing your own Material class:

#include "Material.h"
#include "LinearInterpolation.h"

class ExampleMaterial;

template <>
InputParameters validParams<ExampleMaterial>();

class ExampleMaterial : public Material
{
public:
  ExampleMaterial(const InputParameters & parameters);

protected:
  virtual void computeQpProperties() override;
(examples/ex08_materials/include/materials/ExampleMaterial.h)

The ExampleMaterial object couples to the gradient of the "diffused" variable and uses this to make the "convection_velocity" material property. It also uses tabulated values specified in its input file parameters and the z-coordinate of the current quadrature point to linearly interpolate values for a "diffusivity" property. We need to create member variables to hold the material properties in addition to ones for helping compute those property values:

private:
  /// member variable to hold the computed diffusivity coefficient
  MaterialProperty<Real> & _diffusivity;
  /// member variable to hold the computed convection velocity gradient term
  MaterialProperty<RealGradient> & _convection_velocity;

  /// A place to store the coupled variable gradient for calculating the convection velocity
  /// property.
  const VariableGradient & _diffusion_gradient;

  /// A helper object for performaing linear interpolations on tabulated data for calculating the
  /// diffusivity property.
  LinearInterpolation _piecewise_func;
};

#endif // EXAMPLEMATERIAL_H
(examples/ex08_materials/include/materials/ExampleMaterial.h)

Then we need to specify appropriate input file parameters for users and write code that retrieves the data for use in calculations:

#include "ExampleMaterial.h"

registerMooseObject("ExampleApp", ExampleMaterial);

template <>
InputParameters
validParams<ExampleMaterial>()
{
  InputParameters params = validParams<Material>();

  // Allow users to specify vectors defining the points of a piecewise function formed via linear
  // interpolation.
  params.addRequiredParam<std::vector<Real>>(
      "independent_vals",
      "The vector of z-coordinate values for a piecewise function's independent variable");
  params.addRequiredParam<std::vector<Real>>(
      "dependent_vals", "The vector of diffusivity values for a piecewise function's dependent");

  // Allow the user to specify which independent variable's gradient to use for calculating the
  // convection velocity property:
  params.addCoupledVar(
      "diffusion_gradient",
      "The gradient of this variable will be used to compute a velocity vector property.");

  return params;
}

ExampleMaterial::ExampleMaterial(const InputParameters & parameters)
  : Material(parameters),
    // Declare that this material is going to provide a Real value typed
    // material property named "diffusivity" that Kernels and other objects can use.
    // This property is "bound" to the class's "_diffusivity" member.
    _diffusivity(declareProperty<Real>("diffusivity")),

    // Also declare a second "convection_velocity" RealGradient value typed property.
    _convection_velocity(declareProperty<RealGradient>("convection_velocity")),

    // Get the reference to the variable coupled into this Material.
    _diffusion_gradient(isCoupled("diffusion_gradient") ? coupledGradient("diffusion_gradient")
                                                        : _grad_zero),

    // Initialize our piecewise function helper with the user-specified interpolation points.
    _piecewise_func(getParam<std::vector<Real>>("independent_vals"),
                    getParam<std::vector<Real>>("dependent_vals"))
{
}

void
(examples/ex08_materials/src/materials/ExampleMaterial.C)

The computeQpProperties function is where we put the code for actually calculating the material property values. It will be automatically called by MOOSE at the right times and for each quadrature point. When we calculate a material property value, we "set" it by storing the calculated value in the member variable that was bound to the corresponding property in the class's constructor (i.e. _diffusivity and _convection_velocity):

void
ExampleMaterial::computeQpProperties()
{
  // Diffusivity will be the value of the (linearly-interpolated) piece-wise function described by
  // the user.
  _diffusivity[_qp] = _piecewise_func.sample(_q_point[_qp](2));

  // Convection velocity is set equal to the gradient of the variable set by the user.
  _convection_velocity[_qp] = _diffusion_gradient[_qp];
}
(examples/ex08_materials/src/materials/ExampleMaterial.C)

Plumbing Into Materials

In order to use the material properties we created, we need objects (e.g. our Kernels) to actually support reading information from material properties. For this problem, the ExampleDiffusion kernel will use a "diffusivity" material property coefficient provided by our ExampleMaterial class/object. To do this we to have special code in three places:

  • A member variable to store the material property value:

    
      const MaterialProperty<Real> & _diffusivity;
    

  • A line in our constructor to bind our material property member to the value that is computed by the actual Material object:

    
    ExampleDiffusion::ExampleDiffusion(const InputParameters & parameters)
      : Diffusion(parameters), _diffusivity(getMaterialProperty<Real>("diffusivity"))
    {
    }
    

  • Code that uses the material property to calculate something (e.g. our residual and jacobian):

    
    Real
    ExampleDiffusion::computeQpResidual()
    {
      return _diffusivity[_qp] * Diffusion::computeQpResidual();
    ...
    

Instead of directly coupling another variable into the convection kernel to use as the velocity gradient term as in Example 3, we will instead use a "convection_velocity" material property to provide the gradient in the ExampleConvection kernel. Just like for ExampleDiffusion we make the three changes resulting in ExampleConvection.C looking something like this:

ExampleConvection::ExampleConvection(const InputParameters & parameters)
  : Kernel(parameters),
    // Retrieve and store gradient from a material property to use for the convection velocity
    _velocity(getMaterialProperty<RealGradient>("convection_velocity"))
{
}

Real
ExampleConvection::computeQpResidual()
{
  // Use the velocity gradient just like before in example 3
  return _test[_i][_qp] * (_velocity[_qp] * _grad_u[_qp]);
}

Real
ExampleConvection::computeQpJacobian()
{
  return _test[_i][_qp] * (_velocity[_qp] * _grad_phi[_j][_qp]);
}
(examples/ex08_materials/src/kernels/ExampleConvection.C)

Using Material Properties

Material properties now give us the flexibility to change/tweak our problem details without requiring code modifications and compiling every time. Changing how the convection velocity term is computed requires nothing more than changing Material objects we are using. Different materials can also be applied to different subdomains/blocks in your mesh. Let's see how we can use our material properties in an input file:

[Materials]
  [./example]
    type = ExampleMaterial
    block = 'fuel'
    diffusion_gradient = 'diffused'

    # Approximate Parabolic Diffusivity
    independent_vals = '0 0.25 0.5 0.75 1.0'
    dependent_vals = '1e-2 5e-3 1e-3 5e-3 1e-2'
  [../]

  [./example1]
    type = ExampleMaterial
    block = 'deflector'
    diffusion_gradient = 'diffused'

    # Constant Diffusivity
    independent_vals = '0 1.0'
    dependent_vals = '1e-1 1e-1'
  [../]
[]
(examples/ex08_materials/ex08.i)

In ex08.i, there are two material objects with each applied to a separate named subdomain of the mesh via the block = '...' lines. These objects will provide the "diffused" and "convection_velocity" properties that our convection and diffusion kernels now look for.

Results

Convection

Diffusion

Complete Source Files