OpenFOAM 流体模拟入门

OpenFOAM 框架结构、网格生成、边界条件与并行运行实战指南

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将表面节点贴合 STLsnapControls.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;
    }
}

常见类型对照如下:

边界类型适用变量物理含义
fixedValueU, T, k, epsilon固定值(Dirichlet)
zeroGradientU, T, p零梯度(Neumann)
noSlipU壁面无滑移
kqRWallFunctionk, q, R壁面函数
freestreamU远场自由来流
cyclicAMIU, 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); ... }
}

性能调优要点

  1. 离散格式选择:对流项优先使用 bounded Gauss linearUpwind grad(U);扩散项保持 Gauss linear corrected
  2. 求解器松弛因子p 取 0.3,U 取 0.7,湍流变量取 0.5~0.7,过大易发散。
  3. 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–3005–101.2–1.3
低雷诺数解析(Low-Re)≤ 120–401.1–1.15
LES≤ 120–501.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/OthreadedIO yes;计算与 I/O 重叠

4. 千万级网格扩展性实测

在 1024 核集群上的典型扩展效率:

核心数网格数/核理想加速比实际加速比效率
64156k1x1x100%
25639k4x3.6x90%
10249.8k16x12.8x80%
40962.4k64x38x59%

当每核网格数 < 10k 时,通信开销开始显著影响扩展性。建议保持每核 20k–100k 网格为最佳区间。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「hpc」更多文章

  1. Slurm 集群调度系统深度解析与实战
  2. Roofline 性能模型:判定性能瓶颈与优化方向
  3. ROCm HIP GPU 编程实战