fluent转载内容
本节内容来源自网络,作者总结的很好,特此收藏。若有侵权立即删除。
Fluent UDF【3】:环境配置
发表于 2019-10-22 | 分类于 后端 | 没有评论
windows操作系统下UDF的编译需要借助Visual Studio中的C编译器。因此若要想编译UDF,则必须事先配置好编译环境。
Visual Stuido(后面简称VS)是微软开发的一款程序设计IDE,可以用于windows环境下计算机软件的开发。以下内容来自百度百科
:
Microsoft Visual Studio(简称VS)是美国微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等。所写的目标代码适用于微软支持的所有平台,包括Microsoft Windows、Windows Mobile、Windows CE、.NET Framework、.NET Compact Framework和Microsoft Silverlight 及Windows Phone。
Visual Studio各版本列表:转存失败重新上传取消
名称 | 内部版本 | 发布日期 |
---|---|---|
visual studio | 4.0 | 1995-04 |
visual studio 97 | 5.0 | 1997-02 |
visual studio 6.0 | 6.0 | 1998-06 |
visual studio.Net 2002 | 7.0 | 2002-02 |
visual studio.Net 2003 | 8.0 | 2003-04 |
visual studio 2005 | 8.0 | 2005-11 |
visual studio 2008 | 9.0 | 2007-11 |
visual studio 2010 | 10.0 | 2010-04 |
visual studio 2012 RTM | 11.0 | 2012-08 |
visual studio 2013 | 12.0 | 2013-10 |
visual studio 2015 | 14.0 | 2014-11 |
visual studio 2015 RTM | 14.0 | 2015-07 |
visual studio 2017 | 15.0 | 2017-03 |
经常有小伙伴询问与Fluent搭配的VisualStudio版本,其实并不存在什么版本搭配的问题,一般情况下只要VS能够正常安装及使用,通过环境设置后都可以作为UDF的编译器。
Fluent12.0之后的版本推荐使用VS2005之后的版本。推荐VS2010版本,我Fluent 18.0搭配使用的是VS2015版本,从未发现编译器方面的问题。
udf.bat文件
12.0之后版本的Fluent环境变量配置依赖于UDF.bat文件。如下图所示。转存失败重新上传取消
通过勾选选项Set up Compilation Environment for UDF
,之后设置udf.bat文件即可完成配置。
这里来看看udf.bat文件的内容。打开udf.bat文件可以看到其实该文件是一个设置环境变量的工作。
最重要的是下面几行,我这里以visual studio 2015为例。
该宏以参数作为返回值,因此需要事先通过real x[ND_ND]
定义参数x。程序片段如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ cell_tc; real x[ND_ND]; real y; thread_loop_c(t,d) { begin_c_loop_all(c,t) { C_CENTROID(x,c,t); y = x[1]; ... } } } |
2 C_VOLUME
C_VOLUME
宏用于获取网格单元体积。
1 2 3 4 |
{ real vol; vol = C_VOLUME(c,t); } |
3 C_NNODES
C_NNODES
宏用于获取单元体内节点数量。
4 C_NFACES
C_NNODES
宏用于获取单元体内网格面的数量。
计算单元内部物理量的梯度的宏,通常以_G
为后缀,如计算温度梯度C_T_G
。
注意:梯度变量仅在相关变量被求解后才可用。
如:当定义了能量源项后,UDF中能够利用宏C_T_G
访问单元温度,然而却不能使用C_U_G
宏访问x方向速度梯度。主要 原因在于求解器为了考虑计算效率,在求解时从内存中去除了不被使用的数据。如果一定要保留这些梯度数据,可以使用TUI命令solve/set/expert
,之后在系统提示Keep temporary solver memory from being freed?
后输入yes
。这样的话所有的梯度数据都会被保留,但是计算过程中会消耗更多的内存。
可以使用此方式调用梯度宏:
1 2 |
real xtG = C_T_G(c,t)[0]; |
梯度访问宏包括:
宏 | 参数 | 返回值 |
---|---|---|
C_P_G(c,t) | cell_t c, Thread *t | 压力梯度向量 |
C_U_G(c,t) | cell_t c, Thread *t | u速度梯度向量 |
C_V_G(c,t) | cell_t c, Thread *t | v速度梯度向量 |
C_W_G(c,t) | cell_t c, Thread *t | w速度梯度向量 |
C_T_G(c,t) | cell_t c, Thread *t | 温度梯度向量 |
C_H_G(c,t) | cell_t c, Thread *t | 焓梯度向量 |
C_NUT_G(c,t) | cell_t c, Thread *t | 湍流粘度梯度向量 |
C_K_G(c,t) | cell_t c, Thread *t | 湍动能梯度向量 |
C_D_G(c,t) | cell_t c, Thread *t | 湍动能耗散率梯度向量 |
C_O_G(c,t) | cell_t c, Thread *t | 比耗散率梯度向量 |
C_YI_G(c,t,i) | cell_t c, Thread *t,int i | 组分质量分数梯度向量 |
注意:
- C_P_G只能用于压力基求解器。
- C_YI_G只能用于密度基求解器,若要在压力基中使用此宏,则需要设置’species/save-gradients?为#t
5 物理量参数范围
可以通过宏访问网格单元内的物理量参数,如获取密度、压力、速度等。这些宏在头文件mem.h中定义。
宏 | 参数 | 返回值 |
---|---|---|
C_R(c,t) | cell_t c, Thread *t | real,密度 |
C_P(c,t) | cell_t c, Thread *t | real,压力 |
C_U(c,t) | cell_t c, Thread *t | real,u速度 |
C_V(c,t) | cell_t c, Thread *t | real,v速度 |
C_W(c,t) | cell_t c, Thread *t | real,w速度 |
C_T(c,t) | cell_t c, Thread *t | real,温度 |
C_H(c,t) | cell_t c, Thread *t | real,焓 |
C_K(c,t) | cell_t c, Thread *t | real,湍动能 |
C_NUT(c,t) | cell_t c, Thread *t | real,湍流粘度 |
C_D(c,t) | cell_t c, Thread *t | real,湍动能耗散率 |
C_O(c,t) | cell_t c, Thread *t | real,比耗散率 |
C_YI(c,t,i) | cell_t c, Thread *t,int i | real,组分质量分数 |
C_IGNITE(c,t) | cell_t c, Thread *t | real,点火质量分数 |
C_PREMIXC_T(c,t) | cell t c, Thread *t | 预混燃烧温度 |
C_STORAGE_R(c,t,nv) | cell_t c, Thread *t, real nv | 变量nv的值 |
6 梯度计算宏
-
设置visualstudio的安装路径
转存失败重新上传取消
通常在udf.bat文件中只需要修改这一行就可以了。我将visual studio 2015的安装路径赋值给MSVC_DEFAULT
,如图直接修改就行。
分析该批处理文件,意思是若能在该文件路径下找到vcvarsall.bat文件,则设置MSCV值为MSVC_DEFAULT,否则转到msvc_env140。一般情况下只要在安装Visual Studio的时候选择了安装C++的话,这文件都会存在。
真正实现c文件编译的工作是在vcvarsall.bat文件中指定的。该文件中的内容不要动。总结
UDF编译环境配置其实非常简单,只需要修改UDF.bat文件即可,实际上只需要将本机Visual Studio的安装路径写进去就可以了。
-
Fluent UDF【5】:第一个UDF
发表于 2019-10-02 | 分类于 后端 | 没有评论
这里以一个简单的初始化案例来描述UDF的使用过程。
Fluent中提供了全域初始化以及局部Patch功能。对于整体区域的全局初始化可以采用starndard及hybrid方法进行初始化,指定各种物理量的初始分布。而对于计算域中的局部区域初始化,则可以通过Patch功能来实现。
在使用Patch方法时,需要实现对要进行Patch的区域进行标记。选择Mark/Adapt Cells→Region...
可弹出区域定义对话框。
可以在弹出的对话框中设置几何条件来Mark区域。
然而在此对话框中可定义的形状类型只有三种:Quad、Circle或Cylinder,在3D模型中对应的是Hex、Sphere以及Cylinder。对于更复杂的模型似乎无能为力。此时可以借助UDF来解决问题。1 案例描述
如下图所示的矩形区域为计算区域,其初始温度为300K。计算模型尺寸如图所示。
图中红色部分为要进行初始化处理的椭圆区域,其初始温度为500K。2 网格
网格如图所示。
3 编写UDF
对于这种椭圆形区域的初始化,只能采用UDF来实现。利用DEFINE_INIT宏来实现这种区域的标记工作。
本案例中椭圆方程为:
$$
frac{(x-0.05)^2}{0.03^2}+frac{(x-0.03)^2}{0.015^2} =1
$$
因此可编写UDF如下。4 编译UDF
利用User Defined标签页下的Function→Compiled…,Fluent软件会弹出UDF编译对话框。
在弹出的对话框中利用Add…按钮添加UDF源文件,点击Build按钮进行编译,并点击按钮Load加载UDF。
本案例也可以采用解释的方式运行。5 Hook UDF
UDF编译完成后,需要将UDF加载到Fluent中。这部分工作可以通过相应的GUI来实现。
DEFINE_INIT宏需要在User Defined标签页下的Funcition Hooks…中进行加载。
选择此按钮后打开UDF加载对话框。6 查看结果
在查看初始化结果之前,需要开启相应的模型。由于本案例初始化的是温度变量,所以必须首先开启能量方程。
之后进行初始化。
初始化完毕后可以查看温度云图分布,如下图所示。
可以看到椭圆形区域初始温度设置为500K。
按同样的道理,可以初始化任何形状的区域,只要这些区域可以用数学函数来表达。 -
Fluent UDF【11】:单元数据访问宏
发表于 2019-10-17 | 分类于 人工智能 | 没有评论
自己选的主题,哭着也要更新完。
单元数据要比节点数据复杂得多。与节点数据仅仅存储节点坐标不同,单元数据中不仅包含单元中心节点等,还包含有各种物理量数据。单元数据访问宏返回网格单元内的信息。大部分的单元宏在头文件
metric.h
中定义,这类的宏均以C_
作为前缀。宏
C_CENTROID
用于获取网格单元中心坐标。 - 宏调用形式:C_CENTROID(x,c,t)
- 宏参数:real x[ND_ND], cell_t c, Thread *t
- 数据返回:以参数x传址调用返回
- 宏调用形式:C_VOLUME(c,t)
- 宏参数:cell_t c, Thread *t
- 数据返回:返回real值
- 调用形式:C_NNODE(c,t)
- 参数:cell_t c, Thread *t
- 数据返回:返回int类型的节点数量
- 调用形式:C_NFACES(c,t)
- 参数:cell_t c, Thread *t
- 数据返回:返回int类型的网格面数量
计算单元内部物理量的梯度的宏,通常以_G
为后缀,如计算温度梯度C_T_G
。
注意:梯度变量仅在相关变量被求解后才可用。
如:当定义了能量源项后,UDF中能够利用宏C_T_G
访问单元温度,然而却不能使用C_U_G
宏访问x方向速度梯度。主要 原因在于求解器为了考虑计算效率,在求解时从内存中去除了不被使用的数据。如果一定要保留这些梯度数据,可以使用TUI命令solve/set/expert
,之后在系统提示Keep temporary solver memory from being freed?
后输入yes
。这样的话所有的梯度数据都会被保留,但是计算过程中会消耗更多的内存。
可以使用此方式调用梯度宏:
1 2 |
real xtG = C_T_G(c,t)[0]; |
梯度访问宏包括:
宏 | 参数 | 返回值 |
---|---|---|
C_P_G(c,t) | cell_t c, Thread *t | 压力梯度向量 |
C_U_G(c,t) | cell_t c, Thread *t | u速度梯度向量 |
C_V_G(c,t) | cell_t c, Thread *t | v速度梯度向量 |
C_W_G(c,t) | cell_t c, Thread *t | w速度梯度向量 |
C_T_G(c,t) | cell_t c, Thread *t | 温度梯度向量 |
C_H_G(c,t) | cell_t c, Thread *t | 焓梯度向量 |
C_NUT_G(c,t) | cell_t c, Thread *t | 湍流粘度梯度向量 |
C_K_G(c,t) | cell_t c, Thread *t | 湍动能梯度向量 |
C_D_G(c,t) | cell_t c, Thread *t | 湍动能耗散率梯度向量 |
C_O_G(c,t) | cell_t c, Thread *t | 比耗散率梯度向量 |
C_YI_G(c,t,i) | cell_t c, Thread *t,int i | 组分质量分数梯度向量 |
注意:
- C_P_G只能用于压力基求解器。
- C_YI_G只能用于密度基求解器,若要在压力基中使用此宏,则需要设置’species/save-gradients?为#t
Fluent UDF【13】:循环操作宏
发表于 2019-10-15 | 分类于 后端 | 没有评论
UDF使用过程中,经常要通过循环遍历的方式对数据进行操作,如设置边界条件时,需要给每一个边界网格面赋值,此时需要通过逐层循环的方式访问每一个边界网格面。Fluent UDF中提供了众多循环来实现此功能。这些宏包括:
- 区域中单元循环
thread_loop_c
- 区域中网格面循环
thread_loop_f
- 单元中单元循环
begin...end_c_loop
- 面中面循环
begin...end_f_loop
- 单元中面循环
c_face_loop
- 单元中的节点循环
c_node_loop
- 单元面中的节点循环
f_node_loop
利用thread_loop_c在指定domain中遍历所有的网格单元(cell)。使用方式非常简单,如下:
1 2 3 4 5 6 7 |
Domain *domain; Thread *c_thread; thread_loop_c(c_thread,domain) { ... } |
遍历区域中的网格面
利用宏thread_loop_f来遍历domain中的所有网格面(face)。与遍历网格单元类似的使用。如:
1 2 3 4 5 6 |
Thread *f_thread; Domain *domain; thread_loop_f(f_thread,domain) { /*对网格面进行操作*/ } |
遍历网格单元集合中的所有单元
使用宏begin_c_loop及end_c_loop对所给定的网格单元集合中的所有单元进行遍历。
使用方式:
1 2 3 4 5 6 7 |
cell_t c; Thread *c_thread; begin_c_loop(c, c_thread) { } end_c_loop(c, c_thread) |
例如下面程序计算c_thread中的所有单元的温度和:
1 2 3 4 5 |
begin_c_loop(c, c_thread) { temp += C_T(c, c_thread); } end_c_loop(c, c_thread) |
遍历面集合中的所有面
利用宏begin_f_loop与end_f_loop来遍历给定face集合中的所有网格面。
使用方式:
1 2 3 4 5 6 |
face_t f; Thread *f_thread; begin_f_loop(f, f_thread) { } end_f_loop(f, f_thread) |
以下例程计算给定网格几何f_thread上的所有网格面上温度总和。
1 2 3 4 5 |
begin_f_loop(f, f_thread) { temp += F_T(f, f_thread); } end_f_loop(f, f_thread) |
遍历一个网格单元上的所有面
利用宏c_face_loop来实现遍历网格单元上的所有网格面。如:
1 2 3 4 5 6 7 8 9 10 |
cell_t c; Thread *t; face_t f; Thread *tf; int n; c_face_loop(c, t, n) /* loops over all faces of a cell */ { f = C_FACE(c,t,n); tf = C_FACE_THREAD(c,t,n); } |
遍历网格单元中的节点
利用宏c_node_loop来实现遍历网格单元中的所有网格节点。
1 2 3 4 5 6 7 8 |
cell_t c; Thread *t; int n; Node *node; c_node_loop(c,t,n) { node = C_NODE(c,t,n); } |
遍历网格面中的所有节点
利用宏f_node_loop来实现此目的。
1 2 3 4 5 6 7 8 |
face_t f; Thread *t; int n; Node *node; f_node_loop(f,t,n) { node = F_NODE(f,t,n); } |
Fluent UDF【14】:向量操作宏
发表于 2019-10-04 | 分类于 后端 | 没有评论
CFD计算中存在众多的向量,典型的如速度、角速度等。向量的运算要比标量运算复杂,UDF提供了众多的向量操作宏用于向量的运算。
对于这些向量操作宏,UDF头文件中对这些宏的名称进行了区分。如宏名称中包含v,则表示为向量,S表示为标量,D表示为向量的三个分量序列,在2D模型中,第三个分量被忽略。矢量函数不遵循括号、指数、乘法、除法、加法和减法(PEMDAS)的运算顺序约定。 取而代之的是利用下划线(_)符号将操作数分组成对,以便在成组之前对元素执行操作。
UDF中使用较多的ND操作宏包括:ND_ND、ND_SUM及ND_SET。
1.1 ND_ND宏
ND_ND为常数,在2D模型中其值为2,在3D模型中其值为3。
注意:ND_ND宏的值不可以改变。如下语句ND_ND=1是错误的。在实际应用过程中,把ND_ND当做是数字。
如下语句定义了一个矩阵:
1 |
real A[ND_ND][ND_ND]; |
1.2 ND_SUM宏
ND_SUM宏用于计算其参数的和。
如代码:
1 |
ND_SUM(x,y,z); |
在2D模型中,其等效于:
1 |
x+y; |
而在3D模型中,其等效于:
1 |
x+y+z; |
1.3 ND_SET宏
ND_SET宏用于设置其参数。如:
1 |
ND_SET(u,v,w,C_U(c,t),C_V(c,t),C_W(c,t)); |
在2D模型中,其等效为:
1 2 |
u = C_U(c,t); v = C_V(c,t); |
在3D模型中,其等效为:
1 2 3 |
u = C_U(c,t); v = C_V(c,t); w = C_W(c,t); |
2 NV宏
NV宏与ND宏类似,只不过NV宏操作的是向量。
2.1 NV_V宏
NV_V宏进行向量赋值操作。如代码:
1 |
NV_V(a, = , x); |
其等效于:
1 2 3 |
a[0] = x[0]; a[1] = x[1]; a[2] = x[2]; |
宏中间的操作符可以是+=,此时则换为:
1 2 3 |
a[0] += x[0]; a[1] += x[1]; a[2] += x[2]; |
2.2 NV_VV宏
NV_VV宏能实现向量元素操作。如代码:
1 |
NV_VV(a , = , x , + , y); |
则其等效于:
1 2 |
a[0] = x[0] + y[0]; a[1] = x[1] + y[1]; |
2.3 NV_V_VS宏
此宏可用于向量与标量的乘积运算。如:
1 |
NV_V_VS(a, = , x, + , y, *, 0.5); |
等效于:
1 2 |
a[0] = x[0] + y[0] * 0.5; a[1] = x[1] + y[1] * 0.5; |
2.4 NV_VS_VS宏
矢量与标量的混合运算。如:
1 |
NV_VS_VS(a, =, x, *, 2.0, +, y, *, 0.5); |
此语句等效于:
1 2 |
a[0] = (x[0]*2.0) + (y[0]*0.5); a[1] = (x[1]*2.0) + (y[1]*0.5); |
3 向量操作宏
向量操作宏可用于向量的求模运算、点乘与叉乘运算。
3.1 NV_MAG及NV_MAG2
这两个宏用于求取向量的模及模的平方。如宏NV_MAG示例:
1 |
NV_MAG(x); |
等效于:
1 2 |
2D中: sqrt(x[0]*x[0] + x[1]*x[1]); 3D中: sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); |
而NV_MAG2则计算向量的模的平方。如:
1 |
NV_MAG2(x); |
等效于:
1 2 |
2D: (x[0]*x[0] + x[1]*x[1]); 3D: (x[0]*x[0] + x[1]*x[1] + x[2]*x[2]); |
3.2 NV_DOT宏
NV_DO宏用于向量的点积。可以有多种用法,如下示例:
1 2 3 4 5 6 7 8 9 10 11 |
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); |
3.3 向量叉乘
向量叉乘比较麻烦。如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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 and 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); |