文章目录
-
- OpenFOAM `fvOptions` 框架详解:CFD 中的原生插件系统
- 一、核心架构设计
-
- 1. 三层架构
- 2. 关键类关系
- 3. 三种插件类型
- 二、内置插件使用示例
-
- 案例1:风机盘模型(`actuationDiskSource`)
- 案例2:局部热源(`scalarSemiImplicitSource`)
- 案例3:运行时编译自定义源项(`codedSource`)
- 三、开发自定义 fvOption 插件(完整流程)
-
- 步骤1:创建插件目录结构
- 步骤2:实现插件类(`myCustomSource.H`)
- 步骤3:实现核心逻辑(`myCustomSource.C`)
- 步骤4:编译规则(`Make/files`)
- 步骤5:编译与使用
- 四、高级特性:运行时动态控制
-
- 1. 运行时重载配置(v2312+)
- 2. 插件间数据交换
- 3. 优先级控制
- 五、与通用 Fortran 插件系统的对比
- 六、典型工业应用场景
- 七、最佳实践建议
OpenFOAM fvOptions 框架详解:CFD 中的原生插件系统
fvOptions 是 OpenFOAM 内置的、生产级的插件架构,自 v2.2 (2013) 引入 [[3]],专为在不修改求解器源码的前提下向控制方程动态注入物理模型而设计。它本质上是一个运行时可选择(run-time selectable)的有限体积选项框架,完美契合插件化需求。
一、核心架构设计
1. 三层架构
┌─────────────────────────────────────────────────────┐
│ 求解器 (e.g., pisoFoam, buoyantSimpleFoam) │
│ fvOptions(optionList) → operator()(eqn) │
└───────────────┬─────────────────────────────────────┘
│ 调用接口
┌───────────────▼─────────────────────────────────────┐
│ fv::optionList (插件管理器) │
│ • 按优先级排序插件 │
│ • 管理区域选择 (cellZone/cellSet) │
│ • 调度插件执行 (pre/post/apply) │
└───────────────┬─────────────────────────────────────┘
│ 派发到具体插件
┌───────────────▼─────────────────────────────────────┐
│ 具体 fvOption 插件 (继承 fv::option) │
│ • Sources: 源项 (actuationDiskSource) │
│ • Constraints: 约束 (fixedTemperatureConstraint) │
│ • Corrections: 修正 (porosityModel) │
└─────────────────────────────────────────────────────┘
2. 关键类关系
class fv::option // 抽象基类:定义插件接口
{
virtual void addSup(fvMatrix<scalar>& eqn, ...) = 0; // 显式源项
virtual void addSup(fvMatrix<vector>& eqn, ...) = 0;
virtual void constrain(fvMatrix<scalar>& eqn) = 0; // 约束(如固定值)
virtual bool read(const dictionary& dict); // 运行时重载配置
};
class fv::optionList : public PtrList<fv::option> // 插件容器
{
// 重载 () 运算符:求解器通过 fvOptions() 调用
template<class Type>
tmp<fvMatrix<Type>> operator()(fvMatrix<Type>& eqn) const;
};
3. 三种插件类型
| Sources | 向方程添加源项 | 风机盘、热源、化学反应 | addSup() – 求解前 |
| Constraints | 强制约束解 | 固定温度、速度边界 | constrain() – 求解后修正 |
| Corrections | 修正通量/梯度 | 多孔介质阻力 | correct() – 通量修正阶段 |
💡 关键特性:插件通过 selectionMode 精确控制作用区域(cellZone/cellSet/points/all),实现空间局部化 [[1]]。
二、内置插件使用示例
案例1:风机盘模型(actuationDiskSource)
场景:模拟风力机对流场的推力作用,无需几何建模
constant/fvOptions 配置:
actuationDisk1
{
type actuationDiskSource; // 插件类型(运行时选择)
active true; // 启用开关
selectionMode cellSet; // 作用区域:cellSet
cellSet actuationDiskZone; // 区域名称
fields (U); // 作用于速度场 U
actuationDiskSourceCoeffs
{
diskDir (–1 0 0); // 盘面法向(来流反向)
Cp 0.8; // 功率系数
Ct 0.6; // 推力系数
diskArea 12.566; // 盘面积 π*2²
upstreamPoint (–5 0 0); // 盘上游参考点
upstreamCellSet upstreamCells; // 上游监测区域(用于速度采样)
}
}
求解器集成(以 pisoFoam 为例):
// pisoFoam.C 片段
fvVectorMatrix UEqn
(
fvm::ddt(U)
+ fvm::div(phi, U)
– fvm::laplacian(nu, U)
);
UEqn.relax();
// === 关键:自动注入所有注册的 fvOption ===
fvOptions.constrain(UEqn); // 约束类插件(如固定速度)
UEqn.solve();
// 动量方程求解后,源项类插件自动生效
fvOptions.correct(U); // 修正类插件(如多孔介质)
效果:在 actuationDiskZone 区域内,速度方程自动添加推力源项
−
1
2
ρ
C
T
A
U
2
-\\frac{1}{2}\\rho C_T A U^2
−21ρCTAU2,无需修改 pisoFoam 源码 [[30]]。
案例2:局部热源(scalarSemiImplicitSource)
场景:电子设备散热模拟,芯片区域添加 100W 热源
constant/fvOptions 配置:
heatSource1
{
type scalarSemiImplicitSource;
active true;
selectionMode cellZone; // 作用区域:cellZone
cellZone chipZone; // 芯片区域
fields (h); // 作用于焓场 h
scalarSemiImplicitSourceCoeffs
{
volumeMode absolute; // 模式:absolute=总功率, specific=单位体积
injectionRateSuSp
{
h (100 0); // (源强, 系数) → 100W 恒定热源
}
}
}
物理意义:
- volumeMode absolute:总功率 100W 均匀分布到 chipZone 所有网格 [[40]]
- injectionRateSuSp (h (100 0)):源项形式
S
=
S
u
+
S
p
⋅
h
S = S_u + S_p \\cdot h
S=Su+Sp⋅h,此处S
u
=
100
S_u=100
Su=100,S
p
=
0
S_p=0
Sp=0(显式源项) - 若设为 (100 -10) 则为半隐式:
S
=
100
−
10
⋅
h
S = 100 – 10 \\cdot h
S=100−10⋅h,提升稳定性
案例3:运行时编译自定义源项(codedSource)
场景:快速原型开发,无需编译独立库
constant/fvOptions 配置:
customSource1
{
type codedSource;
active true;
selectionMode all; // 作用于全场
fields (U); // 作用于速度场
// === 内嵌 C++ 代码(运行时自动编译)===
codeInclude
#{
#include "fvMatrix.H"
#};
codeCorrect
#{
Pout<< "Custom source applied at time " << mesh.time().value() << endl;
#};
codeAddSup
#{
const scalar magU = mag(U).internalField();
const vectorField& C = mesh.C().internalField();
// 添加与速度平方成正比的阻力:F = -0.1 * |U| * U
forAll(C, i)
{
if (magU[i] > 0.1) // 仅当速度>0.1m/s时生效
{
eqn.source()[i] -= 0.1 * magU[i] * U[i] * mesh.V()[i];
}
}
#};
codeSetValue // 约束类插件使用
#{
// 固定特定区域速度
#};
}
工作流程:
⚠️ 注意:codedSource 适合快速验证,生产环境建议开发独立插件(见下文)。
三、开发自定义 fvOption 插件(完整流程)
步骤1:创建插件目录结构
$FOAM_USER_SRC/fvOptions/myCustomSource/
├── myCustomSource.H # 头文件
├── myCustomSource.C # 实现文件
├── createFields.H # (可选)创建插件私有场
└── Make/
├── files # 编译规则
└── options # 依赖库
步骤2:实现插件类(myCustomSource.H)
#ifndef myCustomSource_H
#define myCustomSource_H
#include "fvOption.H" // 基类
namespace Foam
{
namespace fv
{
class myCustomSource
:
public option // 继承 fv::option
{
// 私有数据成员
scalar strength_; // 源项强度
vector direction_; // 方向向量
scalarField alpha_; // 空间权重场(预计算)
// 私有方法
void calculateAlpha(); // 计算空间分布
public:
// 运行时类型信息(关键:实现插件注册)
TypeName("myCustomSource");
// 构造函数
myCustomSource
(
const word& name,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
);
// 重载基类虚函数
virtual void addSup
(
fvMatrix<vector>& eqn,
const label fieldi
);
virtual bool read(const dictionary& dict); // 支持运行时重载
};
} // End namespace fv
} // End namespace Foam
#endif
步骤3:实现核心逻辑(myCustomSource.C)
#include "myCustomSource.H"
#include "fvMatrices.H"
#include "DimensionedField.H"
// 注册到运行时选择表(关键:使插件可被 fvOptions 识别)
makeFvOption(myCustomSource);
namespace Foam
{
namespace fv
{
myCustomSource::myCustomSource
(
const word& name,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
)
:
option(name, modelType, dict, mesh),
strength_(dict.get<scalar>("strength")),
direction_(dict.get<vector>("direction"))
{
// 从 dict 读取区域选择(自动处理 cellZone/cellSet)
read(dict);
// 预计算空间权重(如高斯分布)
calculateAlpha();
}
void myCustomSource::calculateAlpha()
{
// 根据 selectionMode 获取作用单元
const labelList& cells = cells_;
alpha_.setSize(mesh_.nCells(), 0.0);
forAll(cells, i)
{
label celli = cells[i];
const vector& C = mesh_.C()[celli];
// 高斯分布:中心在 (0.5,0.5,0),标准差 0.1
scalar dx = C.x() – 0.5;
scalar dy = C.y() – 0.5;
alpha_[celli] = exp(–(dx*dx + dy*dy) / (2.0*0.1*0.1));
}
}
// 重载:向矢量方程添加源项
void myCustomSource::addSup
(
fvMatrix<vector>& eqn,
const label fieldi
)
{
// 仅作用于指定场(如 U)
if (fieldNames_[fieldi] != "U") return;
const labelList& cells = cells_;
forAll(cells, i)
{
label celli = cells[i];
// 源项 = 强度 * 方向 * 空间权重 * 体积
eqn.source()[celli] += strength_ * direction_ * alpha_[celli] * mesh_.V()[celli];
}
}
// 支持运行时重载配置(OpenFOAM v2312+ 增强)
bool myCustomSource::read(const dictionary& dict)
{
if (option::read(dict))
{
strength_ = dict.get<scalar>("strength");
direction_ = dict.get<vector>("direction");
calculateAlpha(); // 重算空间分布
return true;
}
return false;
}
} // End namespace fv
} // End namespace Foam
步骤4:编译规则(Make/files)
myCustomSource.C
LIB = $(FOAM_USER_LIBBIN)/libmyFvOptions
Make/options:
EXE_INC = \\
-I$(LIB_SRC)/finiteVolume/lnInclude \\
-I$(LIB_SRC)/fvOptions/lnInclude
LIB_LIBS = \\
-lfiniteVolume \\
-lfvOptions
步骤5:编译与使用
# 编译插件
cd $FOAM_USER_SRC/fvOptions/myCustomSource
wmake libso
# 在 case 中启用
echo "libs (\\"libmyFvOptions.so\\");" >> system/controlDict
# 配置 fvOptions
cat > constant/fvOptions << EOF
mySource1
{
type myCustomSource; // 运行时通过 TypeName 匹配
active true;
selectionMode all;
strength 10.0; // 自定义参数
direction (1 0 0);
}
EOF
# 运行求解器(自动加载插件)
pisoFoam
四、高级特性:运行时动态控制
1. 运行时重载配置(v2312+)
OpenFOAM v2312 支持 运行时更新区域选择 [[5]]:
// 在求解器循环中
if (runTime.timeIndex() % 100 == 0)
{
// 动态修改源项强度
dictionary newDict = fvOptions.dict().subDict("mySource1");
newDict.set("strength", 20.0);
fvOptions.read(newDict); // 触发插件 read() 重载
}
2. 插件间数据交换
通过 mesh.thisDb().lookupObject<volScalarField>("T") 访问其他插件生成的场,实现插件协作链:
温度源项插件 → 生成 T_field → 湍流源项插件读取 T_field → 计算浮力源项
3. 优先级控制
在 fvOptions 字典中通过 priority 字段控制执行顺序:
sourceA { priority 10; ... } // 先执行
sourceB { priority 20; ... } // 后执行
五、与通用 Fortran 插件系统的对比
| 集成度 | 深度集成求解器框架,自动调度 | 需手动在求解循环中插入触发点 |
| 区域管理 | 内置 selectionMode(cellZone/cellSet) | 需自行实现网格遍历逻辑 |
| 类型安全 | 通过模板 fvMatrix<Type> 保证 | 依赖 c_funptr + 手动类型转换 |
| 配置驱动 | 原生支持 dictionary 运行时重载 | 需额外解析 JSON/YAML |
| 调试支持 | Pout/Info 自动关联时间步 | 需自行实现日志路由 |
| 跨平台 | 仅限 OpenFOAM 生态 | 通用(Linux/Windows) |
| 学习曲线 | 需掌握 OpenFOAM 对象模型 | 仅需 ISO_C_BINDING 基础 |
💡 建议:在 OpenFOAM 项目中优先使用 fvOptions,避免重复造轮子;通用 Fortran 插件系统适用于非 OpenFOAM 的 HPC 代码(如自研求解器)。
六、典型工业应用场景
风电场仿真:
- actuationDiskSource 模拟多台风机(避免几何建模)
- radialActuationDiskSource 支持径向变化的推力分布 [[24]]
电子散热:
- scalarSemiImplicitSource 添加芯片热源
- fixedTemperatureConstraint 固定散热器温度
燃烧模拟:
- 自定义 chemistrySource 插件实现简化化学反应
- 与 reactingFoam 求解器无缝集成
多孔介质:
- porosityModel 修正动量方程(Darcy-Forchheimer 阻力)
- thermalPorosity 添加热传导修正
主动流动控制:
- syntheticJetSource 模拟合成射流(周期性源项)
- 通过 codedSource 快速验证控制律
七、最佳实践建议
S
p
<
0
S_p<0
Sp<0 可增强对角占优
🔍 深入学习:参考 $FOAM_SRC/fvOptions 源码,重点阅读:
- sources/general/semiImplicitSource/:通用源项模板
- sources/derived/actuationDiskSource/:复杂物理模型实现
- constraints/fixedTemperature/:约束类插件范例
通过 fvOptions,OpenFOAM 实现了高度模块化、可扩展的物理模型注入机制,是 CFD 领域插件化架构的典范设计,完全满足用户对"在程序特定位置执行计算"的精细化控制需求。
