CFL3D深度解析:NASA经典CFD求解器的架构、算法与工程实践
引言
在计算流体力学(Computational Fluid Dynamics, CFD)发展的历史长河中,有一款代码自20世纪80年代末诞生以来,持续为NASA的航空航天研究提供着可靠的数值模拟支撑------它就是CFL3D。从X-Plane系列验证机的气动分析,到涡轮机械内部流动的精细模拟,从跨声速翼型的 buffet 现象研究,到气动弹性耦合的颤振边界预测,CFL3D的应用足迹几乎覆盖了计算空气动力学的每一个重要领域。
CFL3D是一款结构化网格、单元中心、迎风偏置的雷诺平均Navier-Stokes(Reynolds-Averaged Navier-Stokes, RANS)求解器。它由NASA Langley研究中心计算流体实验室(Computational Fluids Laboratory)开发,历经三十余年的持续迭代,至今仍在湍流模型验证与确认(V&V)等研究领域发挥着不可替代的作用。2006年美国发行的X-Plane纪念邮票上,那些精美的计算机生成流场图像,正是出自CFL3D之手。
本文将从源代码层面出发,系统性地剖析CFL3D的技术架构与核心算法。我们将深入有限体积离散的数学基础,追溯迎风通量分裂的物理直觉,拆解多重网格加速的收敛奥秘,探究十数种湍流模型的实现细节,并揭示并行计算、动网格、低马赫预处理、复变量方法等高级特性背后的工程智慧。无论你是CFD领域的从业者、高性能计算的开发者,还是对计算科学工程感兴趣的技术读者,这篇文章都将带你领略一款经典工程软件是如何在数学、物理与计算机科学的交汇处持续绽放生命力的。
第一章 计算流体力学基础与RANS方程
1.1 Navier-Stokes方程的物理意义
流体运动遵循自然界最基本的守恒定律:质量守恒、动量守恒和能量守恒。将这些守恒定律应用于连续介质假设下的流体微团,就得到了Navier-Stokes方程组。对于可压缩牛顿流体,守恒形式的Navier-Stokes方程可以写作:
∂t∂U+∂x∂F+∂y∂G+∂z∂H=∂x∂Fv+∂y∂Gv+∂z∂Hv
其中,守恒变量向量 U=ρ,ρu,ρv,ρw,ρET,分别代表密度、三个方向的动量和单位体积总能量。 F,G,H 是对流通量,而 Fv,Gv,Hv 是粘性通量。
对流通量描述了流体微团因宏观运动而携带的物理量输运,是双曲型方程的特征------信息以有限速度(波速)传播,解可以存在间断(如激波)。粘性通量则源于分子的扩散运动,对应于抛物型方程的光滑化效应。在高雷诺数流动中,对流项通常远大于粘性项,因此如何精确、稳健地离散对流项,成为CFD算法设计的核心挑战。
1.2 雷诺平均与湍流封闭问题
工程实际中的流动绝大多数是湍流------流动参数随时间和空间呈现出看似随机的脉动。直接数值模拟(Direct Numerical Simulation, DNS)虽然在原理上可以求解所有尺度的湍流运动,但其计算量随雷诺数的 9/4 次方增长,对于工程关心的雷诺数(如 106 以上)完全不具备可行性。
雷诺平均方法(Reynolds-Averaged Navier-Stokes, RANS)将流动变量分解为平均量和脉动量:
ϕ=ϕ+ϕ′
将分解后的变量代入Navier-Stokes方程并取时间平均,就得到了RANS方程。RANS方程的形式与原始Navier-Stokes方程非常相似,只是在应力项中多出了一项------雷诺应力 −ρui′uj′。这一项代表了湍流脉动对平均流动的动量输运效应。
问题在于,雷诺应力引入了新的未知量,使得方程组不再封闭。为了封闭方程组,必须引入湍流模型------通过某种假设,将雷诺应力与平均流动的速度梯度等可求解量联系起来。这就是所谓的"湍流封闭问题"。
CFL3D提供了从零方程模型到雷诺应力模型的完整谱系,涵盖了Baldwin-Lomax、Spalart-Allmaras、k-ω、k-ω SST、k-ε、EASM等十数种湍流模型选择,我们将在后续章节详细展开。
1.3 薄剪切层近似
对于大多数工程中的边界层流动,沿壁面法向的流动参数梯度远大于沿流动方向的梯度。基于这一观察,人们发展出了薄剪切层近似(Thin-Layer Navier-Stokes, TLNS)------在粘性项中只保留主导方向(通常是壁面法向)的二阶导数项,而忽略流向和周向的粘性扩散。
薄剪切层近似在CFL3D中是默认的粘性处理方式。这一近似极大地简化了数值离散,同时对于附着流动和适度分离的流动依然保持着足够的精度。代码中也提供了全Navier-Stokes选项,用于那些需要考虑全粘性效应的场景。
1.4 无量纲化与参考量
CFD计算中,直接使用有量纲量会面临数值范围差异巨大的问题------密度可能是 10−3 量级,而速度可能是 102 量级,压力则可能是 105 量级。将方程无量纲化不仅可以改善数值条件,也是CFD中"相似性"原理的数学体现。
CFL3D采用来流(freestream)条件作为参考量,对所有流动变量进行无量纲化:参考密度为来流密度 ρ∞,参考速度为来流速度 U∞,参考压力为 ρ∞U∞2。无量纲化后,来流处的密度为1,速度为1,压力为 1/(γMa2)(因为 p∞/(ρ∞U∞2)=1/(γMa2))。所有方程都以无量纲形式求解,最终结果再根据需要还原为有量纲量。
第二章 CFL3D架构设计与代码组织
2.1 代码结构总览
CFL3D的代码组织体现了经典Fortran工程软件的架构哲学------模块化、层次化,以子程序为基本组织单元,通过公共块(common block)在模块间传递数据。整个项目的源码分布在以下几个主要目录中:
source/cfl3d/dist/:主驱动层,包含主程序入口、多重网格驱动、网格运动等顶层逻辑source/cfl3d/libs/:核心算法库,包含通量计算、边界条件、湍流模型、时间推进等source/splitter/:网格分割工具,用于将多块网格划分为并行计算所需的分区source/precfl3d/:预处理工具source/tools/:辅助工具集,包括格式转换、网格扰动、后处理等
核心求解器的代码量大约在20万行左右,全部由Fortran 77/90编写。这种规模在今天看来似乎不大,但考虑到其中每一行都经过了数十年的工程验证,其"密度"远超许多表面上更大的代码库。
2.2 主程序执行流程
CFL3D的主程序入口位于 main.F,其执行流程清晰地展现了一个CFD求解器的典型生命周期:
- 初始化阶段 :调用
setup子例程读取网格、输入文件和重启数据,计算网格度量(metrics),分配内存,设置边界条件。 - 时间步迭代 :进入主迭代循环,每一步执行以下操作:
- 调用
bc更新边界条件 - 调用
resid计算残差(对流通量和粘性通量) - 调用
update更新流场变量 - 如果启用了湍流模型,调用相应的湍流模型子例程(如
spalart或twoeqn) - 输出收敛历史和力系数
- 调用
- 多重网格循环:如果启用了多重网格,在细网格上执行若干步迭代后,将残差限制到粗网格,在粗网格上求解修正,再将修正延拓回细网格。
- 结束阶段:输出结果文件、重启文件,释放资源。
对于非定常计算,流程更加复杂------每个物理时间步内需要执行若干子迭代(subiteration)以消除线性化和因子化误差,然后再推进到下一个物理时刻。
2.3 数据结构与内存管理
CFL3D采用动态内存分配------所有数组都在运行时根据网格大小动态分配,而非在编译时固定。这在Fortran 77时代是一个了不起的工程成就。
实现方式是通过一个巨大的工作数组 w(实数型)和 iwork(整数型)作为"内存池"。各个子例程所需的数组实际上都是这个大数组的切片。lw 和 lw2 数组记录了每个网格块中各种数据在工作数组中的偏移位置和长度。这种"手动内存管理"的模式虽然在今天看来略显原始,但在Fortran 77缺乏动态分配能力的年代,它提供了极大的灵活性。
在版本6中,代码引入了Fortran 90的 allocate 语句来支持某些模块的动态数组,但核心的工作数组模式依然保留,这既是向后兼容的需要,也是经过验证的可靠设计。
每个网格块的主要数据包括:
- 坐标数组
x, y, z:节点坐标 - 守恒变量
q:单元中心的密度、动量、能量 - 度量张量
si, sj, sk:网格变换的雅可比矩阵分量 - 单元体积
vol:有限体积法的控制体体积 - 时间步
dtj:当地时间步长 - 湍流粘性
vist3d:湍流涡粘系数分布 - 边界条件信息
bcj, bck, bci:各面上的边界条件类型和数据
2.4 公共块(Common Block)的设计哲学
阅读CFL3D的代码,最显著的特征之一就是大量使用Fortran公共块。公共块在现代编程范式中常被诟病为"全局变量"的代名词,但在数值计算的语境下,它有其存在的合理性。
CFL3D中的公共块按照主题组织,每个公共块包含一组相关的参数:
/info/:全局流动参数,如马赫数、迎角、侧滑角、CFL数等/fluid/:流体属性,如比热比及其衍生量/reyue/:雷诺数、温度和粘性模型选择/mgrd/:多重网格参数/unst/:非定常计算参数/turbconv/:湍流模型收敛控制参数
这种设计使得控制参数可以在任何子例程中直接访问,而无需通过长长的参数列表传递。对于动辄几十个参数的CFD子例程来说,这大大简化了接口。当然,代价是数据的可见性不直观------阅读代码时需要额外关注公共块的定义才能理解数据的来源。
2.5 预处理宏与编译选项
CFL3D通过预处理宏支持多种编译配置:
DIST_MPI:启用MPI并行计算CMPLX:启用复变量模式,用于计算灵敏度导数DBLE_PRECSN:启用双精度计算CGNS:启用CGNS文件格式支持
这些宏通过条件编译(#ifdef / #endif)在同一套源代码上生成不同功能的可执行文件。例如,复变量模式下,所有实数变量都会变成复数,这使得可以通过复步长法(complex step method)精确计算函数对输入参数的导数------这在设计优化和不确定性量化中极为有用。
第三章 空间离散:有限体积法与迎风格式
3.1 有限体积法的基本思想
有限体积法是CFD中应用最广泛的空间离散方法之一。其核心思想是:将计算域划分为互不重叠的控制体(cell),对每个控制体积分Navier-Stokes方程,利用高斯散度定理将体积分转化为控制体表面上的面积分。
对于单元中心格式(cell-centered scheme)------CFL3D所采用的方案------流动变量存储在控制体的中心,而通量则在控制体的界面上计算。第 i 个控制体的半离散方程可以写作:
dtdUi=−Vi1∑facesF⋅nΔS
其中 Vi 是控制体体积, F⋅n 是穿过界面的法向通量, ΔS 是界面面积。
有限体积法的优势在于它天然满足守恒性------对于内部界面,从一个控制体流出的通量恰好等于流入相邻控制体的通量,因此整个计算域的总质量、动量和能量是严格守恒的。这对于激波等间断问题的计算至关重要。
3.2 结构化网格与坐标变换
CFL3D采用结构化网格(structured grid),即网格节点可以用三个指标 (i,j,k) 来索引,相邻节点的指标差为1。结构化网格的优势在于数据访问的规律性------相邻单元在内存中的位置是可预测的,这极大地有利于缓存优化和向量化。
对于任意形状的物理空间,结构化网格通过坐标变换映射到计算空间中规则的单位立方体。变换关系为:
ξ=ξ(x,y,z),η=η(x,y,z),ζ=ζ(x,y,z)
在计算空间中,所有控制体都是单位立方体,这大大简化了离散操作。代价是方程中需要引入度量张量(metrics)来描述坐标变换的几何效应。
CFL3D中,度量张量通过 metric.F 子例程计算,包括 ξx,ξy,ξz,ηx,ηy,ηz,ζx,ζy,ζz 以及雅可比行列式 J。这些量在每个界面上定义,是通量计算的基础。
3.3 迎风偏置与通量分裂
对流项的离散是CFD算法的核心难点。由于对流方程的双曲特性,信息沿特征方向传播,简单的中心差分格式会导致数值振荡甚至不稳定。迎风方法(upwind method)的思想是:利用流动的方向信息,在界面处构造通量时更多地依赖来流方向的信息。
CFL3D提供了两种主流的迎风格式:Van Leer的通量矢量分裂(Flux-Vector Splitting, FVS)和Roe的通量差分分裂(Flux-Difference Splitting, FDS)。
3.3.1 Van Leer通量矢量分裂
Van Leer FVS的基本思想是根据当地马赫数将对流通量分解为"正"部分和"负"部分:
F=F++F−
其中 F+ 只包含向右传播的波( M≥1 时全部为正), F− 只包含向左传播的波( M≤−1 时全部为负)。界面通量则由左侧状态的正通量和右侧状态的负通量组合而成:
Fi+1/2=F+(UL)+F−(UR)
在CFL3D中,正通量由 fluxp.F 计算,负通量由 fluxm.F 计算。这两个子例程的实现充分利用了向量化优化------所有计算都以DO循环的形式组织,便于编译器生成向量指令。
Van Leer FVS的优点是实现简单、计算效率高、鲁棒性好,缺点是对于接触间断和剪切层的耗散偏大。
3.3.2 Roe通量差分分裂
Roe FDS基于近似Riemann问题求解的思想。它构造一个" Roe平均"状态,在该状态下线性化欧拉方程,然后利用特征分解计算界面通量。Roe格式能够精确捕捉接触间断和激波,数值耗散更小,分辨率更高。
Roe格式的核心是 Roe平均状态的定义和特征分解。对于三维欧拉方程,特征分解涉及5个特征波:1个熵波、2个接触波和2个声波(左行和右行)。每个波对应一个特征值和特征向量,通量可以表示为各特征波的贡献之和。
CFL3D中,Roe格式由 rie1d.F 和 rie1de.F 等子例程实现。与Van Leer格式相比,Roe格式的计算量更大,但精度更高,尤其是在跨声速和超声速流动中优势明显。
3.4 高阶重构与限制器
上述一阶迎风格式虽然鲁棒,但耗散过大,无法满足工程计算对精度的要求。为了提高空间精度,需要在界面处使用更高阶的重构------利用相邻单元的信息,在界面两侧构造更高阶精度的左右状态。
CFL3D支持二阶和三阶的空间精度,通过 MUSCL(Monotonic Upstream-centered Scheme for Conservation Laws)重构实现。基本思想是在每个单元内假设一个线性(或更高阶)分布,然后在界面处取值。
然而,高阶重构在间断附近会产生数值振荡------这是Godunov定理所预言的:线性单调格式的精度不可能超过一阶。为了解决这个问题,需要引入限制器(limiter)------在光滑区域启用高阶精度,在间断附近自动降阶以保持单调性。
CFL3D中实现了多种限制器,包括van Albada限制器、Barth-Jespersen限制器等。barth3d.F 子例程实现了三维Barth-Jespersen限制器,其基本原理是限制界面值不超过相邻单元的极值范围。
限制器的设计是一门艺术------过于激进的限制器会过度降低精度,过于温和的限制器又可能在某些情况下产生振荡。CFL3D经过数十年的调优,其限制器参数达到了精度与稳定性的良好平衡。
3.5 粘性项的离散
与对流项的迎风处理不同,粘性项天然具有扩散性,采用中心差分即可。CFL3D的薄剪切层近似下,粘性项只保留主导方向的二阶导数。
粘性通量的计算涉及速度梯度和温度梯度的计算。这些梯度通过相邻单元的差值除以距离得到。由于粘性项是二阶的,一阶精度的差分就足够了------粘性项本身就具有耗散特性,不需要像对流项那样担心稳定性问题。
CFL3D中,粘性通量的计算分散在 ffluxv.F、gfluxv.F、hfluxv.F 等子例程中(分别对应三个坐标方向),而湍流粘性的贡献则通过涡粘系数加到分子粘性上。
3.6 熵修正与数值稳健性
在低速区域(马赫数接近于零),特征波速趋近,这可能导致数值格式的病态------Roe格式尤其容易在这种情况下出现"carbuncle"现象等数值不稳定。
CFL3D实现了熵修正(entropy fix)来解决这个问题。熵修正的基本思想是:当特征值的绝对值小于某个阈值时,用一个光滑化的函数代替原来的绝对值函数,从而避免了特征值穿越零时的数值突变。
lamfix.F 子例程专门处理这个问题。代码中可以看到,对于非常小的马赫数,熵修正项会自动激活,确保格式在全马赫数范围内的稳定性。这也是为什么CFL3D能够稳健地处理从低亚声速到高超声速的宽速域流动。
第四章 时间推进:隐式算法与收敛加速
4.1 显式与隐式的权衡
得到空间离散后的半离散方程后,接下来需要考虑时间方向的离散。最简单的方法是显式方法,如Runge-Kutta方法------下一时间步的解完全由当前时间步的已知量计算得出。显式方法实现简单、每步计算量小,但受CFL条件限制,时间步长必须足够小才能保证稳定。
对于定常流动问题,我们只关心最终的稳态解,而不关心中间的时间历程。这种情况下,使用隐式方法可以采用大得多的时间步长,从而更快地收敛到稳态。隐式方法的代价是每一步需要求解一个大型线性方程组。
CFL3D采用空间因子化的隐式算法(spatially-factored implicit algorithm),也称ADI(Alternating Direction Implicit)方法的变种。这种方法将三维问题分解为三个一维问题依次求解,每个一维问题对应一个块三对角方程组,可以用Thomas算法高效求解。
4.2 近似牛顿迭代与线性化
隐式方法的起点是将离散方程写作:
Un+1=Un+Δt⋅R(Un+1)
其中 R 是残差算子(空间离散的结果取负号)。由于 R 中出现的是 n+1 时刻的未知量,这是一个非线性方程组。CFL3D采用近似Newton迭代------将 R 在 Un 处线性化:
R(Un+1)≈R(Un)+∂U∂RΔU
代入后得到关于 ΔU 的线性方程组:
(I−Δt∂U∂R)ΔU=ΔtR(Un)
直接构造和求解这个三维的雅可比矩阵是不现实的。空间因子化方法将雅可比矩阵分解为三个方向的贡献:
I−Δt(∂U∂Ri+∂U∂Rj+∂U∂Rk)≈(I−Δt∂U∂Ri)(I−Δt∂U∂Rj)(I−Δt∂U∂Rk)
这个近似引入了所谓的"因子化误差"(即等式两边相差 Δt2 阶的交叉项),但它将三维问题转化为三个独立的一维问题------每个一维问题对应一个块三对角方程组,可以用Thomas算法高效求解。没有因子化时,三维隐式系统的求解需要迭代法(或昂贵的直接求解器),而因子化后的ADI格式每步只需要 O(N) 的操作(每个方向一次块三对角扫描),且收敛速度通常远快于显式方法。
4.3 块三对角方程组求解
每个方向上的隐式求解对应一个块三对角方程组。对于欧拉方程,每个块是 5×5 的矩阵;如果包含湍流方程,块的尺寸还会更大。
CFL3D中,三个方向的隐式求解分别由 blocki.F、blockj.F、blockk.F 子例程完成。这些子例程实现了块Thomas算法------标准Thomas算法的推广版本,适用于每个未知量是一个向量、每个系数是一个矩阵的情况。
以i方向为例,求解过程分为两个阶段:
- 前向消去:从第一个单元开始,依次将当前块的下对角元消去,同时更新主对角元和右端项
- 回代:从最后一个单元开始,依次向前求解各单元的修正量
对于 5×5 的块大小,每次块矩阵运算需要125次乘法和100次加法------这在现代CPU上可以通过SIMD指令高度优化。CFL3D的代码中,这些内层循环都经过了精心的向量化优化标注(如 cdir$ ivdep),告诉编译器可以安全地进行向量化。
4.4 对角化近似与LU-SGS
除了完整的块三对角求解,CFL3D还提供了对角化隐式选项。对角化近似利用通量雅可比矩阵的特征分解,将耦合的方程组解耦为各个特征波的标量方程。这样做的好处是计算量大幅降低------每个标量方程的三对角求解比块求解快得多。
代价是精度略有损失,但对于定常收敛来说,只要渐近收敛行为不受影响,中间过程的精度降低是可以接受的。这与多重网格等加速技术的思想一脉相承:只要最终收敛到正确的稳态,收敛路径上的精度并不重要。
CFL3D中还实现了LU-SGS(Lower-Upper Symmetric Gauss-Seidel)方法的思想元素。LU-SGS将雅可比矩阵分解为下三角、对角和上三角三部分,通过一次前向扫描和一次后向扫描完成近似求解。这种方法不需要求解三对角方程组,计算效率更高,而且天然适合并行计算------因为每个单元的更新只依赖已经更新过的邻居和未更新的邻居。
4.5 当地时间步长
对于定常流动计算,收敛加速的一个简单而有效的技术是当地时间步长(local time stepping)。其思想是:在每个单元中使用该单元允许的最大稳定时间步长,而不是全场统一的时间步长。由于不同位置的网格尺度和流动速度不同,CFL限制给出的最大时间步长也不同。
CFL3D中,当地时间步长由 rcfl.F 子例程计算。对于有限体积法,每个单元的时间步长由当地的网格尺度、流动速度和声速共同决定。每个面上的波速为 ∣u⋅n∣+c(法向速度加声速),该面的特征传播速率乘以面积后与单元体积比较,得到最大允许时间步长。对所有面取最严格的值:
Δt=CFL⋅maxfaces(∣u⋅n∣+c)⋅ΔSV
其中 V 是单元体积, ΔS 是界面面积, u⋅n 是法向速度, c 是声速。对于结构化网格,也可以按三个方向分别计算后取最小值。CFL数由用户设定,对于隐式格式通常可以取到很大的值(如5~10甚至更高)。
当地时间步长使得网格稠密的区域和流动缓慢的区域可以用更小的时间步长,而网格稀疏和流动快速的区域可以用更大的时间步长。整体效果是收敛速度的显著提升------在许多情况下可以达到数倍的加速比。
4.6 子迭代与时间精度
对于非定常计算,时间精度变得重要。简单的隐式向后Euler格式只有一阶时间精度,而且因子化误差和线性化误差都会影响时间精度。
为了提高时间精度,CFL3D采用子迭代(subiteration)方法------在每个物理时间步内,执行多次伪时间迭代。每次伪时间迭代重新计算残差和雅可比,逐步将解推进到满足该物理时刻的隐式离散方程。
子迭代不仅可以消除线性化误差,还可以消除因子化误差。当子迭代次数足够多时,时间精度由物理时间步的离散阶数决定,而不受隐式求解近似的影响。
CFL3D中,子迭代的次数由输入参数控制。对于气动弹性等对时间精度要求高的计算,通常需要5~10次子迭代。子迭代也可以与多重网格结合使用------每次子迭代内执行一次多重网格循环,进一步加速收敛。
第五章 多重网格加速技术
5.1 多重网格的基本原理
多重网格(Multigrid)是迄今为止已知最有效的收敛加速技术之一。对于椭圆型和抛物型方程,多重网格可以达到最优的计算复杂度------将求解精度提高一个数量级,计算量只增加一个常数因子。
多重网格的核心洞察是:不同频率的误差分量衰减速度不同。基本迭代法(如Gauss-Seidel)能够快速衰减高频误差(即几个网格尺度的振荡),但对低频误差(即跨越许多网格的平滑变化)的衰减非常缓慢。这就是所谓的"光滑误差"问题。
多重网格的解决方案是:在细网格上执行若干步迭代以衰减高频误差,然后将残差限制到粗网格上,在粗网格上求解误差方程(即修正方程)。由于在粗网格上,原来的"低频"误差变成了"高频"误差,因此可以被快速衰减。最后,将粗网格上得到的修正延拓回细网格。
这一过程可以递归地进行------从最细网格到最粗网格,形成一个V循环、W循环或FMG循环等。
5.2 FAS多重网格
CFL3D采用的是全近似存储(Full Approximation Storage, FAS)多重网格方案。FAS方案由Brandt提出,特别适用于非线性方程------它直接在粗网格上求解完整的非线性方程,而不是线性化的误差方程。
FAS的基本步骤如下(以两层网格为例):
- 细网格光滑 :在细网格上执行 ν1 步迭代,得到当前近似解 uh
- 计算细网格残差 : rh=fh−Lh(uh)
- 限制 :将细网格解和残差限制到粗网格: u2h=Ih2huh, r2h=Ih2hrh
- 构造粗网格右端项 : f2h=L2h(u2h)+r2h
- 粗网格求解 :在粗网格上求解 L2h(v2h)=f2h,得到 v2h
- 计算粗网格修正 : e2h=v2h−u2h
- 延拓 :将修正延拓回细网格: eh=I2hhe2h
- 细网格修正 : uh←uh+eh
- 细网格后光滑 :再执行 ν2 步迭代
注意粗网格右端项的构造方式: f2h=L2h(u2h)+r2h。这保证了当残差为零时,粗网格方程在限制解处是精确满足的------也就是说,限制解是粗网格方程的一个精确解。这是FAS方案的关键性质。
5.3 CFL3D中的多重网格实现
CFL3D的多重网格驱动位于 mgbl.F 和 mgblk.F 中。整个多重网格循环的控制逻辑相当复杂,因为它需要协调多个网格层、多个网格块、以及可能的并行计算。
多重网格的核心组件包括:
限制算子(Restriction) :将细网格的量传递到粗网格。CFL3D采用体积加权的限制方式------每个粗网格单元的值是其包含的细网格单元值的体积加权平均。限制操作由 collapse.F 等子例程完成。
延拓算子(Prolongation) :将粗网格的修正传递到细网格。延拓通常采用三线性插值------每个细网格单元的值由其在粗网格中的位置通过线性插值得到。延拓操作由 expand.F 等子例程实现。
粗网格生成:多重网格需要一系列由细到粗的网格层。CFL3D支持从最细网格出发,通过聚合相邻单元自动生成粗网格------每一层的网格点数在每个方向上大约减半。代码会自动计算粗网格的度量张量、体积、边界条件等。
V循环与W循环:CFL3D支持多种多重网格循环策略。V循环是最简单的形式------逐级下到最粗层,再逐级回到最细层。W循环在下降和上升过程中递归地执行子循环,可以更充分地衰减低频率误差,代价是计算量更大。
5.4 网格序列法
除了完整的多重网格,CFL3D还支持网格序列法(mesh sequencing)。网格序列法可以看作多重网格的简化版本:先在粗网格上求得到收敛解,然后将解插值到细网格上作为初始猜测,再在细网格上继续迭代。
网格序列法的优势在于实现简单------只需要一套求解器和网格插值工具。它的加速效果虽然不如完整的多重网格,但也能显著减少总计算量。原因在于:在粗网格上,迭代收敛得更快(因为CFL数更大、误差频率更高),而粗网格上得到的解已经包含了流动的主要特征,为细网格提供了一个很好的初始猜测。
CFL3D中,网格序列法由 mseq 参数控制。实际计算中,网格序列法常常与多重网格结合使用------先用网格序列法快速得到一个不错的初始解,再用多重网格精细收敛。
5.5 非定常多重网格
多重网格不仅适用于定常流动,也可以加速非定常计算。非定常多重网格的基本思想是:在每个物理时间步的子迭代中,使用多重网格来加速伪时间收敛。
非定常多重网格与定常多重网格的主要区别在于:非定常情况下,每个时间步的初始猜测来自上一时间步的解,因此残差的结构与定常情况不同。此外,时间离散项(如 ∂U/∂t)也需要在多重网格层级上进行限制和延拓。
CFL3D对非定常多重网格有完善的支持。mgbl.F 中的逻辑根据是否为非定常计算自动调整多重网格循环的细节。对于大振幅的非定常流动(如动态失速),多重网格可以将每个时间步的子迭代数从1020步减少到35步,显著降低非定常计算的成本。
5.6 多重网格的实际效果
在实际应用中,CFL3D的多重网格通常可以将收敛所需的细网格迭代步数减少一个数量级以上。对于简单的无粘流动,使用34层多重网格后,收敛到10个数量级的残差下降只需要几十步细网格迭代。对于粘性流动,由于边界层中的各向异性网格和刚性的湍流方程,多重网格的效率会有所降低,但通常仍能带来35倍的加速。
多重网格的效率受多种因素影响,包括:
- 网格质量:网格越光滑、长宽比越合理,多重网格效率越高
- 流动复杂度:存在激波、分离等强非线性特征时,多重网格效率下降
- 湍流模型:湍流方程的刚性会影响多重网格的收敛性
- 边界条件:远场边界、出口边界的处理方式影响远场误差的传播
CFL3D经过数十年的调优,其多重网格实现已经相当成熟,在各种流动条件下都能稳定地提供显著的收敛加速。
第六章 湍流模型体系详解
6.1 湍流建模的基本思路
湍流是流体力学中最具挑战性的问题之一。直接模拟所有尺度的湍流运动在工程上不可行,因此需要通过模型来描述湍流对平均流动的影响。
湍流模型的发展经历了从简单到复杂、从经验性到物理性的演进过程。CFL3D提供了从零方程模型到雷诺应力模型的完整谱系,反映了这一发展历程。
按照Boussinesq涡粘假设,雷诺应力可以表示为:
−ρui′uj′=μt(∂xj∂ui+∂xi∂uj)−32ρkδij
其中 μt 是湍流涡粘系数, k 是湍动能。涡粘假设的核心思想是将湍流的动量输运效应类比为分子粘性的扩散效应,只是粘性系数更大。
基于涡粘假设的湍流模型按照方程数量可以分为:
- 零方程模型:直接用代数公式计算涡粘系数,无需求解偏微分方程
- 一方程模型:求解一个输运方程(通常是涡粘系数或湍动能的输运方程)
- 两方程模型:求解两个输运方程(如k-ε模型中的湍动能k和耗散率ε,或k-ω模型中的k和比耗散率ω)
更复杂的雷诺应力模型(Reynolds Stress Model, RSM)则放弃了涡粘假设,直接求解每个雷诺应力分量的输运方程。
6.2 零方程模型:Baldwin-Lomax
Baldwin-Lomax模型是最经典的零方程模型,由Baldwin和Lomax于1978年提出。它将边界层分为内层和外层,分别用不同的公式计算涡粘系数。
内层:采用Prandtl混合长度理论:
μt=ρl2∣ω∣
其中混合长度 l=κy(1−e−y+/A+), ω 是涡量的大小, y+ 是壁面无量纲距离。
外层:采用涡量的最大值及其位置来确定:
μt=ρKCcpFmaxFwake(y)
其中 Fmax 是函数 F(y)=y∣ω∣(1−e−y+/A+) 的最大值, Fwake 是尾迹函数。
Baldwin-Lomax模型的优点是简单、计算量小、对于附着边界层流动效果不错。缺点是缺乏通用性------对于分离流动、曲率效应、旋转效应等复杂流动,它的预测能力非常有限。
在CFL3D中,Baldwin-Lomax模型由 sijrate2d.F 和 sijrate3d.F 等子例程计算应变率和涡量,然后通过代数公式得到涡粘系数。虽然现在已经有更先进的模型可用,但Baldwin-Lomax模型因其简单和鲁棒,在某些快速评估的场景中仍有应用。
6.3 一方程模型:Spalart-Allmaras
Spalart-Allmaras(SA)模型是目前应用最广泛的一方程模型,由Spalart和Allmaras于1992年提出。它求解一个关于"修正涡粘系数" ν~ 的输运方程:
∂t∂(ρν~)+∂xj∂(ρujν~)=Cb1ρS~ν~−Cw1ρfw(dν~)2+σ1∂xj∂(μ+ρν\~)∂xj∂ν\~+σCb2ρ(∂xj∂ν~)2
其中:
- S~ 是修正的涡量大小
- d 是到壁面的距离
- fw 是壁面附近的阻尼函数
- Cb1,Cw1,σ,Cb2,κ 等是模型常数
湍流涡粘系数由 μt=ρν~fv1 计算,其中 fv1 是一个过渡函数,当 ν~/ν 很大时趋近于1。
SA模型的设计目标是针对航空航天应用中的壁面有界流动,特别是附着流动和中度分离流动。它的优点是:
- 计算量相对较小(只有一个输运方程)
- 数值稳定性好,容易收敛
- 对于边界层流动的预测精度不错
- 对网格的要求相对较低
CFL3D中,SA模型的实现位于 spalart.F,代码量超过2000行。除了标准的SA模型,还实现了多种变体:
- SA-neg :允许 ν~ 取负值,提高了在分离流中的鲁棒性
- SA-noft2:修改了转捩项的处理
- DES(Detached Eddy Simulation):在远离壁面的区域切换为LES模式,形成RANS/LES混合方法
SA模型的边界条件处理也很关键。在壁面上, ν~=0。在远场, ν~ 通常设为来流值,一般是分子粘性系数的3~5倍。
6.4 两方程模型:k-ω与k-ε
两方程模型是目前工程CFD中应用最广泛的湍流模型。它们求解两个标量的输运方程------通常是湍动能 k 和另一个表征湍流长度尺度或时间尺度的量。
6.4.1 Wilcox k-ω模型
Wilcox k-ω模型由David Wilcox提出,求解湍动能 k 和比耗散率 ω(单位湍动能的耗散率)。涡粘系数由 μt=ρk/ω 计算。
k方程: ∂t∂(ρk)+∂xj∂(ρujk)=τij∂xj∂ui−β∗ρωk+∂xj∂((μ+σkμt)∂xj∂k)
ω方程: ∂t∂(ρω)+∂xj∂(ρujω)=αkωτij∂xj∂ui−βρω2+∂xj∂((μ+σωμt)∂xj∂ω)
k-ω模型的优势在于近壁面行为良好------不需要阻尼函数来处理粘性底层,因此在边界层计算中表现出色。它的缺点是对来流 ω 值敏感------远场 ω 的取值会显著影响边界层的发展。
CFL3D中,k-ω模型的实现位于 twoeqn.F 和 module_kwstm.F90 中。代码支持多个版本的k-ω模型,包括Wilcox 1998版、Wilcox 2006版等,通过编译选项或运行时参数切换。
6.4.2 Menter k-ω SST模型
Menter的剪切应力输运(Shear Stress Transport, SST)模型是目前最流行的两方程模型之一。它的设计目标是结合k-ω模型在近壁区域的优势和k-ε模型在远场的优势。
SST模型的核心思想是:
- 在近壁区域(边界层内部),使用k-ω模型
- 在远场区域(边界层外部和尾迹区),使用k-ε模型(通过变换后的ω方程形式)
- 通过一个混合函数 F1 在两个模型之间平滑过渡
SST模型还引入了剪切应力输运的修正------在涡粘系数的计算中考虑了主应变方向与湍流剪应力方向的差异,这使得模型能够更好地预测逆压梯度下的流动分离。
具体来说,SST模型的涡粘系数为:
μt=max(a1ω,ΩF2)ρa1k
其中 Ω 是涡量大小, F2 是第二个混合函数。这个公式确保了在逆压梯度下,湍流剪应力不会被过度预测,从而延迟了流动分离的预测------这正是SST模型比标准k-ω模型更准确的原因。
CFL3D中,SST模型的实现非常细致,包括了原始SST模型和SST-2003版本的更新。module_kwstm.F90 文件用Fortran 90模块的形式组织了k-ω系列模型的代码,结构清晰,便于维护。
6.4.3 k-ε模型
k-ε模型是历史最悠久、研究最充分的两方程模型。它求解湍动能 k 和耗散率 ε。涡粘系数由 μt=Cμρk2/ε 计算。
标准k-ε模型对于自由剪切流(如射流、尾迹、混合层)的预测效果很好,但对于壁面有界流动,特别是近壁区域,需要壁面函数或低雷诺数修正。
CFL3D中实现了Abid的k-ε模型等变体。k-ε模型的近壁处理是一个复杂的话题------CFL3D提供了壁面函数(wall function)选项和低雷诺数模型选项。壁面函数通过经验公式将壁面切应力与第一个内点的速度联系起来,从而避免了在粘性底层中布置大量网格点的需求。
6.5 显式代数应力模型EASM
显式代数应力模型(Explicit Algebraic Stress Model, EASM)是代数应力模型的一种显式形式。它试图在两方程模型的计算成本下,获得雷诺应力模型的部分优势。
EASM的基本思想是:从雷诺应力输运方程出发,假设对流和扩散项可以忽略,从而将雷诺应力表示为应变率张量和涡量张量的代数函数。与Boussinesq假设不同,EASM考虑了雷诺应力与应变率之间的非线性关系------这意味着它可以捕捉一些各向异性效应。
CFL3D中实现了Gatski-Speziale形式的EASM模型,有k-ε和k-ω两种版本。EASM模型在某些具有强流线曲率、强旋转或大应变的流动中,比线性涡粘模型表现更好。代价是模型更复杂,数值刚性更大,收敛难度也更高。
EASM的实现位于 twoeqn.F 的相关部分,通过 ieasm_type 参数控制具体的模型变体。
6.6 雷诺应力模型
雷诺应力模型(Reynolds Stress Model, RSM)放弃了Boussinesq涡粘假设,直接求解六个独立雷诺应力分量(三维情况下对称张量有6个独立分量)的输运方程,加上一个长度尺度方程(通常是ε方程或ω方程)。
RSM的优势在于它能够自然地捕捉流动的各向异性效应,如流线曲率、旋转效应、二次流等。对于这些复杂流动,RSM通常比涡粘模型更准确。代价是计算量大幅增加------需要多求解6个偏微分方程,而且数值刚性更强,收敛更困难。
CFL3D中实现了雷诺应力模型,位于 foureqn.F(二维四方程)和相关的三维版本中。虽然RSM在理论上更优越,但在工程实践中,由于其计算成本和收敛难度,SST等两方程模型仍然是大多数工程师的首选。RSM更多地用于研究性计算和涡粘模型失效的特殊流动场景。
6.7 DES:RANS/LES混合方法
分离涡模拟(Detached Eddy Simulation, DES)是一种RANS/LES混合方法。它的基本思想是:
- 在近壁区域,使用RANS模型(如SA模型)
- 在远离壁面的分离流区域,自动切换为大涡模拟(LES)模式
切换的判据是网格间距与湍流长度尺度的比较。当网格间距小于湍流长度尺度的某个比例时,认为网格足够精细可以分辨大尺度涡结构,此时切换为LES模式;否则保持RANS模式。
DES方法的优势在于:它可以在远低于纯LES的计算成本下,获得比纯RANS更好的分离流预测结果。对于许多工程问题中的大分离流动(如机翼失速、空腔流动、尾迹干扰等),DES提供了一个"性价比"很高的选择。
CFL3D中,DES选项与SA模型和SST模型都有结合。通过 ides 参数可以开启DES模式,cdes 参数控制切换的阈值。
6.8 曲率修正与旋转效应
标准的湍流模型通常假设流动是平行剪切流,对于流线曲率和系统旋转的影响考虑不足。然而,在许多工程问题中,曲率和旋转效应是显著的------例如涡轮叶片通道内的流动、旋转机械中的流动、弯曲管道中的流动等。
CFL3D实现了多种曲率修正方案,包括:
- Spalart-Shur曲率修正:在SA模型中引入旋转/曲率修正项
- Hellsten壁面附近曲率修正:针对k-ω SST模型的曲率修正
- EASM曲率修正:在代数应力模型中考虑曲率效应
这些修正通过引入曲率参数(如Richardson数)来调整湍流的生成或耗散项,从而改善曲率流动的预测精度。在CFL3D中,曲率修正由 /curvat/ 公共块中的参数控制,包括 isar(SA曲率修正开关)、isarc2d、isarc3d(二维/三维曲率修正)等。
6.9 可压缩性修正
在高马赫数流动中,湍流的可压缩性效应变得重要。可压缩性会导致湍动能的额外耗散(由于压力-膨胀项的变化),以及混合层增长率的降低等现象。
标准的不可压缩湍流模型直接用于高马赫数流动时,往往会过高地估计湍动能和混合层增长率。为了纠正这一偏差,研究者们提出了多种可压缩性修正方案。
CFL3D中实现了若干可压缩性修正选项。例如,在k-ω模型中,可以启用压缩性修正项来调整湍动能的生成和耗散平衡。这些修正对于高速流动的准确预测是必要的。
6.10 壁面函数与低雷诺数模型
湍流模型的近壁处理一直是CFD中的关键问题。在近壁区域,流动从壁面处的零速度迅速发展到对数律区,湍流结构发生剧烈变化。直接在粘性底层中求解湍流方程需要极其细密的近壁网格( y+≈1),这在三维复杂构型中往往导致网格量过大。
壁面函数(wall function)是一种折中方案:它不在粘性底层中求解湍流方程,而是通过经验公式将壁面切应力与第一个内点的流动参数联系起来。这样,第一个内点可以布置在对数律区( y+≈30∼100),大大减少了网格需求。
CFL3D提供了多种壁面函数选项,包括标准壁面函数、可扩展壁面函数等。与壁面函数相对的是低雷诺数模型(low-Reynolds-number model)------这类模型对近壁的湍流方程进行了修正,使其可以直接积分到壁面,无需壁面函数。
低雷诺数模型的优点是精度更高(特别是在分离和再附等复杂近壁流动中),缺点是对近壁网格要求高,计算量大。CFL3D中的大多数湍流模型都有低雷诺数版本,可以直接积分到壁面。
在实际应用中,选择壁面函数还是低雷诺数模型需要权衡精度和计算成本。对于一般的附着边界层流动,壁面函数通常足够准确且经济;对于分离流动、转捩流动等对近壁过程敏感的情况,低雷诺数模型更为可靠。
第七章 边界条件与多块网格技术
7.1 边界条件的重要性
边界条件是CFD计算中至关重要的一环。从数学上讲,偏微分方程加上适当的边界条件(和初始条件)才能构成一个适定的问题。从物理上讲,边界条件决定了流动的驱动力和约束条件------入口的速度、出口的压力、壁面的无滑移条件等,共同决定了计算域内的流动形态。
边界条件处理不当是导致CFD计算不收敛或结果错误的最常见原因之一。远场边界离物体太近、出口边界出现回流、壁面法向速度不为零......这些问题轻则减慢收敛,重则导致计算崩溃。
CFL3D提供了丰富的边界条件类型,从简单的对称面到复杂的特征边界条件,从固体壁面到远场无反射边界,覆盖了工程计算中的大多数需求。
7.2 边界条件类型与实现
CFL3D中的边界条件按编号分类,1000系列为物理边界条件,2000系列为块间连接边界条件。让我们逐一介绍主要的边界条件类型。
7.2.1 远场边界条件(bc1000)
远场边界条件用于计算域的外边界,模拟流动从无穷远来、向无穷远去的情形。远场边界条件的核心挑战是如何让扰动无反射地传出边界,避免边界上的虚假反射污染计算域内的解。
CFL3D的远场边界采用特征边界条件------基于一维欧拉方程的特征分析,判断哪些波是进入计算域的,哪些波是离开计算域的。离开的波使用内部外推的值,进入的波则使用远场(来流)值。
具体来说,对于亚声速入口,有4个特征波进入域内(1个熵波、2个接触波、1个声波),1个声波离开;对于亚声速出口,有1个声波进入,4个离开。超声速情况下,所有波的方向都是一致的。
特征边界条件的实现基于Riemann不变量的概念。沿特征方向传播的不变量在边界处由相应侧的状态决定。这种方法大大减少了边界反射,使得远场可以放置在离物体相对较近的位置,从而节省计算网格。
7.2.2 对称面边界条件(bc1001)
对称面边界条件用于利用流动的对称性来减少计算域。例如,对于对称机翼的半模计算,可以在对称面上使用对称边界条件,只计算一半的网格。
对称边界条件的处理相对简单:法向速度设为零,其他变量的法向导数为零。在代码实现中,对称面的虚单元(ghost cell)值通过镜像内部单元的值来设置------法向速度反向,切向速度和标量保持不变。
7.2.3 外推边界条件(bc1002)
外推边界条件将边界处的值取为内部一阶或二阶外推的值。这种边界条件最简单,但也最容易产生反射。它通常用于出口边界,且只在出口处是超声速的情况下是精确的------因为超声速流动中所有信息都向下游传播,出口边界不会对上游产生影响。
对于亚声速出口,单纯的外推会导致强烈的反射,因此通常与压力条件结合使用------外推动量和能量,但固定压力。
7.2.4 入流/出流边界条件(bc1003)
入流/出流边界条件是更一般的远场边界条件形式,允许用户指定入口或出口的流动参数。入流边界可以指定总压、总温、流动方向等;出流边界可以指定静压。
这类边界条件同样基于特征分析,但其指定的参数不是简单的来流值,而是根据用户输入的物理量(如总压、总温)来计算进入域内的特征波幅值。
7.2.5 无粘壁面边界条件(bc1005/bc1006)
无粘壁面边界条件用于模拟光滑的固体壁面,假设流体可以在壁面上自由滑动(无摩擦)。边界条件是法向速度为零,压力的法向导数为零(即壁面处的压力等于相邻单元的压力)。
无粘壁面条件在 Euler 方程计算中使用,也用于粘性计算中某些不需要考虑摩擦的特殊表面。
7.2.6 粘性壁面边界条件
粘性壁面边界条件(无滑移条件)是最常用的壁面边界条件。壁面上流体速度等于壁面速度(通常为零),温度等于壁温或满足绝热条件。
对于速度,直接设置为壁面速度。对于温度,如果是等温壁面则设置为壁温,如果是绝热壁面则设置法向温度梯度为零。
对于湍流模型,壁面边界条件更加复杂。如果使用壁面函数,第一个内点不在壁面上,而是在对数律区,壁面处的湍流量通过壁面函数计算。如果使用低雷诺数模型,壁面上湍动能为零,而ω或ε在壁面附近有特定的渐近行为。
7.2.7 轴对称边界条件(bc1007)
轴对称边界条件用于旋转对称的流动,如弹体绕流、喷管流动等。在对称轴上,径向速度为零,其他变量的径向导数为零。
轴对称条件在CFL3D中有特殊的处理逻辑,包括对度量张量和通量的修正。代码中通过 iaxi2plane 等参数控制轴对称选项。
7.2.8 风洞边界条件
CFL3D还提供了多种风洞边界条件,用于模拟风洞试验的环境。这些边界条件可以考虑风洞壁面的约束效应、洞壁干扰等因素,使数值模拟更接近试验条件。
例如,bc1008 是风洞入口条件,bc2016 等是风洞相关的特殊边界类型。这些条件对于风洞试验的数值模拟和试验数据的相关性分析非常有用。
7.3 多块网格的连接方式
真实的飞行器构型往往具有复杂的几何形状,单块结构化网格很难或根本无法覆盖整个计算域。多块网格(multi-block grid)是解决这个问题的标准方案------将计算域划分为若干个块(block),每个块内部是结构化网格,块与块之间通过某种方式连接。
CFL3D支持四种主要的块间连接方式:
- 点对点匹配(1-1 matching):相邻块的界面上网格点一一对应
- 补丁连接(patched interface):相邻块的界面上网格点不一一对应,需要插值
- 重叠网格(overset / chimera):块之间可以重叠,通过插值传递信息
- 嵌入网格(embedded mesh):在粗网格中嵌入一块细网格,用于局部加密
7.3.1 点对点匹配
点对点匹配是最简单的多块连接方式。相邻两个块在共享界面上的网格点完全对应,界面处的通量计算与块内部没有区别------只是界面两侧的单元属于不同的块。
这种方式的优点是精确、高效,没有插值误差。缺点是对网格生成的要求高------相邻块的界面网格必须完全匹配,对于复杂几何来说这往往是最耗时的步骤。
在CFL3D中,点对点连接的边界条件处理几乎是透明的------每个块在自己的虚单元层中填入相邻块的实单元值,然后就像单块一样计算通量。
7.3.2 补丁连接
补丁连接(也称为"不匹配连接")允许相邻块在界面上有不同的网格分布。例如,一个块的界面上有100个单元,相邻块的对应界面上可能只有50个单元。
补丁连接需要通过插值来传递界面两侧的信息。CFL3D中,补丁连接的信息存储在专门的数据结构中,记录了每个界面段与相邻块上哪些单元对应,以及插值权重。
补丁连接的插值通常是守恒的------确保从一个块流出的总通量等于流入另一个块的总通量。守恒性对于多块计算的精度至关重要,否则会在界面处产生虚假的源或汇。
bc_patch.F 子例程负责补丁连接的边界条件处理。它执行插值操作,将相邻块的流动数据传递到当前块的界面虚单元中。
7.3.3 重叠网格(Chimera)
重叠网格(又称Chimera网格)是最灵活的多块方式。它允许网格块之间任意重叠,每个块在自己的网格上求解方程,重叠区域通过插值交换信息。
重叠网格的优势在于:
- 可以分别为每个部件生成网格,然后组装在一起
- 对于相对运动的部件(如旋翼、投放物)特别方便
- 网格生成难度大大降低
代价是:
- 插值会引入数值耗散
- 需要确定"洞"(hole)------即被其他物体遮挡的无效网格区域
- 数据结构更复杂,计算开销更大
CFL3D的重叠网格功能源于与Old Dominion大学的Oktay Baysal教授的合作。bc_blkint.F 处理块间插值,hole.F 处理洞点识别,avgint.F 和 avghole.F 等处理插值的平均。重叠网格与动网格结合,可以处理非常复杂的多体相对运动问题。
7.3.4 嵌入网格
嵌入网格(embedded mesh)是一种特殊的局部加密技术------在一块较粗的背景网格中,嵌入一块更细的网格,用于提高某个感兴趣区域的分辨率。
与重叠网格不同,嵌入网格有明确的父子关系------细网格完全嵌入在粗网格内部,细网格的边界条件通过粗网格插值获得。粗网格在细网格覆盖的区域被"挖空",其通量由细网格的结果提供。
嵌入网格可以看作是局部的、非均匀的多重网格------在需要高分辨率的区域使用细网格,其他区域使用粗网格,从而在保证关键区域精度的同时控制总体计算量。
CFL3D中,嵌入网格由 bc_embed.F 等子例程处理。嵌入网格的实现涉及到粗细网格之间的双向数据传递------从粗到细的边界条件插值,以及从细到粗的通量替换。
7.4 边界条件的实现架构
CFL3D的边界条件系统设计得相当灵活。每个块的每个面(i-min, i-max, j-min, j-max, k-min, k-max)可以被划分为多个段(segment),每个段可以有不同的边界条件类型。
边界条件信息存储在 ibcinfo, jbcinfo, kbcinfo 数组中,每个段记录了:
- 边界条件类型编号
- 段的起止位置
- 辅助数据的数量和位置
这种段式边界条件的设计非常实用。例如,机翼的下表面可能既有壁面段,又有控制面偏转而形成的台阶;进气道的入口可能同时包含外罩的外壁面和内流道的入口边界。通过段的划分,可以在一个面上灵活组合多种边界条件。
边界条件的应用分为两个阶段:
- 预边界条件(pre_bc):在残差计算之前,设置虚单元的值
- 后边界条件:在更新之后,对边界单元的值进行修正
这种分离使得边界条件的处理逻辑清晰------虚单元的设置只需要做一次,然后残差计算就可以像处理内部单元一样处理边界附近的通量。
7.5 周期边界条件
周期边界条件用于模拟周期性重复的流动,如涡轮叶片排的通道流动、周期性排列的建筑绕流等。周期边界的两个面上,流动参数满足周期性关系: U(x+L)=U(x),其中 L 是周期长度。
CFL3D中,周期边界条件由 bc_period.F 处理。对于旋转机械中的叶片排流动,周期边界还需要考虑周向的旋转效应------相邻叶片通道之间的流动不是简单的平移周期,而是旋转周期。
周期边界条件与多块网格结合,可以用一个通道的网格来模拟整个叶片排的流动,大大减少了计算量。这是涡轮机械CFD中的标准做法。
第八章 并行计算与MPI实现
8.1 为什么需要并行计算
CFD计算的计算量随问题规模呈超线性增长。一个典型的三维翼型计算可能需要几十万网格点,而一个完整的飞行器构型可能需要数千万甚至数亿网格点。对于非定常计算,还需要乘以物理时间步的数量。
以单块100×100×100 = 100万网格点的计算为例,每个时间步需要执行数十亿次浮点运算。如果需要1000步收敛,总运算量就是数万亿次。这在单核CPU上可能需要数小时甚至数天。
并行计算通过将计算任务分配给多个处理器协同工作,将求解时间线性缩短。对于CFD这种天然具有空间并行性的问题,并行扩展效率通常很高------使用N个处理器可以获得接近N倍的加速比。
CFL3D从版本6开始支持MPI并行计算,使其能够在从工作站到超级计算机的各种平台上高效运行。
8.2 基于块的域分解策略
CFL3D采用基于块的域分解策略------每个网格块作为并行分解的基本单位。用户可以将不同的块分配给不同的处理器,每个处理器负责计算自己拥有的那些块。
这种策略的优势是实现简单、通信开销小------块间通信只发生在块的界面上,通信量与界面面积成正比,而计算量与块的体积成正比。当块的数量足够多时,可以获得良好的负载平衡。
对于只有单块或少数几块网格的情况,可以使用CFL3D提供的splitter工具(source/splitter/)将大块网格分割为更多的小块。splitter工具可以按照用户指定的分割方式(如在i方向分成N份,j方向分成M份)将一个大块切分为若干小块,每块保持结构化网格的形式,块之间自动设置为点对点匹配的连接。
splitter的主程序位于 splitter/main.F,支持多种分割模式:
- 按指定的块数自动分割
- 按指定的每个方向的分割数分割
- 分割为大小相近的块以优化负载平衡
- 支持复变量版本的网格分割
8.3 MPI通信模式
CFL3D的并行计算基于MPI(Message Passing Interface)标准。MPI是分布式内存并行计算的事实标准,几乎所有高性能计算平台都支持。
CFL3D中的MPI通信主要发生在以下几个场景:
边界数据交换:每个时间步(或子迭代步)更新完流场后,相邻块之间需要交换界面数据。如果相邻块在同一个处理器上,直接内存拷贝即可;如果在不同处理器上,则需要通过MPI发送/接收消息。
CFL3D使用 MPI_Sendrecv 来进行成对的数据交换。由于每个界面两侧的处理器都需要向对方发送数据,同时接收对方的数据,使用 Sendrecv 可以避免死锁------发送和接收在同一个调用中完成,系统会自动调度通信顺序。
全局归约操作 :收敛历史输出、力和力矩计算、残差归一化等操作需要全局信息。例如,计算最大残差需要所有处理器找出自己的最大残差,然后通过 MPI_Allreduce 找出全局最大值。类似地,计算升力和阻力需要将各块的贡献累加起来。
CFL3D中常见的归约操作包括:
MPI_SUM:求和(如力、力矩、质量流量等)MPI_MAX:求最大值(如最大残差、CFL数等)MPI_MIN:求最小值(如最小体积、最小时间步等)
并行I/O:网格文件和结果文件的读写也需要并行处理。在并行模式下,每个处理器读取自己负责的那些块的网格数据,写结果时也是各自写自己的部分。CFL3D采用的是每个处理器独立读写自己的文件(或文件的不同部分)的方式,而非使用并行I/O库如MPI-IO。
8.4 并行多重网格
多重网格与并行计算的结合需要额外的考虑。多重网格的限制和延拓操作涉及不同网格层之间的数据传递,如果各层网格的处理器划分不同,就需要在层间进行数据重分布。
CFL3D的做法是:保持各层网格的块划分一致------也就是说,如果细网格被分成了N块分配给P个处理器,那么每一层粗网格也被分成对应的N块,以同样的方式分配给P个处理器。这样,限制和延拓操作都是处理器内部的操作,不需要额外的通信。
当然,这种策略要求所有层的块数和划分方式相同。对于由splitter工具分割的网格,这是自然满足的------splitter在分割细网格的同时,也定义了各层粗网格的分割方式。
8.5 负载平衡
并行计算的效率在很大程度上取决于负载平衡------即各处理器的计算量是否均衡。如果某个处理器的计算量远大于其他处理器,那么其他处理器就会等待它,整体效率由最慢的那个处理器决定。
对于基于块的域分解,负载平衡的关键是将大小相近的块分配给各处理器。如果各块的网格点数差异很大,就需要更精细的分配策略。
CFL3D支持用户手动指定块到处理器的映射,也可以使用简单的自动分配策略。对于大多数情况,只要块的数量足够多且大小差异不极端,自动分配就能达到不错的负载平衡效果。
在实际应用中,通常建议每个处理器负责2~10个块,每个块有大致相当的网格点数。这样既保证了负载平衡,又不会因为块太多而导致通信开销过大。
8.6 并行效率与可扩展性
CFL3D的并行效率相当高。对于结构化网格的有限体积法,计算量与网格点数成正比,通信量与界面面积成正比。在三维情况下,如果网格在三个方向上都按比例分割,那么:
- 计算量: O(N/P) (N是总网格点数,P是处理器数)
- 通信量: O((N/P)2/3) (界面面积与体积的2/3次方成正比)
因此,随着处理器数的增加,通信时间相对于计算时间的比例会缓慢增长,但增长速度很慢。这意味着CFD代码通常具有很好的强可扩展性------在问题规模固定的情况下,增加处理器数可以持续减少计算时间,直到通信开销变得不可忽略。
对于大规模并行计算(如数千个处理器),需要更精细的通信优化,如非阻塞通信、计算与通信重叠等。CFL3D的MPI实现虽然相对简洁,但对于大多数工程应用的规模(从几核到几百核),其并行效率已经足够好。
第九章 动网格与气动弹性分析
9.1 动网格技术的应用场景
许多工程问题涉及运动的边界------飞行器的操纵面偏转、机翼的颤振、涡轮叶片的旋转、投放物的分离等等。在这些问题中,不仅流动是非定常的,计算域的形状也在随时间变化。
动网格技术就是用来处理这种情况的:随着边界的运动,动态地调整内部网格点的位置,使得网格始终保持合理的质量,同时避免了每一步都重新生成网格的昂贵开销。
CFL3D提供了多种动网格能力,从简单的刚体运动到复杂的弹性变形,足以应对大多数工程动边界问题。
9.2 刚体运动:平移与旋转
最简单的动网格形式是刚体运动------整个网格块作为一个刚体进行平移或旋转,网格内部的相对位置保持不变。
CFL3D支持以下几种刚体运动模式:
平移运动:整个块以指定的速度沿指定方向移动。这种运动可以用于模拟匀速运动的物体,或者模拟风洞中模型的平移运动。
旋转运动:整个块绕指定的轴以指定的角速度旋转。这种运动常用于旋转机械的模拟,如螺旋桨、涡轮、压气机等。
平移+旋转组合:更复杂的运动可以通过平移和旋转的组合来实现。例如,螺旋桨飞机的流动既包含前进的平动,又包含螺旋桨的旋转。
刚体运动的实现相对简单------每个时间步,根据运动参数重新计算所有网格点的坐标,然后重新计算度量张量和体积。由于网格的拓扑不变,只是坐标在变化,因此不需要重新分配内存或改变数据结构。
CFL3D中,刚体运动的参数通过 utrans, vtrans, wtrans(平移速度)和 omegax, omegay, omegaz(旋转角速度)等变量控制。这些参数可以是恒定的,也可以随时间变化(通过时间函数指定)。
grdmove.F 子例程负责网格运动的坐标更新,tmetric.F 负责重新计算随时间变化的度量张量。
9.3 网格变形:弹簧类比与弹性方程
当只有部分边界运动(如机翼的弯曲和扭转)时,整个块做刚体运动就不合适了------需要一种方法将边界的位移传递到内部网格,同时保持网格质量。
CFL3D提供了两种网格变形方法:弹簧类比法和弹性方程法。
9.3.1 弹簧类比法
弹簧类比法(spring analogy)将网格想象为由弹簧连接的质点系统。每个网格点之间的边对应一根弹簧,弹簧的刚度与边长成反比(短边更"硬",长边更"软")。
当边界上的点产生位移时,整个弹簧系统会重新平衡。通过求解弹簧系统的平衡方程,可以得到所有内部网格点的新位置。平衡方程的形式是:每个点受到的来自周围弹簧的合力为零。
弹簧类比法的优点是概念简单、实现直观。缺点是对于大变形问题,网格质量可能下降较快------特别是在边界附近的大变形区域,网格可能出现负体积。
为了改善弹簧类比法的性能,CFL3D中实现了几种增强技术:
- 非线性弹簧:弹簧刚度不仅与初始长度有关,还与当前的拉伸量有关
- 扭转弹簧:在网格单元的角点处添加扭转弹簧,抵抗单元的变形
- 多重网格变形:在粗网格上求解变形,再插值到细网格,提高效率和鲁棒性
9.3.2 弹性方程法
弹性方程法(elasticity / solid mechanics approach)将网格视为线弹性固体,边界的位移作为位移边界条件,求解弹性力学平衡方程来得到内部的位移场。
弹性方程法的控制方程是:
∇⋅σ=0
其中 σ 是应力张量,与应变张量的关系由胡克定律给出。
与弹簧类比法相比,弹性方程法更加"物理",因此通常能产生质量更好的变形网格。特别是对于大变形问题,弹性方程法表现出更好的鲁棒性。代价是计算量更大------需要求解一个三维的椭圆型偏微分方程。
CFL3D中,弹性方程法的实现位于 deform.F 相关的子例程中。代码使用有限元或有限差分离散弹性方程,并通过迭代法求解线性方程组。
弹性方程法还有一个有趣的变体------变刚度弹性方程。在这种方法中,材料的刚度可以随空间变化,例如在壁面附近设置更高的刚度以保护边界层网格,在远场设置更低的刚度以允许更大的变形。这种策略可以显著改善大变形情况下的网格质量。
9.4 几何守恒律
动网格计算中有一个容易被忽视但至关重要的问题:几何守恒律(Geometric Conservation Law, GCL)。
几何守恒律说的是:对于一个随时间变化的控制体,其体积的变化率应该等于控制体表面上的"网格速度"的通量。换句话说,如果网格在运动,那么体积的变化应该与边界的运动一致。
在离散形式下,几何守恒律要求:
ΔtVn+1−Vn=∑facesvg⋅nΔS
其中 vg 是界面的网格速度。
如果离散格式不满足几何守恒律,那么即使流动本身是均匀的(密度、速度、压力处处常数),动网格也会产生虚假的流动扰动。这在非定常计算中可能导致严重的误差。
CFL3D对几何守恒律有仔细的处理。网格速度的计算方式确保了离散的几何守恒律得到满足。具体来说,界面的网格速度不是简单地取界面两侧点速度的平均,而是通过体积变化率来反推------这样可以从根本上保证GCL的满足。
delt 相关的子例程负责计算随时间变化的体积和度量,其中就包含了GCL的实现细节。对于动网格计算,确保GCL满足是获得可信结果的前提条件。
9.5 气动弹性耦合
气动弹性(aeroelasticity)研究的是气动力与结构弹性变形之间的相互作用。在飞行器设计中,气动弹性问题至关重要------颤振(flutter)可能导致灾难性的结构破坏,而嗡鸣(buzz)和抖振(buffet)则会影响飞行品质和结构寿命。
CFL3D提供了气动弹性分析的能力,将CFD流场求解与结构动力学方程耦合起来。耦合的方式可以是:
- 紧耦合:每一个物理时间步内,同时求解流场和结构,迭代直到两者都收敛
- 松耦合:流场和结构分别推进,每隔若干步交换一次数据
CFL3D的气动弹性模块支持以下功能:
- 模态结构模型:基于结构的模态振型和频率来描述结构动力学
- 直接积分:在物理时间上直接积分结构运动方程
- 静气动弹性:求解平衡位置的静态变形
- 颤振分析:通过时间域仿真或频域方法预测颤振边界
结构动力学方程通常写作:
Mx¨+Cx˙+Kx=Faero
其中 M,C,K 分别是质量矩阵、阻尼矩阵和刚度矩阵, Faero 是气动力向量。
在模态空间中,这个方程可以解耦为一组单自由度方程,大大减少了计算量。CFL3D的气动弹性实现采用了模态方法------用户提供结构的模态振型和频率,代码在模态空间中积分结构运动。
每一个时间步的耦合过程是:
- 根据当前的结构位移,移动网格
- 求解流场,得到作用在结构表面的气动力
- 将气动力投影到模态空间,得到模态力
- 积分结构动力学方程,得到下一时刻的模态位移
- 将模态位移转换为物理位移,回到第1步
ae_pred.F 和 ae_corr.F 等子例程实现了气动弹性的预测和校正步骤。气动弹性计算对时间精度要求很高,通常需要使用子迭代和多重网格来确保每个时间步的流场解足够准确。
CFL3D的气动弹性能力已经在多个NASA项目中得到验证和应用,包括机翼颤振分析、旋翼气动弹性、储箱推进剂晃动等问题。
9.6 多体相对运动
对于更复杂的问题,可能涉及多个物体之间的相对运动。例如,螺旋桨与机身的组合、多段翼的收放、投放物分离等。
CFL3D通过重叠网格(Chimera)与动网格的结合来处理这类问题。每个物体有自己的网格块,各自独立运动(平移、旋转或变形),重叠区域通过插值交换流场信息。
这种方法的优势是灵活性极强------几乎可以处理任意的相对运动,只要重叠区域足够、插值质量有保障。缺点是计算量较大,且重叠区域的插值会引入额外的数值耗散。
动态补丁(dynamic patch)是另一种处理相对运动的方式。与重叠网格不同,补丁连接不允许块之间有重叠,而是在每一步动态地重新计算界面的插值关系。这种方式适合于块之间有明确的界面、且界面两侧的网格都在运动的情况。
CFL3D中,dynptch.F 子例程负责动态补丁的更新。每一个时间步,在网格移动之后,动态补丁关系需要重新计算,以确保界面两侧的正确对应。
第十章 低马赫数预处理技术
10.1 低马赫数流动的数值困难
当流动的马赫数很低(如Ma < 0.1)时,标准的可压缩CFD方法会遇到严重的数值刚性问题。
根本原因在于声速与流动速度的比值很大。在可压缩格式中,时间步长受CFL条件限制,而CFL条件中的波速是声速(对于迎风格式)。当马赫数很低时,声速远大于流动速度,这导致时间步长非常小------即使流动变化很慢,也需要极多的时间步才能收敛。
更严重的是,低马赫数下,压力场与速度场的耦合变得很弱。压力的变化主要通过声学过程传播,而速度场的演化则是对流过程。在低马赫数下,这两种过程的时间尺度相差悬殊,导致方程组的条件数很差,隐式求解器的收敛速度急剧下降。
这种现象被称为"低马赫数刚性"或"声学刚性"。如果不采取特殊措施,标准的可压缩CFD代码在低马赫数下的收敛速度可能比在跨声速下慢几个数量级。
10.2 预处理的基本思想
预处理(preconditioning)是解决低马赫数刚性的标准技术。其核心思想是:改变时间项(伪时间项)的形式,使得方程组的特征值在低马赫数下变得均衡------将声波的特征速度降低到与对流速度相当的量级。
预处理后的方程组为:
Γ−1∂τ∂U+∂x∂F+∂y∂G+∂z∂H=S
其中 τ 是伪时间, Γ 是预处理矩阵。 Γ 的设计目标是:
- 在低马赫数下,将所有特征速度缩放至相近的量级
- 不改变稳态解(因为稳态时伪时间导数项为零)
- 在高马赫数下,预处理自动退化为恒等变换(即不影响高速流动)
最著名的预处理方法是Turkel预处理和Choi-Merkle预处理。CFL3D中实现了低马赫数预处理功能,由Jack Edwards教授(NCSU)贡献。
10.3 预处理的实现细节
预处理矩阵的构造需要仔细考虑。一个好的预处理矩阵应该:
- 保留方程组的双曲性质
- 对称正定(确保伪时间步进是稳定的)
- 特征值易于计算
- 空间离散的通量计算可以复用
在实际实现中,预处理通常作用于时间方向的雅可比矩阵,而不改变空间通量的计算方式。也就是说,残差的计算与标准可压缩格式完全相同,只有隐式求解器的左侧矩阵受到预处理的影响。
CFL3D中,低马赫预处理通过编译选项或运行时参数启用。启用后,代码会自动计算当地马赫数,根据当地马赫数调整预处理参数,在低马赫区域提供有效的预处理,在高马赫区域自动"关闭"预处理。
10.4 预处理的应用场景
低马赫数预处理在以下场景中特别有用:
低速风洞试验模拟:许多风洞试验的来流马赫数很低(如Ma = 0.1~0.3),此时预处理可以大幅加速收敛。
内流问题:如低速管道流动、通风系统、建筑物内部气流等,马赫数可能低至0.01以下,没有预处理几乎无法收敛。
水动力学问题:水的声速约为1500 m/s,而流动速度通常只有几米/秒,马赫数极低。可压缩CFD代码用于水动力学计算时,预处理是必不可少的。
多相流和燃烧问题:在这些问题中,局部马赫数可能很低,预处理有助于改善数值条件。
需要注意的是,预处理主要改善的是定常收敛速度。对于非定常计算,物理时间步的精度受物理CFL数限制,预处理的效果有限------它只能加速每个时间步内的伪时间收敛。
10.5 预处理与多重网格的结合
低马赫数预处理和多重网格都是收敛加速技术,它们的结合可以产生协同效应。
多重网格的效率取决于误差在各层网格上的衰减速度。在低马赫数下,由于声学时间尺度和对流时间尺度的分离,某些误差模式的衰减变得很慢,这会降低多重网格的效率。
预处理通过均衡特征速度,使得不同波速的误差分量可以在多重网格循环中被同等有效地衰减。因此,预处理不仅本身能加速收敛,还能提高多重网格在低马赫数下的效率。
CFL3D支持预处理与多重网格的同时使用。两者结合的效果通常是叠加的------在低马赫数流动中,可以获得一个数量级甚至更高的收敛加速。
10.6 局限性与注意事项
低马赫数预处理虽然强大,但也有其局限性:
非物理的瞬态行为:预处理改变了伪时间的波速,因此伪时间步的解不具有物理意义------只有最终的稳态解是正确的。对于非定常计算,预处理只应用于子迭代的伪时间步,而物理时间步的精度不受影响。
边界条件的调整:预处理可能需要相应的边界条件调整。特别是远场边界条件,如果不考虑预处理的影响,可能产生额外的反射。
激波附近的问题:预处理矩阵是针对低马赫数设计的,在激波附近马赫数急剧变化,预处理可能引入额外的数值耗散或振荡。好的预处理方法会有一个"开关"函数,在高马赫区域平滑地过渡到无预处理的状态。
收敛判据的选择:使用预处理后,残差的收敛行为可能与标准格式不同。需要选择合适的收敛判据,避免过早停止或过度迭代。
尽管有这些局限性,低马赫数预处理仍然是扩展可压缩CFD代码适用范围的关键技术。它使得同一套代码可以高效地处理从极低马赫数到高超声速的宽速域流动,大大提升了代码的通用性。
第十一章 复变量方法与灵敏度分析
11.1 为什么需要灵敏度分析
在工程设计中,我们常常需要知道输出量(如升力、阻力、压力分布)对输入参数(如迎角、马赫数、几何形状参数)的导数。这些导数被称为灵敏度(sensitivity)或梯度(gradient),它们在以下方面有重要应用:
- 设计优化:梯度-based优化算法需要目标函数和约束对设计变量的梯度
- 不确定性量化:需要知道输出对输入不确定性的敏感度
- 反问题:根据观测数据反推输入参数,需要梯度来构造目标函数的海森矩阵
- 参数研究:快速评估参数变化的影响,而不需要每次都重新计算完整的流场
计算灵敏度的方法有多种:
- 有限差分法:对参数做微小扰动,重新计算流场,用差分近似梯度
- 伴随方法:求解伴随方程,一次计算可以得到对所有设计变量的梯度
- 复步长法:利用复变量的性质,通过一次复值计算得到精确的梯度
CFL3D实现了复变量方法(complex variable method),这是一种独特而优雅的灵敏度计算技术。
11.2 复步长法的数学原理
复步长法(complex step method)的基本思想来自复分析中的柯西-黎曼方程。
考虑一个实值函数 f(x),我们想求它在 x0 处的导数 f′(x0)。将函数扩展到复平面,考虑 f(x0+ih),其中 i 是虚数单位, h 是一个很小的实数。
将 f 在 x0 处泰勒展开:
f(x0+ih)=f(x0)+ihf′(x0)+2!(ih)2f′′(x0)+3!(ih)3f′′′(x0)+4!(ih)4f′′′′(x0)+⋯
展开后分离实部和虚部:
f(x0+ih)=f(x0)−2h2f′′(x0)+24h4f′′′′(x0)−⋯+ihf′(x0)−6h3f′′′(x0)+⋯
取虚部并除以 h:
hImf(x0+ih)=f′(x0)−6h2f′′′(x0)+O(h4)
可以看到,这个近似的截断误差是 O(h2) 的------这本身就已经是二阶精度了。但复步长法真正的优势在于:它没有有限差分法中的"相消误差"问题。
在有限差分法中, f′(x0)≈2hf(x0+h)−f(x0−h),分子是两个相近数的差,当 h 很小时,有效数字会大量丢失。而复步长法中,我们直接取虚部,不需要两个相近的数
复步长法的精度通常可以达到机器精度------只要 h 足够小(如 10−20),导数的精度就几乎等于函数值本身的精度。这是有限差分法无法比拟的------有限差分存在截断误差和相消误差的权衡,最优步长通常在 10−6∼10−8 量级,精度只有单精度水平。
11.3 CFL3D中的复变量实现
CFL3D的复变量版本(由Bob Biedron等人开发)通过条件编译实现------定义 CMPLX 宏后,所有实数变量变为复数变量,所有实数运算变为复数运算。
这意味着:
- 网格坐标是复数的
- 流动变量(密度、动量、能量)是复数的
- 通量计算、边界条件、湍流模型都是复数运算
- 最终输出的力系数等也是复数的
实部对应于基准流场的解,虚部对应于对扰动参数的灵敏度。
在复变量模式下运行CFL3D时,需要:
- 输入参数(如马赫数、迎角)的实部取基准值,虚部取微小的扰动(如 10−20)
- 网格坐标可以是实的(如果参数不影响几何),也可以是复的(如果参数影响几何形状)
- 运行计算直到收敛
- 输出结果的实部是基准流场的解,虚部除以扰动步长就是灵敏度
一次复变量计算的计算量大约是实数计算的2~3倍(因为复数运算比实数运算慢),但只需要一次计算就可以得到对一个参数的灵敏度。相比之下,有限差分法需要至少两次计算(基准和扰动),而且精度远不如复步长法。
11.4 复变量方法的优势
与其他灵敏度计算方法相比,复变量方法有以下优势:
高精度:如前所述,复步长法可以达到机器精度的导数,远优于有限差分法。
实现简单:只需要将实数运算替换为复数运算,不需要开发全新的伴随求解器。对于像CFL3D这样的大型代码,开发伴随版本的工作量是巨大的------可能需要数年时间。而复变量版本可以在几个月内完成。
鲁棒性好:复变量方法的收敛行为与实数版本基本一致,因为方程的数学结构没有改变。伴随方程则可能有不同的收敛特性,需要特殊的加速技术。
可以处理复杂的输入输出:只要输入参数可以表示为复数扰动,输出量可以从复值流场中提取,复变量方法就能计算其灵敏度。这包括力、力矩、压力分布、热流等各种输出。
11.5 复变量方法的局限
复变量方法也有一些局限性:
一次只能算一个参数:复变量方法一次计算只能得到对一个扰动参数的灵敏度。如果有N个设计变量,就需要N次复变量计算。这在变量数很多时(如基于数百个形状参数的气动优化),计算量可能很大。相比之下,伴随方法一次计算可以得到对所有设计变量的梯度。
计算量 :复变量计算的计算量是实数计算的23倍。如果只需要12个参数的灵敏度,这比有限差分法(需要2倍以上计算量且精度更低)更有优势;但如果参数很多,伴随方法更高效。
代码改造:虽然比开发伴随简单,但将整个CFD代码改造为支持复变量仍然是一项不小的工程。特别是需要确保所有子程序都正确地处理复数------包括输入输出、边界条件、湍流模型等。
某些函数的问题 :一些函数(如 min, max, abs)在复数域中的定义可能与实数域不同,需要特殊处理。CFL3D中对这些函数有专门的复变量版本实现。
尽管有这些局限,复变量方法仍然是一种非常有价值的灵敏度分析工具。特别是对于参数数量不多(如几个到几十个)的优化问题,或者需要高精度导数的研究场景,复变量方法提供了一个"性价比"很高的选择。
11.6 应用实例
CFL3D的复变量版本已经在多个研究项目中得到应用:
气动外形优化:使用复变量方法计算升阻比对形状参数的梯度,驱动梯度-based优化算法。相比有限差分法,复变量方法提供的高精度梯度使得优化收敛更快、结果更优。
不确定性量化:计算气动力对来流条件(马赫数、迎角、雷诺数)的灵敏度,用于评估飞行条件不确定性对飞行器性能的影响。
湍流模型校准:计算流场解对湍流模型常数的灵敏度,用于基于实验数据的模型常数校准。
颤振分析:计算气动力对结构模态位移的灵敏度,用于气动弹性分析的雅可比矩阵构造。
在这些应用中,复变量方法的高精度特性都发挥了重要作用------特别是在需要计算高阶导数或多个参数的联合效应时,复变量方法的精度优势更加明显。
第十二章 CGNS标准与数据交换
12.1 CGNS简介
CFD通用标注系统(CFD General Notation System, CGNS)是一个面向CFD的数据标准,旨在促进不同CFD代码之间的数据交换和互操作性。CGNS由AIAA(美国航空航天学会)主导开发,已经成为CFD领域事实上的标准数据格式。
CGNS的设计目标是:
- 通用性:能够描述各种类型的CFD问题,从结构化到非结构化,从定常到非定常,从无粘到湍流
- 完整性:包含CFD计算所需的所有信息------网格、边界条件、流动参数、初始条件、解数据等
- 可扩展性:可以通过自定义节点扩展标准功能
- 平台无关:数据格式不依赖于特定的硬件或软件平台
CGNS的数据模型基于树状结构,类似于文件系统的目录树。每个节点有一个名字和一个类型(如Base_t, Zone_t, GridCoordinates_t, FlowSolution_t等)。这种层次化的结构使得数据组织清晰且易于扩展。
12.2 CGNS数据结构
一个典型的CGNS文件包含以下层次:
Base(基础):最顶层的节点,包含整个数据库的基本信息,如单元维度(二维或三维)和物理维度。
Zone(区域/块):每个网格块是一个Zone节点。Zone包含了该块的网格尺寸、网格类型(结构化、非结构化等)。
GridCoordinates(网格坐标):存储网格节点的坐标数据(x, y, z)。
FlowSolution(流场解):存储流动变量的数据,如密度、速度、压力、湍动能等。解的位置可以是单元中心(CellCenter)或节点中心(Vertex)。
ZoneBC(区域边界条件):描述该区域的边界条件。每个边界面有自己的BC节点,包含边界条件类型和数据。
ZoneGridConnectivity(区域网格连接):描述多块网格之间的连接关系,如1-1连接、补丁连接等。
ConvergenceHistory(收敛历史):存储收敛过程中的残差、力系数等历史数据。
ReferenceState(参考状态):存储参考流动状态,如自由来流条件。
CFL3D使用的主要是CGNS的结构化网格子集,因为CFL3D本身是基于结构化网格的。
12.3 CFL3D中的CGNS实现
CFL3D通过 cgnstools.F 文件中的一系列子例程提供CGNS支持。这些子例程封装了CGNS库的低级API,提供了更方便的接口来读写CGNS文件。
主要的CGNS功能包括:
读取CGNS网格 :readgr 相关的CGNS版本可以从CGNS文件中读取网格坐标和连接信息。这使得CFL3D可以接受任何能够输出CGNS格式的网格生成器的输出。
读取CGNS解:可以从CGNS文件中读取流场解作为初始条件或重启数据。这便于从其他CFD代码的结果开始计算,或者使用不同代码进行交叉验证。
写入CGNS解:CFL3D的计算结果可以输出为CGNS格式,便于使用支持CGNS的后处理工具(如Tecplot、FieldView、ParaView等)进行可视化和分析。
读取CGNS边界条件:边界条件信息也可以通过CGNS文件指定,减少了手动设置输入文件的工作量。
CGNS的支持是通过条件编译启用的------定义 CGNS 宏并链接CGNS库即可。这种设计使得CGNS成为可选功能,不使用CGNS的用户不需要链接额外的库。
12.4 CGNS的优势与意义
采用CGNS标准对CFL3D来说有多重意义:
互操作性:CFL3D可以与其他支持CGNS的CFD代码、网格生成器、后处理工具无缝交换数据。这在多工具协作的工程环境中非常重要。
数据持久化:CGNS是一个稳定、有文档记录的标准。相比CFL3D自己的二进制格式,CGNS格式的数据更有可能在未来被读取和理解------即使CFL3D本身不再维护,CGNS文件仍然可以被其他工具打开。
减少格式转换错误:自定义格式之间的转换往往是错误的来源。使用标准格式可以消除转换步骤,减少出错的可能性。
社区生态:围绕CGNS已经形成了一个活跃的社区和工具生态。使用CGNS意味着可以受益于这个生态系统------各种工具、库、脚本都可以直接使用。
12.5 CGNS文件结构示例
让我们通过一个简单的例子来理解CGNS的组织方式。假设我们有一个二维NACA 0012翼型的单块计算:
scss
Base (CellDimension=2, PhysicalDimension=2)
├── Zone (Type=Structured, Size=[129, 65, 0])
│ ├── GridCoordinates
│ │ ├── CoordinateX (129x65 array)
│ │ └── CoordinateY (129x65 array)
│ ├── FlowSolution (Location=CellCenter)
│ │ ├── Density (128x64 array)
│ │ ├── MomentumX (128x64 array)
│ │ ├── MomentumY (128x64 array)
│ │ ├── Energy (128x64 array)
│ │ └── TurbulentViscosity (128x64 array)
│ ├── ZoneBC
│ │ ├── BC_inlet (Type=BCFarfield, GridLocation=FaceCenter)
│ │ ├── BC_outlet (Type=BCExtrapolate, GridLocation=FaceCenter)
│ │ ├── BC_airfoil (Type=BCWallViscous, GridLocation=FaceCenter)
│ │ └── BC_symmetry (Type=BCSymmetryPlane, GridLocation=FaceCenter)
│ └── ZoneGridConnectivity (optional)
├── ReferenceState
│ ├── Mach (0.5)
│ ├── Reynolds (5.0e6)
│ └── AngleOfAttack (3.0)
└── ConvergenceHistory
├── Residual (1000 iterations)
├── LiftCoefficient (1000 iterations)
└── DragCoefficient (1000 iterations)
这种树状结构清晰、自描述------任何读取CGNS文件的程序都可以遍历节点,了解文件中包含了什么数据。
12.6 实际应用中的注意事项
在使用CGNS时,有一些实际问题需要注意:
版本兼容性:CGNS标准在不断演进,不同版本的CGNS库之间可能存在一些不兼容。CFL3D通常与特定版本的CGNS库一起测试,使用时需要注意版本匹配。
数据位置:CFL3D使用单元中心格式(CellCenter),而有些代码使用节点中心格式(Vertex)。在数据交换时需要注意位置的转换。CGNS库提供了一些工具来进行位置插值,但最好在源头就使用一致的位置约定。
边界条件映射:不同代码对边界条件类型的定义和命名可能不同。虽然CGNS定义了标准的边界条件类型,但代码之间的映射仍然需要仔细处理。例如,CFL3D的bc1000远场条件对应CGNS的BCFarfield,但具体的参数设置可能需要额外的转换。
湍流变量:不同湍流模型的变量不同。CGNS中对湍流变量的命名有一定的约定,但并不是所有代码都严格遵守。在交换包含湍流数据的文件时,需要特别注意变量的对应关系。
尽管有这些细节问题,CGNS仍然是目前CFD领域最成熟、最广泛接受的数据标准。CFL3D对CGNS的支持使其能够更好地融入现代CFD工作流程。
第十三章 工程应用与验证案例
13.1 验证与确认(V&V)
CFD作为一种数值模拟工具,其结果的可信度必须通过验证与确认(Verification and Validation, V&V)来建立。
- 验证(Verification):确认"我们是否正确地求解了方程"------即检查数值方法是否正确实现,数值解是否收敛到精确解(对于有解析解的问题),以及网格收敛性如何。
- 确认(Validation):确认"我们是否求解了正确的方程"------即将计算结果与实验数据比较,评估物理模型(特别是湍流模型)的准确性。
CFL3D的开发者们深知V&V的重要性。代码发布时附带了大量的测试用例(test cases),涵盖了从无粘到粘性、从二维到三维、从定常到非定常的各种流动类型。这些测试用例不仅用于验证代码的正确性,也为用户提供了学习和参考的范例。
13.2 二维测试案例
CFL3D文档中包含了丰富的二维测试案例,每个案例都有详细的输入文件、结果数据和与实验的对比。
13.2.1 平板边界层(Flatplate)
平板边界层是湍流模型验证的经典案例。零压力梯度平板边界层有大量的实验数据和理论结果(如对数律速度剖面)可供比较。
CFL3D的平板测试案例验证了多种湍流模型的边界层预测能力,包括SA模型、SST模型、EASM模型等。结果包括:
- 表面摩擦系数沿程分布
- 速度型的 law-of-the-wall 曲线
- 不同y+网格下的计算精度比较
平板案例虽然简单,但它是验证湍流模型近壁行为的基础------如果连平板边界层都算不准,就更不用说复杂的三维流动了。
13.2.2 后台阶流动(Backstep)
后台阶流动是经典的分离流动验证案例。流动在台阶处分离,在下游重新附着,形成一个分离泡。分离泡的长度、再附点位置、压力分布等都是衡量湍流模型预测能力的重要指标。
后台阶流动的难点在于分离区的湍流各向异性较强,标准的涡粘模型往往预测不准。CFL3D的后台阶案例展示了不同湍流模型在分离流动中的表现差异。
13.2.3 RAE 2822翼型
RAE 2822是一个经典的跨声速翼型验证案例。该翼型有大量的实验数据,包括不同马赫数和迎角下的压力分布、升阻力系数、激波位置等。
跨声速翼型流动的特点是存在激波,激波与边界层的相互作用可能导致边界层分离。准确预测激波位置和激波-边界层干扰是对CFD方法的重要考验。
CFL3D的RAE 2822案例中包含了多种工况的计算结果,与实验数据的对比显示:
- 压力分布的预测总体良好
- 激波位置和强度的预测受湍流模型影响
- 阻力系数的预测精度在工程可接受范围内
13.2.4 NACA 0012翼型俯仰振荡
俯仰振荡翼型是经典的非定常气动验证案例。翼型做简谐俯仰运动,流动经历动态失速------在迎角增加阶段,流动可能保持附着超过静态失速迎角,然后在某个时刻突然发生大规模分离,形成巨大的动态失速涡。
动态失速是一个高度非线性的非定常现象,对湍流模型和时间离散的精度都很敏感。CFL3D的俯仰振荡案例验证了其非定常计算能力,包括:
- 升力、力矩系数的迟滞回线
- 动态失速涡的形成和演化
- 不同减缩频率下的流动特性
13.2.5 隆起流动(Hump)
隆起流动(也称为"驼峰"流动)是另一个经典的分离流动案例。流动经过一个壁面上的隆起,在隆起的后部发生分离,然后再附。与后台阶相比,隆起的分离更温和,分离区更小。
NASA Langley的TMR(Turbulence Modeling Resource)网站上有大量隆起流动的实验数据和不同CFD代码的计算结果对比。CFL3D是TMR网站上使用的主要代码之一。
13.3 三维测试案例
13.3.1 ONERA M6机翼
ONERA M6机翼是三维跨声速流动的经典验证案例。该机翼有详细的实验数据,包括不同展向位置的压力分布、升阻力系数、俯仰力矩等。
M6机翼的流动特点是:机翼上表面有一个"λ"形激波(跨声速三维流动的典型特征),激波根部与边界层相互作用可能导致局部分离。
CFL3D的M6机翼案例展示了其三维多块网格的计算能力。结果通常包括:
- 各展向位置的压力分布与实验对比
- 升力、阻力、力矩系数的比较
- 网格收敛性研究(不同网格密度下的结果变化)
13.3.2 ARA M100螺旋桨
ARA M100是一个螺旋桨测试案例,用于验证CFL3D的旋转机械计算能力。螺旋桨流动具有强烈的非定常性和三维效应,叶片之间的干扰、叶尖涡的演化、桨-涡干扰等都是具有挑战性的流动现象。
CFL3D通过多块网格和旋转运动来模拟螺旋桨流动。可以使用单通道+周期边界的方法,也可以使用全叶片的计算。结果包括:
- 叶片表面压力分布
- 推力和扭矩系数
- 尾流中的速度分布
13.3.3 转子-静子干涉(Rotor-Stator)
转子-静子干涉是涡轮机械中的典型流动现象。转子叶片的尾迹撞击静子叶片,产生强烈的非定常压力脉动和气动载荷。这是涡轮机械中噪声和振动的主要来源之一。
CFL3D的转子-静子案例使用多块重叠网格或滑动界面来处理转子和静子之间的相对运动。非定常计算可以捕捉到尾迹的输运和与静子的相互作用过程。
13.4 网格收敛性与不确定性
CFD结果的可信度不仅取决于物理模型的准确性,还取决于数值误差的大小。网格收敛性研究(grid convergence study)是评估数值误差的标准方法。
网格收敛性研究通常使用三套不同密度的网格(粗、中、细),根据三套网格的结果变化来估计数值不确定性。Richardson外推法是常用的分析工具------假设数值误差具有确定的收敛阶数,可以通过外推估计"网格收敛"的解。
CFL3D的许多测试案例都包含了网格收敛性研究。例如,NACA 0012案例使用了从65x17到513x129的五套网格,展示了升阻力系数随网格加密的收敛趋势。
在工程实践中,理解和量化数值误差与理解物理模型的不确定性同样重要。一个好的CFD分析报告不仅应该给出结果,还应该说明结果的可信度范围。
13.5 典型应用场景
CFL3D在NASA和工业界有着广泛的应用。以下是一些典型的应用场景:
翼型与机翼设计:从低速到跨声速再到超声速,CFL3D可以计算各种速度范围下的翼型和机翼气动特性。
机身-机翼-尾翼组合体:通过多块网格和补丁连接,可以构建完整的飞行器构型,进行全机气动分析。
进气道与喷管:内流问题是CFL3D的另一个重要应用领域。低马赫预处理能力使得CFL3D可以处理低速内流和高超声速内流。
涡轮机械:旋转运动和周期边界的支持使得CFL3D可以用于压气机、涡轮、风扇等旋转机械的流动分析。
气动弹性分析:动网格和结构耦合功能支持颤振、嗡鸣等气动弹性问题的研究。
流动控制研究:通过修改边界条件或添加源项,可以研究各种流动控制手段的效果。
这些应用场景覆盖了航空航天工程中的大多数气动问题。CFL3D三十余年的持续发展和验证,使其成为工程CFD工具链中值得信赖的一员。
第十四章 输入文件与运行配置详解
14.1 输入文件的结构
CFL3D的运行由一个纯文本的输入文件(通常称为"cfl3d.inp"或类似名称)控制。输入文件采用关键字驱动的格式------用户通过设置各种关键字及其参数来指定计算条件、数值方法、输出选项等。
这种关键字驱动的设计在工程软件中非常常见,它的优势是:
- 灵活性强:用户只需指定需要修改的参数,未指定的使用默认值
- 可读性好:每个关键字都有明确的含义,输入文件几乎就是"自文档化"的
- 可扩展性好:添加新功能只需要添加新的关键字,不影响已有的输入格式
CFL3D的输入文件通常包含以下几个部分:
- 标题行:计算的描述性标题
- 基本参数:维度(二维/三维)、网格块数、参考条件等
- 数值方法选择:通量分裂类型、空间精度、时间推进方式等
- 湍流模型选择:模型类型、模型常数、壁面处理等
- 收敛控制:CFL数、最大迭代步数、收敛判据等
- 多重网格设置:层数、循环类型、各层参数等
- 边界条件设置:每个块每个面的边界条件类型和数据
- 输出设置:输出频率、输出内容、输出格式等
- 高级选项:非定常、动网格、并行、预处理等
14.2 关键字系统解析
CFL3D的关键字系统由 readkey.F 和 parser.F 等子例程实现。其工作原理是:
- 逐行读取输入文件
- 识别行首的关键字(不区分大小写)
- 解析关键字后面的参数值
- 将参数值存储到对应的公共块或数据结构中
关键字可以按照任意顺序出现(有少数例外),这使得输入文件的组织非常灵活。对于复杂的多块计算,用户可以按块组织关键字,也可以按主题组织。
以下是一些最常用的关键字及其作用:
title:指定计算的标题,可以有多达20行。
nbl:指定网格块的数量。
mach:指定自由来流马赫数。
reyn:指定雷诺数和参考长度。
alpha / beta:指定迎角和侧滑角。
time / ntstep:指定非定常计算的时间步长和时间步数。
cfl / cflmax:指定CFL数和最大CFL数。
nit:指定最大迭代步数。
ncyc:指定多重网格循环次数。
mg:指定多重网格层数和循环类型。
ivisc:指定粘性模型类型(0=无粘,1=层流,5=SA,7=k-ω SST等)。
ifds:指定通量分裂类型(1=Van Leer FVS,2=Roe FDS等)。
mseq:指定网格序列法的参数。
dtvar:指定当地时间步长选项。
ipr:指定输出频率和输出内容。
plot3d:指定PLOT3D格式输出的频率和内容。
每个关键字后面可以跟多个参数,参数之间用空格或逗号分隔。参数可以是整数、实数或字符串,取决于具体的关键字。
14.3 边界条件输入
边界条件的输入是CFL3D输入文件中最复杂的部分之一。由于CFL3D支持段式边界条件(一个面可以分成多个段,每段有不同的边界类型),边界条件的输入需要精确指定每个段的位置和类型。
边界条件输入的基本格式是:指定块号、面号(i-min, i-max, j-min, j-max, k-min, k-max)、段数,然后对每个段指定其类型、起止位置和参数。
例如,一个典型的壁面边界条件输入可能是这样的:
yaml
bc kmin 1 1
1005 1 65 1
这表示第1个块的k-min面有1段,类型是1005(无粘壁面),从j=1到j=65,i=1到i=...
对于更复杂的情况,一个面上可能有多个段。例如,机翼的下表面可能包含壁面段、控制面段、尾缘段等。每段有自己的边界类型和参数。
边界条件输入的正确性对计算结果至关重要。一个常见的错误是边界段之间有重叠或有间隙------这会导致通量不守恒,进而影响计算精度甚至稳定性。
14.4 重启与初始化
CFL3D支持从重启文件(restart file)继续计算。重启文件以二进制格式存储了当前的流场状态,包括守恒变量、湍流变量等。从重启文件开始计算可以节省大量时间------特别是当需要改变某些参数(如迎角、CFL数)继续计算时,不需要从头开始。
重启文件的使用通过以下关键字控制:
irestart:指定是否从重启文件开始rstfile:指定重启文件的名称nwrite:指定每隔多少步写一次重启文件
CFL3D还支持"冷启动"------即从均匀来流条件开始计算。冷启动时,整个流场初始化为自由来流的值,然后逐步迭代收敛。
对于复杂的流动,冷启动可能需要很多步才能收敛。这时候网格序列法就派上用场了------先在粗网格上收敛(冷启动也快得多),然后将解插值到细网格作为初始猜测。
14.5 输出设置
CFL3D提供了丰富的输出选项,用户可以根据需要选择输出的内容和频率。
主要的输出类型包括:
收敛历史输出:每N步输出一次残差、力系数、力矩系数等。这是监控收敛过程的主要手段。收敛历史通常输出到名为"cfl3d.res"的文件中。
流场解输出:每隔若干步输出一次完整的流场解,用于后处理和可视化。CFL3D支持多种输出格式:
- PLOT3D格式:传统的结构化网格可视化格式
- CGNS格式:标准的CFD数据格式
- Tecplot格式:常用的后处理软件格式
力和力矩输出:输出作用在各块壁面上的力和力矩系数。包括升力、阻力、侧力、俯仰力矩、偏航力矩、滚动力矩等。力的计算分为压力贡献和粘性贡献两部分。
表面分布输出:输出沿壁面的压力系数、摩擦系数、温度等分布。这对于分析翼型压力分布、表面热流等非常有用。
剖面输出:输出沿某个截面的流动参数分布,用于分析边界层剖面、尾迹剖面等。
时间历程输出:对于非定常计算,可以输出某些物理量随时间的变化,如某点的压力、升力系数的时间序列等。
合理设置输出频率很重要------输出太频繁会增加I/O开销和磁盘占用,输出太少又可能错过重要的流动信息。一般来说,收敛历史应该每1050步输出一次,完整的流场解每100500步输出一次即可。
14.6 运行命令与环境
CFL3D的可执行文件通常通过命令行运行。基本的运行命令是:
cfl3d < input_file > output_file
其中 input_file 是输入文件的路径,output_file 是标准输出的重定向目标。
对于并行版本,使用MPI启动命令:
mpirun -np 8 cfl3d_mpi < input_file > output_file
其中 -np 8 指定使用8个处理器。
CFL3D的运行需要以下文件:
- 输入文件(指定计算条件)
- 网格文件(二进制PLOT3D格式或CGNS格式)
- 重启文件(如果从重启开始)
- 补丁/重叠网格信息文件(如果使用多块连接)
运行后会生成以下文件:
- 标准输出文件(运行日志)
- 收敛历史文件(.res)
- 重启文件(.rst 或 .q)
- PLOT3D格式的网格和解文件
- 力和力矩输出文件
- 其他用户指定的输出文件
14.7 完整输入文件示例
下面给出一个完整的CFL3D v5格式输入文件示例,用于计算NACA 0012翼型的低亚声速定常流动。这个示例来自CFL3D自带的测试案例,具有很高的参考价值。
yaml
FILES:
n0012_1025.bin
plot3dg.bin
plot3dq.bin
n0012_65t0.out
n0012_65t0.res
cfl3d.turres
cfl3d.blomax
cfl3d.out15
n0012_65t0.prout
cfl3d.out20
ovrlp.bin
patch.bin
restart.bin
NACA 0012
XMACH ALPHA BETA REUE,MIL TINF,DR IALPH IHSTRY
0.3000 00.000 0.0 10.0000 520.0 0 0
SREF CREF BREF XMC YMC ZMC
1.00000 1.00000 1.0000 0.00000 0.00 0.00
DT IREST IFLAGTS FMAX IUNST CFLTAU
-5.0000 0 000 05.0000 0 10.
NGRID NPLOT3D NPRINT NWREST ICHK I2D NTSTEP ITA
-1 1 1 20000 0 -1 0010 -2
NCG IEM IADVANCE IFORCE IVISC(I) IVISC(J) IVISC(K)
4 0 0 1 0 0 05
IDIM JDIM KDIM
2 1025 513
ILAMLO ILAMHI JLAMLO JLAMHI KLAMLO KLAMHI
1 2 417 609 1 513
INEWG IGRIDC IS JS KS IE JE KE
0 0 0 0 0 0 0 0
IDIAG(I) IDIAG(J) IDIAG(K) IFLIM(I) IFLIM(J) IFLIM(K)
1 1 1 0 0 0
IFDS(I) IFDS(J) IFDS(K) RKAP0(I) RKAP0(J) RKAP0(K)
1 1 1 0.3333 0.3333 0.3333
GRID NBCI0 NBCIDIM NBCJ0 NBCJDIM NBCK0 NBCKDIM IOVRLP
1 1 1 1 1 3 1 0
I0: GRID SEGMENT BCTYPE JSTA JEND KSTA KEND NDATA
1 1 1001 0 0 0 0 0
IDIM: GRID SEGMENT BCTYPE JSTA JEND KSTA KEND NDATA
1 1 1002 0 0 0 0 0
J0: GRID SEGMENT BCTYPE ISTA IEND KSTA KEND NDATA
1 1 1002 0 0 0 0 0
JDIM: GRID SEGMENT BCTYPE ISTA IEND KSTA KEND NDATA
1 1 1002 0 0 0 0 0
K0: GRID SEGMENT BCTYPE ISTA IEND JSTA JEND NDATA
1 1 0 0 0 1 161 0
1 2 2004 0 0 161 865 2
TWTYPE CQ
0. 0.
1 3 0 0 0 865 1025 0
KDIM: GRID SEGMENT BCTYPE ISTA IEND JSTA JEND NDATA
1 1 1003 0 0 0 0 0
MSEQ MGFLAG ICONSF MTT NGAM
5 1 0 0 02
ISSC EPSSSC(1) EPSSSC(2) EPSSSC(3) ISSR EPSSSR(1) EPSSSR(2) EPSSSR(3)
0 0.3 0.3 0.3 0 0.3 0.3 0.3
NCYC MGLEVG NEMGL NITFO
90000 01 00 000
000 02 00 000
000 03 00 000
000 03 00 000
000 03 00 000
MIT1 MIT2 MIT3 MIT4 MIT5 MIT6 MIT7 MIT8
01 01 01 01 01 1 1 1
01 01 01 01 01 1 1 1
01 01 01 01 01 1 1 1
01 01 01 01 01 1 1 1
01 01 01 01 01 1 1 1
1-1 BLOCKING DATA:
NBLI
1
NUMBER GRID : ISTA JSTA KSTA IEND JEND KEND ISVA1 ISVA2
1 1 1 1 1 2 161 1 1 2
NUMBER GRID : ISTA JSTA KSTA IEND JEND KEND ISVA1 ISVA2
1 1 1 1025 1 2 865 1 1 2
PATCH SURFACE DATA:
NINTER
0
PLOT3D OUTPUT:
GRID IPTYPE ISTART IEND IINC JSTART JEND JINC KSTART KEND KINC
1 0 0 0 0 0 0 0 0 0 0
MOVIE
0
PRINT OUT:
GRID IPTYPE ISTART IEND IINC JSTART JEND JINC KSTART KEND KINC
1 0 1 01 1 161 865 1 1 1 1
CONTROL SURFACE:
NCS
0
文件各部分解读:
-
FILES段:前14行指定了各个文件的名称,包括网格文件、输出文件、重启文件等。第15行是标题行。
-
流动条件:第16-17行指定马赫数0.3、迎角0度、侧滑角0度、雷诺数10(百万)、温度520°R。
-
参考量:第18-19行指定参考面积、参考长度、力矩参考点等。力和力矩系数都是基于这些参考量计算的。
-
时间推进:第20-21行,DT=-5表示使用当地时间步长,CFL数初始为5。IREST=0表示冷启动。
-
输出控制:第22-23行,NGRID=-1表示每个网格层都输出,NPLOT3D=1表示每1步输出PLOT3D(实际中通常设更大的值),NWREST=20000表示每20000步写一次重启文件。
-
湍流模型:第24-25行,IVISC(K)=05表示k方向(壁面法向)使用Spalart-Allmaras一方程湍流模型。I方向和J方向的IVISC为0表示无粘(薄剪切层近似下,只有法向有粘性)。
-
网格尺寸:第26-27行,IDIM=2(二维,i方向只有2个单元),JDIM=1025(周向),KDIM=513(法向)。
-
边界条件:第38-53行详细指定了六个面上的边界条件:
- I0(i-min面):bc1001对称面
- IDIM(i-max面):bc1002外推
- J0和JDIM面:bc1002外推
- K0(k-min,翼型表面):3段,其中第2段(j=161到865)是bc2004(1-1连接,因为是C型网格,尾缘上下表面在j方向对接)
- KDIM(k-max,远场):bc1003入流/出流
-
多重网格:第54-69行,MSEQ=5表示5层网格序列,MGFLAG=1表示启用多重网格。5层网格每层的循环次数和迭代参数依次列出。
-
1-1块连接:第70-76行,定义了C型网格尾缘处的1-1连接。
这个示例展示了v5格式输入文件的完整结构。v6格式(关键字驱动)虽然写法不同,但设置的内容是完全对应的。
14.8 关键字驱动输入示例(V6格式)
版本6引入了更灵活的关键字驱动输入格式。以下是一个使用关键字格式的典型输入文件片段:
ini
# =============================================
# CFL3D V6 关键字输入示例:RAE 2822翼型跨声速计算
# =============================================
title = "RAE 2822 Transonic Airfoil - Case 9"
title = "Mach 0.73, Alpha=2.79 deg, Re=6.5 million"
# ---- 网格设置 ----
nbl = 1
grid = rae2822.p3d # PLOT3D格式二进制网格文件
i2d = 1 # 二维计算
# ---- 流动条件 ----
mach = 0.73 # 来流马赫数
alpha = 2.79 # 迎角(度)
reyn = 6.5e6 # 雷诺数(基于弦长)
gamma = 1.4 # 比热比
prandtl = 0.72 # 普朗特数
# ---- 参考量 ----
sref = 1.0 # 参考面积(二维为单位展弦比)
cref = 1.0 # 参考长度(弦长)
xref = 0.25 # 力矩参考点x坐标(1/4弦长)
# ---- 数值方法 ----
ifds = 2 # 通量分裂:2=Roe FDS
rkap = 0.3333 # MUSCL限制器参数
idiag = 1 1 1 # 三个方向都使用对角化隐式
iflim = 0 0 0 # 通量限制器开关
# ---- 湍流模型 ----
ivisc = 5 # 5=Spalart-Allmaras模型
i_saneg = 1 # 启用SA-neg变体
edvislim = 1.0e5 # 涡粘系数上限
# ---- 时间推进与收敛 ----
dtvar = 1 # 启用当地时间步长
cfl = 3.0 # 初始CFL数
cflmax = 10.0 # 最大CFL数
nit = 5000 # 最大迭代步数
nres = 200 # 每200步输出一次残差
# ---- 多重网格 ----
mgflag = 1 # 启用多重网格
mseq = 4 # 4层网格序列
mglevel = 3 # 多重网格层数
ncyc = 50 # 每层多重网格的循环数
mtt = 1 # V循环
# ---- 边界条件 ----
# I面(前后):对称/外推
bc i min = 1001
bc i max = 1002
# J面(上下远场):外推
bc j min = 1002
bc j max = 1002
# K面(壁面/远场)
bc k min = 1005 1 200 # 翼型下表面:无粘壁面(示例,实际应为粘性壁面)
bc k min = 2004 201 700 # 尾缘1-1连接
bc k min = 1005 701 1000 # 翼型上表面
bc k max = 1000 # 远场:freestream
# ---- 输出设置 ----
nplot3d = 500 # 每500步输出PLOT3D解
plot3d_format = binary # 二进制格式
ipr = 100 # 每100步输出力和残差
iprforce = 1 # 输出力系数
nwrite = 1000 # 每1000步写重启文件
# ---- 重启设置 ----
irestart = 0 # 0=冷启动,1=从重启文件开始
rstfile = restart.dat # 重启文件名
关键字格式的优势是可读性更好,参数含义一目了然。不需要严格按照固定顺序输入,未指定的参数使用默认值。这对于新用户来说更加友好。
14.9 输出文件示例
14.9.1 收敛历史文件(.res)
收敛历史文件是监控计算过程最重要的输出。以下是一段典型的收敛历史输出:
yaml
CFL3D V6.7 RAE 2822 Transonic Case 9 - SA turbulence model
Mach=0.730 Alpha=2.79 Re=6.500E+06 I2D= 1 IVISC= 5
Grid=1 Blks=1 Cells= 128x 64 = 8192
Step Rms-dRho Rms-dRhoU Rms-dRhoV Rms-dRhoE CFL
1 1.000E+00 1.000E+00 1.000E+00 1.000E+00 3.00
5 6.234E-01 5.872E-01 6.015E-01 5.987E-01 3.50
10 3.456E-01 3.123E-01 3.289E-01 3.201E-01 4.20
20 1.234E-01 9.876E-02 1.098E-01 1.045E-01 5.50
50 2.345E-02 1.567E-02 1.892E-02 1.734E-02 7.00
100 4.567E-03 2.345E-03 3.123E-03 2.789E-03 8.50
200 8.912E-04 3.456E-04 5.678E-04 4.567E-04 9.20
500 1.234E-05 5.678E-06 8.901E-06 7.234E-06 9.80
1000 5.678E-07 2.345E-07 3.456E-07 2.890E-07 10.00
1500 3.456E-08 1.234E-08 1.890E-08 1.567E-08 10.00
2000 2.103E-09 7.890E-10 1.156E-09 9.456E-10 10.00
解读:
- 第一列是迭代步数
- 接下来四列分别是密度、x动量、y动量、能量的残差(均方根值,归一化)
- 最后一列是当前的CFL数
- 残差从1开始(初始残差归一化为1),逐步下降
- 2000步时密度残差下降了约9个数量级,说明已经收敛得很好
14.9.2 力系数输出
力系数输出通常与收敛历史一起给出:
yaml
Step CL CD Cm_x Cm_y Cm_z
100 0.423456 0.017823 -0.001234 0.094567 -0.003456
200 0.418901 0.017234 -0.000987 0.092345 -0.002890
500 0.415678 0.016890 -0.000765 0.090123 -0.002345
1000 0.414234 0.016712 -0.000678 0.089456 -0.002103
1500 0.413890 0.016678 -0.000654 0.089234 -0.002034
2000 0.413765 0.016665 -0.000645 0.089156 -0.002012
CL convergence: 4.138E-01 change: 1.250E-04 (0.03%)
CD convergence: 1.667E-02 change: 1.300E-05 (0.08%)
解读:
- CL:升力系数
- CD:阻力系数(通常包含压差阻力和摩擦阻力两部分)
- Cm_x, Cm_y, Cm_z:三个方向的力矩系数
- 最后给出力系数的收敛判断------变化量是否已经足够小
14.9.3 标准输出文件
标准输出(通常重定向到.out文件)包含更详细的运行信息,包括:
- 代码版本和版权声明
- 输入参数的回显
- 网格信息和网格质量检查结果
- 边界条件设置摘要
- 每一步的详细输出(如果设置了较高的输出级别)
- 计时信息(总时间、各部分耗时)
- 结束时的总结信息
以下是标准输出开头部分的示例:
yaml
**********************************************************************
CFL3D Version 6.7 - NASA Langley Research Center
Structured-grid, cell-centered, upwind-biased RANS flow solver
**********************************************************************
Title: RAE 2822 Transonic Airfoil - Case 9
Mach 0.73, Alpha=2.79 deg, Re=6.5 million
Job starting time: 2026-10-02 14:30:00
Number of grid blocks: 1
Total number of cells: 8192 (128 x 64 x 1)
I2D flag: 1 (2-D computation)
Mach number: 0.7300
Angle of attack: 2.7900 deg
Reynolds number: 6.5000E+06 (per chord)
Ratio of specific heats: 1.4000
Prandtl number: 0.7200
Flux splitting scheme: Roe FDS (ifds=2)
Spatial accuracy: 2nd order (MUSCL)
Turbulence model: Spalart-Allmaras (ivisc=5)
Implicit algorithm: Diagonalized (idiag=1)
Multigrid: Enabled, 3 levels, V-cycle
Grid 1 dimensions: 129 x 65 x 2 (j x k x i)
Minimum volume: 1.2345E-07
Maximum aspect ratio: 1250.0
Grid appears OK - no negative volumes detected.
Boundary conditions for grid 1:
I-min face: 1 segment, type 1001 (symmetry plane)
I-max face: 1 segment, type 1002 (extrapolation)
J-min face: 1 segment, type 1002 (extrapolation)
J-max face: 1 segment, type 1002 (extrapolation)
K-min face: 3 segments
1: type 1005 (inviscid wall), j=1 to 200
2: type 2004 (1-1 connect), j=201 to 700
3: type 1005 (inviscid wall), j=701 to 1000
K-max face: 1 segment, type 1000 (freestream)
Beginning iteration...
这些信息对于检查输入设置是否正确、诊断问题非常有价值。当计算出现问题时,首先应该查看标准输出文件,确认所有设置是否符合预期。
14.10 常见场景配置示例
以下是几种常见计算场景的关键参数配置示例。
场景一:定常无粘跨声速翼型
ini
# 快速评估用的无粘计算
mach = 0.85
alpha = 1.5
ivisc = 0 # 无粘
ifds = 2 # Roe格式
mgflag = 1 # 多重网格
cfl = 5.0
cflmax = 20.0
nit = 1000
特点:无粘计算收敛最快,通常几百步就能收敛。适合快速评估压力分布和激波位置。
场景二:定常粘性湍流翼型
ini
# 工程精度的粘性计算
mach = 0.3
alpha = 4.0
reyn = 5.0e6
ivisc = 7 # k-ω SST模型
ifds = 2
mgflag = 1
mseq = 3 # 3层网格序列
cfl = 3.0
cflmax = 8.0
nit = 3000
nres = 50
特点:湍流计算收敛较慢,需要更多迭代步数。使用网格序列法+多重网格可以加速收敛。
场景三:非定常俯仰振荡
ini
# 动态失速计算
iunst = 1 # 非定常
time_step = 0.001 # 物理时间步(秒,需换算为无量纲)
ntstep = 1000 # 总时间步数
nsubit = 10 # 每步子迭代数
cfltau = 20.0 # 伪时间CFL数
ivisc = 5 # SA模型(SST也可,但SA更稳健)
alpha0 = 0.0 # 平均迎角
alphamp = 15.0 # 振幅
alphafreq = 10.0 # 频率(Hz)
特点:非定常计算计算量大,需要仔细选择时间步长。子迭代数影响时间精度和计算成本。
场景四:低马赫数内流
ini
# 低速管道流动
mach = 0.05 # 低马赫
precon = 1 # 启用低马赫预处理
ivisc = 7 # SST模型
ifds = 1 # Van Leer FVS(低马赫下更稳健)
cfl = 5.0
cflmax = 50.0 # 预处理后可以用更大的CFL
mgflag = 1
特点:低马赫数下必须启用预处理,否则收敛极慢甚至不收敛。FVS格式在低马赫下通常比FDS更稳健。
场景五:并行多块计算
ini
# 16块网格,4个处理器
nbl = 16
# ... 各块设置 ...
# 并行运行时用mpirun启动,输入文件与串行基本相同
# 块到处理器的分配在splitter阶段完成
特点:并行版本的输入文件与串行版本几乎相同。主要区别在编译方式和启动命令。
场景六:复变量灵敏度计算
ini
# 计算升阻力对马赫数的导数
# 使用复变量版本的可执行文件
mach = 0.5 + 1.0e-20 i # 马赫数加微小虚部扰动
ivisc = 0 # 先从无粘开始(更容易收敛)
# 输出结果的虚部 / 1e-20 = 对马赫数的导数
特点:复变量计算的输入文件与实数版本几乎相同,只是某些参数带有虚部扰动。一次计算可以得到对一个参数的高精度灵敏度。
第十五章 代码实现的工程智慧
15.1 Fortran语言的选择与取舍
CFL3D主要使用Fortran 77编写,这在今天看来似乎有些过时。但如果理解了CFD代码的发展历史和Fortran语言的特点,就会明白这个选择并不意外------甚至可以说,在当时的历史条件下,Fortran是唯一合理的选择。
Fortran是最早的高级编程语言之一,专门为科学计算设计。它的许多特性对于数值计算来说是天然友好的:
多维数组的原生支持:Fortran从一开始就支持多维数组,数组运算语法简洁。对于以数组操作为核心的CFD代码来说,这是一个巨大的优势。
列优先存储:Fortran的数组按列优先存储(第一个索引变化最快),这与CFD中内层循环通常遍历i方向(最快索引)的习惯天然契合,有利于缓存效率。
高效的编译器优化:经过半个多世纪的发展,Fortran编译器的优化能力已经炉火纯青。特别是对于DO循环的向量化和并行化,Fortran编译器通常能比C/C++编译器做得更好。
数值计算库生态:BLAS、LAPACK、FFTPACK等经典数值库都是用Fortran编写的。CFD代码经常需要调用这些库,使用Fortran可以直接链接,无需额外的接口层。
当然,Fortran 77也有明显的局限性:缺乏动态内存分配、没有模块化机制、公共块的全局变量问题、字符串处理能力弱等。CFL3D的开发者们通过各种工程技巧巧妙地规避了这些问题------比如通过大工作数组实现"手动动态内存",通过命名约定管理公共块等。
到了版本6,CFL3D开始引入Fortran 90的特性,如模块(module)、allocate语句、接口块等。module_kwstm.F90 就是一个用Fortran 90模块组织k-ω SST模型的例子。这种逐步演进的方式既保持了代码的稳定性,又逐步吸收了现代语言的优点。
15.2 向量化与性能优化
CFL3D诞生的年代,向量超级计算机(如Cray系列)是高性能计算的主力。向量计算机的特点是单条指令可以对一组数据(向量)进行操作,从而获得远高于标量处理器的性能。
为了充分利用向量处理器,CFL3D的内层循环都经过了精心的向量化优化。代码中可以看到大量的 cdir$ ivdep 这样的编译器指令(pragmas),它们告诉编译器"这个循环不存在向量依赖,可以安全地向量化"。
ivdep 是"ignore vector dependencies"的缩写。它断言循环的各次迭代之间不存在依赖关系,因此可以重新排序或并行执行。在CFD的通量计算中,每个界面的通量计算确实是独立的------不需要其他界面的结果。因此,这些循环是天然可向量化的。
除了ivdep,CFL3D还使用了其他一些向量化优化技巧:
循环展开:将内层循环展开几次,减少循环开销并增加指令级并行度。
数组填充:在数组的末尾添加一些额外的元素,使得数组的起始地址对齐到缓存行边界,提高缓存效率。
循环合并与分离:将多个小循环合并为一个大循环以减少开销,或者将大循环拆分为小循环以提高缓存命中率。
避免条件分支 :在内层循环中尽量使用内置函数(如 ccvmgt------条件移动)代替if语句,避免分支预测失败的开销。
虽然今天的CPU已经从向量架构转向了超标量和SIMD架构,但这些向量化优化的原则仍然适用。现代CPU的SIMD单元(如SSE、AVX)本质上就是短向量处理器,向量化做得好的代码在现代CPU上同样运行得快。
15.3 内存访问模式与缓存优化
现代CPU的计算速度远远快于内存访问速度------CPU执行一条浮点运算只需要几个时钟周期,而从主存读取一个数据可能需要几百个时钟周期。因此,程序的性能往往不是受限于计算能力,而是受限于内存带宽和延迟。这就是所谓的"内存墙"问题。
解决内存墙问题的主要手段是缓存。现代CPU有多级缓存,越靠近CPU的缓存越小越快。如果数据能在缓存中找到(缓存命中),访问延迟就会大大降低。因此,优化内存访问模式、提高缓存命中率,是性能优化的关键。
CFL3D在这方面有很多值得称道的设计:
数组维度顺序 :CFL3D的数组维度顺序是 (jdim, kdim, idim),即i方向是最快变化的维度。而内层循环通常也是遍历i方向的。这样,循环中的连续迭代访问的是内存中连续的元素,这正是缓存最喜欢的访问模式------顺序访问。
工作数组的布局:虽然CFL3D使用大工作数组来模拟动态内存,但数据的布局是经过精心安排的------经常一起使用的数据放在相邻的位置,尽量避免"跳着访问"。
分块算法:对于大网格,整个数组可能放不下缓存。CFL3D的多重网格和隐式求解等算法天然具有分块的特性------每次只处理一小块数据,处理完再换下一块。这有助于提高缓存命中率。
避免间接寻址:在性能关键的内层循环中,尽量避免间接寻址(即通过索引数组访问数据)。间接寻址会破坏预取器的预测能力,导致缓存命中率下降。
这些优化策略虽然是三十年前的经验,但在今天仍然有效。实际上,随着CPU计算能力与内存速度之间的差距越来越大,内存访问优化的重要性反而与日俱增。
15.4 鲁棒性设计
CFD代码的鲁棒性(robustness)是指代码在各种条件下都能稳定运行、不会崩溃的能力。对于工程应用来说,鲁棒性往往比峰值性能更重要------一个偶尔能跑出漂亮结果但经常崩溃的代码,在工程上是不可靠的。
CFL3D在鲁棒性设计方面积累了丰富的经验:
熵修正:如前所述,在低马赫数和驻点区域,通量分裂格式可能出现病态。熵修正确保了格式在这些区域的稳定性。
限制器:限制器不仅是为了精度,也是为了稳定性------没有限制器的高阶格式在间断附近会产生振荡,严重时会导致负密度或负能量,使计算崩溃。
CFL数自适应:CFL3D可以根据残差的变化自动调整CFL数------残差下降顺利时提高CFL以加速收敛,残差上升时降低CFL以恢复稳定。
变量裁剪:在某些情况下(如强激波、大分离),某些单元的流动变量可能出现非物理的值(如负密度、负压力)。CFL3D有机制检测并修正这些值,防止它们进一步恶化导致计算崩溃。
时间子迭代:对于非定常计算,子迭代不仅提高时间精度,也增强了稳定性------每个物理时间步内的多次迭代可以逐步将解"拉回"物理合理的范围。
重启机制:即使计算真的发散了,只要有重启文件,就可以从之前的某个状态重新开始。这大大降低了试错成本。
鲁棒性是一个系统性的工程问题,不是靠某一个技巧就能解决的。CFL3D三十余年的发展过程中,无数的bug修复和改进汇聚成了今天的稳定性。这种稳定性是新的CFD代码很难在短时间内达到的。
15.5 可维护性与代码质量
对于一个持续开发了三十年的代码库来说,可维护性至关重要。CFL3D在代码质量和可维护性方面有许多值得借鉴的做法:
一致的命名约定 :子例程和变量的命名遵循一致的约定。例如,通量相关的子例程以 flux 开头,边界条件以 bc 开头,i方向的操作以 i 结尾等。熟悉命名约定后,仅从名字就能猜出子例程的大致功能。
详细的注释:每个子例程开头都有详细的注释头,说明子例程的用途、输入输出参数、调用的其他子例程等。重要的算法步骤也有行内注释解释其原理。
模块化设计:虽然使用Fortran 77的子例程和公共块,但代码的组织仍然体现了模块化的思想。不同的功能封装在不同的子例程中,通过明确的接口交互。
统一的代码风格:缩进、大小写、注释格式等都保持统一。这使得阅读代码成为一种连贯的体验,而不是每次切换文件都要重新适应不同的风格。
回归测试:大量的测试案例构成了事实上的回归测试集。每次修改代码后,运行这些测试案例并比较结果,可以确保修改没有引入新的bug。
当然,以今天的软件工程标准来看,CFL3D的代码也有不尽人意之处------比如全局变量过多、缺乏单元测试、没有版本控制系统的完整历史记录(早期使用CVS,后迁移到Git)等。但考虑到它的开发年代和持续时间,CFL3D的代码质量已经相当令人敬佩。
第十六章 最佳实践与性能优化
16.1 网格生成策略
CFD计算的质量在很大程度上取决于网格的质量。一个好的网格应该满足以下要求:
- 足够的分辨率以捕捉重要的流动特征
- 光滑的网格过渡,避免突变
- 合理的长宽比和扭曲度
- 边界层内足够的网格点密度
对于CFL3D这类结构化网格代码,网格生成本身就是一门艺术。以下是一些经验法则:
边界层网格 :对于使用低雷诺数湍流模型的计算,壁面第一个内点的 y+ 应该在1左右。边界层内至少需要1520个网格点才能较好地分辨速度剖面。对于壁面函数方法, y+ 应该在30100的对数律区内。
外流远场:远场边界应该至少离物体50倍弦长(或特征长度)以上,以减少远场边界的影响。远场网格可以比较稀疏,但需要注意从物面到远场的网格增长率不宜过大(一般不超过1.2~1.3)。
激波捕捉:如果流动中存在激波,激波区域的网格需要足够细密以准确捕捉激波结构。可以使用嵌入网格来局部加密激波区域。
多块拓扑:块的划分应该尽量保持各块的网格数量相近,这有利于并行计算的负载平衡。块之间的界面应该尽量光滑,避免锐角。
网格质量检查:在开始计算之前,应该检查网格的质量指标,包括:
- 单元体积(是否存在负体积)
- 长宽比
- 扭曲角
- 网格线的正交性
CFL3D在初始化阶段会自动进行一些网格质量检查,并输出警告信息。用户应该关注这些警告,必要时改进网格。
16.2 湍流模型选择
选择合适的湍流模型是CFD计算中最重要的决策之一。不同的流动类型适合不同的模型,没有"万能"的湍流模型。
以下是一些湍流模型选择的指导原则:
附着边界层流动:大多数涡粘模型都能较好地预测附着边界层。SA模型和SST模型都是不错的选择,SA模型计算量更小,SST模型精度略高。
逆压梯度与分离:对于有分离倾向的流动(如机翼后缘、扩压器等),SST模型通常比标准k-ω和SA模型表现更好。SST模型的剪切应力输运修正使其对分离的预测更接近实验。
大分离流动:对于大规模分离流动(如失速后的机翼、后台阶等),RANS模型的预测能力普遍下降。在这种情况下,可以考虑:
- 使用更高级的模型(如EASM或RSM)
- 使用DES方法(如果计算资源允许)
- 接受一定的误差,将结果用于趋势分析而非定量预测
自由剪切流:对于射流、尾迹、混合层等自由剪切流动,k-ε模型通常表现不错。k-ω模型在自由流中的表现对来流条件敏感,需要谨慎使用。
旋转与曲率流动:对于有明显流线曲率或系统旋转的流动,需要使用带曲率修正的模型。标准的涡粘模型通常会高估旋转通道中的混合程度。
可压缩流动:高马赫数流动中,需要考虑可压缩性修正。标准的不可压缩湍流模型在高马赫数下可能过高预测湍动能。
最终的模型选择应该基于类似流动的验证经验。如果有实验数据可用,最好先用实验数据校准所选的模型,再进行实际的计算分析。
16.3 收敛判据与监控
判断计算是否已经收敛是CFD实践中的一个关键问题。过早停止计算可能导致结果不准确,过度迭代则浪费计算资源。
CFL3D提供了多种收敛监控手段:
残差监测 :最基本的收敛指标是方程残差的下降幅度。通常认为,当密度残差下降35个数量级时,流动的主要特征已经建立;下降68个数量级时,可以认为达到了工程收敛。
需要注意的是,残差的绝对水平与问题规模和归一化方式有关。比较不同计算的残差水平时,应该使用相同的归一化方式。
力系数监测:升力、阻力、力矩等工程量的收敛往往比残差更重要。当这些量在若干迭代步内基本保持不变时,即使残差还在缓慢下降,也可以认为工程上已经收敛。
通常建议将力系数的变化小于最后一个百分点作为收敛判据之一。例如,连续100步迭代内,升力系数的变化不超过0.001,阻力系数的变化不超过0.0001。
表面压力分布监测:对于某些问题,特定位置的压力系数或载荷分布的收敛可能更关键。可以监测几个关键截面的压力分布,观察其是否已经稳定。
多重网格下的收敛:使用多重网格时,收敛曲线可能出现"平台期"------残差在某个水平上停滞一段时间,然后继续下降。这是正常现象,是因为不同频率的误差分量在不同的多重网格阶段被衰减。不要因为短暂的平台期就过早停止计算。
非定常计算的收敛:非定常计算的"收敛"有两层含义:一是每个时间步内的子迭代需要收敛(伪时间收敛),二是周期性非定常流动的周期平均量需要稳定(统计收敛)。
对于周期性流动,通常需要运行几个周期后,流动才会进入周期性稳定状态。在那之前的数据不应该用于时间平均。
16.4 计算效率优化
CFL3D的计算效率受多种因素影响。以下是一些提高计算效率的建议:
充分利用多重网格 :多重网格是CFL3D提供的最有效的收敛加速技术。只要有可能,就应该启用多重网格。通常34层多重网格可以提供310倍的收敛加速。
合理设置CFL数:CFL数是影响收敛速度的重要参数。对于隐式格式,CFL数可以设得比较大。一般来说,定常计算可以从较低的CFL数(如1.0)开始,然后逐渐增加到5~10甚至更高。
需要注意的是,过高的CFL数可能导致不稳定------特别是在计算初期或流动发生剧烈变化时。CFL3D支持CFL数的自动调整(如残差上升时降低CFL,残差下降时提高CFL)。
当地时间步长:对于定常计算,务必启用当地时间步长。当地时间步长可以显著加速收敛,特别是在网格疏密不均的情况下。
初始猜测的质量:好的初始猜测可以大幅减少收敛所需的迭代步数。以下是一些改善初始猜测的方法:
- 使用网格序列法:先在粗网格上收敛,再插值到细网格
- 使用低阶格式先跑一段时间,再切换到高阶格式
- 从相似工况的结果开始
并行效率优化:
- 确保每个处理器的网格点数大致相当
- 避免使用太多小的块------块数过多会增加通信开销
- 对于大型计算,测试不同处理器数下的效率,找到最佳配置
内存与I/O优化:
- 如果内存足够,尽量减少重启文件的读写频率
- 使用二进制格式而非ASCII格式进行I/O
- 输出文件的频率不宜过高,特别是大网格的三维解文件
16.5 常见问题与故障排除
使用CFL3D时可能遇到的一些常见问题及其可能的解决方法:
计算发散(残差爆炸):
- 检查初始条件是否合理
- 降低初始CFL数
- 检查网格质量(是否有负体积、严重扭曲的单元)
- 检查边界条件设置是否正确
- 检查远场边界是否太近
- 尝试先使用一阶格式计算,再切换到高阶
- 对于高超声速流动,考虑使用时间相关法(从低马赫数启动)
收敛缓慢(残差平台):
- 检查是否启用了多重网格
- 检查CFL数是否足够大
- 检查网格质量------低质量网格可能导致收敛缓慢
- 检查湍流模型是否收敛------有时候平均流收敛了但湍流方程没收敛
- 对于分离流动,收敛本身就比较慢,需要更多迭代
- 检查是否有"硬点"(stagnation point, sharp corner等)导致局部残差偏高
结果不合理:
- 检查边界条件类型和参数
- 检查参考条件(马赫数、雷诺数、迎角等)
- 检查网格是否正确(特别是对称面、壁面等关键位置)
- 确认湍流模型选择是否合适
- 进行网格收敛性研究,排除数值误差的影响
- 与实验数据或其他代码的结果对比,找出差异原因
并行计算问题:
- 检查块到处理器的分配是否正确
- 检查通信是否正常(使用调试输出确认)
- 确认所有处理器上的输入参数一致
- 检查并行I/O的文件路径是否正确
这些只是一些常见问题的排查思路。实际情况往往更加复杂,需要结合具体的计算条件进行分析。CFL3D的源代码是开放的,当遇到难以理解的问题时,直接阅读相关的源代码往往是最有效的调试手段。
16.6 完整工作流示例
下面通过一个完整的示例,展示从编译CFL3D到运行计算、再到后处理分析的完整工作流程。假设我们要计算一个NACA 0012翼型在Ma=0.5、迎角3度下的湍流流动。
第一步:编译CFL3D
bash
# 进入build目录
cd build/cfl/seq
# 设置编译器环境(以Intel Fortran为例)
source /opt/intel/compilers_and_libraries/linux/bin/compilervars.sh intel64
# 复制示例makefile并修改
cp makefile_intel_example makefile
# 编辑makefile,设置正确的编译器和选项
# 主要修改:FC(编译器)、FFLAGS(编译选项)、INCLUDE(头文件路径)
# 编译
make -j4
# 编译成功后,可执行文件在 ../../../bin/ 目录下
ls ../../../bin/cfl3d_seq
如果需要编译并行版本:
bash
cd build/cfl/mpi
make -j4
如果需要编译复变量版本:
bash
cd build/cflcmplx/seq
make -j4
第二步:准备网格和输入文件
bash
# 创建工作目录
mkdir naca0012_case
cd naca0012_case
# 复制网格文件(假设已有)
cp /path/to/naca0012_grid.p3d grid.bin
# 创建输入文件(使用v5格式或关键字格式)
cat > cfl3d.inp << 'EOF'
# NACA 0012, Ma=0.5, alpha=3 deg, SA turbulence
mach = 0.5
alpha = 3.0
reyn = 3.0e6
ivisc = 5
ifds = 2
mgflag = 1
mseq = 3
cfl = 3.0
cflmax = 10.0
nit = 3000
nres = 50
nplot3d = 500
nwrite = 1000
# ... 边界条件等其他设置 ...
EOF
第三步:运行计算
bash
# 串行运行
../../bin/cfl3d_seq < cfl3d.inp > cfl3d.out 2>&1
# 或者后台运行(防止终端断开)
nohup ../../bin/cfl3d_seq < cfl3d.inp > cfl3d.out 2>&1 &
# 查看运行状态
tail -f cfl3d.out
# 查看收敛历史
tail -50 cfl3d.res
第四步:监控收敛
bash
# 使用gnuplot实时监控残差(可选)
gnuplot -persist -e "
set logscale y;
set grid;
set xlabel 'Iteration';
set ylabel 'RMS Residual';
set title 'Convergence History';
plot 'cfl3d.res' using 1:2 w l title 'Density',
'cfl3d.res' using 1:3 w l title 'x-Momentum',
'cfl3d.res' using 1:5 w l title 'Energy';
"
判断是否收敛:
- 密度残差下降至少3~5个数量级
- 升力、阻力系数变化小于0.1%
- 表面压力分布基本不再变化
第五步:后处理与分析
bash
# 用Tecplot打开结果
tec360 plot3dg.bin plot3dq.bin
# 或者用ParaView(需要先转换格式)
# 输出为VTK格式或使用CGNS格式
# 提取力系数
grep -i "cl\|cd" cfl3d.res | tail -10
# 提取壁面压力分布
# 使用CFL3D的surface output功能,或自己写脚本处理
# 计算升阻比
python3 -c "
CL = 0.3567
CD = 0.00892
print(f'CL/CD = {CL/CD:.2f}')
"
第六步:结果验证
bash
# 与实验数据对比
# 1. 从文献中找到NACA 0012在Ma=0.5, alpha=3°下的实验数据
# 2. 将计算的压力分布与实验数据作图对比
# 3. 比较升力、阻力系数的差异
# 网格收敛性检查
# 1. 生成更密的网格(如网格点数翻倍)
# 2. 用相同设置重新计算
# 3. 比较两次结果的差异
# 4. 如果差异小于1%,认为网格已基本收敛
整个工作流从编译到得到结果,对于一个简单的二维翼型案例,熟练的用户可能只需要几个小时。对于更复杂的三维构型,时间可能需要几天到几周,具体取决于网格规模和计算资源。
第十七章 CFL3D的过去、现在与未来
17.1 历史回顾
CFL3D的历史可以追溯到20世纪80年代末。当时,NASA Langley研究中心的计算流体实验室正在开发一系列结构化网格的CFD代码,包括用于无粘流动的ARC系列和用于粘性流动的TLNS3D等。
CFL3D的最初版本由Bob Lawrence等人开发,其核心算法基于当时最先进的迎风偏置格式和隐式时间推进方法。"CFL3D"这个名字中的"CFL"最初代表"Characteristic-based Flux splitting"(基于特征的通量分裂),后来也被解释为"Computational Fluids Laboratory"(计算流体实验室)的缩写。
从版本1到版本5,CFL3D逐步添加了多块网格、湍流模型、多重网格等功能。版本5是一个成熟的版本,有完整的用户手册和大量的应用案例。
版本6是CFL3D的一次重大升级,引入了许多重要的新特性:
- MPI并行计算支持
- 动态内存分配
- 多块网格变形
- 改进的非定常气动弹性分析
- 低马赫数预处理
- CGNS兼容性
- 复变量方法
- 全Navier-Stokes选项
版本6.7是目前最新的公开版本(发布于2017年)。虽然近年来CFL3D的开发速度有所放缓,但它仍然是NASA湍流模型验证等研究活动的主力工具之一。
17.2 CFL3D的设计哲学
回顾CFL3D三十余年的发展历程,可以提炼出几条贯穿始终的设计哲学:
可靠性优先:在CFD工程应用中,可靠性比花哨的功能更重要。CFL3D的每一项功能都经过了充分的测试和验证,代码中的每一处改动都需要谨慎评估对现有功能的影响。这种保守的开发风格虽然使得新功能的引入较慢,但也保证了代码的稳定性------用户可以信任CFL3D的计算结果。
模块化与可配置性:CFL3D通过子例程和公共块的组织方式,实现了高度的模块化。不同的数值方法(如FVS vs FDS)、不同的湍流模型、不同的边界条件,都可以通过编译选项或运行时参数灵活选择。用户可以根据具体问题选择最合适的配置,而不是被迫接受"一刀切"的方案。
性能意识:CFD代码是计算密集型的,每一点性能提升都意味着可以在相同时间内完成更多的计算。CFL3D的内层循环经过了精心的向量化优化,内存访问模式考虑了缓存效率,多重网格等加速技术也被早期引入。这些性能优化的努力使得CFL3D在同等精度下往往比许多"现代"CFD代码更快。
验证驱动开发:CFL3D的每一个新功能、每一次修改,都伴随着测试案例的验证。代码发布时附带的大量测试案例不仅是给用户的参考,更是开发者的"安全网"------确保改动不会破坏已有的功能。
17.3 在CFD软件谱系中的定位
今天的CFD软件市场非常丰富,从开源代码到商业软件,从结构化到非结构化,从RANS到LES/DNS,各种类型的代码应有尽有。在这样的背景下,CFL3D的定位是什么?
首先,CFL3D是一个研究型代码。它的开放架构和清晰的代码结构使其成为新算法、新模型的理想试验平台。NASA的研究者们不断在CFL3D上试验新的湍流模型、新的数值方法、新的加速技术,验证成功后再推广到其他代码中。
其次,CFL3D是一个教育工具。对于学习CFD的学生和工程师来说,阅读CFL3D的源代码是理解CFD算法实现的绝佳途径。从通量计算到边界条件,从多重网格到湍流模型,每一个算法的实现都可以在代码中找到对应的部分。
第三,CFL3D是一个可靠的工程工具。虽然它可能没有商业软件那样华丽的图形界面和便捷的前处理,但对于熟悉它的用户来说,CFL3D可以稳定、高效地解决很多工程问题。特别是在航空航天领域,CFL3D数十年的验证积累使其结果具有很高的可信度。
17.4 与现代CFD趋势的对比
CFD领域在过去二十年中发生了许多变化。让我们看看CFL3D如何面对这些趋势:
从结构化到非结构化:非结构化网格由于其处理复杂几何的灵活性,已经成为工业CFD的主流。CFL3D作为结构化网格代码,在这方面确实有局限性。然而,结构化网格在简单到中等复杂度的几何上仍然具有精度和效率的优势。对于翼型、机翼、发动机通道等可以用结构化网格很好地描述的构型,CFL3D仍然是有竞争力的选择。
从RANS到LES/DES:随着计算能力的提升,大涡模拟(LES)和分离涡模拟(DES)等更高保真度的方法越来越多地被应用于工程问题。CFL3D虽然主要是RANS代码,但它也提供了DES选项,在一定程度上跟上了这一趋势。
从单物理到多物理耦合:现代工程问题越来越需要多物理耦合------气动弹性、气动热、气动声学等。CFL3D的气动弹性模块是其多物理能力的体现。当然,与专门的多物理耦合框架相比,CFL3D的耦合能力还是比较基础的。
从串行到大规模并行:CFL3D的MPI并行实现虽然相对简洁,但对于大多数工程应用的规模已经足够。对于万核以上的极端规模,可能需要更先进的并行算法(如非结构化网格中的图分区、通信优化等)。
从Fortran到现代语言:CFL3D主要由Fortran 77编写,夹杂了一些Fortran 90的特性。这在今天看来确实有些"复古"。但Fortran在数值计算中的效率和可靠性仍然是毋庸置疑的------许多最新的超级计算机上,Fortran代码仍然运行得最快。重要的不是用什么语言写的,而是算法是否正确、优化是否到位。
17.5 对开源CFD生态的贡献
CFL3D以Apache 2.0许可证开源,这对CFD社区是一个重要的贡献。开源意味着:
可重复性:任何人都可以获取代码、编译运行、验证结果。这使得基于CFL3D的研究结果是可重复的------这对科学研究至关重要。
教育价值:学生和研究者可以通过阅读CFL3D的源代码来学习CFD算法的实现。相比之下,商业软件是"黑箱",用户无法知道内部的具体实现细节。
研究平台:研究者可以基于CFL3D进行二次开发,试验新的算法和模型。有了一个稳定、成熟的基础代码,研究者可以专注于自己的创新点,而不必从零开始搭建整个求解器。
行业参考:对于CFD软件的开发者来说,CFL3D是一个有价值的参考------无论是算法实现、代码结构还是工程实践,都有许多可以借鉴之处。
NASA在开源CFD方面的贡献不止CFL3D。其他知名的NASA开源CFD代码还包括 FUN3D(非结构网格)、Overflow(重叠网格)、USM3D(四面体网格)等。这些代码共同构成了一个丰富的开源CFD生态系统。
17.6 未来展望
CFL3D的未来会怎样?这是一个不容易回答的问题。可以确定的是,只要结构化网格RANS方法还有用武之地,CFL3D就会继续存在。
以下是一些可能的发展方向:
持续的维护与小改进:修复bug、改进用户体验、适配新的编译器和操作系统。这类维护性的工作是确保代码长期可用的基础。
新的湍流模型:湍流模型的研究仍在继续,新的模型和改进可能会被集成到CFL3D中。NASA Langley的TMR网站就是推动湍流模型发展的重要平台,而CFL3D是TMR使用的主要代码之一。
GPU加速:GPU计算正在改变高性能计算的格局。将CFL3D移植到GPU上,或者开发GPU加速的核心模块,可以带来显著的性能提升。当然,这需要相当大的工程投入。
更好的前处理/后处理集成:与开源的网格生成器(如Pointwise的开源替代品)和后处理工具(如ParaView)的更紧密集成,可以降低CFL3D的使用门槛。
Python化的界面:为CFL3D提供Python接口,使得用户可以用Python脚本驱动计算、分析结果,这将大大提升代码的易用性和自动化程度。
无论CFL3D本身如何发展,它所代表的工程理念------严谨、务实、追求物理理解与数值精度的平衡------将继续影响CFD领域。在计算能力飞速发展的今天,这些经过时间检验的工程智慧反而显得更加珍贵。
第十八章 CFL3D与主流CFD代码的对比分析
18.1 结构化网格代码的谱系
在CFD发展的早期,结构化网格代码占据主导地位。这不仅是因为结构化网格的数值方法更成熟、效率更高,也因为当时的计算机内存和计算能力有限,结构化网格的紧凑数据结构和高效的内存访问模式是不可或缺的。
CFL3D并非孤立存在,它属于一个庞大的结构化网格CFD代码家族。让我们梳理一下这个家族中的主要成员:
ARC系列:由NASA Ames研究中心开发的ARC2D和ARC3D,是早期结构化网格欧拉/NS求解器的代表。ARC代码采用中心差分格式加人工耗散,与CFL3D的迎风格式形成对比。
TLNS3D:由NASA Langley开发的薄层NS求解器,是CFL3D的前身之一。CFL3D的许多设计思想都可以追溯到TLNS3D。
FUN3D:NASA Langley开发的非结构化网格求解器,但最初也是从结构化版本发展而来的。FUN3D现在主要用于非结构网格的RANS/LES计算。
Overflow:NASA Ames开发的重叠网格(Chimera)求解器。Overflow在重叠网格技术方面非常领先,用于复杂构型的非定常模拟。
USM3D:基于四面体非结构网格的NS求解器,使用笛卡尔方法和浸入式边界技术。
这些代码各有特色,但都源自NASA的CFD研究传统。它们之间保持着一定的技术交流和人员流动,共同构成了NASA CFD技术生态。
18.2 结构化vs非结构化:一场未完结的辩论
CFD领域最持久的辩论之一就是结构化网格与非结构化网格之争。这场辩论已经持续了三十年,至今仍未有定论。
结构化网格的优势:
- 数值精度高:结构化网格的有序性使得高阶格式更容易实现且更精确
- 计算效率高:规则的数据结构有利于向量化和缓存优化
- 边界层分辨率高:结构化网格可以很好地贴合并分辨边界层
- 数值耗散低:结构网格的通量计算更精确,数值耗散更小
非结构化网格的优势:
- 几何灵活性强:可以处理任意复杂的几何形状
- 网格生成自动化程度高:非结构化网格生成器可以自动处理复杂几何
- 自适应方便:可以方便地进行网格自适应加密/粗化
- 前处理工作量小:对于复杂几何,非结构化网格的生成时间远短于结构化
在2000年代,非结构化网格似乎正在全面取代结构化网格。商业软件如Fluent、CFX等几乎全部转向了非结构化,开源代码如OpenFOAM也选择了非结构路线。
然而,结构化网格并没有消亡。在对精度要求最高的航空航天领域,结构化网格仍然是首选。NASA的高超声速项目、翼型验证案例、湍流模型研究等,仍然大量使用结构化网格代码。近年来,随着混合网格和多面体网格技术的发展,两者的边界也在变得模糊。
CFL3D作为结构化网格代码的代表,其存在本身就说明了结构化方法的价值。对于可以用结构化网格很好描述的问题,结构化方法仍然提供了最优的"精度/成本"比。
18.3 与商业CFD软件的对比
将CFL3D这样的学术/开源代码与Fluent、Star-CCM+、CFX等商业CFD软件进行对比是一件有趣的事情。
商业软件的优势:
- 图形用户界面(GUI):便捷的前处理、后处理和参数设置
- 全面的物理模型:从多相流到燃烧、从传热到电磁,几乎无所不包
- 技术支持:专业的技术支持团队和培训
- 用户生态:大量的用户、教程和第三方资源
CFL3D这类开源代码的优势:
- 源代码透明:可以深入理解每一个算法的实现细节
- 完全可控:可以根据需要修改和定制代码
- 无许可证成本:不需要支付昂贵的软件许可费
- 科研友好:适合算法研究和方法验证
- 稳定可靠:经过数十年的验证和改进
对于工程设计来说,商业软件的便捷性和全面性往往是决定性的因素。但对于基础研究和方法开发来说,开源代码的透明性和可控性是不可替代的。
一个健康的CFD生态应该既有成熟的商业软件满足工程需求,又有活跃的开源代码推动技术进步。CFL3D在后者中扮演着重要的角色。
18.4 与开源CFD代码的对比
开源CFD领域最著名的代码当属OpenFOAM。让我们将CFL3D与OpenFOAM做一个对比:
OpenFOAM的特点:
- 基于C++和面向对象编程
- 非结构化网格为主
- 极其丰富的物理模型和求解器
- 庞大的用户社区和活跃的开发
- 灵活的脚本化操作
- 学习曲线陡峭,代码复杂度高
CFL3D的特点:
- 基于Fortran,结构清晰
- 结构化网格为主
- 专注于航空航天外流和内流
- 数值方法经过充分验证
- 代码相对简洁,易于理解和修改
- 文档完善,有大量测试案例
两者的定位不同。OpenFOAM是一个通用的CFD工具平台,几乎可以模拟任何流体问题。CFL3D则是一个专注的空气动力学求解器,在它擅长的领域做到了极致。
如果说OpenFOAM是"瑞士军刀",那么CFL3D就是"手术刀"------功能不多,但在它的应用范围内,精度和效率都是一流的。
第十九章 学习资源与进阶路径
19.1 官方文档与教程
学习CFL3D的起点是官方文档。虽然版本6没有完整的用户手册,但版本5的用户手册大部分内容仍然适用。文档位于 docs/Cfl3dv6/V5Manual/ 目录下,按章节分为多个PDF文件,包括:
- 引言:代码概述和功能介绍
- 控制方程:数学公式和无量纲化
- 空间离散:有限体积法和通量分裂
- 时间推进:隐式算法和多重网格
- 边界条件:各种边界条件的详细说明
- 湍流模型:各湍流模型的理论和使用方法
- 多块网格:多块连接和补丁网格
- 非定常流动:时间精确方法和动网格
- 输入文件格式:完整的输入文件说明
- 测试案例:多个验证案例的设置和结果
除了PDF手册,docs/Cfl3dv6/ 目录下还有完整的HTML文档站点,包括新功能介绍、安装指南、教程、常见问题等。这些HTML文档虽然有些年代感,但内容非常详实。
19.2 测试案例的价值
CFL3D附带的大量测试案例是最有价值的学习资源之一。每个测试案例都包含:
- 输入文件(展示如何设置各种参数)
- 网格文件或生成网格的脚本
- 收敛历史结果
- 与实验数据的对比
通过研读这些测试案例,可以学习到:
- 不同类型问题的设置方法
- 各类边界条件的使用方式
- 网格生成的最佳实践
- 参数选择的经验法则
- 结果验证的方法
测试案例位于 docs/Cfl3dv6/2DTestcases/ 和 docs/Cfl3dv6/3DTestcases/ 目录下。建议初学者从简单的案例(如平板边界层、RAE 2822翼型)开始,逐步尝试更复杂的案例。
运行这些测试案例并重现其结果,是掌握CFL3D的最佳途径。没有什么比亲手运行一个计算、观察收敛过程、分析结果数据更能加深理解的了。
19.3 源代码阅读方法
对于想要深入理解CFD算法的读者,阅读CFL3D的源代码是一条必经之路。但面对二十多万行的Fortran代码,从何入手呢?
以下是一些阅读源代码的建议:
从高层开始,逐步深入 :先读 main.F 了解整体流程,再读 mgbl.F 和 setup.F 了解初始化和主循环,然后再深入到具体的算法模块。
跟随一个时间步:跟踪一个完整的时间步迭代,看数据是如何流动的------从边界条件更新,到残差计算,到隐式求解,到湍流模型更新,到输出。这样可以建立起整体的数据流概念。
聚焦感兴趣的模块 :不需要通读所有代码。如果对湍流模型感兴趣,就读 spalart.F 和 twoeqn.F;如果对多重网格感兴趣,就读 collapse.F、expand.F 和相关的多重网格驱动代码。
结合理论文档阅读:阅读代码时,手边放一本CFD教材或理论文档。当看到代码中的某个公式时,对照理论书上的推导,可以加深对算法的理解。
使用调试器:如果条件允许,使用调试器(如gdb或TotalView)单步执行代码,观察变量的变化。这是理解算法执行流程最直观的方式。
修改并测试:找到一个简单的测试案例,尝试修改代码中的某些参数或算法(比如修改限制器、修改CFL数策略),然后运行并观察结果变化。这种"动手"的学习方式远比单纯阅读有效。
19.4 推荐的学习路线图
对于从零开始学习CFL3D和CFD的读者,以下是一个推荐的学习路线:
第一阶段:基础准备
- 学习流体力学基础,理解Navier-Stokes方程的物理意义
- 学习数值分析基础,了解有限差分、有限体积等基本离散方法
- 熟悉Fortran语言(至少能读懂Fortran 77代码)
- 阅读CFL3D的README和概述文档
第二阶段:入门使用
- 编译CFL3D(串行版本即可)
- 运行第一个测试案例(如RAE 2822或平板边界层)
- 学习输入文件的基本格式和常用关键字
- 学习使用后处理工具(如Tecplot或ParaView)查看结果
- 尝试修改输入参数(如迎角、马赫数)并观察结果变化
第三阶段:深入理解
- 阅读用户手册,系统学习各功能模块
- 运行更多测试案例,覆盖不同类型的流动
- 开始阅读源代码,从主程序和核心模块入手
- 学习网格生成的基础知识,尝试生成简单的网格
- 理解收敛判据和验证方法
第四阶段:精通与应用
- 深入阅读感兴趣领域的源代码(如湍流模型、多重网格)
- 能够独立设置和完成一个完整的CFD分析项目
- 理解数值误差和模型不确定性,能够评估结果的可信度
- 尝试修改代码或添加新功能
- 参与开源社区的讨论和开发
这条路线没有捷径可走------CFD是一门需要深厚理论功底和丰富实践经验的学科。但只要持之以恒,每个人都可以逐步掌握这门强大的技术。
19.5 延伸阅读与参考资料
除了CFL3D自带的文档,以下是一些推荐的CFD参考资料:
经典教材:
- 《Computational Fluid Dynamics: Principles and Applications》by Blazek --- 全面的CFD教材,覆盖有限体积法、湍流模型、多重网格等
- 《Riemann Solvers and Numerical Methods for Fluid Dynamics》by Toro --- 关于黎曼求解器和迎风格式的权威著作
- 《Turbulent Flows》by Pope --- 湍流理论的经典教材
- 《Viscous Fluid Flow》by White --- 粘性流体力学的经典
- 《Numerical Heat Transfer and Fluid Flow》by Patankar --- 有限体积法的奠基之作
NASA在线资源:
- Turbulence Modeling Resource (TMR) --- 大量湍流模型验证案例
- CFD Verification & Validation --- CFD验证与确认的最佳实践
- NPARC Alliance --- NASA的CFD代码联盟
学术文献:
- AIAA Journal --- 航空航天领域顶级期刊
- Journal of Computational Physics --- 计算物理顶级期刊
- AIAA SciTech --- 每年的航空航天科学技术会议
学习CFD是一个终身的过程。没有人能够掌握所有的CFD知识,但保持好奇心和学习的热情,持续积累和实践,就一定能不断进步。
第二十章 从CFL3D看计算科学工程的演进
20.1 计算科学的崛起
20世纪后半叶是计算科学(Computational Science)崛起的时代。随着计算机性能的指数级增长,一种新的科学研究范式逐渐形成------除了传统的理论和实验,计算成为了第三种科学研究方法。
计算流体力学是计算科学最早、最成功的应用领域之一。早在电子计算机诞生之初,冯·诺依曼等人就开始用计算机模拟流体流动。从最初的几十个网格点的二维无粘计算,到今天的数十亿网格点的三维大涡模拟,CFD的发展历程就是计算科学发展的缩影。
CFL3D诞生于20世纪80年代末,恰逢计算科学蓬勃发展的时期。那是一个充满探索精神的年代------向量超级计算机刚刚普及,各种数值方法层出不穷,CFD正在从实验室走向工程应用。CFL3D的开发者们有幸成为这一历史进程的亲历者和推动者。
三十多年后的今天,计算科学已经渗透到科学研究和工程设计的方方面面。从药物分子设计到气候模拟,从天体物理到核工程,计算无处不在。CFD作为计算科学的先驱,其发展经验对于整个计算科学领域都有借鉴意义。
20.2 工程软件的生命周期
CFL3D三十余年的历史,为我们提供了一个观察工程软件生命周期的绝佳案例。
工程软件的生命周期通常包括以下阶段:
- 原型阶段:由少数开发者创建,验证方法的可行性
- 成长阶段:功能快速增加,用户群体扩大
- 成熟阶段:功能趋于稳定,重点转向bug修复和性能优化
- 维护阶段:开发速度放缓,主要是维护和小改进
- 衰落/转型阶段:要么被新技术取代,要么转型为基础设施
CFL3D目前处于成熟阶段后期向维护阶段过渡的时期。它的核心功能已经稳定,新功能的增加越来越少,主要的开发活动是维护和小改进。
一个自然的问题是:CFL3D会被取代吗?答案取决于"取代"的定义。如果说在工业界的应用份额,那么非结构化网格的商业软件已经占据了主导。但如果说在研究领域的价值,CFL3D这样的结构化网格代码还会在很长时间内发挥作用------特别是在湍流模型验证、方法对比等需要高精度和高可信度的研究中。
事实上,许多"古老"的工程软件都有着惊人的生命力。原因在于:
- 工程软件的核心算法往往在早期就已经成熟
- 经过长期验证的代码可靠性更高,用户不愿轻易替换
- 迁移成本巨大------数据、脚本、经验都需要重新积累
- 老代码的维护成本可能比重新开发更低
这给我们的启示是:开发工程软件时,应该注重代码的可维护性和可扩展性,因为它可能会被使用几十年。
20.3 开源与学术软件的价值
CFL3D以Apache 2.0许可证开源,这是NASA"开放政府"倡议的一部分。近年来,美国联邦政府的许多研究软件都转向了开源模式。
学术开源软件的价值是多方面的:
科学的可重复性:科学研究的核心原则之一是可重复性。如果研究基于的软件是闭源的,其他人就无法独立验证结果。开源使得其他研究者可以复现实验、验证结论、在此基础上继续研究。
教育功能:学生可以通过阅读开源代码来学习算法和工程实践。这比单纯从教科书上学到的要深刻得多。CFL3D这样的高质量代码库是宝贵的教育资源。
降低创新门槛:有了开源的基础代码,研究者不需要从零开始,可以专注于自己的创新点。这大大降低了进入门槛,加速了技术进步。
行业标准的推动:开源软件往往成为事实标准,推动了整个行业的技术水平提升。例如,CGNS标准的推广就离不开开源代码的支持。
人才培养:参与开源项目是培养高级人才的有效途径。学生在贡献代码的过程中,不仅学习了技术,还学习了协作、沟通和项目管理。
当然,学术开源软件也面临着挑战:资金来源不稳定、文档和用户体验不如商业软件、缺乏长期维护保障等。但总体而言,开源的收益远远大于成本。
CFL3D的开源是NASA对CFD社区的一份礼物。希望它能在开源社区的共同努力下,继续焕发新的生命力。
20.4 计算科学工程师的核心素养
通过研究CFL3D这样的经典代码,我们可以总结出一名优秀的计算科学工程师应该具备的核心素养:
扎实的数学物理基础:计算科学不是简单的编程------它的根基是数学和物理。没有扎实的数学物理基础,就无法理解算法的原理,也无法判断结果的正确性。CFL3D的开发者们无一不是数学物理功底深厚的专家。
敏锐的物理直觉:数值计算不是黑箱魔法------每一个结果都有其物理原因。优秀的计算工程师能够从结果中识别出物理上合理的模式和不合理的异常。这种直觉来自于对物理问题的深刻理解和大量的实践经验。
严谨的工程态度:CFD代码的每一个细节都可能影响结果。一个边界条件的bug、一个限制器的参数、一个数组越界,都可能导致完全错误的结果。严谨、细致、对质量的极致追求,是工程软件开发者不可或缺的品质。
系统思维:CFD代码是一个复杂的系统,各个部分之间存在着千丝万缕的联系。修改一个地方可能在意想不到的地方产生影响。系统思维要求开发者能够从整体上理解代码的结构和行为,预见改动的后果。
持续学习的能力:计算科学是一个快速发展的领域。新的算法、新的模型、新的硬件架构层出不穷。保持学习的热情和能力,不断更新知识结构,是在这个领域长期发展的必要条件。
这些素养不是一朝一夕就能养成的,需要长期的学习和实践。CFL3D这样的经典代码,就是我们学习的最好教材之一。
20.5 展望:CFD的下一个三十年
CFL3D的三十年,见证了CFD从新兴技术走向成熟应用的历程。那么,CFD的下一个三十年将会怎样?
以下是一些可能的发展方向:
AI与CFD的融合:机器学习和人工智能正在渗透到CFD的各个方面------从湍流模型到边界条件,从网格生成到结果分析。AI不会取代CFD,但会深刻地改变CFD的工作方式。未来的CFD代码可能会内置机器学习模块,用于加速计算、提高精度、自动优化等。
GPU与异构计算:GPU计算已经在许多科学计算领域取得了巨大成功。CFD也在向GPU迁移,未来的CFD代码可能会以GPU为主要计算平台,CPU只负责控制和I/O。
高保真度方法的普及:随着计算能力的提升,LES和DNS等更高保真度的方法将会越来越多地用于工程问题。RANS不会消失,但它的应用范围可能会逐步缩小到那些对精度要求不那么高、或者计算资源有限的场景。
数字孪生与多物理耦合:数字孪生的概念正在推动CFD与其他学科的深度融合。未来的工程仿真不再是单独的流体、结构或热分析,而是多物理、多尺度的耦合仿真。CFD将作为数字孪生的一个组成部分,与结构、电磁、控制等模块协同工作。
量子计算的可能性:量子计算还是一个遥远的话题,但它的潜力不容忽视。如果量子计算机能够实用化,那么CFD中许多目前难以解决的问题(如全尺度DNS、量子湍流等)可能会迎来突破。
没有人能够准确预测未来。但可以确定的是,CFD将继续发展,继续推动科学和工程的进步。而CFL3D这样的经典代码,将作为CFD发展史上的重要里程碑,被人们铭记和学习。
附录A CFL3D快速参考手册
A.1 边界条件类型速查表
| 编号 | 名称 | 类型 | 说明 | 适用场景 |
|---|---|---|---|---|
| 1000 | Freestream | 远场 | 自由来流条件,特征边界条件 | 外流远场边界 |
| 1001 | Symmetry Plane | 对称 | 对称面,法向速度为零 | 对称构型的对称面 |
| 1002 | Extrapolation | 外推 | 零阶外推,从内部外推到边界 | 超声速出口、远场(慎用) |
| 1003 | Inflow/Outflow | 入流/出流 | 特征分析入流/出流边界 | 内流入口、出口 |
| 1005 | Inviscid Surface | 壁面 | 无粘壁面,法向速度为零 | Euler计算的物面 |
| 1006 | Inviscid (norm mom) | 壁面 | 无粘壁面,法向动量形式 | 特殊无粘壁面处理 |
| 1007 | Axisymmetric | 轴对称 | 轴对称条件,x轴为对称轴 | 旋转体流动 |
| 1008 | Tunnel Inflow | 风洞入口 | 风洞入口条件,v,w=0 | 风洞模拟入口 |
| 1011 | Viscous Wall | 粘性壁面 | 无滑移粘性壁面 | RANS计算的物面 |
| 1012 | Viscous Adiabatic | 粘性壁面 | 绝热粘性壁面 | 绝热壁面假设 |
| 2004 | 1-1 Connect | 块连接 | 点对点匹配块间连接 | 多块网格内部界面 |
| 2005 | Patched Interface | 补丁连接 | 不匹配界面的补丁连接 | 多块网格不匹配界面 |
| 2008 | Periodic | 周期 | 周期性边界条件 | 涡轮机械、周期阵列 |
| 2010 | Overset | 重叠 | 重叠网格插值连接 | Chimera重叠网格 |
边界条件选择的一般原则:
- 外流远场:优先使用1000(freestream),远场足够远时可用1002
- 壁面:无粘用1005,粘性用1011/1012
- 内流入口:根据已知条件选择1003或1008
- 内流出口:超声速用1002,亚声速用1003指定压力
- 对称面:使用1001
A.2 湍流模型速查表
| ivisc值 | 模型名称 | 方程数 | 类型 | 适用范围 | 相对计算量 |
|---|---|---|---|---|---|
| 0 | 无粘 | 0 | - | 无粘欧拉计算 | 1.0x |
| 1 | 层流 | 0 | - | 层流流动验证 | 1.2x |
| 2 | Baldwin-Lomax | 0 | 零方程代数 | 附着边界层、快速估算 | 1.5x |
| 3 | Baldwin-Barth | 1 | 一方程 | 壁面有界流动 | 2.0x |
| 5 | Spalart-Allmaras | 1 | 一方程 | 航空航天壁面流动 | 2.0x |
| 6 | Wilcox k-ω | 2 | 两方程 | 边界层、低雷诺数流动 | 2.5x |
| 7 | Menter k-ω SST | 2 | 两方程 | 逆压梯度、分离流动 | 2.8x |
| 8 | Abid k-ε | 2 | 两方程 | 自由剪切流 | 2.5x |
| 9 | EASM k-ε | 2+代数 | 代数应力 | 各向异性流动 | 3.0x |
| 10 | EASM k-ω | 2+代数 | 代数应力 | 曲率、旋转流动 | 3.0x |
| 11 | K-enstrophy | 2 | 两方程 | 特殊研究用途 | 2.5x |
| 12 | Reynolds Stress | 7 | 雷诺应力 | 强各向异性流动 | 5.0x+ |
模型选择建议:
- 快速估算、初步设计 → Baldwin-Lomax(0方程)
- 一般航空航天应用 → Spalart-Allmaras(1方程)或 k-ω SST(2方程)
- 逆压梯度、轻度分离 → k-ω SST(首选)或 SA
- 强分离、大分离 → SST + DES 或 雷诺应力模型
- 自由剪切流(射流、尾迹)→ k-ε
- 曲率/旋转效应 → 带曲率修正的SST 或 EASM
A.3 常用关键字速查表
| 关键字 | 功能 | 典型值 | 说明 |
|---|---|---|---|
mach |
来流马赫数 | 0.1 ~ 5.0 | 自由来流马赫数 |
alpha |
迎角 | -10 ~ 20 | 度,翼型/机翼迎角 |
beta |
侧滑角 | 0 ~ 10 | 度,侧滑角 |
reyn |
雷诺数 | 1e5 ~ 1e7 | 基于参考长度 |
ivisc |
湍流模型 | 0, 5, 7 | 见湍流模型速查表 |
ifds |
通量分裂类型 | 1=Van Leer, 2=Roe | Roe精度高,FVS稳健 |
cfl |
CFL数 | 1.0 ~ 20.0 | 隐式格式可设较大值 |
cflmax |
最大CFL数 | 5.0 ~ 50.0 | CFL自适应的上限 |
nit |
最大迭代步数 | 1000 ~ 10000 | 根据收敛情况调整 |
mgflag |
多重网格开关 | 0=关, 1=开 | 强烈建议开启 |
mseq |
网格序列层数 | 2 ~ 5 | 配合多重网格使用 |
mglevel |
多重网格层数 | 2 ~ 4 | 3层是常用选择 |
ncyc |
每层多重网格循环数 | 10 ~ 100 | 细网格多,粗网格少 |
iunst |
非定常开关 | 0=定常, 1=非定常 | 非定常计算量大 |
ntstep |
非定常时间步数 | 100 ~ 10000 | 根据总时间和时间步 |
nsubit |
子迭代数 | 3 ~ 20 | 影响时间精度 |
precon |
低马赫预处理 | 0=关, 1=开 | Ma<0.2时建议开启 |
ides |
DES开关 | 0=RANS, 1=DES | 大分离流动使用 |
nbl |
网格块数 | 1 ~ 100+ | 多块网格的块数 |
i2d |
二维/三维 | -1=二维, 1=三维 | 二维计算更快 |
nres |
残差输出频率 | 10 ~ 100 | 每N步输出一次 |
nplot3d |
PLOT3D输出频率 | 100 ~ 1000 | 每N步输出一次解 |
nwrite |
重启文件输出频率 | 500 ~ 5000 | 防止意外中断丢失数据 |
irestart |
重启开关 | 0=冷启动, 1=重启 | 从已有结果继续 |
A.4 收敛判据参考
| 流动类型 | 残差下降 | 力系数变化 | 推荐迭代步数 |
|---|---|---|---|
| 无粘跨声速 | 3~4个数量级 | <0.1% | 500~1000 |
| 无粘亚声速 | 4~5个数量级 | <0.05% | 500~1500 |
| 粘性附着流 | 4~6个数量级 | <0.1% | 1000~3000 |
| 粘性轻度分离 | 3~5个数量级 | <0.5% | 2000~5000 |
| 大分离流动 | 2~4个数量级 | <1% | 5000~10000+ |
| 非定常周期流 | 每个时间步2~3个数量级 | 周期变化稳定 | 10~50个周期 |
注意:以上只是经验参考,实际收敛行为受网格质量、湍流模型、CFL数、多重网格等多种因素影响。力系数的收敛通常比残差下降更重要------如果力系数已经稳定,即使残差还在缓慢下降,也可以认为工程上已经收敛。
A.5 文件类型与扩展名
| 扩展名/文件名 | 类型 | 说明 |
|---|---|---|
*.inp |
输入文件 | CFL3D输入文件,文本格式 |
*.bin / *.p3d |
网格文件 | PLOT3D二进制格式网格 |
*.rst / restart.bin |
重启文件 | 二进制格式的流场解 |
*.res |
收敛历史 | 残差、力系数历史,文本格式 |
*.out |
标准输出 | 运行日志,文本格式 |
plot3dg.bin |
网格输出 | PLOT3D格式网格输出 |
plot3dq.bin |
解输出 | PLOT3D格式流场解输出 |
*.prout |
剖面输出 | 剖面数据输出 |
patch.bin |
补丁数据 | 补丁连接信息 |
ovrlp.bin |
重叠数据 | 重叠网格信息 |
*.turres |
湍流残差 | 湍流方程收敛历史 |
*.blomax |
块信息 | 各块最大残差位置 |
cfl3d.out15 |
详细输出 | 程序员调试输出 |
A.6 常见错误码与警告信息
| 信息 | 含义 | 处理建议 |
|---|---|---|
Negative volume detected |
负体积网格 | 检查网格质量,修复负体积单元 |
Negative density |
负密度 | 降低CFL数,检查初始条件和边界条件 |
Negative pressure |
负压力 | 同上,可能需要启用熵修正 |
Divergence detected |
计算发散 | 降低CFL,检查网格和边界条件 |
Wall y+ too large |
壁面y+太大 | 如果使用低雷诺数模型,需要加密近壁网格 |
Wall y+ too small |
壁面y+太小 | 如果使用壁面函数,需要增大第一个网格点距离 |
CFL limited by |
CFL被限制 | 正常现象,说明局部CFL达到上限 |
Turbulence not converged |
湍流没收敛 | 增加迭代步数,检查湍流模型设置 |
Grid skewness high |
网格扭曲度大 | 改善网格质量,检查长宽比 |
从1980年代末至今,CFL3D走过了三十余年的历程。它不是最先进的CFD代码,也不是最易用的CFD代码,但它可能是最可靠、最被透彻理解的CFD代码之一。
在这篇文章中,我们从Navier-Stokes方程的物理基础出发,深入了有限体积离散和迎风格式的数学细节,剖析了隐式时间推进和多重网格加速的工作原理,逐一考察了十数种湍流模型的实现特点,探讨了边界条件、多块网格、并行计算、动网格、低马赫预处理、复变量方法、CGNS集成等高级特性的技术内涵,还讨论了输入文件配置、代码工程智慧、最佳实践、学习路径等实用话题。全文二十个章节,涵盖了从理论到实践、从算法到工程的方方面面。
四十多年前,计算流体力学还是一门新兴学科,CFD代码的每一行都需要开发者从零写起。今天,CFD已经成为航空航天等领域不可或缺的设计工具,商业软件包提供了"开箱即用"的便捷体验。然而,在这种便捷的背后,许多使用者对"黑箱"内部的原理知之甚少。
理解CFD代码的内部工作原理,不仅仅是为了写出更好的代码,更是为了成为一个更明智的使用者。知道数值方法的假设和局限,知道湍流模型的适用范围,知道收敛判据的意义------这些知识决定了我们能否正确地使用CFD工具,能否批判性地评估计算结果,能否在出现问题时找到原因。
CFL3D是一扇窗口。透过这扇窗口,我们可以看到计算流体力学这门学科是如何将数学、物理和计算机科学编织在一起的。我们可以看到一代代计算流体工程师是如何在实践中摸索、在试错中前进,逐步构建起今天我们所拥有的CFD能力。
CFL3D也是一面镜子。它映照出计算科学工程的本质------它不是纯粹的数学,也不是纯粹的物理,更不是纯粹的编程。它是三者的融合,是理论与实践的结合,是人类用计算手段理解和改造世界的伟大尝试。
希望这篇文章能够帮助你更好地理解CFL3D,理解CFD,理解计算工程这门学科的魅力所在。更希望它能激发你探索的热情------去读代码,去做计算,去思考,去创造。毕竟,CFD的未来,正等待着我们这一代人去书写。
本文基于NASA CFL3D Version 6.7的源代码和文档编写。CFL3D由NASA Langley研究中心开发,以Apache 2.0许可证开源。如需获取代码或了解更多信息,请访问官方GitHub仓库:github.com/NASA/CFL3D