第 10 章 离散算子与插值格式:grad / div / laplacian / ddt 的实现
第 9 章讲了离散框架(
fvMatrix/fvSchemes/fvSolution)。本章深入其内部,看清楚 OpenFOAM 到底怎么把梯度、散度、拉普拉斯、时间导数变成矩阵,以及linear、upwind、limitedLinear这些格式背后在做什么数学。这一章是"数值方法"与"代码"真正交汇的地方。
10.1 有限体积法的四个基本离散
一切有限体积离散都建立在散度定理之上。对控制体 V(单元)与边界面 S:
∫_V ∇·f dV = ∮_S f·n dS ⇒ 离散: ∇·f ≈ (1/V) Σ_f (f_f · Sf)
其中 Sf 是面面积矢量(第 7 章),f_f 是面心处的值。由此得到四个算子的模板:
| 算子 | 连续形式 | 有限体积离散 |
|---|---|---|
梯度 grad | ∇φ | (1/V) Σ_f Sf φ_f |
散度 div | ∇·(φU) | (1/V) Σ_f (Sf·U_f) φ_f |
拉普拉斯 laplacian | ∇·(Γ∇φ) | (1/V) Σ_f Γ_f (Sf·(∇φ)_f) |
时间导数 ddt | ∂φ/∂t | (φ - φ⁰)/Δt(Euler) |
两个关键的中间量:
- 面值 φ_f:由插值格式(interpolation scheme)从单元值得到。
- 面法向梯度 (∇φ)_f:由 snGrad 格式得到。
- 面上的
Sf·U_f:即通量phi(这是在求解器里单独算出来的一个surfaceScalarField,如phi = fvc::flux(U)或由createPhi.H创建)。
OpenFOAM 的全部离散格式,本质上就是对这些"面值/面梯度/通量"的不同近似方式。
10.2 梯度格式(gradSchemes)
10.2.1 gaussGrad:默认的 Gauss 梯度
gaussGrad.H(gradSchemes/gaussGrad/,第 33–35 行):
Description
Basic second-order gradient scheme using face-interpolation
and Gauss' theorem.
它内部持有一个插值格式(第 70–71 行 tmp<surfaceInterpolationScheme<Type>> tinterpScheme_),构造时默认用 linear(第 92–96 行):
gaussGrad(const fvMesh& mesh)
:
gradScheme<Type>(mesh),
tinterpScheme_(new linear<Type>(mesh))
{}
于是 grad(φ) = (1/V) Σ_f Sf·(interpolate(φ))_f。若 fvSchemes 里写 grad(U) cellLimited Gauss linear 1;,则会构造 cellLimitedGrad<Type, ...> 包一个 gaussGrad。
10.2.2 其他梯度格式
| 格式 | 文件 | 特点 |
|---|---|---|
Gauss | gaussGrad | 二阶,Gauss 定理 + 面插值 |
leastSquares | LeastSquaresGrad | 基于最小二乘求梯度向量(非正交网格精度好) |
fourth | fourthGrad | 四阶 |
cellLimited | cellLimitedGrad | 对梯度做单元限幅 |
faceLimited | faceLimitedGrad | 对面限幅 |
cellMDLimited | cellMDLimitedGrad | 多维限幅(分方向) |
faceMDLimited | faceMDLimitedGrad | 面多维限幅 |
iterativeGauss | iterativeGaussGrad | 迭代 Gauss |
**限幅(limiter)**是保证有界性/单调性的关键。cellLimitedGrad.H(第 31–38 行):
Description
cellLimitedGrad gradient scheme applied to a runTime selected base gradient
scheme.
The scalar limiter based on limiting the extrapolated face values
between the maximum and minimum cell and cell neighbour values and is
applied to all components of the gradient.
它内部持有一个基础梯度格式(basicGradScheme_,第 70 行)与限幅系数 k_(第 73 行),先算基础梯度,再用"外推面值是否超出邻居单元极值"的判据限幅。cellLimitedGrad 支持多种 limiter 函数(gradientLimiters/ 下有 VenkatakrishnanGradientLimiter、minmodGradientLimiter、cubicGradientLimiter)。用法:
gradSchemes
{
default Gauss linear;
grad(U) cellLimited Gauss linear 1;
}
10.3 散度/对流格式(divSchemes)
10.3.1 gaussDivScheme + 对流格式
gaussDivScheme.H(第 31–32 行):
Description
Basic second-order div using face-gradients and Gauss' theorem.
但实际使用时,div(phi, φ)(带通量的对流散度)走的是 gaussConvectionScheme(divSchemes/gaussConvectionScheme/),它把"插值格式"组合进来:div(phi, φ) = (1/V) Σ_f phi_f φ_f,其中 φ_f 由选定的对流插值格式给出。
divSchemes 里常见的写法:
divSchemes
{
default none;
div(phi,U) Gauss linearUpwind grad(U);
div(phi,k) Gauss limitedLinear 1;
div(phi,epsilon) Gauss limitedLinear 1;
div(phi,omega) Gauss limitedLinear 1;
div((nuEff*dev2(T(grad(U))))) Gauss linear;
}
div(phi,U) ... linearUpwind grad(U):对 U 用线性迎风(借助 U 的梯度),二阶、较低耗散。div(phi,k) ... limitedLinear 1:对 k 用限幅线性,TVD,防止湍流量过冲。boundedConvectionScheme(divSchemes/boundedConvectionScheme/):有界对流格式,用于保证标量(如相分数 α)在 [0,1] 内。multivariateGaussConvectionScheme:多元格式,用于多相流 vof 的多个场一起插值。
10.3.2 通量 phi:散度的输入
注意散度格式的第一个参数是通量 phi(surfaceScalarField),不是场本身。phi = Sf·U_f 的符号与大小决定了对流方向。这是有限体积法"守衡"的关键:所有方程共用同一个离散通量,才能保证质量守恒。这也解释了 fvSchemes 里的 fluxRequired——它声明哪些场需要计算并保存 phi(典型是压力 p,用于压力修正)。
10.4 拉普拉斯格式与"非正交修正"
10.4.1 基本形式
gaussLaplacianScheme.H(第 33–34 行):
Description
Basic second-order laplacian using face-gradients and Gauss' theorem.
laplacian(Γ, φ) = (1/V) Σ_f Γ_f (Sf·(∇φ)_f)。它由两部分组成(laplacianScheme.H 第 77–79 行):
const fvMesh& mesh_;
tmp<surfaceInterpolationScheme<GType>> tinterpGammaScheme_; // Γ 的插值(默认 linear)
tmp<snGradScheme<Type>> tsnGradScheme_; // 面法向梯度(默认 corrected)
默认组合就是 Gauss linear corrected——即"Γ 用 linear 插值 + 面法向梯度用 corrected"。
10.4.2 非正交网格的"正交 + 修正"分解
这是 OpenFOAM 最重要的数值技术之一。在非正交网格上,面法向向量 Sf 与"连接 owner/neighbour 体心的向量 d"不平行。于是把 Sf 分解为:
Sf = Δ (正交分量) + k (非正交分量)
- 正交分量 Δ 沿着
d方向,可直接用"两侧值之差 / 距离"隐式表达 → 贡献到矩阵的upper/lower/diag。 - 非正交分量 k 引入的"交叉扩散"不能隐式表达,只能作为显式修正项,在矩阵组装后迭代补偿。
这对应 snGradSchemes 的选择:
| snGrad 格式 | 含义 |
|---|---|
uncorrected | 只用正交分量(忽略非正交) |
corrected(默认) | 完全修正非正交 |
orthogonal | 假定网格正交 |
limited | 限幅的非正交修正 |
skewCorrected | 额外修正"偏斜"(面心不在连接线上) |
faceCorrected | 面尺度修正 |
修正项存在 fvMatrix::faceFluxCorrectionPtr_(第 9 章),并在 fvSolution 的 nNonOrthogonalCorrectors 次外层迭代里被反复应用:
laplacianSchemes
{
default Gauss linear corrected;
}
配合
SIMPLE { nNonOrthogonalCorrectors 1; } // 或 PIMPLE 里
每有一次 nNonOrthogonalCorrectors,就多做一轮"重算修正 → 再解一次"。这就是 nNonOrthogonalCorrectors 的全部含义。
10.5 时间格式(ddtSchemes)
ddt 格式决定"时间导数如何离散",直接影响时间精度与稳定性:
| 格式 | 文件 | 阶数/特点 |
|---|---|---|
steadyState | steadyStateDdtScheme | 稳态(ddt 项为零,用于 SIMPLE) |
Euler | EulerDdtScheme | 一阶隐式/显式(最常用、最稳) |
backward | backwardDdtScheme | 二阶隐式(用三个时间层) |
CrankNicolson | CrankNicolsonDdtScheme | 二阶,带混合系数(可加 bounded 防过冲) |
localEuler | localEulerDdtScheme | 局部时间步(LES 常用) |
CoEuler | CoEulerDdtScheme | 按库朗数自适应 |
SLTS | SLTSDdtScheme | 局部时间步进 |
bounded | boundedDdtScheme | 有界包装 |
EulerDdtScheme.H(第 31–33 行)说明:
Description
Basic first-order Euler implicit/explicit ddt using only the current and
previous time-step values.
即 ∂φ/∂t ≈ (φ - φ⁰)/Δt。实现上:
- 隐式:把
φ留在对角(diag += V/Δt),φ⁰移到源项; - 显式:整个项作为源项。
二阶格式(backward、CrankNicolson)会用到 φ⁰、φ⁰⁰(旧时间/旧旧时间),这正是第 8 章 GeometricField::field0Ptr_ 存在的意义。bounded 变体在计算后对场做一次限幅以保证物理有界性。
10.6 插值格式(interpolationSchemes)与限幅框架
10.6.1 基类与"权重"
surfaceInterpolationScheme.H(interpolation/surfaceInterpolation/surfaceInterpolationScheme/,第 28–94 行):
Description
Abstract base class for surface interpolation schemes.
template<class Type>
class surfaceInterpolationScheme : public refCount
{
const fvMesh& mesh_;
...
declareRunTimeSelectionTable(tmp, surfaceInterpolationScheme, Mesh,
(const fvMesh& mesh, Istream& schemeData), (mesh, schemeData));
declareRunTimeSelectionTable(...);
};
核心接口是 interpolate(ctf):把体心场插值到面。线性插值的定义是"用几何权重把 owner 与 neighbour 的值加权平均"。权重由 surfaceInterpolation(fvMesh 的成员)提供,基于面心在连接线上的位置。
10.6.2 格式家族
OpenFOAM 的插值格式非常多(interpolation/ 目录下几十个),按性质分类:
基本/高阶插值:
| 格式 | 特点 |
|---|---|
linear | 中心差分(CD),二阶 |
pointLinear | 基于点的线性 |
cubic | 三阶 |
midPoint | 中点线性 |
harmonic | 调和平均 |
reverseLinear | 反向线性 |
迎风类:
| 格式 | 特点 |
|---|---|
upwind | 一阶迎风(稳定但耗散大) |
linearUpwind | 二阶迎风(用梯度) |
downwind | 顺风(不稳定,需 blending) |
skewCorrected | 校正偏斜 |
限幅/TVD 类(最常用):
| 格式 | 特点 |
|---|---|
limitedLinear | TVD 限幅线性 |
vanLeer | TVD,平滑 |
vanAlbada | TVD |
UMIST | 高精度 TVD |
SuperBee | 高精度(压缩) |
Minmod | 最保守 |
QUICK | 三阶迎风 |
LUST | linearUpwind+SuperBee 混合 |
SFCD、OSPRE、limitedCubic、MUSCL、CLUSTER… | 其它 TVD/高分辨率 |
10.6.3 限幅的框架实现:LimitedScheme + LimiterFunc
TVD 格式不是一个个独立实现,而是共享一套**"限幅函数 + 模板生成"**框架。limitedLinear.H(第 31–38 行):
Description
Class with limiter function which returns the limiter for the
TVD limited linear differencing scheme based on r obtained from the
LimiterFunc class.
Used in conjunction with the template class LimitedScheme.
limitedLinearLimiter<LimiterFunc>(第 57–81 行)读入系数 k(0..1),构造时检查合法性并预计算 twoByk_ = 2/max(k, SMALL)。真正生成"格式"的是 LimitedScheme.H 里的模板:它把"限幅函数"与"面值计算"组合起来,形成 limitedLinear<Type> 等具体格式。这套框架让"新增一个 TVD 限幅器"只需写一个小的 limiter 类。
限幅的核心量是 r(相邻梯度比)与 NVD/TVD 判据(NVDTVD.H、NVDVTVDV.H、LimitFuncs.H)。blended 系列(blended.H、localBlended.H、limiterBlended.H)则允许在"迎风"与"中心差分"之间按权重混合。
10.7 面插值的基础设施:surfaceInterpolation
fvMesh 继承 surfaceInterpolation(第 8 章)。它提供:
- 插值权重:由面心相对 owner/neighbour 体心的几何位置决定;
- 非正交/偏斜修正向量:
nonOrthogonalCorrectionVectors、skewCorrectionVectors(skewCorrected/skewCorrectionVectors.H); interpolate():把体心场插到面。
10.8 一致性与守恒:为什么"共享通量"如此重要
有限体积法的生命力在于守恒。OpenFOAM 通过两条约定保证守恒:
- 同一个
phi被所有方程共享:质量、动量、能量方程用同一个面通量,离散后总量守恒。 - owner/neighbour 镜像对称:内部面的
upper/lower用同一组系数,保证"流出 A 的等于流入 B 的"。
这也是为什么 fvSchemes 有 fluxRequired、求解器里总有 #include "createPhi.H"——通量是"共享的离散结构",必须显式创建与复用。
10.9 从配置到代码:一次 fvm::laplacian 的旅程
把本章串起来,fvm::laplacian(nu, U) 的执行流程是:
- 从
fvSchemes的laplacianSchemes取到Gauss linear corrected; laplacianScheme::New经 RTS 构造gaussLaplacianScheme<Type, GType>;- 内部用
linear插值nu到面,得到Γ_f; - 用
correctedSnGrad计算(∇U)_f(正交部分隐式进矩阵,非正交部分进faceFluxCorrectionPtr_); - 遍历面组装
fvMatrix:diag/upper/lower(正交部分)+ 源项(非正交修正); - 若
nNonOrthogonalCorrectors > 0,在solve外层重复步骤 4–5 补偿修正项。
每一步都可配置、可替换、可组合——这正是 OpenFOAM "用户可完全掌控数值格式"的体现。
本章要点回顾
- 四个基本离散:
grad = (1/V)Σ Sf φ_f、div = (1/V)Σ phi_f φ_f、laplacian = (1/V)Σ Γ_f Sf·(∇φ)_f、ddt(Euler 一阶/backward·CrankNicolson 二阶)。 - 面值由插值格式给出,面法向梯度由 snGrad 格式给出;通量
phi是被所有方程共享的关键结构(守恒之源)。 - 梯度格式:
Gauss/leastSquares/fourth+cellLimited/faceLimited/cellMDLimited/faceMDLimited限幅。 - 散度/对流:
gaussConvectionScheme组合插值格式;bounded/multivariate变体。 - 拉普拉斯的核心是非正交修正:
Sf = Δ(正交,隐式) + k(非正交,显式),由snGrad的uncorrected/corrected/orthogonal/limited/skewCorrected/faceCorrected控制,并由nNonOrthogonalCorrectors迭代补偿。 - 时间格式:
steadyState/Euler(一阶)/backward·CrankNicolson(二阶)/localEuler/CoEuler/SLTS/bounded。 - 插值格式:
linear/upwind/linearUpwind/cubic/QUICK+ TVD 限幅族(limitedLinear/vanLeer/UMIST/SuperBee/Minmod…),由LimitedScheme+LimiterFunc框架统一生成。