> 文章列表 > 【Fluent UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果

【Fluent UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果

【Fluent UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果

一、初始化对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_HOSTThread *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_NODEFILE *fp = NULL;char filename[]="out.txt";static int remain_num = -1;  /* Static variables are initialized only once */#endif#if !RP_HOSTsheet_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;#endifnode_to_host_real_4(End_iter_time, bou_temp, curing_ratio_ave, heat_ave);#if !RP_NODEif(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);elseMessage("\\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);elseMessage("\\nIt is available to Write data to %s...\\n", filename);}#endif#if !RP_NODEMessage("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 UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果
后来我猜测fluent初始化并不会让程序重新运行,让静态变量再一次进行(程序变量)初始化,因此flow-time必须满足个位更新(我在UDF源文件最前面的全局区域定义writig_frequency为1.0)的条件才会执行倒数第6行的代码。

这只是猜想,接下来我们在第二部分验证。

二、重载UDF再计算对UDF运行的影响

本部分研究【停止正在进行的计算后重载UDF再计算会产生的效果】。

如果你仅仅是用下图中的两个stop按钮之一停止计算,做一些步长调整(或其他参数调整)后,或者你停止计算后进行了初始化。

再重新开始计算时,你的程序之前保存的静态变量取值还保存着。

【Fluent UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果

当我这次将原来加载的libudf卸载,重新加载时,再开始计算。

这次我发现,倒数第6行的代码被很快运行,说明这次程序满足第一次运行就写入数据的条件,也说明静态变量在重载后会被重新进行(程序变量)初始化。
【Fluent UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果

三、后话

为了避免下一次再出现同样的问题,我在DEFINE_EXECUTE_AT_END宏中加了下面这条代码。

使得这个辅助判断的变量remain_num在第一次迭代时一定满足写入数据条件,不管是否之前已经执行过。【Fluent UDF】浮点溢出错误后初始化对UDF运行的影响、停止正在进行的计算后重载UDF再计算会产生的效果