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

一、问题背景

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

在迭代计算的过程中,UDM的取值发散成了无穷大inf(第一次计算取值是NAN),如下图所示。
【fluent udf】定义源项宏时,在迭代计算过程中UDM变量变inf、NAN、发散时如何解决?_第1张图片
由于每一次迭代计算过程中,需要用到以前的数据进行累加,所以某一步计算结果是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_HOST
    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)
    #endif
}

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

小标题啥意思呢?

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

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

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

        #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);
        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_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

三、如何无需从头开始计算就转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_HOST
    Thread *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_NODE
    Message("UDM1 is initialized successfully.\n");

    #endif
}

你可能感兴趣的:(fluent,udf,fluent,UDF)