Ansys Fluent文档-UDF篇:通用DEFINE宏(一)
①在源代码中,必须将DEFINE宏的所有参数放在同一行。将DEFINE语句拆分成多行会导致编译错误。
②确保宏(如DEFINE_PROFILE)与参数的第一个括号之间没有空格,否则在Windows中会导致错误。
③不要在源代码的注释中包含DEFINE宏语句(例如DEFINE_PROFILE)。这会导致编译错误。
2.2 通用DEFINE宏
(1)DEFINE_ADJUST
①描述
DEFINE_ADJUST是一种通用宏,可用于调整或修改未作为参数传递的Fluent变量。例如,可以使用DEFINE_ADJUST来修改流动变量(如速度、压力)并计算积分。还可以用它来对域内的标量进行积分,并根据结果调整边界条件。使用DEFINE_ADJUST定义的函数会在每次迭代时执行,并在求解输运方程之前的每次迭代开始时被调用。
②用法
DEFINE_ADJUST (name, d)
name:UDF名称;
Domain *d:指向调整函数所要应用的域。域参数提供了对网格中所有单元和面线程的访问。对于多相流,求解器传递给函数的指针是混合物级别的域。
DEFINE_ADJUST有两个参数:name和d。需要提供UDF的名称name,而d则由Fluent求解器传递给的UDF。
③示例1
以下名为my_adjust的UDF通过DEFINE_ADJUST在整个域上积分湍流耗散值,随后在控制台中显示该值。此UDF在每次迭代时被调用一次,可在Fluent中作为解释型或编译型UDF执行。
#include"udf.h"DEFINE_ADJUST(my_adjust,d){Thread *t;// 声明线程指针,用于遍历不同的网格区域(边界、内部区域等)/* Integrate dissipation. */real sum_diss=0.;// 声明并初始化实型变量sum_diss为0,用于累加湍流耗散率的体积积分值cell_t c;// 声明单元索引,用于遍历网格中的每个单元thread_loop_c(t,d)// 循环遍历计算域中的所有单元线程(包括不同区域和边界){begin_c_loop(c,t)// 开始在当前线程t中循环遍历所有单元sum_diss += C_D(c,t)* C_VOLUME(c,t);//累加:当前单元的湍流耗散率 × 单元体积;C_D(c,t): 获取单元(c,t)的湍流耗散率值;C_VOLUME(c,t): 获取单元(c,t)的体积end_c_loop(c,t)// 结束当前线程的单元循环}printf("Volume integral of turbulent dissipation: %g\n", sum_diss);//输出体积积分结果到控制台,%g: 自动选择浮点数格式输出}
④示例2
以下名为adjust_fcn的UDF使用DEFINE_ADJUST宏,将用户自定义标量定义为另一个用户自定义标量梯度的函数。该函数在每次迭代中调用一次,并在Fluent中以编译型UDF的形式执行。
# include"udf.h"DEFINE_ADJUST(adjust_fcn,d){Thread *t;// 声明线程指针,用于遍历不同的网格区域cell_t c;// 声明单元索引,用于遍历网格单元real K_EL = 1.0;// 声明并初始化常数K_EL为1.0(可能是弹性系数或其他物理参数)/* Do nothing if gradient isn't allocated yet. */// 检查数据是否有效,如果梯度数据尚未分配,则直接返回(避免在初始化阶段出错)if (! Data_Valid_P())return;// 循环遍历计算域中的所有线程thread_loop_c(t,d){// 检查当前线程是否为流体线程(排除固体区域等)if (FLUID_THREAD_P(t)){// 开始在当前流体线程中循环遍历所有单元// 注意:这里使用begin_c_loop_all而不是begin_c_loop,表示包含所有单元(包括挂起的单元)begin_c_loop_all(c,t){// 更新用户自定义标量(UDS)索引1的值:// C_UDSI_G(c,t,0): 获取UDS索引0的梯度向量// NV_MAG2(): 计算向量的平方模(各分量的平方和)// ... * C_VOLUME(c,t): 再乘以单元体积// 最后将结果累加到UDS索引1的当前值上C_UDSI(c,t,1) += K_EL * NV_MAG2(C_UDSI_G(c,t,0)) * C_VOLUME(c,t);}end_c_loop_all(c,t) // 结束单元循环}}}
(2)DEFINE_DELTAT
①描述
DEFINE_DELTAT是一个通用宏,可用于在瞬态问题求解过程中控制时间步长的大小。请注意,仅当在Fluent的Run Calculation任务页面中从Type下拉列表选择User-Defined Function时,此宏才可使用。
②用法
DEFINE_DELTAT (name, d)
name:UDF名称;
Domain *d:指向时间步进控制函数所要应用的域。域参数提供了对网格中所有单元和面线程的访问。对于多相流,求解器传递给函数的指针是混合物级别的域。
DEFINE_DELTAT有两个参数:name和domain。需要提供name,即UDF的名称。domain由Fluent求解器传递给UDF。UDF需要计算物理时间步长的实际值并将其返回给求解器。
③示例
以下名为mydeltat的UDF是一个简单函数,展示了如何使用DEFINE_DELTAT来改变模拟中的时间步长值。首先,使用CURRENT_TIME获取当前模拟时间的值(该值被赋予变量flow_time)。在计算的前0.5秒内,时间步长设置为0.1;模拟剩余部分的时间步长则设置为0.2。随后将时间步长变量返回给求解器。
# include"udf.h"DEFINE_DELTAT(mydeltat,d){real time_step;real flow_time = CURRENT_TIME;if (flow_time < 0.5)time_step = 0.1;elsetime_step = 0.2;return time_step;}
(3)DEFINE_EXECUTE_AT_END
①描述
DEFINE_EXECUTE_AT_END是一种通用宏,可在稳态运行的迭代结束时或瞬态运行的时间步长结束时执行。当需要在这些特定时刻计算流量参数时,可使用DEFINE_EXECUTE_AT_END。请注意,无需指定执行末端UDF是在时间步长结束时还是在迭代结束时执行——在Fluent模型中选择稳态或非稳态时间方法时,系统会自动完成此判定。
②用法
DEFINE_EXECUTE_AT_END(name)
name:UDF名称;
DEFINE_EXECUTE_AT_END只有一个参数:name。需要提供UDF的名称。与DEFINE_ADJUST不同,DEFINE_EXECUTE_AT_END不会传递域指针。因此,如果函数需要访问域指针,则需要使用工具Get_Domain(ID)显式获取它。如果UDF在多相流解决方案中需要访问相域指针,则需要将相应的相ID传递给Get_Domain以获取它。
③示例
以下名为execute_at_end的UDF,通过DEFINE_EXECUTE_AT_END将整个域中的湍流耗散进行积分,并在当前迭代或时间步结束时在控制台中显示。该UDF可在Fluent中作为解释型或编译型UDF执行。
# include"udf.h"DEFINE_EXECUTE_AT_END(execute_at_end){Domain *d; // 声明域指针,用于指向计算域Thread *t; // 声明线程指针,用于遍历不同的网格区域/* Integrate dissipation. */real sum_diss = 0.;// 声明并初始化实型变量sum_diss为0,用于累加湍流耗散率的体积积分值cell_t c;// 声明单元索引,用于遍历网格中的每个单元// 获取计算域指针// Get_Domain(1): 获取域ID为1的域,在多相流中通常指混合物域d = Get_Domain(1); /* mixture domain if multiphase */// 循环遍历计算域中的所有单元线程thread_loop_c(t,d){// 检查当前线程是否为流体线程(排除固体区域等)if (FLUID_THREAD_P(t)){// 开始在当前流体线程中循环遍历所有单元begin_c_loop(c,t)// 累加:当前单元的湍流耗散率 × 单元体积// C_D(c,t): 获取单元(c,t)的湍流耗散率值(通常是k-epsilon模型中的ε)// C_VOLUME(c,t): 获取单元(c,t)的体积sum_diss += C_D(c,t) * C_VOLUME(c,t);// 结束当前线程的单元循环end_c_loop(c,t)}}// 输出湍流耗散率的体积积分结果到控制台// %g: 自动选择浮点数格式输出printf("Volume integral of turbulent dissipation: %g\n", sum_diss);// 强制刷新标准输出缓冲区,确保信息立即显示在控制台fflush(stdout);}
(4)DEFINE_EXECUTE_AT_EXIT
①描述
DEFINE_EXECUTE_AT_EXIT是一个通用宏,可用于在Fluent会话结束时执行函数。
②用法
DEFINE_EXECUTE_AT_EXIT(name)
name:UDF名称;
DEFINE_EXECUTE_AT_END只有一个参数:name。需要提供UDF的名称。
(5)DEFINE_EXECUTE_FROM_GUI
①描述
DEFINE_EXECUTE_FROM_GUI是一种通用宏,可用于定义通过用户自定义图形界面(GUI)执行的UDF。例如,使用DEFINE_EXECUTE_FROM_GUI定义的C函数可在用户自定义GUI中点击按钮时执行。
②用法
DEFINE_EXECUTE_FROM_GUI (name,libname,mode)
name:UDF名称;
char *libname:Fluent中已加载的UDF库名称;
int mode:从Scheme程序中传递的整数,用于定义用户自定义GUI。
DEFINE_EXECUTE_FROM_GUI有三个参数:name、libname和mode。需要提供name,即UDF的名称。变量libname和mode由Fluent求解器传递给UDF。整型变量mode从定义用户自定义GUI的Scheme程序传递而来,代表GUI对话框中可用的用户选项。每个选项都可以调用UDF中不同的C函数。例如,用户自定义的GUI对话框可能有多个按钮。每个按钮可由不同的整数表示,点击时将执行相应的C函数。
重要提示:DEFINE_EXECUTE_FROM_GUI必须作为编译型UDF实现,且每个UDF库中只能存在一个此类函数。
③示例
以下名为reset_udm的UDF在用户自定义GUI对话框中的重置按钮被点击时,会重置所有用户自定义内存(UDM)值。按钮点击动作由0表示,该值由Fluent求解器传递给UDF。
# include"udf.h"DEFINE_EXECUTE_FROM_GUI(reset_udm, myudflib, mode){Domain *domain = Get_Domain(1);/* Get domain pointer */// 获取域指针,参数1通常表示主域或混合物域Thread *t; // 声明线程指针,用于遍历不同的网格区域cell_t c; // 声明单元索引,用于遍历网格单元int i; // 声明整数变量,用于循环计数器/* Return if mode is not zero */if (mode != 0) return;// 检查执行模式,如果mode不为0,则直接返回(通常mode=0表示执行操作)/* Return if no User-Defined Memory is defined in Ansys Fluent */if (n_udm == 0) return;// 检查Fluent中是否定义了用户自定义内存(UDM),如果没有定义,则直接返回/* Loop over all cell threads in domain */// 循环遍历计算域中的所有单元线程thread_loop_c(t, domain){/* Loop over all cells */// 开始在当前线程中循环遍历所有单元begin_c_loop(c, t){/* Set all UDMs to zero */// 循环遍历所有已定义的UDM索引for (i = 0; i < n_udm; i++){// 将当前单元的每个UDM值设置为0.0C_UDMI(c, t, i) = 0.0;}}end_c_loop(c, t); // 结束单元循环}}
参考资料:《Ansys Fluent UDF Manual》 2023R1
CFD理论基础合集(持续更新中):
Ansys Fluent帮助文档-UDF篇:用户自定义函数概述(UDFs)(一)
Ansys Fluent帮助文档-UDF篇:用户自定义函数概述(UDFs)(二)
特别感谢您的阅读、点赞、转发、推荐!
夜雨聆风
