Ansys Fluent文档-UDF篇:通用DEFINE宏(二)
①描述
DEFINE_EXECUTE_ON_LOADING是一种通用宏,可用于指定在编译的UDF库加载到Fluent后立即执行的函数。当在加载UDF库时初始化或设置UDF模型时,此功能非常有用。(另外,如果在加载共享库时保存案例文件,则后续每次读取该案例文件时都会执行该UDF。)
编译后的UDF库可通过“编译UDF”功能或UDF库管理器对话框加载。EXECUTE_ON_LOADING类型的UDF是特定库中预留用户自定义标量(UDS)和用户自定义内存(UDM)的最佳位置,同时也可设置UDS和UDM名称。
重要提示:DEFINE_EXECUTE_ON_LOADING只能作为已编译的UDF执行。注意:不建议使用DEFINE_EXECUTE_ON_LOADING重命名DPM标量,因为在读取包含此类UDF的DPM案例时可能导致Fluent异常终止。该问题的成因在于DEFINE_EXECUTE_ON_LOADING类型UDF会在启用DPM模型之前执行。建议改用DEFINE_EXECUTE_AFTER_CASE来实现此功能。
②用法
DEFINE_EXECUTE_ON_LOADING (name, libname)
name:UDF名称;
char *libname:Fluent中已加载的UDF库名称;
DEFINE_EXECUTE_ON_LOADING有两个参数:name和libname。需要为UDF提供一个名称,Fluent将在报告正在运行的EXECUTE_ON_LOADING UDF时使用该名称。libname由Fluent设置为指定的库名称(例如libudf),该名称由您输入或保留默认的libudf。传递libname是为了在UDF的消息中使用它。
③示例1
以下名为report_version的简单UDF会在控制台打印一条消息,其中包含正在加载的库的版本号和发行号。
#include"udf.h"// 定义两个静态整型变量,用于存储版本信息// static关键字使这些变量仅在当前源文件中可见static int version = 1; // 主版本号,初始化为1static int release = 2; // 次版本号(发布版本号),初始化为2DEFINE_EXECUTE_ON_LOADING(report_version, libname){// 输出加载信息到Fluent控制台和信息窗口Message("\nLoading %s version %d.%d\n",libname,version,release);}// 定义更详细的版本信息#include"udf.h"static int major_version = 2;static int minor_version = 1;static int patch_version = 3;static char *build_date = "2024-01-15";static char *author = "Your Name";DEFINE_EXECUTE_ON_LOADING(report_version, libname){Message("\n========================================\n");Message("Loading UDF Library: %s\n", libname);Message("Version: %d.%d.%d\n", major_version, minor_version, patch_version);Message("Build Date: %s\n", build_date);Message("Author: %s\n", author);Message("========================================\n");}
④示例2
以下源代码包含两个用户自定义函数(UDF)。第一个UDF是EXECUTE_ON_LOADING函数,用于为库保留三个UDM(通过Reserve_User_Memory_Vars)并为UDM存储位置设置唯一名称(通过Set_User_Memory_Name)。第二个UDF是ON_DEMAND函数,用于在求解初始化后设置UDM存储位置的值。该ON_DEMAND通过udm_offset(在加载UDF中定义)设置UDM存储位置的初始值。请注意,必须在求解初始化after执行该按需UDF以重置UDM的初始值。
# include"udf.h"// 定义宏,表示需要预留的用户自定义内存(UDM)数量为3# define NUM_UDM 3// 声明静态全局变量udm_offset,用于存储预留的UDM起始索引// 初始化为UDM_UNRESERVED(通常为-1),表示尚未预留static int udm_offset = UDM_UNRESERVED;// 定义在UDF库加载时自动执行的函数// on_loading: 函数名// libname: 库名称参数,由Fluent在加载时自动传入DEFINE_EXECUTE_ON_LOADING(on_loading, libname){// 如果udm_offset为未预留状态,则尝试预留NUM_UDM个UDM变量if (udm_offset == UDM_UNRESERVED)udm_offset = Reserve_User_Memory_Vars(NUM_UDM); // 预留UDM,返回起始索引// 检查预留是否成功(返回值仍为UDM_UNRESERVED表示失败)if (udm_offset == UDM_UNRESERVED)// 预留失败,输出提示信息要求用户在GUI中定义更多UDMMessage("\nYou need to define up to %d extra UDMs in GUI and ""then reload current library %s\n", NUM_UDM, libname);else // 预留成功{// 输出成功预留UDM的信息Message("%d UDMs have been reserved by the current ""library %s\n", NUM_UDM, libname);// 为预留的UDM设置描述性名称,便于在Fluent界面中识别Set_User_Memory_Name(udm_offset, "lib1-UDM-0"); // 第一个UDMSet_User_Memory_Name(udm_offset + 1, "lib1-UDM-1"); // 第二个UDMSet_User_Memory_Name(udm_offset + 2, "lib1-UDM-2"); // 第三个UDM}// 输出当前库的UDM起始偏移量Message("\nUDM Offset for Current Loaded Library = %d", udm_offset);}// 定义ON_DEMAND函数,可以通过Fluent界面手动执行// set_udms: 函数名DEFINE_ON_DEMAND(set_udms){Domain *d; // 声明域指针Thread *ct; // 声明线程指针cell_t c; // 声明单元索引int i; // 声明循环计数器// 获取域指针(主域或混合物域)d = Get_Domain(1);// 检查UDM是否已成功预留if(udm_offset != UDM_UNRESERVED){// UDM已预留,开始设置UDM的值Message("Setting UDMs\n");// 循环遍历预留的每个UDM(共NUM_UDM个)for (i = 0; i < NUM_UDM; i++){// 遍历域中的所有单元线程thread_loop_c(ct, d){// 在当前线程中遍历所有单元begin_c_loop(c, ct){// 将当前单元的当前UDM设置为特定值// udm_offset+i: UDM的实际索引(起始偏移量 + 序号)// 3.0 + i/10.0: 设置的值,例如:// i=0 -> 3.0 + 0/10.0 = 3.0// i=1 -> 3.0 + 1/10.0 = 3.1// i=2 -> 3.0 + 2/10.0 = 3.2C_UDMI(c, ct, udm_offset + i) = 3.0 + i / 10.0;}end_c_loop(c, ct) // 结束单元循环}}}else // UDM未预留{// 输出错误信息Message("UDMs have not yet been reserved for library 1\n");}}
(7)DEFINE_EXECUTE_AFTER_CASE/DATA
①描述
DEFINE_EXECUTE_AFTER_CASE和DEFINE_EXECUTE_AFTER_DATA是通用宏,可用于指定在Fluent中读取案例文件和/或数据文件后执行的函数。这非常有用,因为它提供了在读取案例文件和/或数据文件后访问UDF函数的能力。
重要提示:DEFINE_EXECUTE_AFTER_CASE和DEFINE_EXECUTE_AFTER_DATA只能作为编译型UDF执行。
②用法
DEFINE_EXECUTE_AFTER_CASE/DATA (name,libname)
name:UDF名称;
char *libname:Fluent中已加载的UDF库名称;
DEFINE_EXECUTE_AFTER_CASE和DEFINE_EXECUTE_AFTER_DATA有两个参数:name和libname。需要提供一个名称,Fluent将在报告正在运行的 EXECUTE_AFTER_CASE或EXECUTE_AFTER_DATA时使用该名称。libname由Fluent设置为指定的库名称(例如libudf)(通过输入名称或保留默认的libudf)。传递libname是为了可以在UDF的消息中使用它。
③示例
以下名为after_case和after_data的简单UDF,会向控制台打印一条包含正在加载库名称的消息。
#include "udf.h"DEFINE_EXECUTE_AFTER_CASE(after_case, libname){Message("EXECUTE_AFTER_CASE called from $s\n", libname);}DEFINE_EXECUTE_AFTER_DATA(after_data, libname){Message("EXECUTE_AFTER_DATA called from $s\n", libname);}
(8)DEFINE_INIT
①描述
DEFINE_INIT是一种通用宏,可用于为求解设定初始值。DEFINE_INIT通过用户自定义函数(UDF)实现与修补相同的效果,但实现方式不同。DEFINE_INIT函数在每次初始化时执行一次,并在求解器完成默认初始化后立即调用。由于该函数在流场初始化完成后才被调用,因此通常用于设置流量的初始值。
②用法
DEFINE_INIT (name, d)
name:UDF名称;
Domain *d:指向初始化函数所要应用的域。域参数提供对网格中所有单元和面线程的访问。对于多相流,求解器传递给函数的指针是混合物级别的域。
DEFINE_INIT有两个参数:name和d。需要提供UDF的名称name,而d则由Fluent求解器传递给UDF。
③示例
以下名为my_init_func的UDF用于初始化解决方案中的流场变行。该函数在求解过程开始时执行一次,可在Fluent中作为解释型或编译型UDF执行。
#include"udf.h"// 定义初始化函数,在求解器初始化阶段执行(在迭代开始前执行一次)// my_init_func: 函数名// d: 域指针,指向整个计算域DEFINE_INIT(my_init_func, d){cell_t c; // 声明单元索引,用于遍历网格单元Thread *t; // 声明线程指针,用于遍历不同的网格区域real xc[ND_ND]; // 声明实型数组,用于存储单元中心坐标/* loop over all cell threads in the domain */// 循环遍历域中的所有单元线程thread_loop_c(t, d){/* loop over all cells */// 开始在当前线程中循环遍历所有单元begin_c_loop_all(c, t){// 获取当前单元的中心坐标,存储在xc数组中// ND_ND: Fluent宏,表示空间维度数(2D时为2,3D时为3)// xc[0], xc[1], xc[2] 分别对应x, y, z坐标C_CENTROID(xc, c, t);// 计算当前单元中心到点(0.5, 0.5, 0.5)的欧几里得距离// ND_SUM: 对参数求和,用于处理不同维度的情况// pow(xc[0] - 0.5, 2.): 计算(x-0.5)²// pow(xc[1] - 0.5, 2.): 计算(y-0.5)²// pow(xc[2] - 0.5, 2.): 计算(z-0.5)²(如果是2D,此项为0)// sqrt(...): 计算平方根,得到距离if (sqrt(ND_SUM(pow(xc[0] - 0.5, 2.),pow(xc[1] - 0.5, 2.),pow(xc[2] - 0.5, 2.))) < 0.25)// 如果距离小于0.25,设置单元温度为400KC_T(c, t) = 400.;else// 否则,设置单元温度为300KC_T(c, t) = 300.;}end_c_loop_all(c, t) // 结束单元循环}}
(9)DEFINE_ON_DEMAND
①描述
DEFINE_ON_DEMAND是一种通用宏,可用于指定在Fluent中“按需”执行的UDF,而不是由Fluent在计算过程中自动调用。UDF在激活后会立即执行,但在求解器迭代期间不可访问。请注意,域指针d不会作为参数显式传递给DEFINE_ON_DEMAND。因此,若要在按需函数中使用域变量,需要先使用Fluent提供的Get_Domain实用程序获取该变量。
②用法
DEFINE_ON_DEMAND (name)
name:UDF名称。
DEFINE_ON_DEMAND 只有一个参数:name,需要定义UDF的名称。
③示例
以下名为on_demand_calc的UDF会计算并输出当前数据字段的最低、最高和平均温度,随后计算温度函数,并将其存储在用户定义的0内存位置。挂载按需UDF后,该字段值将在Fluent后处理对话框的下来列表中可用。可以通过选择“用户定义内存…”类别中的“用户内存0”来选定此字段。执行UDF后若写入数据文件,用户定义内存字段将保存至数据文件中。
# include"udf.h"DEFINE_ON_DEMAND(on_demand_calc){Domain *d; /* declare domain pointer since it is not passed as anargument to the DEFINE macro */ // 声明域指针(ON_DEMAND函数没有域参数)// 声明并初始化温度统计变量real tavg = 0.; // 体积平均温度real tmax = 0.; // 最高温度real tmin = 0.; // 最低温度// 声明局部变量real temp, volume, vol_tot; // 临时温度、单元体积、总体积Thread *t; // 声明线程指针cell_t c; // 声明单元索引d = Get_Domain(1); /* Get the domain using Ansys Fluent utility */ // 获取域指针/* Loop over all cell threads in the domain */// 循环遍历域中的所有单元线程thread_loop_c(t, d){// 重置体积累加器(注意:应该在循环开始前初始化vol_tot)vol_tot = 0.;/* Compute max, min, volume-averaged temperature *//* Loop over all cells */// 开始在当前线程中循环遍历所有单元,计算温度统计值begin_c_loop(c, t){volume = C_VOLUME(c, t); /* get cell volume */ // 获取单元体积temp = C_T(c, t); /* get cell temperature */ // 获取单元温度// 更新最低温度if (temp < tmin || tmin == 0.)tmin = temp;// 更新最高温度if (temp > tmax || tmax == 0.)tmax = temp;vol_tot += volume; // 累加总体积tavg += temp * volume; // 累加温度×体积(用于计算体积加权平均值)}end_c_loop(c, t) // 结束单元循环// 计算体积平均温度tavg /= vol_tot; // 平均温度 = 总和(温度×体积) / 总体积// 输出温度统计结果到控制台printf("\n Tmin = %g Tmax = %g Tavg = %g\n", tmin, tmax, tavg);/* Compute temperature function and store in user-defined memory*//* (location index 0) */// 计算温度归一化值并存储到用户自定义内存(UDM)索引0begin_c_loop(c, t){temp = C_T(c, t); // 获取单元温度// 计算归一化温度:(温度 - 最低温度) / (最高温度 - 最低温度)C_UDMI(c, t, 0) = (temp - tmin) / (tmax - tmin);}end_c_loop(c, t) // 结束单元循环}}
Get_Domain是一个用于获取域指针的宏。由于域指针未作为显式参数传递给DEFINE_ON_DEMAND,因此必须使用此宏来获取域指针。该函数名为on_demand_calc,不接受任何显式参数。在函数内部主体部分,首先定义并初始化函数要使用的变量。变量声明之后,使用循环宏对域中的每个单元线程进行循环。在该循环内部,另一个循环用于遍历所有单元。在内层循环中,计算总体积以及最小、最大和体积平均温度。这些计算值将输出到Fluent控制台。随后对每个单元进行第二次循环用于计算函数f(x)并将其存储在用户自定义内存0位置。
(10)DEFINE_REPORT_DEFINITION_FN
①描述
DEFINE_REPORT_DEFINITION_FN是一个宏,可以使用它来指定用于报告单值表达式的UDF,该表达式可以被绘制、写入或打印到控制台作为报告定义。
②用法
DEFINE_REPORT_DEFINITION_FN (name)
name:用户自定义报告定义函数的名称。
DEFINE_REPORT_DEFINITION_FN只有一个参数:name,需要定义UDF的名称。
③示例
该函数计算入口处的体积流量,展示了在输入变量上执行操作的能力,并将结果输出用于绘图、打印或作为用户自定义报告定义的一部分写入文件。
#include "udf.h"DEFINE_REPORT_DEFINITION_FN(volume_flow_rate_inlet){real inlet_velocity = Get_Input_Parameter("vel_in");real inlet_area = 0.015607214;real volumeFlow = inlet_velocity*inlet_area;return volumeFlow;}
参考资料:《Ansys Fluent UDF Manual》 2023R1
CFD理论基础合集(持续更新中):
Ansys Fluent帮助文档-UDF篇:用户自定义函数概述(UDFs)(一)
Ansys Fluent帮助文档-UDF篇:用户自定义函数概述(UDFs)(二)
Ansys Fluent帮助文档-UDF篇:通用DEFINE宏(一)
特别感谢您的阅读、点赞、转发、推荐!
夜雨聆风
