OpenFOAM 是业界最广泛使用的开源计算流体力学(CFD)框架,基于 C++ 编写,采用有限体积法(Finite Volume Method)求解 Navier-Stokes 方程。本文从工程实践角度拆解其框架、网格、求解器配置与并行策略。
框架三层结构
+------------------+ +------------------+ +------------------+
| 求解器层 | | 库 层 | | utilities 层 |
| (solver) | | (Library) | | (postProcess) |
|------------------| |------------------| |------------------|
| simpleFoam | | finiteVolume | | patchAverage |
| pimpleFoam | | turbulenceModels | | yPlusRAS |
| interFoam | | transportModels | | sample |
+------------------+ +------------------+ +------------------+
| | |
+----------------------+----------------------+
v
+---------------------+
| OpenFOAM Core |
| Foam::fvMesh |
| Foam::fvMatrix |
+---------------------+
三层各司其职:求解器层定义时间推进与离散格式,库层提供湍流模型、物性模型等可插拔组件,utilities 层负责前后处理与诊断。
网格生成
blockMesh
适合规则结构的六面体网格,通过 blockMeshDict 描述坐标块与边界。
// blockMeshDict (简化)
vertices
(
(0 0 0) // 0-left bottom back
(2 0 0) // 1-right bottom back
(2 1 0) // 2-right top back
(0 1 0) // 3-left top back
...
);
blocks
(
hex (0 1 2 3 4 5 6 7) (100 50 1) simpleGrading (1 1 1)
);
boundary
(
inlet { type patch; faces (...); }
outlet { type patch; faces (...); }
wall { type wall; faces (...); }
);
snappyHexMesh
适合复杂几何的自动四面体-六面体混合网格。输入 STL 表面文件后,snappyHexMesh 依次执行 castellation、snapping 与 layer addition 三步:
| 步骤 | 功能 | 关键参数 |
|---|---|---|
| castellatedMesh | 体素化切割背景网格 | locationInMesh, refinementSurfaces |
| snap | 将表面节点贴合 STL | snapControls.tolerance |
| addLayers | 边界层拉伸 | finalLayerThickness, expansionRatio |
foamJob snappyHexMesh 2>&1 | tee log.snappy
边界条件配置
OpenFOAM 采用文件化边界条件系统,位于 case/0/ 目录下。以速度场 U 为例:
// 0/U (稳态单位 m/s)
dimensions [0 1 -1 0 0 0 0];
internalField uniform (10 0 0);
boundaryField
{
inlet
{
type fixedValue;
value uniform (10 0 0);
}
outlet
{
type zeroGradient;
}
wall
{
type noSlip;
}
symmetry
{
type symmetry;
}
}
常见类型对照如下:
| 边界类型 | 适用变量 | 物理含义 |
|---|---|---|
fixedValue | U, T, k, epsilon | 固定值(Dirichlet) |
zeroGradient | U, T, p | 零梯度(Neumann) |
noSlip | U | 壁面无滑移 |
kqRWallFunction | k, q, R | 壁面函数 |
freestream | U | 远场自由来流 |
cyclicAMI | U, p | 滑移网格周期性边界 |
并行运行:decomposePar + reconstructPar
OpenFOAM 的并行基于 MPI 分区执行,流程如下:
# 1. 配置分区方案(scotch / simple / hierarchical)
# system/decomposeParDict
decompositionMethod scotch;
numberOfSubdomains 64;
# 2. 执行分区
decomposePar -force
# 3. 并行运行(推荐用 mpirun 或 foamJob)
mpirun -np 64 simpleFoam -parallel > log.solve 2>&1
# 4. 结果重构回单域
reconstructPar
分区策略选择建议:
| 策略 | 适用场景 | 内存/速度 |
|---|---|---|
simple | 规则块结构网格 | 快速但负载略差 |
scotch | 非结构复杂网格 | 负载均衡最佳 |
hierarchical | 各向异性长网格 | 沿某轴优先切割 |
对于千万级网格,建议搭配 --oversubscribe 或 Slurm srun --mpi=pmix 调度,避免单节点内存溢出。
后处理:ParaView + OpenFOAM 原生工具
# 生成 ParaView 可读的 .foam 文件
touch case.foam # 空文件即可
paraFoam # 或直接 paraview case.foam
# 批量切片采样
postProcess -func sampleDict
# 计算壁面 Y+ 值
yPlusRAS -latestTime
典型后处理 pipeline:先以 sample 提取监测线数据 CSV,再用 Python/Matplotlib 绘制速度型线,与实验值对比验证收敛性。
典型算例:绕翼型稳态层流
以一个 simpleFoam 稳态算例为例,完整 case 树如下:
airfoil_case/
|-- 0/ # 初始场:U, p, k, epsilon, nut
|-- constant/
| |-- polyMesh/ # blockMesh/snappyHexMesh 生成的网格
| |-- transportProperties # 流体物性 nu
| `-- turbulenceProperties # 湍流模型开关
|-- system/
| |-- controlDict # 时间步、输出间隔
| |-- fvSchemes # 离散格式
| |-- fvSolution # 线性求解器参数
| |-- decomposeParDict
| `-- blockMeshDict
`-- run.sh # 自动化脚本
system/controlDict 核心参数示例:
application simpleFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 2000;
deltaT 1;
writeControl timeStep;
writeInterval 100;
functions // 内嵌后处理函数
{
forces { type forces; patches (airfoil); ... }
}
性能调优要点
- 离散格式选择:对流项优先使用
bounded Gauss linearUpwind grad(U);扩散项保持Gauss linear corrected。 - 求解器松弛因子:
p取 0.3,U取 0.7,湍流变量取 0.5~0.7,过大易发散。 - GAMG vs PBiCGStab:压力方程用
GAMG大幅加速(Dict 中设置smoother GaussSeidel),速度方程用smoothSolver。
从网格到求解器、从串行到千核并行,OpenFOAM 的模块化设计使其成为高性能 CFD 工程落地的首选开源方案。
湍流模型选择与边界层处理
RANS(Reynolds-Averaged Navier-Stokes)是工程中最常用的湍流建模方法,OpenFOAM 提供多种 RANS 模型:
| 模型 | 特点 | 适用场景 | 计算成本 |
|---|---|---|---|
kEpsilon | 经典双方程,鲁棒性强 | 充分发展的湍流、管道流动 | 低 |
realizableKE | 修正涡粘假设,改善旋转/回流 | 旋流、燃烧室 | 低 |
kOmegaSST | 近壁面精度高,分离流预测好 | 翼型、外流、边界层分离 | 中 |
SpalartAllmaras | 单方程,结构简单 | 航空器外流、旋转机械 | 低 |
LES / DES | 解析大尺度涡,精度最高 | 非定常分离、噪声预测 | 极高 |
边界层网格是 CFD 计算精度的关键。yPlus 值决定第一层网格高度:
# 计算壁面 Y+ 值(后处理)
yPlusRAS -latestTime
# 查看壁面附近流速分布
sample -latestTime
| 模拟类型 | 目标 y+ | 网格层数 | 增长率 |
|---|---|---|---|
| 壁面函数(Wall Function) | 30–300 | 5–10 | 1.2–1.3 |
| 低雷诺数解析(Low-Re) | ≤ 1 | 20–40 | 1.1–1.15 |
| LES | ≤ 1 | 20–50 | 1.05–1.1 |
工业标准做法:先用壁面函数快速迭代,确认几何与边界条件无误后,再切换到低雷诺数网格进行高精度计算。
自定义求解器开发
OpenFOAM 的面向对象设计使得自定义求解器相对直观。以下是一个极简的标量输运求解器骨架:
// myScalarTransportFoam.C
#include "fvCFD.H"
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
#include "createFields.H"
Info << "\nStarting time loop\n" << endl;
while (runTime.loop())
{
Info << "Time = " << runTime.timeName() << nl << endl;
solve
(
fvm::ddt(T) + fvm::div(phi, T) - fvm::laplacian(DT, T)
==
fvOptions(T)
);
runTime.write();
Info << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
}
Info << "End\n" << endl;
return 0;
}
编译自定义求解器:
# 创建工作目录结构
mkdir -p $FOAM_RUN/mySolver
foamNewSource application myScalarTransportFoam
# 编辑 Make/files 和 Make/options
# Make/files:
# myScalarTransportFoam.C
# EXE = $(FOAM_USER_APPBIN)/myScalarTransportFoam
# Make/options:
# EXE_INC = -I$(LIB_SRC)/finiteVolume/lnInclude
# EXE_LIBS = -lfiniteVolume
wmake # 编译
Python 自动化与后处理
PyFoam 是 OpenFOAM 的 Python 接口,可实现参数化研究与批量运行:
from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile
import itertools
# 参数化研究:不同雷诺数下的翼型升阻力
case = SolutionDirectory("airfoil_case")
reynolds_numbers = [1e5, 5e5, 1e6, 2e6]
angles = [0, 5, 10, 15]
for re, alpha in itertools.product(reynolds_numbers, angles):
# 克隆 case
new_case = case.cloneCase(f"re_{re:.0e}_a{alpha}")
# 修改控制参数
control = ParsedParameterFile(new_case.controlDict())
control["endTime"] = 5000
control.writeFile()
# 修改物性(运动粘度随雷诺数变化)
transport = ParsedParameterFile(new_case.transportProperties())
transport["nu"] = [0, 2, -1, 0, 0, 0, 0, 1.0 / re]
transport.writeFile()
# 提交运行
import subprocess
subprocess.run(["blockMesh"], cwd=new_case.name)
subprocess.run(["simpleFoam"], cwd=new_case.name)
Python + ParaView 后处理:
from paraview.simple import *
# 批量生成云图
reader = OpenFOAMReader(FileName='case.foam')
rep = Show(reader)
ColorBy(rep, ('POINTS', 'U', 'Magnitude'))
Render()
# 保存截图
SaveScreenshot('velocity_field.png', ImageResolution=[1920, 1080])
MPI 并行性能调优
大规模并行计算时,除 decomposePar 外,还需关注以下调优维度:
1. 进程绑定(Process Affinity)
# OpenMPI 绑定策略
mpirun --bind-to core --map-by core -np 64 simpleFoam -parallel
# 跨节点通信优化(InfiniBand)
mpirun --mca btl openib,self -np 128 simpleFoam -parallel
2. 负载均衡检查
# 查看各子域网格数与计算耗时
decomposePar -cellDist
# 后处理:检查并行效率
checkMesh -parallel
3. 通信开销优化
| 策略 | 命令/配置 | 效果 |
|---|---|---|
| 减少写入频率 | writeInterval 500; | 降低 I/O 瓶颈 |
| 使用二进制格式 | writeFormat binary; | 减少存储与解析开销 |
| 开启文件聚合 | fileHandler collated; | 减少小文件数量 |
| 异步 I/O | threadedIO yes; | 计算与 I/O 重叠 |
4. 千万级网格扩展性实测
在 1024 核集群上的典型扩展效率:
| 核心数 | 网格数/核 | 理想加速比 | 实际加速比 | 效率 |
|---|---|---|---|---|
| 64 | 156k | 1x | 1x | 100% |
| 256 | 39k | 4x | 3.6x | 90% |
| 1024 | 9.8k | 16x | 12.8x | 80% |
| 4096 | 2.4k | 64x | 38x | 59% |
当每核网格数 < 10k 时,通信开销开始显著影响扩展性。建议保持每核 20k–100k 网格为最佳区间。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。