跳转至

第 19 章:OpenFOAM® 湍流应用算例(An OpenFOAM® Turbulent Flow Application)

19.1 引言(Introduction)

汽车车身的设计是一件要求很高的工作,需要在品牌风格与消费者审美之间找到妥协,同时还要满足燃油经济性所要求的高效气动特性。在这一情境下使用 CFD 工具是至关重要的:它能帮助研究气动力、粘性效应与湍流边界层的相互作用、流场对车身形状变化的敏感性,以及在各种工况下车辆的阻力系数。本章使用 simpleFoamTurbulent 求解器以及前几章开发并实现的边界条件,分析一个被广泛研究的测试算例——Ahmed 钝体(Ahmed bluff body)。

19.2 Ahmed 钝体(The Ahmed Bluff Body)

在汽车应用中,对阻力贡献最大的因素是车体后方形成的尾流,而对这一尾流的预测是 CFD 中一项困难任务。其原因在于:湍流流动中的流动分离在数值上仍是一个挑战,但分离区的大小极大地影响作用在车体上的预测阻力。因此,对诱导涡流和分离过程的精确模拟是正确预测气动效率的关键。

当代汽车设计包含许多复杂的几何特征,使建模和实验研究都具有挑战性。因此,本章选择 Ahmed 钝体(参考文献 [1, 2])作为研究对象,它在 Fig. 19.1 中示意性地给出。Fig. 19.1a 给出侧视、正视与俯视图,可从中推断出尺寸;Fig. 19.1b 给出该钝体的三维可视化。尽管几何形状简单,Ahmed 钝体能够发展出三维分离流区域,可研究各种流动现象并与实验数据对比。

Ahmed 钝体是一个广为人知的构型,被广泛用作基准。其后端的斜面几何在侧缘产生一对反向旋转的涡,其强度主要由基底斜面角度决定。该钝体有两种构型,区别在于斜面角度值(25° 与 35°)。本章的模拟考虑 25° 斜面角的构型。

19.3 域与网格(Domain and Mesh)

计算域如 Fig. 19.2 所示,沿 Ahmed 钝体形状的中间截面施加对称条件。利用对称性来缩减计算域,并减轻由于钝体后端涡脱落而预期出现的瞬态行为;这同样有助于增强数值稳定性。

入流与出流边界条件被设置在远离钝体的位置,以最小化与主流区域之间不必要的相互作用,特别是出口与钝体后端流动之间的相互作用。

网格由 snappyHexMesh 生成,它是 OpenFOAM® [3] 软件包自带的一个工具。snappyHexMesh 生成三维网格,包含六面体(hex)与分裂六面体(split-hex)单元,这些单元由立体光刻(STL)格式的三角化表面几何自动生成。网格通过对初始网格逐步细化并将所得 split-hex 网格变形到表面上,从而逐渐贴合表面。可选的阶段会将所得网格回退并插入 cell 层。网格细化级别的设定非常灵活,表面处理对预设的最终网格质量也很稳健。它在并行模式下运行,并在每次迭代中加入负载均衡步骤 [4]。

本章的目的不在于对 snappyHexMesh 应用给出详细介绍,但案例目录 "Ahmed_body/system/snappyHexMeshDict" 中提供了一份带注释的设置文件。Listing 19.1 给出了该文件的一段摘录。摘录中 castellatedMesh true; snap true; addLayers true; 表明三个阶段(castellatedMesh 阶段、snap 阶段、addLayers 阶段)都被启用;几何 geometry 块中定义了一个 triSurfaceMesh 类型的 ahmed_body.stl,命名 ahmed_bodycastellatedMeshControlsmaxLocalCells 300000; 表示在细化前先按权重进行负载均衡的阈值。

网格通过在案例目录下按所示顺序执行以下命令生成:blockMesh—由 system/blockMeshDict 定义 snappyHexMesh 工作所在的总体计算域,该域应在其内部包含 STL 几何;snappyHexMesh—snappyHexMesh 通过三个阶段生成网格,每个阶段的结果分别写入文件夹(1/2/3/);mv 3/polyMesh constant/—将 snappyHexMesh 生成的最终网格移动到 constant 目录中供求解使用;createPatch—overwrite—删除所有空的 patch。

贴体网格由大约 800 000 个多面体单元组成,主要分布在钝体周围两个区域。这使得在保持计算域单元数较少的同时能够很好地分辨尾流区域。钝体附近生成的网格细节如 Fig. 19.3 所示。

在感兴趣区域进行网格单元聚类是常见的做法,它能在恰当分辨流动主要特征的同时降低计算成本。生成的网格完全非结构化,单元为多面体,最多有 15 个面。网格质量最好用 checkMesh 来评估,其输出如 Listing 19.2 所示。Listing 19.2 给出统计信息:points: 806136faces: 2331063internal faces: 2292117cells: 762865faces per cell: 6.060285896boundary patches: 10。单元类型按面数分类:hexahedra 744610,prisms 1057,wedges 0,pyramids 0,tet wedges 1,tetrahedra 0,polyhedra 17197;多面体中按面数再分类(4 面 82、5 面 59、6 面 4523、7 面 1563、8 面 410、9 面 6961、10 面 5、11 面 3、12 面 2782、14 面 2、15 面 807)。质量检查输出给出:bounding box (-5 -0.00189057368 0) (10 5 5),boundary openness (-2.59e-17 -1.40e-15 -4.46e-14) OK,max cell openness 3.96e-16 OK,max aspect ratio 13.98 OK,face area magnitudes OK,cell volumes OK(min 8.48e-09,max 0.0587,total 374.94),non-orthogonality max 62.13、average 5.02 OK,face pyramids OK,max skewness 2.52 OK,coupled point location match (average 0) OK,最终输出 Mesh OK. End

物理边界条件在 "Ahmed_body/constant/polyMesh/" 目录下的 boundary 文件中设定,如 Listing 19.3 所示。Listing 19.3 给出 10 个 patch 列表:inlet(patch, nFaces 298, startFace 2292117)、outlet(patch, nFaces 298, startFace 2292415)、ffmaxy(patch, nFaces 640, startFace 2292713)、floor(wall, nFaces 13779, startFace 2293353)、top(patch, nFaces 520, startFace 2307132)、ahmed_body_body(wall, nFaces 5750, startFace 2307652)、ahmed_body_body_front_h(wall, nFaces 864, startFace 2313402)、ahmed_body_body_front_v(wall, nFaces 1270, startFace 2314266)、ahmed_body_stilts(wall, nFaces 256, startFace 2315536)、cp(wall, nFaces 15271, startFace 2315792)。

patch inletoutlet 定义为 patch 类型,而 cp 设置为 wall 而非 symmetry plane。为降低流动求解的复杂度,cp patch 将采用 slip 边界条件。代表车体的 "ahmed_body*" patch 定义为 "wall",其余 patch 定义外部计算域。

19.3.1 初始与边界条件(Initial and Boundary Conditions)

0 目录必须包含以下四个基本文件以进行湍流不可压缩流动模拟:速度 U、压力 p,以及对于 kEpsilon 湍流模型,分别为湍流动能 k 与耗散率 ε。文件 U 定义了速度的边界条件(Listing 19.4)。

U 文件的关键内容如下:dimensions [0 1 -1 0 0 0 0];internalField uniform (40 0 0);;boundaryField 中 inlet 类型为 surfaceNormalFixedValuerefValue uniform -40(注意 refValue 取负以对应 -40 m/s 法向入流);outlet 类型为 inletOutletinletValue uniform (0 0 0)value uniform (0 0 0)ffmaxytopslipahmed_body_bodyahmed_body_body_front_hahmed_body_body_front_vahmed_body_stiltsfloor 全部为 noSlipWall(即第 18 章中开发的新边界条件),value uniform (0 0 0)cpslip

新的 noSlipWall 边界条件被用来在壁面(包括车身与地面)施加无滑移条件。入口处流体速度设为 40 m/s。沿 cp 平面,使用 slip 壁面边界条件——将粘性力设为零,以模拟一个对称面(patch cp 上由于网格划分造成的轻微几何误差使得无法直接使用 symmetryPlane 边界条件)。zeroGradient 压力边界条件使用零阶外推来计算边界处压力。在出口处,应用 Dirichlet 边界条件以设定参考压力(Listing 19.5)。Listing 19.5 给出压力 boundaryField:inletzeroGradientoutletfixedValuevalue uniform 0ffmaxyzeroGradient

对于 kEpsilon 模型,在入流边界上设定湍流强度与积分长度尺度,而在所有壁面上自动采用标准壁面函数(第 17 章)。k 文件如 Listing 19.6 所示,ε 文件如 Listing 19.7 所示。k 文件中 inlet 类型为 turbulentIntensityKineticEnergyInletintensity 0.01value uniform 0.002outletzeroGradientepsilon 文件中 inlet 类型为 turbulentMixingLengthFrequencyInletmixingLength 0.01phi phik kvalue uniform 0.002outletzeroGradient

19.3.2 系统文件(Systems Files)

controlDict 文件(Listing 19.8)配置为执行 500 次 SIMPLE 迭代。此外,为了使用针对速度的新 noSlipWall 边界条件,相应的库必须与入流湍流边界条件所需的库一起被包含。这些通过 libs 声明设定。还包含一个特定的运行时后处理配置,以迭代地监测升力与阻力系数的变化,这通过 functions 声明设定。对于外部气动应用而言,比起残差水平,监测钝体上的载荷或力更便于检查收敛性。

controlDict 文件的关键内容:startFrom startTime;startTime 0;stopAt endTime;endTime 500;libs ("libNoSlip.so" "libincompressibleRASModels.so" "libincompressibleRASModels.so");functions 中定义 forceCoeffs1,其类型为 forceCoeffsfunctionObjectLibs ("libforces.so")outputControl timeStepoutputInterval 1log yespatches ("ahmed_body*")pName pUName UrhoName rhoInf(表示不可压缩),rhoInf 1(对不可压缩冗余),liftDir (0 0 1)dragDir (1 0 0)CofR (0.72 0 0)(地面上车轴中点),pitchAxis (0 1 0)magUInf 40lRef 1.45(轴距长度),Aref 2.618(估算面积)。

线性求解器规格与松弛因子在 fvSolution 文件中配置,如 Listing 19.9 所示。这里为所有方程选择带不完全分解预条件子的预处理共轭梯度法。对于压力修正方程(pp),由于该方程的拉普拉斯性质,指定对称矩阵求解器。值得指出的是,使用压力修正格式时不需要非正交修正迭代。

fvSolution 文件中 solvers 块的关键内容:ppPCGpreconditioner DICtolerance 1e-06relTol 0.01"(U|k|epsilon)"PBiCGpreconditioner DILUtolerance 1e-15relTol 0.1SIMPLE { nNonOrthogonalCorrectors 0; }relaxationFactorspp 0.3U 0.7k 0.7epsilon 0.7

空间离散设置在 fvSchemes 文件中配置,如 Listing 19.10 所示。对于本模拟,对流项使用一阶迎风格离散,梯度重构使用高斯方法,变量面插值使用线性剖面。

fvSchemes 文件的关键内容:ddtSchemes { default steadyState; }gradSchemes { default Gauss linear; grad(p) Gauss linear; grad(U) Gauss linear; }divSchemesdefault Gauss upwinddiv(phi,U) Gauss upwinddiv(phi,k) Gauss upwinddiv(phi,epsilon) Gauss upwinddiv(R) Gauss lineardiv((nuEff*dev(T(grad(U))))) Gauss linearlaplacianSchemesdefault Gauss linear corrected,对 laplacian(nuEff,U)laplacian((1|A(U)),p)laplacian(DkEff,k)laplacian(DepsilonEff,epsilon)laplacian(DREff,R)laplacian(DnuTildaEff,nuTilda) 一律 Gauss linear correctedinterpolationSchemes { default linear; interpolate(U) linear; }snGradSchemes { default corrected; }fluxRequired { default no; pp ; }

19.3.3 运行求解器(Running the Solver)

在运行开始时,求解器提供方程残差与力系数信息(Listing 19.11)。基于 controlDict 的设置,力系数也会被写入文件 Ahmed_body/postProcessing/forceCoeffs1/0/forceCoeffs.dat,可用于检查收敛历史。

Listing 19.11 显示第一次迭代(Time = 1)的求解器详细输出:求解 Ux(DILUPBiCG: Initial residual = 1, Final residual = 0.02308834211, No Iterations 2)、求解 Uy(Final residual 0.07259752325, No Iterations 1)、求解 Uz(Final residual 0.05706016776, No Iterations 1)、求解 pp(DICPCG: Final residual 0.009688743115, No Iterations 140)、求解 epsilon(Final residual 2.962105429e-05, No Iterations 1)、求解 k(Final residual 0.000587089458, No Iterations 1);ExecutionTime = 9.73 s ClockTime = 9 s;forceCoeffs 输出 Cm = 5.971060664, Cd = 18.59033988, Cl = 3.888152128, Cl(f) = 7.915136728, Cl(r) = -4.0269846

值得指出的是,对于压力修正方程,任何迭代上的残差始终为 1,这是由于 OpenFOAM® 归一化残差的方式(第 10 章中的计算指引)。Fig. 19.4a 给出动量方程残差的收敛历史曲线,Fig. 19.4b 给出升力与阻力系数随模拟进行的变化。Result 明确显示,在 300 次迭代时解已经完全收敛,升力与阻力系数值的变化已变得可忽略。Fig. 19.5 给出钝体周围的静压等值线。由于动压分量的恢复,车身前部压力值显著。等值线还显示,由于流体在曲面上的加速,车身前方位置下游存在低压区。

Fig. 19.6 中钝体后侧出现回流区域(recirculation region),并伴随低速区。Fig. 19.7 中钝体后部形成的尾流在矢量图中清晰可见。该涡流区域的形成是压力损失的原因,是对钝体阻力贡献的主要来源。

19.4 小结(Conclusion)

simpleFoamTurbulent 求解器与前几章开发的边界条件被用于求解 Ahmed 钝体周围的湍流。尽管采用了低阶对流格式与相对粗糙的网格,流动的主要特征仍得到了展示。

本章个人批注

本章是 Moukalled 全书的最后一章,承担"应用算例"的收尾角色。前 18 章建立了从一般输运方程的有限体离散、压力基算法(SIMPLE/SIMPLEC)、湍流模型(标准 k-ε、Realizable k-ε、k-ω SST 等)到 OpenFOAM®/uFVM 边界条件实现的完整知识链条;本章则把这一切打包成"一个真实算例"演示出来。值得注意的是作者选择了 Ahmed 钝体作为基准——这是一个被工业界和学术界广泛接受的几何构型,其气动特性有大量公开实验数据(参考文献 [1] Ahmed 1984、[2] Lienhart 2000)。这意味着本章不仅是一个教程,更是一个"对照实验":读者可以用自己的结果与实验数据对比来验证其理解。

让我印象深刻的是本章对对称性 + slip 边界条件的组合处理。Ahmed 钝体在中间截面上几何对称,但作者没有直接使用 symmetryPlane 边界条件,而是选择了 cp 壁面配合 slip 边界条件,理由是 "the slight geometric error due to meshing on patch cp does not allow the direct use of a symmetryPlane boundary condition"。这是一个工程上很现实的考虑:snappyHexMesh 生成的网格在 cp 平面附近不可能严格几何对称,强制使用 symmetryPlane 会引入非物理约束;而 slip(零剪切应力)则"放过了"法向速度的不匹配,代价是无法强制两侧速度完全镜像——这个权衡是工程数值方法的一个典型微调。另一个细节是 surfaceNormalFixedValue 在入口处的设置:作者用 refValue uniform -40 而 internalField 是 (40 0 0),负号源于 surfaceNormalFixedValue 中"参考方向是 patch 的外法向"——这是 OpenFOAM® 边界条件语义的微妙之处。

我还注意到作者在 Listing 19.8 中写"0 0 1"作为 liftDir,而车体的实际 lift 方向应该是 z 方向(垂直于地面)——这里 liftDir (0 0 1)dragDir (1 0 0)pitchAxis (0 1 0) 共同构成右手系。在 magUInf 40lRef 1.45Aref 2.618 这一组参数下,归一化后得到的 Cd = 18.59 在第一次迭代时显然还未收敛到合理量级——这是初始残差为 1 的瞬态显示值,需要在 ~300 步后才能稳定到工业级 Cd ~0.25 范围。书中没有给出最终收敛的 Cd 数值,这多少让我有些意犹未尽;不过从收敛曲线 Fig. 19.4b 来看,作者已经暗示了"300 步后解完全收敛"这一事实——这与书中"500 步"的总配置形成了一致的安全余量。

从全书视角看,ch19 的意义在于它把前 18 章抽象的 FVM 理论与 OpenFOAM® 的具体实现对接到一个"用户视角的真实算例"上。读者只要按书中 Listing 19.1–19.10 抄写 case 文件、运行 blockMesh → snappyHexMesh → simpleFoamTurbulent 就能复现整个工作流。这种"理论 → 工具链 → 算例"的三段式收尾,是教科书把读者从"理解"带到"动手"的常用手法。

与上下章的衔接(一段话)

第 19 章是 Moukalled 全书(Ch. 1–19)的最后一章,承接第 18 章末尾"the next chapter is devoted to detailing the steps needed to solve a turbulent flow problem in OpenFOAM®"的明确预告。第 18 章开发了 noSlipWall 边界条件并展示了 uFVM 的对应实现,本章则在"非正交网格 + 标准 k-ε + SIMPLE 算法 + 多种边界条件类型"的最复杂组合下,把这套工具链落到一个工业级 CFD 基准算例(Ahmed 25° 钝体)上。从全书曲线看:第 1–4 章铺垫 FVM 基础与一般输运方程的数学形式,第 5–12 章建立离散与求解框架,第 13–14 章处理源项与松弛,第 15 章给出不可压缩流的压力基算法(SIMPLE/SIMPLEC),第 16 章拓展到可压缩流,第 17 章引入湍流模型,第 18 章完成边界条件的代码实现,第 19 章则把这一切"打包展示"——构成了 Moukalled 团队"数学 → 数值 → 物理建模 → 软件实现 → 工程算例"的完整闭环。本章引用的 4 篇参考文献(Ahmed 1984、Lienhart 2000、OpenFOAM® 2.3.x、OpenFOAM® User Guide)也都是 OpenFOAM® 社区最常引用的资源——这一选择本身就暗示了本章在"教学算例"与"工程工具"之间的桥梁作用。