Fluent UDF 利用的是 C 语言,本文简单介绍在 UDF 中经常会用到的 C 语言常识。
本文部分内容来自 UDF 手册。
C 语言中的注释利用/*及*/
来实现。例如:
/*这是一个注释*/
注释也可以跨行实现,如:
/*这是一个
跨行注释*/
注意: 在编写 UDF 的过程中,不能把 DEFINE 宏 (如 DEFINE_PROFILE) 放置在注释中,否则会引起编译错误
Fluent UDF 解释器支持的标准 C 数据类型包括:
int
。整形,存储形如 1,2,3 之类的整数。long
。长整形。存储数据与 int 类似,但范围更广。float
。浮点型。存储小数,如 1.234 等double
。双精度浮点型。与 float 类似。char
。字符型,如'a','b','c'等。
Fluent UDF 中还有real
型,其实这是 Fluent 自定义的数据类型,在双精度求解器中,real 类型与 double 类型相同,而在单精度求解器中,real 类型等同于 float 类型。UDF 自动进行转换,因此在需要浮点数时,可以全部采用 real 类型。
附:
%d 有符号 10 进制整数(%ld 长整型,%hd 短整型 )
%hu 无符号短整形(%u 无符号整形,%lu 无符号长整形)
%i 有符号 10 进制整数 (%i 和 %d 没有区别,%i 是老式写法,都是整型格式)
%o 无符号 8 进制整数
%u 无符号 10 进制整数
%x 无符号的 16 进制数字,并以小写 abcdef 表示
%X 无符号的 16 进制数字,并以大写 ABCDEF 表示
%f 输入输出为浮点型 (%lf 双精度浮点型)
%E/e 用科学表示格式的浮点数
%g 输入输出为实数,它根据数值的大小,自动选f格式或e格式(选择输出时占宽度较小的一种),且不输出无意义的0
%c 输入输出为单个字符
%s 输入输出为字符串
在 C 语言中可以利用 #define 来定义常数。需要注意的是,定义为常数类型后,该变量的值不能改变。如:
#define WALL_ID 5
#define YMIN 0.0
#define YMAX 0.4
这样定义完毕后,WALL_ID 的值不能再发生改变,因此如下的语句会引发编译错误:
WALL_ID = WALL_ID +1 ;
变量用于存储数据。所有变量都包含类型、名称以及值,有时候还包含存储标记(如静态变量和外部变量)。C 语言中所有的变量在使用之前都必须声明,这样 C 编译器才会知道该如何为此变量分配内存。
- 全局变量和局部变量
C 语言中的全局变量定义在函数的外部,该变量可以被源文件中所有的函数引用。全局变量如果未被声明为静态变量的话,还可以被外部函数引用。如下例中的全局变量声明:
#include "udf.h"
real volume; /*此处定义的是全局变量*/
DEFINE_ADJUST(vol,domain)
{
/*此处可以访问变量volume*/
}
局部变量一般定义在函数体内,其只在函数体内起作用,在函数体外无法被访问到。如下程序中的局部变量定义。
DEFINE_PROPERTY(cell_viscosity, cell, thread)
{
real mu_lam; /*局部变量 */
real temp = C_T(cell, thread); /* 局部变量 */
if (temp > 288.)
mu_lam = 5.5e-3;
else if (temp > 286.)
mu_lam = 143.2135 - 0.49725 * temp;
else
mu_lam = 1.;
return mu_lam;
}
- 外部变量
当在某个源文件中定义了一个未加 static 的全局变量后,若想在另一个源文件中调用此变量,此时可以使用外部变量声明来实现。采用如下声明:
extern real volume;
注意:extern 声明只能用于编译型 UDF 中。
以下是一个利用 extern 的案例。
假设在源文件 file1.c 中定义了全局变量:
#include "udf.h"
real volume;
DEFINE_ADJUST(compute_volume, domain)
{
volume = ....
}
若其他的的源文件想要利用此全局变量 volume, 此时可以创建头文件,并将变量 volume 声明为 extern 变量,如创建头文件 extfile.h,写入内容:
extern real volume;
之后就可以在其他的源文件中使用此变量 volume 了,如在源文件 file2.c 中:
#include "udf.h"
#include "extfile.h"
DEFINE_SOURCE(heat_source,c,t,ds,eqn)
{
real total_source = ...;
real source;
source = total_source/volume;
return source;
}
温馨提示:外部变量使用起来很麻烦也很容易出错,如果对其不甚了解的话,建议不要使用。
- 静态变量
静态变量(声明时添加 static 关键字)在用于局部变量或全局变量时具有不同的作用。局部变量被声明为 static 时,当函数返回后变量并不销毁,变量的值依旧被保留。
全局变量被声明为 static 时,该变量能够被此源文件中的所有函数调用,但不能被其他源文件中的函数调用。实际上是变量被隐藏了。
例如在文件 mysource.c 中有如下代码:
#include "udf.h"
static real abs_coeff = 1.0; /*静态全局变量*/
/* 此变量只能被本文件中的其他函数调用 */
DEFINE_SOURCE(energy_source, c, t, dS, eqn)
{
real source; /* 局部变量*/
int P1 = ....; /* 局部变量*/
/*变量只能被当前函数调用,但在函数返回时变量并不释放 */
dS[eqn] = -16.* abs_coeff;
source =-abs_coeff *(4.* SIGMA_SBC );
return source;
}
DEFINE_SOURCE(p1_source, c, t, dS, eqn)
{
real source;
int P1 = ...;
dS[eqn] = -abs_coeff;
source = abs_coeff *(4.* SIGMA_SBC);
return source;
}
更多关于 static 的描述可参见文章 [www.cnblogs.com/stoneJin/archive/2011/09/21/2183313.html] (www.cnblogs.com/stoneJin/archive/2011/09/21/2183313.html)
温馨提示:与全局变量类似,静态变量也尽量少用,容易造成不必要的麻烦。
C 语言允许用户自己定义数据类型,通过使用结构体及typedef
关键字。如定义类型:
typedef struct list
{
int a;
real b;
int c;
}mylist;
mylist x,y,z;
上例定义了一个结构体类型 mylist,并定义了三个结构体变量 x,y,z。
在 C 语言中,有时需要对类型进行强制转换,如将浮点型强制转换为整形,如下例中。
int x =1;
real y=3.1415926;
int z=x+(int)y;
计算完毕后,z=4。
C 语言中的函数执行独立的任务。函数能够被同一源文件中的其他函数调用,也可以由源文件之外的函数调用。
函数定义包含函数名以及被传递给函数的零个或多个参数列表。函数包含一个包含在大括号内的主体,主体中包含执行任务的指令。 函数可以返回特定类型的值。
函数返回特定数据类型的值(例如,实数),如果类型为 void,则不返回任何值。 要确定 DEFINE 宏的返回数据类型,可查看 udf.h 文件中宏的相应 #define 语句。
C 语言中数组变量定义为name[size]
,其中 name 为数组变量的名称,size 为数组中存储的单元数量。C 语言中数组索引从 0 开始。
int a[10], b[10][10];
/*a
real rad[5];
a[0] = 1;
rad[4] = 3.14159265;
b[10][10] = 4;
指针是一种存储变量内存地址的变量。换句话说,指针是一个变量,这个变量指向另外一个变量的内存地址。指针变量的声明:
int *ip;/*定义指针变量ip*/
定义了指针变量后,可以利用取址运算符将其他变量的地址赋予指针变量,如:
int *ip;
ip =&a;
也可以为指针变量赋值,如:
*ip =4;
当指针作为函数的参数,此时为传址调用,在函数体内修改指针参数的值,会改变调用函数时传递的参数的值。此功能可以实现一个函数返回多个值。
如下的 C 程序:
#include <stdio.h>
int add(int *a,int b)
{
int sum = 0;
sum = *a + b;
*a = 5;
return sum;
}
int main() {
int *ip;
int a = 1;
int b = 2;
int sum = 0;
ip = &a;
sum = add(ip,b);
printf("sum=%d,a=%d\n",sum,a);
return 0;
}
输出结果:
sum=3,a=5
传递的参数值被函数体内的程序改变。
C 语言中可以用逻辑判断和循环来进行流程控制。
- if 语句
if 语句用于逻辑判断。可写成:
if(逻辑判断表达式)
{
语句块;
}
例如:
if(q!=1)
{
a=0;
b=1;
}
若逻辑判断存在多个分支,可以采用 if-else 结构。如:
if(x<0)
{
y = x/50;
}
else(x>=0 && x<3)
{
x=-x;
y = x/25;
}
else
{
x= 0;
y = 0;
}
- for 循环
for 语句常用于循环表达。
int i,j,n<=10;
for(i=1;i<n;i++)
{
j = i*i;
printf("%d%d\n",i,j)
}
常用的代数操作符:
= 赋值操作
+ 加法计算
- 减法计算
* 乘法运算
/ 除法运算
% 求模运算
++ 累加
-- 累减
常用的逻辑操作符:
< 小于
<= 小于等于
> 大于
>= 大于等于
== 等于
!= 不等于
常用的三角函数:
double acos (double x);
double asin (double x);
double atan (double x);
double atan2 (double x, double y);
double cos (double x);
double sin (double x);
double tan (double x);
double cosh (double x);
double sinh (double x);
double tanh (double x);
常用的数学函数:
double sqrt (double x);
double pow(double x, double y);
double exp (double x);
double log (double x);
double log10 (double x);
double fabs (double x);
double ceil (double x);
double floor (double x);
一些常用的标准输入输出函数:
FILE *fopen(char *filename, char *mode);
int fclose(FILE *fp);
int printf(char *format,...);
int fscanf(FILE *fp, char *format,...);
int fscanf(FILE *fp, char *format,...);