
简介这份代码包面向使用Fluent开展多相流模拟的工程师与科研人员系统整理VOF、Eulerian-Eulerian、Eulerian-Lagrangian三大模型的原理、适用场景与设置要点。VOF模型适合油水分离、波浪模拟等自由表面流动Eulerian-Eulerian模型适用于流化床、混合器中的气固/液固两相流Eulerian-Lagrangian模型则用于喷雾干燥、气力输送中颗粒或液滴追踪。包体共3个文件以HTML页面为主体呈现完整解析内容另附inscode配置与.gitignore文件整体仅6KB轻量易用。已有243人学习参考。从中可快速建立起多相流模型选型的判断框架理解不同模型对相间动量交换、界面追踪和计算资源的差异要求同时内容还整理了模型选择依据强调需结合流动特性、物理模型与计算资源综合判断涵盖网格划分、边界条件与求解器参数设置等关键环节说明适合初学者入门也方便有经验者当作速查手册使用。1. 多相流模型怎么选三个主模型的底层逻辑我最早接触Fluent多相流是从一个气液两相流项目开始的。当时手头有个鼓泡塔气泡直径、气含率、流场分布都要预测软件里Model列表一排就是VOF、Mixture、Eulerian三项新手很容易随便选一个就开算。但后面我吃了不少亏才发现模型选错后面做再多都是白费甚至算出来看起来合理实际上物理图景完全不对。多相流这个名称本身容易让人误解。Fluent里这三个模型并不是“精度高低”的关系而是“适用尺度”和“相界面处理方式”的差异。用大白话说VOF是画界面的Mixture是算混合场的Eulerian是算每一种流体各自的场。1.1 VOF模型哪些场景必须用它VOF模型的核心思路是在同一个计算网格里用相体积分数来确定每个网格里装了多少水、多少空气。体积分数是0就是纯空气是1就是纯水在0到1之间说明这里就是相界面。它最大的特点是把自由界面当作一个可以追踪的几何对象来处理。所以做水坝溃决、船体兴波、液滴碰撞、射流破碎这类问题VOF是标配选择。因为这类问题里界面形态本身就是最重要的结果你需要看到界面怎么变形、怎么破碎、怎么合并。如果这时候用Mixture或Eulerian你就只能得到两相各自的速度和体积分数界面会糊成一片渐变带根本谈不上“捕捉”。但VOF也有它的局限。它默认所有相共享同一个速度场和压力场也就是说它假设每个网格内的流体虽然可能是不同相但它们运动速度相同。这在大尺度界面问题中基本成立可一旦遇到相间滑移明显、比如气泡在水中快速上升同一个网格里液相上升速度是0.1m/s、气相是2m/sVOF就表达不了这种速度差。另外VOF对网格分辨率极其敏感界面区域的网格如果不够密界面会严重破碎气液之间变成一团混杂。还有一个被很多人忽略的点VOF虽然只有一套动量方程但这不代表它省事。它表面张力项的曲率计算依赖界面附近二阶导数的精度网格质量稍微差一点就会出现寄生电流界面会莫名抖动。我第一次做微流控液滴时界面被拉出了很多小尖角排查了很久才发现是网格在界面区偏斜太厉害。1.2 Mixture模型轻量级的“半宏观”方案Mixture模型在工程界用得极多因为它的计算成本比Eulerian低一个量级。它的物理假设是各相在局部尺寸上达到平衡相与相之间存在很小的滑移速度可以把这个滑移用代数关系式来表达而不是求解第二套动量方程。做过沉淀池模拟的朋友应该比较熟悉泥水两相用Mixture算泥相体积分数、沉降速度、浓度分布都能出来而且收敛速度快不容易发散。鼓泡塔初始筛选阶段也可以用Mixture算出来的气含率分布、流型趋势往往和实验对得上能快速给方案定一个大方向。但这里要特别提醒Mixture虽然叫“多相流”但它是一个“混合场”框架它求解的是混合物的动量方程再通过相对速度来反推各相分布。如果相间相对速度本身很大那么代数滑移公式的误差就会膨胀。算旋风分离器内的颗粒颗粒粒径到了微米级还行如果是毫米级颗粒Mixture模型算出来的颗粒轨迹和真实情况偏差就会相当大。另一个经常被忽略的是Mixture模型里“液相”是由各相体积分数加权后的属性如果你要做蒸发冷凝这类涉及传质的工况Mixture后面挂传质模型也挺麻烦不如直接用Eulerian或者VOF里的蒸发冷凝模型。所以我的经验是Mixture适合“趋势型”研究不适合“机理型”研究。1.3 Eulerian模型全双流体框架Eulerian模型是我个人认为最难调、但上限最高的多相流框架。它为每一相独立求解动量方程、连续性方程相与相之间通过交换系数动量交换、热量交换、质量交换耦合起来。这意味着你的曳力模型、升力模型、湍流分散力等等都要给清楚。流化床、气力输送、液液萃取、有强相间作用的体系基本都要上Eulerian。因为只有它能够表达“气固两相各自独立运动且相互影响”这种物理本质。做过流化床的人应该都知道Eulerian模型调起来有多疼几何模型容易搭最难的是曳力模型参数、颗粒温度granular temperature、径向分布函数、镜面反射系数……每一个都可能导致床层膨胀高度不对。我记得第一次做鼓泡塔的Eulerian模拟算出来的气含率比实验值差了将近一倍。后来一个一个排查发现问题出在两处一是初场的体积分数初始化没设置好二是曳力模型用了默认的Schiller-Naumann适配大粒径其实不合适。换成Grace模型之后气含率曲线马上就贴近实验值了。这种经验不踩坑真的学不会。1.4 选型对照表从物理场景直接定位综合下来我平时给团队同事做选型建议时基本都是按下面这张表的逻辑来判断物理场景推荐模型选择理由自由界面清晰、需要捕捉界面形态VOF界面体积分数物理意义清晰能输出界面几何气泡/颗粒含量低、重点关注连续相流场Mixture计算开销小收敛快工程筛选够用相间滑移显著、各相独立运动且相互影响Eulerian双流体框架能表达各相独立动量演化分层流油水分层等VOF界面稳定重力驱动占主导均相流动、相间趋于平衡Mixture无需追踪界面混合属性即可表达流化床、颗粒浓度高Eulerian颗粒相压力、粘度等微观作用只能由它表达还有一个朴素但重要的经验如果不能确定用哪个先做网格无关性验证和模型对比验证用同一套网格分别算一遍看关键物理量的差异。算力宽裕就用Eulerian做基准算力不够就用Mixture做趋势筛选VOF做界面细节分析。2. 网格准备与求解设置里的关键细节很多人以为多相流难在模型选择模型选完就能一路算到底。实际上多相流项目里至少一半的精力要花在网格和求解设置的细节上。同样的模型、同样的UDF网格拓扑换一下结果可能就天翻地覆。2.1 网格质量对多相流的影响Fluent对网格质量的通用标准是偏斜度Skewness低于0.85正交质量高于0.1。但在多相流里这个标准往往要更苛刻尤其是VOF模型和Eulerian模型。原因很简单多相流计算中界面曲率、体积分数的梯度都依赖网格面上的通量计算网格一旦畸变通量插值就会出现非物理振荡。我自己做自由液面的时候一般要求界面附近区域的偏斜度低于0.7体积变化率控制在1.2以内。六面体网格优先因为它的通量计算是最稳定的四面体网格虽然自动生成方便但界面捕捉的精度下降得厉害界面会变得又粗又抖。多孔介质和动静区域交界处的网格也是重灾区。大家搜“多孔介质Fluent参数设定”会看到很多帖子但真正关键的一点是多孔介质区域网格方向要与流动方向对齐。如果多孔区域的惯性阻力系数设置合理但网格斜向反算出来的压降就会偏大很多。我做过一个蜂窝陶瓷载体项目就是因为网格方向没对齐压差比实验值高了20%以上。2.2 表面张力、接触角与相间作用多相流里还有一个让人头疼的参数表面张力系数和接触角。Fluent里设置表面张力很简单拉一个常数就行但你要是真用常数去算微流控、喷雾、毛细现象大概率会翻车。实际液滴在运动过程中表面张力会受温度、表面活性剂浓度影响发生动态变化。所以在需要精确刻画气液界面的场景里我倾向于用UDF让表面张力随温度或组分变化。接触角方面如果是静态接触角可以直接给数值但动态润湿过程里接触角滞后Contact Angle Hysteresis是真实存在的前进角和后退角往往差十几度。Fluent默认简化处理不会自动考虑滞后因此做液滴在斜面上的滚动模拟时要自己写UDF去控制接触角。再说到相间作用力。Eulerian模型里动量交换的曳力系数、升力系数、虚拟质量力都要手动指定或通过UDF定义。对很多工程刚入门的朋友来说这些力全是生面孔。我用一个生活化类比解释曳力就像你在水里推一个球水阻碍球运动的那股力升力是球在水中运动时因两侧速度差产生的横向推力虚拟质量力则是球加速时带动周围水一起加速水产生反作用力带来的“惯性增加”效应。球越小、密度差越大虚拟质量力的作用越明显。2.3 求解模式与库朗数的控制很多人在多相流计算中遇到发散第一反应是调低松弛因子。但松弛因子不是万能药它只是让变量更新变慢物理本质没有变化。更关键的一步是瞬态多相流计算中需要控制库朗数Courant Number。库朗数的定义很直观CFL 速度 × 时间步长 / 网格尺寸。它表示在一个时间步里流体穿过多少个网格。VOF模型里如果CFL大于1界面区域会产生严重的数值振荡界面网格上的体积分数会超过1或者变成负数计算没几步就崩了。我做VOF的工程经验是时间步长选取要让CFL保持在0.5以下最好在0.2-0.4之间。Fluent里用自适应时间步长可以帮忙把最大库朗数设置为0.5它会自动调整时间步。Eulerian模型对CFL的需求略宽一些但超过2也会明显影响稳定性。还要提一个高级一点的问题能量方程和多相流耦合时时间尺度往往是跨数量级的。例如考虑相变的气液两相流界面运动的时间尺度是毫秒级而热扩散的时间尺度可能是秒级。这种情况下用全局统一时间步长效率极低。我的做法是把能量方程和多相流方程分开做算子分裂Operator Splitting先算多相流一个时间步再冻结流场散热几个外部时间步。这个方法虽然要多写一点控制脚本但能节省大量机时。3. 代码实操从UDF编写到编译调试标题里带着“代码”两个字那正文必须要聊透UDF的问题。很多人在搜索框里打“fluent里udf文件在哪里编辑”这个问题的含义其实有两层一是编辑器在哪里打开二是UDF怎么组织。Fluent本身不自带代码编辑器我一般用Visual Studio Code写C语言代码再用Fluent的编译环境编译。Visual Studio Code有代码提示和高亮比Fluent内嵌的简单文本框好用了不止一个级别。3.1 UDF在Fluent中如何组织UDFUser Defined Function是Fluent开放的C语言接口让你能自定义边界条件、源项、材料物性、相间作用力、初始化场等等。标准UDF文件的基本结构是这样的#include udf.h DEFINE_PROPERTY(water_viscosity, c, t) { real temp C_T(c, t); return 2.414e-5 * pow(10.0, 247.8 / (temp - 140.0)); }很多新手把udf.h当成一个普通头文件其实它的作用远不止引入函数库。Fluent在编译UDF时通过你include的udf.h来匹配当前版本的数据结构宏定义所以不同版本Fluent编译UDF时这套头文件必须与求解器版本对应。如果你用Fluent 2023 R1的udf.h去编译给Fluent 2023 R2用大概率报出一堆莫名其妙的类型冲突。在组织Fluent项目代码时我习惯把不同功能的UDF拆成不同文件。比如一个文件放物性定义一个文件放源项一个文件放初始化宏。这样调试的时候定位问题更快bin和lib目录也不会乱成一团。再说了多相流的UDF联动性很强一个宏出错往往牵一串函数拆开文件至少能把出错范围缩小。3.2 曳力系数自定义一个完整可参考的示例我觉得最值得写出来的UDF案例是Eulerian模型里自定义曳力系数的过程。这里我用一个幂律型曳力模型来演示#include udf.h #define RHO_P 2500.0 /* 颗粒密度kg/m3 */ #define D_P 0.0003 /* 颗粒直径m */ #define A 0.44 /* 模型参数A */ #define B 2.65 /* 模型参数B */ DEFINE_EXCHANGE_PROPERTY(custom_drag, c, t, li, tj) { real rho_cont C_R(c, t); /* 连续相密度 */ real mu_cont C_MU_L(c, t); /* 连续相动力粘度 */ real slip_x C_U(c, t) - C_U(c, tj); /* 相间滑移速度x分量 */ real slip_y C_V(c, t) - C_V(c, tj); /* 相间滑移速度y分量 */ real slip_z C_W(c, t) - C_W(c, tj); /* 相间滑移速度z分量 */ real slip_mag sqrt(slip_x * slip_x slip_y * slip_y slip_z * slip_z); real re_p rho_cont * slip_mag * D_P / mu_cont; /* 颗粒雷诺数 */ real cd 0.0; real drag 0.0; if (re_p 1.0e-6) re_p 1.0e-6; /* 幂律型曳力模型 */ cd A B / re_p; drag 18.0 * mu_cont * cd * re_p / (24.0 * D_P * D_P); return drag; }这个UDF里DEFINE_EXCHANGE_PROPERTY是专门用来定义相间交换系数的宏它和Fluent内置的相间曳力模型是同一层级的接口。函数里几个关键的细节我提一下第一C_MU_L(c, t)在单相流里是层流粘度在多相流里它取的是连续相的层流粘度而不是混合粘度。这一点不打开Fluent的User Guide很多照着扒代码的人是看不出来的。第二颗粒雷诺数趋近于零时公式中B/re_p会爆炸。所以我对re_p做了一个下限裁剪clip这个操作在实际工程中非常重要因为迭代初期的流场往往极不物理滑移速度接近零的情况很常见。第三曳力系数的量纲和单位。DEFINE_EXCHANGE_PROPERTY返回的交换系数在Fluent中被用来乘相间滑移速度、再乘相的体积分数从而组成动量交换源项。它的单位是kg/(m3·s)。如果量纲给错了计算机会报units mismatch或者干脆不收敛。我见过不少朋友在这里栽跟头算出来流化床颗粒全部飘到顶上去原因就是曳力返回量级差了三个数量级。3.3 编译运行中的常见坑UDF编译报错是家常便饭最典型的几类问题环境变量缺失导致编译器无法识别。Windows下Fluent需要识别Visual Studio的C编译器如果报“Error: Unable to locate compiler”多半是环境变量没有配置。解决方案是打开Fluent后File → Solution → Environment里检查或者直接用Fluent自带的Compile UDF命令让它自动探测。宏参数写错。比如DEFINE_PROPERTY和DEFINE_EXCHANGE_PROPERTY的参数列表完全不同前者是(name, c, t)后者是(name, c, t, li, tj)。我见过很多代码第一步就把宏头写错编译器根本不会提示你宏参数对不对而是直接爆出一堆typedef类型不匹配的报错。这种报错很具有迷惑性因为你按报错去找往往以为是某个结构体定义错了。还有一个很隐蔽的坑Fluent的并行计算对UDF代码有特殊要求。如果你的UDF里有全局变量或static变量在并行分区计算时这些变量在每个计算节点上都是独立副本无法跨节点通信。我在做大规模气液两相流时遇到过弱收敛无论怎么调都差一口气最后排查发现是UDF里用了static变量累计了质量通量而并行节点不共享这个变量残差就永远停在一个小值附近。4. 从计算发散到结果可信常见问题排查实录最好写也最实用的部分应该是问题排查。我这些年做多相流仿真九成的时间不是在“算”而是在“救”那些算不动的模型。下面把几个高频问题整理成表格按现场排查的思路讲一遍。4.1 收敛困难残差、通量与质量守恒多相流不发散的少一发散就是大动静。残差曲线冲到1e10那基本可以判定是某个源项或者交换系数出问题了。第一排查项不是松弛因子而是欠松弛因子初始化。很多发散问题在迭代的第三到第五步就开始酝酿了这时候看云图会发现某个区域的压力出现非物理的负值。负压一般都和初始化场不合理有关比如Eulerian模型里第二相体积分数初始值为0但速度场非零动量方程里就出现了“除以零”效应。我处理这类问题的办法是把第二相体积分数初始化成一个极小值比如1e-6而不是0然后打开体积分数方程的Quadratic Upwind插值。第二排查项是有限体积法里的通量限制。多相流里体积分数必须严格保持在0到1之间任何数值弥散造成越界都会连锁产生负密度、负粘度。在Fluent中直接调Limited格式能让体积分数的越界变少但代价是界面被抹得更平。如果计算本身对界面精度要求不高这是一笔划算的买卖。第三排查项是质量守恒。很多看似“收敛”的计算实际上全场质量平衡有10%以上的误差。检查方法很简单Report → Fluxes里看进口和出口的净通量再看Graphics里某截面的速度分布是否光滑。如果进口出口差了10%以上说明缺陷在边界条件或者网格质量残差再低也不能作为收敛依据。4.2 “孤儿网格”和梯度警告搜过“fluent孤儿网格”的朋友大概率都在报错日志里见到过类似的警告Warning: orphan faces, cells, or nodes were detected。孤儿网格的意思是网格拓扑中存在一些单元格或节点和周围网格没有正确的连接关系导致求解器在处理通量时把它们孤立出来了。导致孤儿网格的原因主要有三种一是从其他网格软件导出时格式转换出错二是Fluent里的网格重排序或重构操作不当三是TUI命令手工删除了某些网格实体但关联关系没有更新。处理时我会先用Mesh → Check看诊断信息如果确认有孤儿网格最稳妥的方法是重新导入原始网格导出文件或者用Separate和Merge修复部分缝隙。如果网格拓扑破损严重重新划分比手动修要快得多。梯度和多相流的组合还有一个很多人不知道的坑默认的Green-Gauss Node-Based梯度重构在界面附近会出现振荡因为界面区域的体积分数梯度非常大而线性重构假设是光滑的。我在VOF计算中会优先使用Least Squares Cell-Based梯度它对网格畸变和多相界面更鲁棒。曾经一个算例用Node-Based梯度连发散三次改成Least Squares后直接平稳收敛到目标残差。4.3 结果可信度检查计算收敛之后不代表结果就可靠。我做项目验证时从来不看残差这一个指标而是看三件事物理合理性、网格无关性、和实验或经验公式的对比。物理合理性是最快的筛子。你把速度矢量图打开看看有没有局部回流和漩涡遍地方向都不对把压力云图打开看看压降趋势是否符合常识。多相流里要特别看体积分数云图如果相同位置出现“水中有气泡、气泡里有水”这样的穿甲现象说明界面已经糊了结果不可用。网格无关性检验在什么时候做应该是在你最终确定几何和物理模型之后而不是在方案还没定的时候就做。至少用三套网格粗、中、细。如果关键物理量比如某个截面的平均气含率在中等网格和细网格之间变化小于5%那么中等网格就可以接受。如果始终不稳定很可能不是网格问题而是物理模型本身选择有误。实验对比是最硬核的验证方式。没有实验数据时退而求其次和经验公式对比。气液两相流中用得非常多的漂移通量模型或者流化床里最小流化速度的经验关联式都能做参考基准。但要注意经验公式的适用范围往往很窄比如只适用于某个粒径范围或某个雷诺数范围不能直接套到所有工况上。5. 多相流仿真的算力与资源调度心得写到这里发现UDF和多相流模型还可以结合一个现实问题聊算力。多相流仿真的计算开销远高于单相流尤其Eulerian模型相数越多、网格越密内存和CPU时间的消耗都是几何级增长。这篇博文主要是技术解析这部分就当个人经验补充来聊了。我自己的一个经验准则是VOF模型用单个工作站算两百万网格的瞬态问题是可以接受的Mixture模型可以再翻一倍网格量Eulerian模型则不要轻易超过三百万网格除非你的机器内存足够大。Eulerian模型里面每增加一相每个额外相都要多一套动量方程和连续性方程内存占用会线性增加而且相间耦合矩阵会让线性方程组的迭代次数剧增CPU开销增长远超线性。并行计算的进程数也要斟酌。Fluent的并行对多相流没有单相流那么友好因为界面区域和相间耦合引入了更多的通信量。我从实践中总结出来的经验是先跑几十个迭代步记录单步耗时然后逐渐增加进程数找到拐点。比如四核性价比最高八核提升并不明显那就别浪费核数。如果项目对周期敏感我通常建议先做一版Li代模型比如用Mixture替代Eulerian跑通整个流程逻辑拿到近似的流场趋势再针对重点区域换高保真模型重算。这种方法在方案阶段特别管用能省下至少一半的试错时间。最后再分享一个小细节多相流的自动保存频率一定要高。Eulerian模型调参的时候经常是算了一百步之后突然发散如果数据保存间隔太长发散前的流场全都丢了。我习惯每200步保存一次数据文件UDF调试阶段每50步就存一次看起来多占点磁盘其实换来的是反复迭代调参的安心。这种经验都是踩过坑才有的。本文还有配套的精品资源点击获取