前述章节 UDF 案例中穿插应用了一些向量和维度宏(如定义数组x[ND_ND]
),Fluent 提供了一些预定义宏来处理二维和三维问题,并对向量进行操作运算。本文将系统介绍这类向量运算和维度处理宏。
在 UDF 中处理二维和三维表达式的方法有两种。第一种方法是使用显式方法,在条件语句中使用 RP_2D
和 RP_3D
来控制UDF的编译运行;第二种方法使用通用的 3D 表达式,并使用 ND
和 NV
宏在 2D 问题编译时删除 z 分量。NV 宏对向量进行操作, ND 宏对向量分量进行操作。
1. RP_2D 和 RP_3D 宏
在条件语句中使用 RP_2D 或 RP_3D 宏将指示编译器分别对RP宏标记部分进行编译。
示例:3D 问题中使用 RP_3D 对旋流项进行操作
#if RP_3D
/* 计算旋流项 */
#endif
2. ND 宏
在 UDF 中,可以使用 ND 宏来实现通用的维度表达式,根据问题维度的不同,ND宏会自动删除处理对应的向量分量。ND 宏适用于 2D 和 3D 情况,无需进行任何修改。
2.1. ND_ND
ND_ND
是一个整型常量,在二维问题下ND_ND=2
,三维问题ND_ND=3
。
该宏在UDF中使用比较频繁,例如前述章节定义一个数组储存面心坐标:
real FC[ND_ND]; //定义数组存储面心坐标,根据问题维度不同ND_ND取值不同
F_CENTROID(FC, face, face_thread); // 获取面 face 的质心坐标,并存储在 FC 数组中
fx = FC[0]; // 获取 x 坐标
fy = FC[1]; // 获取 y 坐标
如下 UDF 片段定义一个数组并对数组元素进行遍历赋值,使用ND_ND
操作宏使得代码在 2D 和 3D 模式下都能正确执行,而无需分别编写不同维度的代码。
// 定义一个数组 A
real A[ND_ND][ND_ND];
// 循环变量 i 和 j
int i, j;
// 外层循环:遍历数组的行
for (i = 0; i < ND_ND; ++i)
{
// 内层循环:遍历数组的列
for (j = 0; j < ND_ND; ++j)
{
// 将函数 f(i, j) 的返回值赋值给数组 A 的相应位置
A[i][j] = f(i, j);
}
}
2.2. ND_SUM
ND_SUM
宏用于计算 ND_ND
各分量和。
// 在 2D 模式下
real sum_2d = ND_SUM(x, y); // 结果为 x + y
// 在 3D 模式下
real sum_3d = ND_SUM(x, y, z); // 结果为 x + y + z
示例:
// 定义变量
real x = 1.0;
real y = 2.0;
real z = 3.0;
// 计算和
real sum;
// 在 2D 模式下,sum 将是 x + y
// 在 3D 模式下,sum 将是 x + y + z
sum = ND_SUM(x, y, z);
printf("The sum is: %f\n", sum);
2.3. ND_SET
ND_SET
用于生成 ND_ND
赋值语句。其根据当前模拟的维度(2D 或 3D),生成适当数量的赋值语句。
ND_SET(u, v, w, C_U(c, t), C_V(c, t), C_W(c, t))
// u = C_U(c, t);
// v = C_V(c, t);
#if RP_3D
// w = C_W(c, t);
#endif
UDF示例:
#include "udf.h"
DEFINE_ADJUST(set_velocity_components, domain)
{
cell_t c;
Thread *t;
real u, v, w;
/* 遍历所有单元格 */
begin_c_loop(c, t)
{
/* 使用 ND_SET 宏生成适当的赋值语句 */
ND_SET(u, v, w, C_U(c, t), C_V(c, t), C_W(c, t));
/* 现在可以使用 u, v, w 进行其他操作 */
message("Velocity components: u = %f, v = %f, w = %f\n", u, v, w);
}
end_c_loop(c, t)
}
3. NV 宏
前述 ND 宏是对向量各分量进行操作,而 NV宏 则对维度为ND_ND
不同向量进行操作运算。
3.1. NV_V
NV_V
宏对两个向量执行操作。假设我们有两个向量 a
和 x
,并希望将 x
的值赋给 a
,我们可以使用以下代码:
NV_V(a, =, x);
这段代码在二维计算中相当于:
a[0] = x[0];
a[1] = x[1];
在三维计算中相当于:
a[0] = x[0];
a[1] = x[1];
a[2] = x[2];
3.2. NV_VV
NV_VV
宏对向量各分量执行操作。宏的调用形式为 NV_VV(a, =, x, +, y);
,其含义是在 a
向量的各个分量上执行指定操作,将 x
和 y
向量的相应分量根据操作符进行计算,并赋给 a
。执行的操作取决于宏调用中 +
号位置使用运算符号(如 -
、/
、*
)。
NV_VV(a, =, x, +, y)
// 2D: a[0] = x[0] + y[0], a[1] = x[1] + y[1];
3.3. NV_V_VS
NV_V_VS
宏用于执行向量与标量的乘积运算。
NV_V_VS(a, =, x, +, y, *, 0.5);
// 2D: a[0] = x[0] + (y[0]*0.5), a[1] = x[1] + (y[1]*0.5);
请注意,可以用 -、/
或 *
替换 +
号,*
号可以用 /
替换。
3.4. NV_VS_VS
NV_V_VS
宏用于执行向量与标量的混合运算。
NV_VS_VS(a, =, x, *, 2.0, +, y, *, 0.5);
// 2D:
a[0] = (x[0]*2.0) + (y[0]*0.5),
a[1] = (x[1]*2.0) + (y[1]*0.5);
//3D:
a[0] = (x[0]*2.0) + (y[0]*0.5);
a[1] = (x[1]*2.0) + (y[1]*0.5);
a[2] = (x[2]*2.0) + (y[2]*0.5);
同理,可以用 -、/
或 *
替换 +
号,*
号可以用 /
替换。
4. 向量运算宏
向量运算在 UDF 中的应用非常广泛,涵盖了从基础的速度和力的计算到复杂的涡度和轨迹分析等多个方面,在 UDF 中,可以使用一些宏来执行向量操作,例如计算向量的模、点积和叉积等。
4.1. 向量大小
NV_MAG
操作宏用于计算向量的模,即向量各分量平方和的平方根。
NV_MAG(x)
// 2D: sqrt(x[0]*x[0] + x[1]*x[1]);
// 3D: sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
使用示例:
real magnitude;
real vector[ND_ND] = {3.0, 4.0, 0.0}; // 一个三维向量,z 分量为 0 表示二维情况
magnitude = NV_MAG(vector);
NV_MAG2
操作宏用于计算向量各分量的平方和。
NV_MAG2(x)
// 2D: (x[0]*x[0] + x[1]*x[1]);
// 3D: (x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
4.2. 向量点积
ND_DOT
和 NV_DOT
用于计算两个向量的点积。ND_DOT
适用于分别提供的向量分量,而 NV_DOT
适用于向量数组。
ND_DOT(x, y, z, u, v, w)
// 2D: (x*u + y*v);
// 3D: (x*u + y*v + z*w);
NV_DOT(x, u)
// 2D: (x[0]*u[0] + x[1]*u[1]);
// 3D: (x[0]*u[0] + x[1]*u[1] + x[2]*u[2]);
NVD_DOT(x, u, v, w)
// 2D: (x[0]*u + x[1]*v);
// 3D: (x[0]*u + x[1]*v + x[2]*w);
4.3. 向量叉积
ND_CROSS
和 NV_CROSS
用于计算两个向量的叉积。对于二维情况,叉积的结果为零,因为在二维中,向量没有 z
分量。
ND_CROSS_X(x0, x1, x2, y0, y1, y2)
// 2D: 0.0
// 3D: (((x1)*(y2))-(y1)*(x2)))
ND_CROSS_Y(x0, x1, x2, y0, y1, y2)
// 2D: 0.0
// 3D: (((x2)*(y0))-(y2)*(x0)))
ND_CROSS_Z(x0, x1, x2, y0, y1, y2)
// 2D 和 3D: (((x0)*(y1))-(y0)*(x1)))
NV_CROSS_X(x, y)
ND_CROSS_X(x[0], x[1], x[2], y[0], y[1], y[2])
NV_CROSS_Y(x, y)
ND_CROSS_Y(x[0], x[1], x[2], y[0], y[1], y[2])
NV_CROSS_Z(x, y)
ND_CROSS_Z(x[0], x[1], x[2], y[0], y[1], y[2])
NV_CROSS(a, x, y)
// a[0] = NV_CROSS_X(x, y);
// a[1] = NV_CROSS_Y(x, y);
// a[2] = NV_CROSS_Z(x, y);