一、初始化对UDF运行的影响
初始化只会初始化网格上的物理数据、在UDF中常用的实际时间flow-time(CURRENT_TIME)、迭代步数N_ITER、UDM中的数据(其实也就是网格物理数据)。
初始化之后,UDF程序中的静态变量不会再初始化(程序变量初始化和fluent的初始化不同,请注意区分),也即fluent初始化后再计算不会让程序再回到第一次执行的状态,UDF程序依稀记得初始化前静态变量在运算过程中得到取值。
不知道各位读者理没理解上面这句话,如果不理解请再继续阅读下面的。
我举个例子。假设我们需要在UDF中实现写入数据,具体来说需要每次迭代结束时判断flow-time是否经历了一次写入周期(比如1秒写入一次),如果经历了一个周期就写入一次,而且第一次一定要写入一次。
为了实现上述特征,我编写了如下UDF代码。
DEFINE_EXECUTE_AT_END(iter_ending)
{
real End_iter_time=0.0;
real curing_ratio_ave=0.0; /* Volume weighted average curing degree */
real heat_ave=0.0; /* Volume weighted average heating energy */
#if !RP_HOST
Thread *sheet_ct;
int sheet_id = sheet_zone_id;
cell_t c;
real curing_ratio_weighted_sum=0.0;
real heat_weighted_sum=0.0;
real volume_sum=0.0;
#endif
#if !RP_NODE
FILE *fp = NULL;
char filename[]="out.txt";
static int remain_num = -1; /* Static variables are initialized only once */
#endif
#if !RP_HOST
sheet_ct = Lookup_Thread(Get_Domain(1), sheet_id);
begin_c_loop_int(c, sheet_ct)
{
curing_ratio_weighted_sum += C_VOLUME(c, sheet_ct) * C_UDMI(c, sheet_ct, 0);
heat_weighted_sum += C_VOLUME(c, sheet_ct) * C_UDMI(c, sheet_ct, 3);
volume_sum += C_VOLUME(c, sheet_ct);
}
end_c_loop_int(c, sheet_ct)
curing_ratio_weighted_sum = PRF_GRSUM1(curing_ratio_weighted_sum);
heat_weighted_sum = PRF_GRSUM1(heat_weighted_sum);
volume_sum = PRF_GRSUM1(volume_sum);
curing_ratio_ave = curing_ratio_weighted_sum / volume_sum;
heat_ave = heat_weighted_sum / volume_sum;
End_iter_time = CURRENT_TIME;
#endif
node_to_host_real_4(End_iter_time, bou_temp, curing_ratio_ave, heat_ave);
#if !RP_NODE
if(N_ITER<1) /* Clear the file when open the file for the first time */
{
if ((fp = fopen(filename, "w"))==NULL)
Message("\nWarning: Unable to open %s for writing\n", filename);
else
Message("\nWriting info to %s...\n", filename);
fprintf(fp, "real-time \t bou_temp \t curing_ratio_ave \t heat_ave\n");
}
else
{
if ((fp = fopen(filename, "a"))==NULL)
Message("\nWarning: Unable to open %s for writing\n", filename);
else
Message("\nIt is available to Write data to %s...\n", filename);
}
#endif
#if !RP_NODE
Message("real-time:%lf \t bou_temp:%lf \t curing_ratio_ave:%lf \t heat_ave:%lf\n", End_iter_time, bou_temp, curing_ratio_ave, heat_ave);
if(remain_num != (int) (End_iter_time / writig_frequency))
{
remain_num = (int) (End_iter_time / writig_frequency);
Message("\nWritting data to %s...\n", filename);
fprintf(fp, "%lf \t %lf \t %lf \t %lf \n", End_iter_time, bou_temp, curing_ratio_ave, heat_ave);
}
fclose(fp);
Message("Iter_Done\n");
#endif
}
我的UDF代码中的DEFINE_EXECUTE_AT_END宏里定义了一个静态变量。
静态变量有两个特点:1、不会被其他文件误调用,即使同名;2、取值仅仅初始化一次。
我就是看中了后面这一点,才在此处加了static关键字,因为我想让这个变量在程序在第一次执行时取值符合某种条件(满足条件就写入数据到文件),后续迭代步时取值仅仅由初始化代码的后面代码决定。
-------------------------------------UDF代码讲完了,接着讲常规操作-----------------------------------------
将刚定义好的cas文件载入,加载UDF后(在加载前编译成功,并且进行了hook和在边界条件等处应用了UDF),接着设置一个自认为合理的时间步长,开始计算。
可是,没一会儿就报错——浮点溢出了(floating point exception)。
于是乎我们进行一次fluent初始化,清除掉所有的网格数据(还有flow-time、N_ITER等),调小时间步长再计算(注意我们没有卸载UDF再重载)。
我们发现在UDF中的DEFINE_EXECUTE_AT_END宏里定义的初次运行会写入一次数字数据的操作(倒数第6行)失效了。
后来我猜测fluent初始化并不会让程序重新运行,让静态变量再一次进行(程序变量)初始化,因此flow-time必须满足个位更新(我在UDF源文件最前面的全局区域定义writig_frequency为1.0)的条件才会执行倒数第6行的代码。
这只是猜想,接下来我们在第二部分验证。
二、重载UDF再计算对UDF运行的影响
本部分研究【停止正在进行的计算后重载UDF再计算会产生的效果】。
如果你仅仅是用下图中的两个stop按钮之一停止计算,做一些步长调整(或其他参数调整)后,或者你停止计算后进行了初始化。
再重新开始计算时,你的程序之前保存的静态变量取值还保存着。
当我这次将原来加载的libudf卸载,重新加载时,再开始计算。
这次我发现,倒数第6行的代码被很快运行,说明这次程序满足第一次运行就写入数据的条件,也说明静态变量在重载后会被重新进行(程序变量)初始化。
三、后话
为了避免下一次再出现同样的问题,我在DEFINE_EXECUTE_AT_END宏中加了下面这条代码。
使得这个辅助判断的变量remain_num在第一次迭代时一定满足写入数据条件,不管是否之前已经执行过。