Fluent UDF(五)数据访问宏(3)

前述两节介绍了UDF中常用的网格节点、网格面及网格单元数据访问宏,除此之外,UDF的编写常常需要配合一些特殊的数据访问宏,本节继续介绍一些UDF常用的数据访问宏。

  • Lookup_Thread
  • THREAD_ID
  • Get_Domain
  • F_PROFILE
  • THREAD_SHADOW
4.1 获取线程指针 (Lookup_Thread)

如果 UDF 需要在特定线程上操作(而不是遍历所有线程),并且 DEFINE 宏没有从求解器传递线程指针(如 DEFINE_ADJUST),则可以使用 Lookup_Thread 获取所需的线程指针。将 zone_ID 作为参数传递给 Lookup_Thread,它返回与该区域 ID 关联的线程指针。

参数类型返回值
Lookup_Thread(domain,zone_ID)Domain *domain, int Zone_IDThread *t

参数和用法

int zone_ID = 16;
Thread *thread_name = Lookup_Thread(domain, zone_ID);
  • domain:指向 domain 的指针,由 Ansys Fluent 传递。
  • zone_ID:Ansys Fluent 自动分配的区域 ID 号。

Zone ID可由对应的边界条件或单元区域条件面板中查看:
在这里插入图片描述

UDF示例:

#include "udf.h"

// 定义 ADJUST 宏,每次迭代执行
DEFINE_ADJUST(face_centroid, domain)
{
    real FC[ND_ND];  // 定义一个数组用于存储坐标
    face_t face;  // 定义一个 face_t 类型的变量,用于存储面索引
    int FACE_ID = 16;  // 定义面 ID,在 Fluent 中查看,可以用宏常量定义:#define FACE_ID 16
    real fx, fy;  // 定义变量存储坐标值

    // 查找在domain中ID为FACE_ID的面线程face_thread
    Thread *face_thread;
    face_thread = Lookup_Thread(domain, FACE_ID);

    // 检查face_thread是否为空
    if (face_thread == NULL)
    {
        Message("Error: face_thread is NULL. Check FACE_ID.\n");
        return;
    }

    // 遍历 face_thread 中的所有面face
    begin_f_loop(face, face_thread)
    {
        F_CENTROID(FC, face, face_thread);  // 获取面 face 的质心坐标,并存储在 FC 数组中
        fx = FC[0];  // 获取 x 坐标
        fy = FC[1];  // 获取 y 坐标

        // 打印坐标信息
        Message("Centroid Coordinates: x = %f, y = %f\n", fx, fy);
    }
    end_f_loop(face, face_thread)  // 结束面循环
}

该UDF的使用与详解参见本专栏第三节面数据访问宏-面心坐标

4.2 获取 Zone ID (THREAD_ID)

THREAD_ID 宏用于在已知线程指针 t 的情况下,获取与该线程关联的Zone ID ,该宏的功能与上述获取线程指针宏 Lookup_Thread 相反。THREAD_ID 宏接收一个线程指针 t 并返回该线程所关联的Zone ID

参数类型返回值
THREAD_ID(t)Thread *tint Zone_ID
 int zone_ID = THREAD_ID(t); 
4.3 获取域指针 (Get_Domain)

Get_Domain 宏用于获取域指针。在某些情况下,求解器不会将域指针自动传给UDF,则需要Get_Domain 宏获取域指针以便进行后续操作。

例如在 DEFINE_ON_DEMAND 宏中特别常用,因为 DEFINE_ON_DEMAND 函数不会从 Ansys Fluent 求解器中传入任何参数。

Get_Domain(domain_id);

对于单相流domain_id 为 1,Get_Domain(1) 将返回流体域指针。

DEFINE_ON_DEMAND(my_udf)
{
    Domain *domain;          /* 声明域指针变量 */
    domain = Get_Domain(1);  /* 返回流体域指针 */
    ...
}

对于多相流Get_Domain 返回的值可以是混合级域、相级域或交互相级域指针。domain_id 的值对于混合域始终为 1。可以通过 Fluent 图形用户界面获取 domain_id,获取方法与获取 Zone ID 类似。只需转到 “Phases” 对话框并选择所需的相,即可显示 domain_id
SetupModelsMultiphasePhasesEdit…

DEFINE_ON_DEMAND(my_udf)
{
    Domain *mixture_domain;
    mixture_domain = Get_Domain(1); /* 返回混合域指针 */
    
    Domain *subdomain;
    subdomain = Get_Domain(2);      /* 返回 ID 为 2 的相域指针 */
    ...
}

UDF示例:构建名为 get_coords 的 UDF,打印两个指定线程 ID 的线程面质心。自定义函数 Print_Thread_Face_Centroids 使用 Lookup_Thread 宏确定线程指针,然后将指定线程中所有面的面质心写入文件。Get_Domain(1) 函数调用返回域指针(在多相流中返回混合域指针),此参数没有传递给 DEFINE_ON_DEMAND

#include "udf.h"  
 
FILE *fout;  // 定义一个文件指针,用于输出文件
 
// 定义函数,打印指定线程的面质心
void Print_Thread_Face_Centroids(Domain *domain, int id)
{
    real FC[3];  // 用于存储面质心坐标的数组
    face_t f;  // 定义面标识符
    Thread *t = Lookup_Thread(domain, id);  // 通过线程 ID 查找线程指针

    fprintf(fout,"thread id %d\n", id);  // 输出线程 ID 到文件

    // 开始循环遍历线程中的每个面
    begin_f_loop(f, t)
    {
        F_CENTROID(FC, f, t);  // 获取当前面的质心坐标并存储在 FC 数组中
        // 将当前面的 ID 及其质心坐标输出到文件
        fprintf(fout, "f%d %g %g %g\n", f, FC[0], FC[1], FC[2]);
    }
    end_f_loop(f, t)  // 结束循环遍历
    fprintf(fout, "\n");  // 在文件中添加一个换行符,用于分隔不同线程的数据
}
 
// 定义按需执行的 UDF 函数
DEFINE_ON_DEMAND(get_coords)
{
    Domain *domain;  // 声明一个域指针变量
    domain = Get_Domain(1);  // 获取域指针,1 表示单相流的流体域

    fout = fopen("faces.out", "w");  // 打开文件 faces.out 以写入模式

    // 打印 ID 为 2 的线程的面质心
    Print_Thread_Face_Centroids(domain, 2);//调用函数

    // 打印 ID 为 4 的线程的面质心
    Print_Thread_Face_Centroids(domain, 4);

    fclose(fout);  // 关闭文件
}

在后续多相流专栏中还会重点讲解Get_Domain 宏的应用。

4.4 边界条件设置 (F_PROFILE)

F_PROFILE 通常用于 DEFINE_PROFILE 宏中为给定的面和线程设置边界条件值

参数类型返回值
F_PROFILE(f,t,i)face_t f,Thread *t,int ivoid
  • face_t f:面标识符
  • Thread *t:线程指针
  • int i:需要设置的特定面变量的整数索引。在将 DEFINE_PROFILE UDF 挂接到边界条件对话框中的特定变量(例如,压力、温度、速度)时,Ansys Fluent 会定义该索引,并将其传递给 UDF,使函数知道要操作哪个变量。

F_PROFILE 宏使用框架如下:

#include "udf.h"
DEFINE_PROFILE(boundary_condition,t,i)
{
   /* 定义其他需要的变量   */
      face_t f;
      begin_f_loop(f,t)
      {
          
           //对 F_PROFILE(f,t,i) 进行赋值或其他操作 
      }
      end_f_loop(f,t)
}

UDF示例案例链接

1.案例描述:如下图所示二维矩形流场,矩形尺寸 40 × 20 mm 40×20\text{mm} 40×20mm,上下边界类型为wall,两侧分别为速度入口和压力出口,现采用UDF使入口速度呈抛物线分布:
v ( y ) = V max ⁡ ( 1 − y 2 y max ⁡ 2 ) v(y)=V_{\max}\left(1-\frac{y^2}{y_{\max}^2}\right) v(y)=Vmax(1ymax2y2)

  • V m a x V_{max} Vmax 为轴心处最大速度,本案例为 0.01 m/s 0.01\text{m/s} 0.01m/s
  • y m a x y_{max} ymax 为流域半宽度,本案例为 10 mm 10\text{mm} 10mm
    2D流场示意图

2.UDF文件

#include "udf.h"

// 定义入口速度分布为抛物线形状的 UDF
DEFINE_PROFILE(velocity_profile, t, i)
{
    real x[ND_ND];    // 数组,用于存储质心坐标
    real y;           // 变量,用于存储 y 坐标值
    face_t f;         // 面标识符
    real max_velocity = 0.01;  // 最大速度值
    real y_max = 0.01;         // y 方向的最大值,用于归一化

    // 开始循环遍历线程中的每个面
    begin_f_loop(f, t)
    {
        // 获取当前面的质心坐标并存储在 x 数组中
        F_CENTROID(x, f, t);
        // 提取 y 坐标
        y = x[1];
        // 计算抛物线形状的速度值并将其存储到当前面
        F_PROFILE(f, t, i) = max_velocity * (1.0 - (y*y)/(y_max*y_max));
    }
    end_f_loop(f, t)  // 结束循环遍历
}

将UDF保存为.c文件类型并储存在案例文件夹下。

3.案例设置:本案例仅为演示抛物线入口速度分布,除入口速度采用UDF外,其余设置保持默认
在这里插入图片描述

4.求解查看:初始化完成后,进行迭代求解(本案例迭代次数为10)

速度云图如下
在这里插入图片描述

入口速度分布:
抛物线速度分布

4.5 影子面 (THREAD_SHADOW)

在 Ansys Fluent 中,薄壁通常由两个面线程组成:一个是实际的面线程,另一个是对应的影子线程。THREAD_SHADOW(t) 宏可以在 UDF 中获取影子线程,以便在薄壁的两侧进行操作。通过检查 THREAD_SHADOW(t) 返回值是否为 NULL,可确定一个线程是否是薄壁的一部分,并进行相应的处理。

if (!NULLP(ts = THREAD_SHADOW(t)))
{
    /* 在此处使用影子壁面线程 (ts) 进行操作 */
}

这行代码检查线程 t 是否有影子线程。如果有,THREAD_SHADOW(t) 会返回影子线程指针,并将其赋值给 tsNULLP(ts) 用于检查 ts 是否为 NULL。

UDF示例:假设有一个薄壁,需要在 UDF 中分别对薄壁两侧进行操作,可以使用以下代码:

#include "udf.h"

DEFINE_ADJUST(adjust_thin_wall, domain)
{
    Thread *t;
    Thread *ts;
    face_t f;
    
    thread_loop_f(t, domain)
    {
        if (!NULLP(ts = THREAD_SHADOW(t)))
        {
            begin_f_loop(f, t)
            {
                /* 在实际壁面线程 t 上进行操作 */
            }
            end_f_loop(f, t)
            
            begin_f_loop(f, ts)
            {
                /* 在影子壁面线程 ts 上进行操作 */
            }
            end_f_loop(f, ts)
        }
    }
}

本节介绍了几个UDF中特殊的数据获取宏,结合前两节内容。常用的数据获取宏介绍完毕,剩下一些多相流模型、DPM模型、梯度与导数数据获取宏后续有需求再补充。

欢迎评论区留言或私信讨论交流,不仅仅是CFD。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值