fluent UDF第3章.docx
《fluent UDF第3章.docx》由会员分享,可在线阅读,更多相关《fluent UDF第3章.docx(27页珍藏版)》请在冰豆网上搜索。
fluentUDF第3章
UDF第3章写UDF
本章主要概述了如何在FLUENT写UDF。
3.1概述
3.2写解释式UDF的限制
3.3FLUENT中UDF求解过程的顺序
3.4FLUENT网格拓扑
3.5FLUENT数据类型
3.6使用DEFINEMacros定义你的UDF
3.7在你的UDF源文件中包含udf.h文件
3.8定义你的函数中的变量
3.9函数体
3.10UDF任务
3.11为多相流应用写UDF
3.12在并行中使用你的UDF
3.1概述(Introduction)
UDF是用来增强FLUENT代码的标准功能的,在写UDF之前,我们要明确以下几个基本的要求。
首先,必须用C语言编写UDF。
必须使用FLUENT提供的DEFINE宏来定义UDF。
UDF必须含有包含于源代码开始指示的udf.h文件;它允许为DEFINEmacros和包含在编译过程的其它FLUENT提供的函数定义。
UDF只使用预先确定的宏和函数从FLUENT求解器访问数据。
通过UDF传递到求解器的任何值或从求解器返回到UDF的值,都指定为国际(SI)单位。
总之,当写UDF时,你必须记住下面的FLUENT要求。
UDF:
1.采用C语言编写。
2.必须为udf.h文件有一个包含声明。
3.使用Fluent.Inc提供的DEFINEmacros来定义。
4.使用Fluent.Inc提供的预定义宏和函数来访问FLUENT求解器数据。
5.必须使返回到FLUENT求解器的所有值指定为国际单位。
3.2写解释式UDF的限制(RestrictiononWritingInterpretedUDF)
无论UDF在FLUENT中以解释还是编译方式执行,用户定义C函数(说明在Section3.1中)的基本要求是相同的,但还是有一些影响解释式UDF的重大编程限制。
FLUENT解释程序不支持所有的C语言编程原理。
解释式UDF不能包含以下C语言编程原理的任何一个:
1.goto语句。
2.非ANSI-C原型语法
3.直接的数据结构查询(directdatastructurereferences)
4.局部结构的声明
5.联合(unions)
6.指向函数的指针(pointerstofunctions)
7.函数数组。
在访问FLUENT求解器数据的方式上解释式UDF也有限制。
解释式UDF不能直接访问存储在FLUENT结构中的数据。
它们只能通过使用Fluent提供的宏间接地访问这些数据。
另一方面,编译式UDF没有任何C编程语言或其它注意的求解器数据结构的限制。
3.3FLUENT求解过程中UDF的先后顺序(SequencingofUDFintheFLUENTSolutionProcess)
当你开始写UDF代码的过程时(依赖于你写的UDF的类型),理解FLUENT求解过程中UDF调用的内容或许是重要的。
求解器中包含连接你写的用户定义函数的call-outs。
知道FLUENT求解过程中迭代之内函数调用的先后顺序能帮助你在给定的任意时间内确定那些数据是当前的和有效的。
分离式求解器
在分离式求解器求解过程中(Figure3.3.1),用户定义的初始化函数(使用DEFINE_INIT定义的)在迭代循环开始之前执行。
然后迭代循环开始执行用户定义的调整函数(使用DEFINE_ADJUST定义的)。
接着,求解守恒方程,顺序是从动量方程和后来的压力修正方程到与特定计算相关的附加标量方程。
守恒方程之后,属性被更新(包含用户定义属性)。
这样,如果你的模型涉及到气体定律,这时,密度将随更新的温度(和压力and/or物质质量分数)而被更新。
进行收敛或者附加要求的迭代的检查,循环或者继续或停止。
Figure3.3.1:
分离解算器的解程序
耦合求解器
在耦合求解器求解过程中(Figure3.3.2),用户定义的初始化函数(使用DEFINE_INIT定义的)在迭代循环开始之前执行。
然后,迭代循环开始执行用户定义的调整函数(使用DEFINE_ADJUST定义的)。
接着,FLUENT求解连续、动量和(适合的地方)能量的控制方程和同时地一套物质输运或矢量方程。
其余的求解步骤与分离式求解器相同(Figure3.3.1)。
Figure3.3.2:
SolutionProcedurefortheCoupledSolver
3.4FLUENT网格拓扑
在我们开始讨论FLUENT特殊的数据类型之前,你必须理解网格拓扑学的术语因为FLUENT数据类型是为这些实体定义的。
下面是显示在Figure3.4.1中的网格实体的定义。
单元(cell)区域被分割成的控制容积
单元中心(cellcenter)FLUENT中场数据存储的地方
面(face)单元(2Dor3D)的边界
边(edge)面(3D)的边界
节点(node)网格点
单元线索(cellthread)在其中分配了材料数据和源项的单元组
面线索(facethread)在其中分配了边界数据的面组
节点线索(nodethread)节点组
区域(domain)由网格定义的所有节点、面和单元线索的组合
Figure3.4.1:
GridTerminology
3.5FLUENT数据类型
除了标准的C语言数据类型如real,int等可用于在你的UDF中定义数据外,还有几个FLUENT指定的与求解器数据相关的数据类型。
这些数据类型描述了FLUENT中定义的网格的计算单位(见Figure3.4.1)。
使用这些数据类型定义的变量既有代表性地补充了DEFINEmacros的自变量,也补充了其它专门的访问FLUENT求解器数据的函数。
一些更为经常使用的FLUENT数据类型如下:
cell_t
face_t
Thread
Domain
Node
cell_t是线索(thread)内单元标识符的数据类型。
它是一个识别给定线索内单元的整数下标。
face_t是线索内面标识符的数据类型。
它是一个识别给定线索内面的整数下标。
Thread数据类型是 FLUENT中的数据结构。
它充当了一个与它描述的单元或面的组合相关的数据容器。
Node数据类型也是FLUENT中的数据结构。
它充当了一个与单元或面的拐角相关的数据容器。
Domain数据类型代表了FLUENT中最高水平的数据结构。
它充当了一个与网格中所有节点、面和单元线索组合相关的数据容器。
!
!
注意,FLUENT中所有数据类型都是情形敏感的(case-sensitive)。
3.6使用DEFINEMacros定义你的UDF
Fluent.Inc为你提供了一套你必须使用它来定义你的UDF的预定义函数。
这些定义UDF的函数在代码中作为宏执行,可在作为DEFINE(全部大写)宏的文献中查阅。
对每个DEFINE宏的完整描述和它的应用例子,可参考第四章。
DEFINE宏的通用格式为:
DEFINE_MACRONAME(udf_name,passed-invariables)
这里括号内第一个自变量是你的UDF的名称。
名称自变量是情形敏感的必须用小写字母指定。
一旦函数被编译(和连接),你为你的UDF选择的名字在FLUENT下拉列表中将变成可见的和可选的。
第二套输入到DEFINE宏的自变量是从FLUENT求解器传递到你的函数的变量。
在下面的例子中,宏
DEFINE_PROFILE(inlet_x_velocity,thread,index)
用两个从FLUENT传递到函数的变量thread和index定义了名字为inlet_x_velocity的分布函数。
这些passed-in变量是边界条件区域的ID(作为指向thread的指针)而index确定了被存储的变量。
一旦UDF被编译,它的名字(例如,inlet_x_velocity)将在FLUENT适当的边界条件面板(例如,VelocityInlet面板)的下拉列表中变为可见的和可选的。
!
!
注意,所有用于DEFINE宏的自变量必须放在你的源代码的同一行上。
分割DEFINE的声明为几行可能导致编译错误。
3.7在你的UDF源文件中包含udf.h文件(Includingtheudf.hFileinYourUDFSourceFile)
DEFINE宏的定义位于称为udf.h(见附录A的列表)的头文件中。
为了使DEFINE宏延伸到编译过程,你必须在你写的每个UDF源文件的开始包含udf.h 文件。
#include"udf.h"
/*Alwaysincludeudf.hwhenwritingaUDF.IttranslatestheDEFINE*/
/*andothermacrosintoC,whichiswhatthecompilerunderstands.*/
通过在你的UDF源文件中包含udf.h,编译过程中所有的DEFINE宏的定义与源代码一起被包含进来。
udf.h文件也为所有的C库函数头文件包含#include指示,与大部分头文件是针对Fluent提供的宏和函数是一样的(例如,mem.h)。
除非有另外的指示,没必要在你的UDF中个别地包含这些头文件。
还有,当你编译你的UDF时,你不必放置udf.h的拷贝在你的当地目录下;一旦你的UDF被编译,FLUENT求解器会自动地从Fluent.Inc/fluent6.x/src/目录来读取udf.h文件。
举例
从前面部分的宏
DEFINE_PROFILE(inlet_x_velocity,thread,index)
定义在udf.h文件中为
#defineDEFINE_PROFILE(name,t,i)voidname(Thread*t,inti)
在编译过程中延伸为
voidinlet_x_velocity(Thread*thread,intindex)
名字为inlet_x_velocity的函数不返回值由于它被声明为空的数据类型。
3.8在你的函数中定义变量(DefiningVariableinYourFunction)
在你的UDF源文件中包含了udf.h头文件后,你必须定义真实的变量。
使用把它们定义在所有函数之外的全局变量(如果它们被源文件中大部分或所有函数共享)是非常方便的。
关于全局变量的信息见Section2.5.3。
局部于函数的任何变量必须在函数内声明。
局部变量的信息见Section2.5.2。
3.9函数体(FunctinBody)
你的UDF源文件中的C函数体被包含在DEFINE声明之下的一对大括号内,显示在下面的例子中。
在这个例子中,mu_lan和temp是局部变量。
只有cell_viscosity函数认识它们。
例子
DEFINE_PROPERTY(cell_viscosity,cell,thread)
{
realmu_lam;
realtemp=C_T(cell,thread);
if(temp>288.)
mu_lam=5.5e-3;
elseif(temp>286.)
mu_lam=143.2135-0.49725*temp;
else
mu_lam=1.;
returnmu_lam;
}
3.10UDF任务(UDFTasks)
UDF可执行的任务有五种不同的类型:
1.返回值
2.修改自变量
3.返回值和修改自变量
4.修改FLUENT变量(不能作为自变量传递)
5.写信息到(或读取信息从)case或data文件
函数能返回值,除非它们在udf.h文件中被定义为void。
如果它们不返回值,它们能修改自变量,修改存储在内存中的变量,或与case和data文件一起执行输入输出(I/O)任务。
在Section3.10.1-3.10.5中,提供了描述上面提到的五种不同的函数任务中每一种的UDF源代码例子。
3.10.1返回值的函数(FunctionthatReturnaValue)
下面的UDF是一个返回值到FLUENT求解器的函数例子。
名为cell_viscosity的函数计算了依赖温度的粘度值(mu_lam)并返回这个值到求解器。
/********************************************************************/
/*UDFthatreturnsavaluetothesolver*/
/*Specifiesatemperature-dependentviscosityproperty*/
/********************************************************************/#include"udf.h"
DEFINE_PROPERTY(cell_viscosity,cell,thread)
{
realmu_lam;
realtemp=C_T(cell,thread);
if(temp>288.)
mu_lam=5.5e-3;
elseif(temp>286.)
mu_lam=143.2135-0.49725*temp;
else
mu_lam=1.;
returnmu_lam;
}
cell_viscosity使用了DEFINE_PROPERTY宏(在Section4.3.6中描述)来定义。
DEFINE_PROPERTY返回一个udf.h中指定的real数据类型。
两个real变量传入函数:
通过函数计算的层流粘度mu_lam;和C_T(cell,thread)的值,它是在考虑中的单元的温度值。
温度值在它下降范围的基础上被检测,mu_lam的适当值被计算。
在函数结尾,mu_lam的计算值被返回。
3.10.2修改自变量的函数(FunctionthatModifyanArgument)
下面的UDF是一个修改一个自变量的函数的例子。
名字为user_rate的函数为一个两种气态物质的的简单系统产生一个自定义的体积反应速率。
Real指针rr作为自变量传递给函数,指针指向的变量在函数内被修改。
/**************************************************************/
/*UDFthatmodifiesoneofitsarguments*/
/*Specifiesareactionrateinaporousmedium*/
/**************************************************************/
#include"udf.h"
#defineK12.0e-2
#defineK25.
DEFINE_VR_RATE(user_rate,c,t,r,mole_weight,species_mf,rr,rr_t)
{
reals1=species_mf[0];
realmw1=mole_weight[0];
if(FLUID_THREAD_P(t)&&THREAD_VAR(t).fluid.porous)
*rr=K1*s1/pow((1.+K2*s1),2.0)/mw1;
else
*rr=0.;
}
user_rate使用了DEFINE_VR_RATE宏(见Section4.3.14)来定义。
该函数执行一个当前考虑的单元是否在多孔区域的测试,这个反应速率只应用于多孔区域。
real指针变量rr是一个传递给函数的自变量。
UDF使用废弃操作符*分配反应速率值给废弃指针*rr。
指针rr指向的目标是设置反应速率。
通过这个操作,存储在内存中这个指针上的字符的地址被改变了,不再是指针地址本身。
(关于废弃指针的详细内容见[3])。
3.10.3返回一个值和修改一个自变量的函数(FunctionsthatReturnaValueansModifyanArgument)
下面的UDF是一个修改它的自变量并返回一个值到FLUENT求解器的函数例子。
名字为user_swirl的函数修改ds自变量,指定旋转速度源项并返回它到求解器。
/**************************************************************/
/*UDFthatreturnsavalueandmodifiesanargument*/
/*Specifiesaswirl-velocitysourceterm*/
/**************************************************************/
#include"udf.h"
#defineOMEGA50./*rotationalspeedofswirler*/
#defineWEIGHT1.e20/*weightingcoefficientsinlinearizedequation*/
DEFINE_SOURCE(user_swirl,cell,thread,dS,eqn)
{
realw_vel,x[ND_ND],y,source;
C_CENTROID(x,cell,thread);
y=x[1];
w_vel=y*OMEGA;/*linearw-velocityatthecell*/
source=WEIGHT*(w_vel-C_WSWIRL(cell,thread));
dS[eqn]=-WEIGHT;
returnsource;
}
user_swirl使用DEFINE_SOURCE宏来定义(在Section4.3.8中描述)。
DEFINE_SOURCE返回一个在udf.h中指定的数据类型。
函数采用自变量ds(它是数组的名字)并设置由eqn指定的元素为关于
速度(w_vel)导数的值。
(这是z动量方程源项)。
这个函数也计算了旋转速度源项的值source,并返回这个值到求解器。
3.10.4修改FLUENT变量的函数
下面的UDF是一个修改存储在内存中FLUENT变量的函数例子。
名字为inlet_x_velocity的函数使用F_PROFILE(aFluentInc.providedutility(应用程序)“Translateby金山词霸”)来修改存储在内存中的x速度分布边界条件。
/********************************************************************/
/*UDFthatmodifiesaFLUENTsolvervariable*/
/*Specifiesasteady-statevelocityprofileboundarycondition*/
/********************************************************************/
#include"udf.h"
DEFINE_PROFILE(inlet_x_velocity,thread,index)
{
realx[ND_ND];/*thiswillholdthepositionvector*/
realy;
face_tf;
begin_f_loop(f,thread)
{
F_CENTROID(x,f,thread);
y=x[1];
F_PROFILE(f,thread,index)=20.-y*y/(.0745*.0745)*20.;
}
end_f_loop(f,thread)
}
inlet_x_velocity使用DEFINE_PROFLIE宏来定义(在Section4.3.5中描述)。
它的自变量是thread和index。
Thread是一个指向面线索的指针,而index是一个每个循环内为变量设置数值标签的整数。
DEFINE_PROPERTY在udf.h文件中一个返回void的数据类型。
函数由声明变量f作为face_t数据类型开始。
一维数组x和变量y是real数据类型。
循环宏用来在区域中每个面上循环以创建型线或数据数组。
在每个循环内,F_CENTROID为含有indexf的面输出面质心的值(数组x),indexf在由thread指向的线索上。
存储在x[1]中的y坐标分配给变量y,它用于计算x速度。
然后这个值分配给F_PROFILE,它使用整数index(由求解器传递个它)来设置内存中面上的x速度值。
3.10.5写入Case或Data文件或从中读取的函数(FunctionsthatWritetoorReadfromaCaseorDataFile)
下面的C源代码包含了写信息到data文件和读回它的函数例子。
这是一个包含多个连接在一起的UDF的单个C文件例子。
/******************************************************************/
/*UDFthatincrementavariable,writeittoadatafile*/
/*andreaditbackin*/
/******************************************************************/
#include"udf.h"
intkount=0;/*defineglobalvariablekount*/
DEFINE_ADJUST(demo_calc,domain)
{
kount++;
printf("kount=%d\n",kount);
}
DEFINE_RW_FILE(writer,fp)
{
printf("WritingUDFdatatodatafile...\n");
fprintf(fp,"%d",kount);/*writeoutkounttodatafile*/
}
DEFINE_RW_FILE(reader,fp)
{
printf("ReadingUDFdatafromdatafile...\n");
fscanf(fp,"%d",&kount);/*readkountfromdatafile*/
}
在顶部的列表中,整数kount被定义为全局的(由于它被源代码文件中的所有三个函数使用)并初始化为0。
名字为demo_calc的第一个函数,使用DEFINE_SDJUST宏来定义。
(关于DEFINE_ADJUST的详细信息见Section4.2.1)。
在demo_calc中,kount的值每次迭代后增加因为每次迭代调用