Step 5: Develop a Kernel Object

In this step, the basic components of Kernel Objects will be presented. To demonstrate their use, a new Kernel will be created to solve Darcy's Pressure equation, whose weak form was derived in the previous step. The concept of class inheritance shall also be demonstrated, as the object to solve Darcy's equation will inherit from the ADKernel class.

Kernel Objects

The Kernels System in MOOSE is one for computing the residual contribution from a volumetric term within a PDE using the Galerkin FEM. One way to identify kernels is to check which term(s) in a weak form expression are multiplied by the gradient of the test function , or to check those which represent an integral over the whole domain .

In Listing 1, notice that the ADDiffusion object is declared as one that inherits from the ADKernelGrad base class, which, in turn, inherits from the ADKernel base class. This means that ADDiffusion is a unique object that builds upon what the MOOSE Kernels system is designed to do.

Listing 1: Syntax defining the ADDiffusion class as an object which inherits from the ADKernelGrad class.

class ADDiffusion : public ADKernelGrad
(framework/include/kernels/ADDiffusion.h)
commentnote:Automatic Differentiation

"AD" (often used as a prefix for class names) stands for "Automatic Differentiation," which is a feature available to MOOSE application developers that drastically simplifies the implementation of new a MooseObject.

Now, one might inspect the files that provide the base class, i.e., ADKernel.h and ADKernel.C, to see what tools are available and decide how to properly implement a new object of this type. Variable members that ADKernel objects have access to include, but are not limited to, the following:

  • _u, _grad_u
    Value and gradient of the variable being operated on.

  • _test, _grad_test
    Value () and gradient () of the test function.

  • _i
    Current index for the test function component.

  • _q_point
    Coordinates of the current quadrature point.

  • _qp
    Current quadrature point index.

There are several methods that ADKernel (and Kernel) objects may override. The most important ones are those which work to evaluate the kernel term in the weak form and they are explained in Table 1.

Table 1: Methods used by different types of Kernel objects that compute the residual term.

BaseOverrideUse
Kernel
ADKernel
computeQpResidualUse when the term in the PDE is multiplied by both the test function and the gradient of the test function (_test and _grad_test must be applied)
KernelValue
ADKernelValue
precomputeQpResidualUse when the term computed in the PDE is only multiplied by the test function (do not use _test in the override, it is applied automatically)
KernelGrad
ADKernelGrad
precomputeQpResidualUse when the term computed in the PDE is only multiplied by the gradient of the test function (do not use _grad_test in the override, it is applied automatically)

For this step, the method to be aware of is precomputeQpResidual(); the same one used by ADDiffusion. The "Qp" stands for "quadrature point," which is a characteristic feature of the Gaussian quadrature. These are the points at which the weak form of a PDE is numerically integrated. Finite elements usually contain multiple quadrature points at specific, symmetrically placed locations and the Gauss quadrature formula is a summation over all of these points that yields an exact value for the integral of a polynomial over .

Demonstration

In the previous step, it was shown that the weak form of the Darcy pressure equation is the following:

(1)

Eq. (1) must satisfy the following BVP: at the inlet (left) boundary, at the outlet (right) boundary, and on the remaining boundaries. Therefore, it is possible to drop the second term in Eq. (1) and express it, more simply, as

(2)

where is a scalar and was substituted under the assertion that the permeability be isotropic, such that the full tensor may be consolidated into a single value. It was specified on the Problem Statement page that the viscosity of the fluid (water) is . Also, assume that the isotropic permeability represents the 1 mm steel sphere medium inside the pipe (obtained by setting in Problem Statement, Eq. (8)).

Source Code

To evaluate Eq. (2), a new ADKernelGrad object can be created and it shall be called DarcyPressure. Start by making the directories to store files for objects that are part of the Kernels System:

cd ~/projects/babbler
mkdir include/kernels src/kernels

In include/kernels, create a file named DarcyPressure.h and add the code given in Listing 2. Here, the DarcyPressure class was defined as a type of ADKernelGrad object, and so the header file ADKernelGrad.h was included. A MooseObject must have a validParams() method and a constructor, and so these were included as part of the public members. The precomputeQpResidual() method was overridden so that Eq. (2) may set its returned value in accordance with Table 1. Finally, two variables, _permeability and _viscosity, were created to store the values for and , respectively, and were assigned const types to ensure that their values aren't accidentally modified after they are set by the constructor method.

Listing 2: Header file for the DarcyPressure object.


#pragma once

// Including the "ADKernel" base class here so we can extend it
#include "ADKernelGrad.h"

/**
 * Computes the residual contribution: K / mu * grad_test * grad_u.
 */
class DarcyPressure : public ADKernelGrad
{
public:
  static InputParameters validParams();

  DarcyPressure(const InputParameters & parameters);

protected:
  /// ADKernel objects must override precomputeQpResidual
  virtual ADRealVectorValue precomputeQpResidual() override;

  /// The variables which hold the value for K and mu
  const Real _permeability;
  const Real _viscosity;
};

In src/kernels, create a file named DarcyPressure.C and add the code given in Listing 3. Here, the header file for this object was included. Next, the registerMooseObject() method was called for "BabblerApp" and the DarcyPressure object. The validParams() method is the subject of the next step, so, for now, it is okay to simply copy and paste its definition. In the constructor method the _permeability and _viscosity attributes were set according to the values that were given earlier. Finally, the precomputeQpResidual() method was programmed to return the left-hand side of Eq. (2), except that the (_grad_test) term is automatically handled by the base class.

Listing 3: Source file for the DarcyPressure object.


#include "DarcyPressure.h"

registerMooseObject("BabblerApp", DarcyPressure);

InputParameters
DarcyPressure::validParams()
{
  InputParameters params = ADKernelGrad::validParams();
  params.addClassDescription("Compute the diffusion term for Darcy pressure ($p$) equation: "
                             "$-\\nabla \\cdot \\frac{\\mathbf{K}}{\\mu} \\nabla p = 0$");

  return params;
}

DarcyPressure::DarcyPressure(const InputParameters & parameters)
  : ADKernelGrad(parameters),

    // Set the coefficients for the pressure kernel
    _permeability(0.8451e-09),
    _viscosity(7.98e-04)
{
}

ADRealVectorValue
DarcyPressure::precomputeQpResidual()
{
  return (_permeability / _viscosity) * _grad_u[_qp];
}

Since the source code has been modified, the executable must be recompiled:

cd ~/projects/babbler
make -j4

Input File

Instead of the ADDiffusion class, the problem model should now use DarcyPressure. In the pressure_diffusion.i input file, which was created in Step 2, replace the [Kernels] block with the following:

[Kernels]
  [diffusion]
    type = DarcyPressure # Zero-gravity, divergence-free form of Darcy's law
    variable = pressure # Operate on the "pressure" variable from above
  []
[]

Now, execute the input file:

cd ~/projects/babbler/problems
../babbler-opt -i pressure_diffusion.i

Results

Visualize the solution with PEACOCK and confirm that it resembles that which is shown in Figure 1:

cd ~/projects/babbler/problems
~/projects/moose/python/peacock/peacock -r pressure_diffusion_out.e

Figure 1: Rendering of the FEM solution of Darcy's pressure equation subject to the given BVP.

One should be convinced that, because this is a steady-state problem, where the coefficient is constant and since the foregoing BVP is a simple one that involves only essential boundary conditions, the solution produced by the new DarcyPressure object, shown in Figure 1, is identical to the previous one produced by the ADDiffusion object.

Commit

Add the two new files, DarcyPressure.h and DarcyPressure.C, to the git tracker and update the pressure_diffusion.i file:

cd ~/projects/babbler
git add include/kernels src/kernels problems/pressure_diffusion.i

Now, commit and push the changes to the remote repository:

git commit -m "developed kernel to solve Darcy pressure and updated the problem input file"
git push