> 文章列表 > 【fluent udf】定义源项宏时,在迭代计算过程中UDM变量变inf、NAN、发散时如何解决?

【fluent udf】定义源项宏时,在迭代计算过程中UDM变量变inf、NAN、发散时如何解决?

【fluent udf】定义源项宏时,在迭代计算过程中UDM变量变inf、NAN、发散时如何解决?

一、问题背景

最近做的一个fluent仿真算例里用到源项宏,源项宏里用UDM定义了树脂固化度场。

迭代计算的过程中,UDM的取值发散成了无穷大inf(第一次计算取值是NAN),如下图所示。
【fluent udf】定义源项宏时,在迭代计算过程中UDM变量变inf、NAN、发散时如何解决?
由于每一次迭代计算过程中,需要用到以前的数据进行累加,所以某一步计算结果是inf,后面所有结果都会是无穷大。

本文介绍一种方法,在改动导致inf错误的代码的同时,可以不用从头开始计算(前提是已经迭代计算的流动时间占总时间的极小比例)。

二、解决办法

2.1 检查是否有UDF数据结构定义在了HOST节点

以下是出错的源码,可以看到我原来将面网格数据结构定义在了host节点中,这样很容易出错。

因为host节点不存储任何网格数据,强行计算就可能会导致除以0而发散的悲剧。

notes:以下的代码只是profile宏,对于包括头文件的代码以及定义全局变量bou_temp 的代码被省略(实际存在)。

DEFINE_PROFILE(Inlet_Temp, t, i)
{real time = CURRENT_TIME;face_t f;if(time<=7200){bou_temp = 300 + 0.025*time;}else if(time>7200 && time<=18000){bou_temp = 480;}else if(time>18000 && time<=28800){bou_temp = 480 - (time-18000)/60;}else bou_temp = 300;begin_f_loop(f, t){if (PRINCIPAL_FACE_P(f, t)){F_PROFILE(f, t, i) = bou_temp;}}end_f_loop(f, t)
}

改成如下形式。

DEFINE_PROFILE(Inlet_Temp, t, i)
{#if !RP_HOSTreal time = CURRENT_TIME;face_t f;if(time<=7200){bou_temp = 300 + 0.025*time;}else if(time>7200 && time<=18000){bou_temp = 480;}else if(time>18000 && time<=28800){bou_temp = 480 - (time-18000)/60;}else bou_temp = 300;begin_f_loop(f, t){if (PRINCIPAL_FACE_P(f, t)){F_PROFILE(f, t, i) = bou_temp;}}end_f_loop(f, t)#endif
}

2.2 计算面积或体积权重平均物理量时分母是否偏小

小标题啥意思呢?

例如说一个实体中有3个网格单元,你需要计算这个实体的体积平均温度,公式如下。

【fluent udf】定义源项宏时,在迭代计算过程中UDM变量变inf、NAN、发散时如何解决?
但是你在写代码的过程中,可能将分子计算成了V1或V2或V3,而如果这个实体中计算节点足够多,你的实体足够大,单个V占整个总体积的比例越小,你的T_ave就会越趋于发散。

我就犯了如此大错,代码如下:

        #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);curing_ratio_ave = curing_ratio_weighted_sum / volume_sum;heat_ave = heat_weighted_sum / volume_sum;End_iter_time = CURRENT_TIME;#endif

我没有将volume_sum用全局约简宏将所有计算节点上的总体积求和起来,因而就容易趋于发散。

代码改成下面的形式。

        #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;#endif

三、如何无需从头开始计算就转inf为正常值

关于curing_ratio这个UDM变量,我在源项宏中对它的迭代计算公式是curing_ratio=curing_ratio+curing_ratio_rate*timestep,很显然如果curing_ratio有一步算出来是inf发散的,那么后面的所有迭代步就都是发散的。

因为已经变成inf(并且第二步就已经发散了),我不知道它迭代到当前步是什么值,所以最终就直接决定将其赋值为0,毕竟当前步和初始步之间的步数占总步数的千分之一还不到。

用什么赋值为0呢?

当然是帅气且灵活的DEFINE_ON_DEMAND宏啦,代码如下。

DEFINE_ON_DEMAND(init_UDM1)
{#if !RP_HOSTThread *sheet_ct;int sheet_id = sheet_zone_id;cell_t c;sheet_ct = Lookup_Thread(Get_Domain(1), sheet_id);begin_c_loop_int(c, sheet_ct){C_UDMI(c, sheet_ct, 1) = 0.0;}end_c_loop_int(c, sheet_ct)#endif#if !RP_NODEMessage("UDM1 is initialized successfully.\\n");#endif
}