添加自定义内核

Example 2: Adding a Custom Kernel

概述

本例子基于例1用以说明如何创建自己的内核以添加新的物理场。

当您准备好为自己的物理/问题构建自定义物理和代码时,您应该在自己的基于MOOSE的应用程序中工作。

问题陈述

我们考虑三维域\(\Omega\)中的稳态流-扩散方程,

\[\begin{equation}\label{M-2} -\nabla \cdot \nabla u + \vec{v}\cdot \nabla u = 0 \in \Omega \end{equation}\]

底部\(u=1\),顶部\(u=0\),其余边界则是\(\nabla u \cdot \hat{n}=0\)。 速度\(\vec{v}\)是已知常数(在垂直方向为1,否则为0)

方程的弱形式(用内部相乘符号)如下:

\[\begin{equation}\label{M-3} (\nabla \phi_i , \nabla u_h )+(\vec{v}\cdot\nabla u , \phi_i ) = 0\ \ \forall \ \phi_i \end{equation}\]

其中\(\phi_i\)是测试函数,\(u_h\)是有限元的解。

创建流内核

该问题的流组件通过创建从存在的MOOSE对象中继承的C++对象来定义。

一般而言,向MOOSE添加一个新对象需要创建从合适的MOOSE对象中继承的C++对象,在这个情况下是内核。 示例如下(include/kernels/ExampleConvection.h):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#pragma once //告诉编译器在编译过程中只包含一次指定的头文件

#include "Kernel.h" //将名为 “Kernel.h” 的头文件包含到当前源文件中

/**
* 为如下的对流算子定义内核:
*
* (V . grad(u), test)
*
* where V 是给定的恒速度场。
*/
class ExampleConvection : public Kernel //类从Kernel继承,访问级别为公共
{
public: //构造函数是公共的
/**
* 这是构造函数声明; This class takes a
* 该类采用字符串和InputParameters对象,就像其他Kernel衍生类一样。
*/
ExampleConvection(const InputParameters & parameters);

/**
* validParams返回此内核接受/需要的参数
* 函数的实际主体必须在.C文件
*/
static InputParameters validParams(); //静态函数声明;返回类型;静态函数名称。

protected: //接下来声明的成员只能在当前类以及其派生类中访问
/**
* 负责计算一个正交点的残差。
* 该函数也必须在.C文件中定义。
*/
virtual Real computeQpResidual() override;

/**
* 负责计算预处理矩阵的对角线块。这本质上是残差的偏导数,对应于内核算符在("u")处的变化。
* 请注意,这可以是近似或线性化。在该情况下,不是由于该算符的Jacobian容易计算。
* 该函数也必须在.C文件中定义。
*/
virtual Real computeQpJacobian() override;

private:
/**
* 用于存储速度的矢量对象。 方便计算点乘
*/
RealVectorValue _velocity;
};

src/kernels/ExampleConvection.C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "ExampleConvection.h"

/**
* 您创建的所有基于MOOSE的对象类都必须使用此宏进行注册。
* 第一个参数是你输入的APP的名字,when 运行stork.sh脚本 with "APP"后缀。
* 如果你运行的是"stork.sh Example",则此处的参数将变成"ExampleApp"。
* 第二个参数是你创建的C++的类。
*/
registerMooseObject("ExampleApp", ExampleConvection);

/**
* 此函数定义了此内核的有效参数及其默认值。
*/
InputParameters
ExampleConvection::validParams()
{
InputParameters params = Kernel::validParams();
params.addRequiredParam<RealVectorValue>("velocity", "Velocity Vector");
return params;
}

ExampleConvection::ExampleConvection(const InputParameters & parameters)
: // 你必须先调用基类的构造函数。
Kernel(parameters),
_velocity(getParam<RealVectorValue>("velocity"))
{
}

Real
ExampleConvection::computeQpResidual()
{
// velocity * _grad_u[_qp] 实际上是做点乘
return _test[_i][_qp] * (_velocity * _grad_u[_qp]);
}

Real
ExampleConvection::computeQpJacobian()
{
// the partial derivative of _grad_u is just _grad_phi[_j]
return _test[_i][_qp] * (_velocity * _grad_phi[_j][_qp]);
}

输入文件语法

本示例与示例1的唯一区别在于,必须包含上面创建的自定义内核对象。由于这个新对象被注册了,它可以使用与扩散内核类似的语法进行访问。因此,输入文件中的[内核]块变成:

1
2
3
4
5
6
7
8
9
10
11
[Kernels]
[./diff]
type = Diffusion
variable = convected
[../]
[./conv]
type = ExampleConvection
variable = convected
velocity = '0.0 0.0 1.0'
[../]
[]

请注意,在本例中,变量名称也更改为对流。

运行该问题

1
2
3
cd ~/projects/moose/examples/ex02_kernel
make -j8
./ex02-opt -i ex02.i

这将生成结果文件out.e,如图所示。可以使用Peacock或支持Exodus II格式的外部应用程序(例如Paraview)查看此文件。