ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenFOAM二次开发教程(09):湍流模型架构——从 RASModel 到 eddyViscosity 与 kOmegaSST

OpenFOAM二次开发教程(09):湍流模型架构——从 RASModel 到 eddyViscosity 与 kOmegaSST OpenFOAM二次开发教程09湍流模型架构——从 RASModel 到 eddyViscosity 与 kOmegaSST版本与事实声明kOmegaSST属Foam::RASModels命名空间在部分版本中其类型模板参数标注为BasicMomentumTransportModel官方课程讲义指出kOmegaSST的实现继承自名为kOmegaSSTBase的类。kOmegaSSTLM的官方说明为Langtry-Menter 4-equation transitional SST model based on the k-omega-SST RAS model多方程转捩 SST 模型基于 k-omega-SST。eddyViscosity的构造签名含alphaField、rhoField、U、alphaRhoPhi、phi、viscosity等参数见官方 Doxygen 类页。类名与模板参数在不同大版本间有演进例如输运模型基类名称的变迁本文给出的继承链为当前主流形态落笔前请以本机$FOAM_SRC/TurbulenceModels/源码与对应版本 Doxygen 为准。一句话结论OpenFOAM 的湍流模型是一条清晰的继承链——BasicMomentumTransportModel→RASModel→eddyViscosity→kOmegaSST真正实现拆到kOmegaSSTBase供多方程变体复用要扩展湍流模型你只需派生新类并按契约实现correct()编译成库后在libs里加载。〇、本篇要解决的认知问题Q1OpenFOAM 的湍流模型为什么分这么多层每一层到底负责什么Q2eddyViscosity是什么为什么几乎所有两方程模型都从它派生Q3kOmegaSST为什么要拆出kOmegaSSTBase这种实现与变体分离的写法对扩展有什么启示Q4correct()的契约是什么不实现会怎样Q5扩展一个湍流模型的正确起点在哪里是从基类写起还是从最像的模型抄一、机制解析1.1 分层继承链每一层解决什么问题┌──────────────────────────────────────────────────────────┐ │ BasicMomentumTransportModel │ │ 最抽象层定义“湍流模型”的公共接口如 nut、kappa 的取用│ └──────────────────────────────────────────────────────────┘ ▲ 继承 ┌──────────────────────────────────────────────────────────┐ │ RASModelBasicMomentumTransportModel │ │ RAS 家族层RANS 特有契约如 k、epsilon、omega 的创建、 │ │ correct() 的调用约定、模型字典的读取 │ └──────────────────────────────────────────────────────────┘ ▲ 继承 ┌──────────────────────────────────────────────────────────┐ │ eddyViscosityRASModelBasicMomentumTransportModel │ │ 涡黏层提供 Boussinesq 假设下的涡黏度 nu_t 机制 │ │ 把雷诺应力表达为“涡黏 × 平均应变率” │ └──────────────────────────────────────────────────────────┘ ▲ 继承 ┌──────────────────────────────────────────────────────────┐ │ kOmegaSSTBase真正实现 k-omega-SST 的方程与系数 │ └──────────────────────────────────────────────────────────┘ ▲ 继承 ┌──────────────────────────────────────────────────────────┐ │ kOmegaSST薄封装把 Base 与 RASModel 组合暴露标准用法│ └──────────────────────────────────────────────────────────┘每一层的职责这是一个抽象逐级下降的经典设计层负责不负责BasicMomentumTransportModel定义公共接口涡黏度nut、热扩散率等如何被外部取用具体方程、具体系数RASModelRANS 家族契约模型字典读取、correct()的调用约定、必要场的登记涡黏假设的具体形式eddyViscosity涡黏假设机制提供nut_与相关接口用什么方程算nut_kOmegaSSTBasek-omega-SST 的具体控制方程、系数与更新逻辑如何与 RASModel 组装kOmegaSST组装并暴露标准用法新增物理为什么这对你重要想扩展模型时先确定你在哪一层动手。想换涡黏假设改eddyViscosity的派生层。想换nut_的求解方程写一个新的xxxBase并组合。想加非 Boussinesq 的雷诺应力模型要跳出eddyViscosity这条线——层次搞错改一百行代码也是白费。1.2 eddyViscosity为什么它是绝大多数模型的落脚点涡黏假设Boussinesq 假设把雷诺应力表示为雷诺应力 ≈ -ν_t · (平均应变率) (2/3)·k·I其中ν_t代码里常写作nut就是涡黏度。eddyViscosity把如何把nut组织进动量方程与相关接口这件事一次性实现子类只需回答一个问题“我的nut怎么算出来”这就是为什么两方程模型k-ε、k-ω、SST全都挂在eddyViscosity下面它们共用同一套涡黏机制只是算nut的方程不同。实践经验读任何两方程模型的源码先找它如何更新nut_——这是理解该模型在做什么的最短路径。1.3 kOmegaSST 与 kOmegaSSTBase实现与变体分离官方课程讲义明确指出一个反直觉的事实在kOmegaSST目录下找不到 k-omega-SST 方程的实现——因为实现被放进了它继承的kOmegaSSTBase类里。为什么要这么设计k-omega-SST 有多个变体例如带转捩的四方程模型kOmegaSSTLM官方说明为基于 k-omega-SST 的 Langtry-Menter 四方程转捩 SST 模型。把核心方程实现放在Base、把组装方式放在各变体里就能避免每个变体复制一遍方程。kOmegaSSTBase ←─ 核心方程与系数一处实现 ▲ ├── kOmegaSST 标准 SSTBase 标准 RASModel 组装 └── kOmegaSSTLM 转捩变体Base 转捩输运方程对你的直接启示写自定义模型时抄最像的那个并判断该抄 Base 还是抄封装层。如果你的模型是某模型的带额外方程变体正确做法是继承它的 Base而不是复制整个封装层。1.4 correct() 契约湍流模型的心跳correct()是湍流模型的时间推进接口求解器每个时间步或每次外迭代调用一次模型在其中更新湍流量、进而更新nut。契约要点必须实现通常是覆盖基类的虚函数。不实现会导致编译失败纯虚或运行期行为缺失漏更新。调用时机由求解器决定官方求解器一般在动量方程之前调用turbulence-correct()让nut是最新的。内部要更新所有它负责的场例如 k-ω-SST 需更新k、omega、nut。应通过Info/日志暴露收敛线索如各方程的残差否则出问题时无从下手。反直觉点correct()并不自动被时间循环调用。它的调用是你的求解器代码的责任turbulence-correct();。很多人自建求解器后忘了加这一行结果湍流量永远停在初值——研究里湍流模型不生效的头号原因。1.5 源码路径与阅读入口内容典型路径以本机$FOAM_SRC为准湍流模型族根目录$FOAM_SRC/TurbulenceModels/不同版本层级略有差异RAS 模型实现.../turbulenceModels/RAS/下按模型名分目录如kOmegaSST涡黏基类.../turbulenceModels/eddyViscosity.H附近以实际为准运行时类型注册各模型源文件中的注册宏决定字典type的可选名阅读顺序建议三步先读模型.H看继承与成员再读kOmegaSSTBase的.C看方程装配最后用foamToC列可用模型类型名核对字典写法。二、完整代码与逐行剖析代码 2-1用 foamToC 与源码定位把继承链挖出来POSIX Shell#!/bin/sh# inspect_turbulence.sh —— 湍流模型架构自省脚本# 用法sh inspect_turbulence.sh [模型名默认 kOmegaSST]set-eumodel${1:-kOmegaSST}echo 1. 列出本环境可用的动量输运湍流模型类型名 # 以工具输出为权威不靠记忆写类型名铁律 1foamToC-tablemomentumTransport2/dev/null\||echo (该版本表名或 -table 用法可能不同请查官方文档确认)echoecho 2. 定位模型源码目录 dir$(find$FOAM_SRC/TurbulenceModels-typed-name$model2/dev/null|head-n1)if[-z$dir];thenecho [WARN] 未在$FOAM_SRC/TurbulenceModels 找到名为$model的目录elseecho 目录:$direcho 文件:;ls-1$dir|seds/^/ /fiechoecho 3. 抽取“继承关系”与“被继承关系”关键行 if[-n${dir:-}];then# .H 文件里通常能看到 class X : public Y 形式以及 TypeName 注册宏grep-nH-Eclass[[:space:]]$model|public[[:space:]]|TypeName\(|Base\$dir/*.H2/dev/null|seds/^/ /|head-n40fiechoecho 4. 找 Base 类实现与变体分离的关键base$(find$FOAM_SRC/TurbulenceModels-name${model}Base.H2/dev/null|head-n1)[-n$base]echo 找到 Base:$base\||echo (该模型可能没有独立的 Base 类以实际源码为准)逐行剖析第 1 步用foamToC -table momentumTransport列可用模型名把能写哪些type从记忆问题变成工具问题。若版本不支持该表名脚本明确提示以官方文档为准不硬编码。第 2 步用find -type d -name $model定位模型目录因为不同版本目录层级会变用搜索而非硬编码路径。第 3 步只抽取继承声明、TypeName宏、Base字样等关键行读源码要会定向 grep而不是从头读到尾。第 4 步专门找${model}Base.H这直接对应 §一.3 的实现与变体分离设计是扩展时判断该抄哪一层的依据。代码 2-2一个薄封装型自定义 RAS 模型的骨架C示意/*---------------------------------------------------------------------------*\ myKOmegaSST.H —— 自定义 RAS 湍流模型骨架示范“抄最像的并复用 Base” 设计要点如果只想改组装方式或加一个系数开关 应继承 kOmegaSSTBase复用它已实现的核心方程而不是重写方程。 具体基类名/模板参数/构造签名请以本机源码为模板不要凭记忆补全。 \*---------------------------------------------------------------------------*/#ifndefmyKOmegaSST_H#definemyKOmegaSST_H#includekOmegaSSTBase.H// 复用核心方程实现本机路径以源码为准#includeRASModel.H// RAS 家族契约本机路径以源码为准namespaceFoam{namespaceRASModels{templateclassBasicMomentumTransportModelclassmyKOmegaSST:publickOmegaSSTBaseBasicMomentumTransportModel// 只做“组装 小改”{public:typedeftypenameBasicMomentumTransportModel::alphaField alphaField;typedeftypenameBasicMomentumTransportModel::rhoField rhoField;TypeName(myKOmegaSST);// 字典 type 与之严格一致// ---- 构造函数签名需与所继承 Base 的契约一致以本机源码为模板----myKOmegaSST(constalphaFieldalpha,constrhoFieldrho,constvolVectorFieldU,constsurfaceScalarFieldalphaRhoPhi,constsurfaceScalarFieldphi,constviscosityviscosity,constwordtypetypeName);// ---- correct()RAS 模型的“心跳”必须实现/覆盖 ----// 内部需更新本模型负责的湍流量k、omega、nut 等// 并通过日志暴露残差以便排查具体实现以 Base 提供的接口为准。virtualvoidcorrect();virtual~myKOmegaSST()default;};}// End namespace RASModels}// End namespace Foam#endif逐行剖析继承kOmegaSSTBase...而非从零继承RASModel这是复用实现、只改变体的正确姿势。它把k-omega-SST 方程的复杂度留在了官方代码里。TypeName(myKOmegaSST)字符串必须与字典type逐字符一致工厂机制契约第 08 篇。构造函数参数列表alpha、rho、U、alphaRhoPhi、phi、viscosity来自eddyViscosity的构造签名官方 Doxygen 明确记载了这组参数——不要自己改签名否则无法与求解器的调用对接。correct()声明为virtual并覆盖契约实现点。若你的模型需要额外更新一个自定义量应在此处完成并调用基类逻辑以 Base 契约要求的方式。明确注释以本机源码为模板模板参数名如BasicMomentumTransportModel在不同版本有演进这类细节最容易编造出错必须现场核对。代码 2-3编译与验证脚本#!/bin/sh# build_my_turbulence.sh —— 编译自定义湍流库并做“模型是否真的被用到”的验证# 用法sh build_my_turbulence.sh 库源码目录 含 momentumTransport 配置的算例set-eulibdir${1:?用法:sh build_my_turbulence.sh 库源码目录 算例}case${2:?缺少算例路径}echo 1. 编译成库产物落用户库目录铁律 4cd$libdirwmake libsols-l$FOAM_USER_LIBBIN|grep-imyKOmegaSST||echo[WARN] 未在用户库目录看到 myKOmegaSST 相关库echo 2. 确认字典已加载该库铁律 5grep-nlibs$case/system/controlDict|seds/^/ /||trueecho 3. 运行并抽取“湍流模型被选中”的证据 cd$casemySolver-case.log.turb21||{echo[FAIL] 运行失败见 log.turb;exit1;}grep-iESelecting.*(momentum|turbulence|RAS).*model|myKOmegaSSTlog.turb|seds/^/ /\||echo [WARN] 未在日志中找到模型选择记录请确认 momentumTransport 字典的 type 已改echo 4. 残差线索 grep-iESolving.*(k|omega)log.turb|tail-n5|seds/^/ /逐行剖析wmake libso编译库不是可执行文件产物应落$FOAM_USER_LIBBIN铁律 4。第 2 步检查controlDict的libs这是运行期类型找不到的第一排查点铁律 5。第 3 步从日志里抓模型选择记录OpenFOAM 在构造湍流模型时会打印类似 “Selecting … model” 的日志这是你的模型真被选中了的客观证据比没报错强得多。第 4 步抓 k/omega 的求解行确认湍流量的方程确实在解若没有这些行很可能是求解器没调correct()或字典没生效。三、常见报错与排查报错 3-1-- FOAM FATAL ERROR: Unknown momentumTransport type myKOmegaSST。现象字典里写了自定义湍流模型运行时报未知类型。根因库未加载controlDict的libs缺项最常见其次是类型名拼写不一致或注册宏写错铁律 5。解法在libs中加载你的库核对TypeName与字典type是否完全一致确认wmake libso产物在$FOAM_USER_LIBBIN。报错 3-2湍流模型不生效——湍流量全程等于初值。现象没有报错但k、omega、nut场从头到尾不变。根因求解器没有调用turbulence-correct()§一.4 的反直觉点或调用顺序不当导致nut用不上新值。解法在动量方程求解前调用一次correct()确认调用的对象是求解器里实际使用的湍流模型实例而非临时对象。报错 3-3编译报cannot convert ... to ...模板参数不匹配。现象自定义模型编译失败。根因基类模板参数名或层次在两个版本间演进例如输运模型基类重命名、eddyViscosity的模板形参变化照抄了别的版本的写法。解法以本机$FOAM_SRC中的同族官方模型为模板逐行对比铁律 1用代码 2-1 的脚本确认本机继承链写法。报错 3-4-- FOAM FATAL IO ERROR: ... momentumTransport中缺必需子项。现象模型构造时报字典缺项。根因模型的字典块缺少必需系数不同模型的必需项不同。解法复制官方同模型的字典块作模板再改用foamToC核对类型名与可选项不要凭记忆补键名。报错 3-5结果能算但明显不对如湍流强度过强/过弱。现象数值稳定但物理异常。根因系数或限幅设置与预期不符例如照抄了别的模型字典块、把系数放错位置或模型方程的项漏实现/写错。解法以官方同族模型为基准做同设置对拍——用同一个算例分别跑官方模型与自定义模型若自定义模型做了无实质改动的复制两者结果应在容差内一致。这是最有效的改对了没有判据铁律 7。四、动手练习练习 1画出继承链运行代码 2-1把kOmegaSST的继承链与源码路径写到纸上。判定能准确列出BasicMomentumTransportModel → RASModel → eddyViscosity → kOmegaSSTBase → kOmegaSST五个层次并给出每一层负责什么、不负责什么的一句话说明。练习 2找 correct在官方含湍流的求解器源码里找到调用correct()的位置与顺序。判定能指出它在动量方程之前还是之后被调用能写出这一行代码能解释为什么漏掉它会表现为湍流量不变。练习 3Base 的价值找出kOmegaSST与kOmegaSSTLM的共同基类说明它们如何共享方程实现。判定能指出共同 Base 类名能列出两个变体各自的附加内容转捩变体多了哪些方程/场。练习 4对拍验证把你复制的自定义模型未做实质改动与官方模型在同一算例上分别运行。判定两者的典型监测量如某个监测点速度或壁面剪应力相对差异在合理容差内工程上常取 1%~5%具体按问题自定若差异明显说明复制过程中漏了某些实现。练习 5思考题无标准答案如果你要扩展一个带额外源项的两方程模型应该从哪一层派生验证要点(a) 是否认识到复用涡黏与方程实现应继承既有 Base/eddyViscosity 层(b) 是否明确只需新增/覆盖correct()与必要场© 是否考虑类型注册 字典 type libs 加载三件套第 08 篇的工厂机制。五、小结与下一篇预告本篇画清了 OpenFOAM 湍流模型的架构地图分层继承链公共接口 → RAS 契约 → 涡黏机制 → 核心方程 Base → 变体封装eddyViscosity的定位几乎所有两方程模型的落脚点子类只回答nut怎么算Base 的价值kOmegaSST的方程实现在kOmegaSSTBase里便于kOmegaSSTLM等变体复用correct()契约与调用责任不调用 模型不生效。第 10 篇《湍流模型扩展实战》将把这张地图变成可编译、可验证的代码从一个官方 RAS 模型复制出myKOmegaSST改类名与注册、配置Make/files与Make/options、wmake libso编译、在libs中加载并用同设置对拍验证行为一致——那是你第一次扩展 OpenFOAM 的物理模型。本篇认知问题回显FAQQ1OpenFOAM 湍流模型为什么分这么多层A分层是抽象逐级下降的经典设计各层职责清晰。BasicMomentumTransportModel 是最抽象层定义公共接口如涡黏度 nut、热扩散率如何被外部取用RASModel 层负责 RANS 家族契约模型字典读取、correct() 调用约定、必要场登记eddyViscosity 层提供 Boussinesq 涡黏假设机制把雷诺应力表达为涡黏乘平均应变率kOmegaSSTBase 实现 k-omega-SST 的具体控制方程与系数kOmegaSST 是薄封装负责把 Base 与 RASModel 组装并暴露标准用法。扩展时必须先确定在哪一层动手否则层次搞错代码再多也无用。Q2eddyViscosity 是什么为什么两方程模型多从它派生AeddyViscosity 是涡黏基类实现 Boussinesq 假设下把涡黏度 nut 组织进动量方程与相关接口的机制雷诺应力 ≈ -nut×平均应变率 (2/3)kI。它把如何组织 nut一次性实现子类只需回答我的 nut 怎么算出来。k-ε、k-ω、SST 等两方程模型共用同一涡黏机制、仅算 nut 的方程不同因此都从 eddyViscosity 派生。实践技巧是读任何两方程模型源码时先找它如何更新 nut_这是理解模型在做什么的最短路径。Q3为什么 kOmegaSST 要拆出 kOmegaSSTBaseA因为 k-omega-SST 存在多个变体官方课程讲义指出在 kOmegaSST 目录下找不到方程实现实现被放在它继承的 kOmegaSSTBase 里。把核心方程与系数集中放在 Base把组装方式放在各变体可避免每个变体重复实现方程。例如官方说明 kOmegaSSTLM 是基于 k-omega-SST 的 Langtry-Menter 四方程转捩 SST 模型它复用同一 Base 并叠加转捩输运方程。启示是写自定义模型时若属某模型的带额外方程变体应继承其 Base 而非复制整个封装层。Q4correct() 的契约是什么不实现会怎样Acorrect() 是湍流模型的时间推进接口求解器每个时间步或外迭代调用一次模型在其中更新湍流量并进而更新 nut。契约要点必须实现或覆盖否则编译失败或运行期行为缺失调用时机由求解器决定官方求解器一般在动量方程前调用使 nut 最新内部必须更新所有它负责的场如 k、omega、nut应通过日志暴露残差线索。反直觉点是 correct() 不会自动被时间循环调用调用是求解器代码的责任turbulence-correct();漏掉这一行会导致湍流量永远停在初值这是湍流模型不生效的头号原因。Q5扩展湍流模型的正确起点在哪里A正确起点是抄最像的那个模型并判断该抄 Base 还是抄封装层。若你的模型是某模型的带额外方程变体应继承其 Base 以复用核心方程实现只新增或覆盖必要内容而非从最抽象基类从零写。动手前应先用脚本定位本机源码中的继承链与构造签名函数参数如 alpha、rho、U、alphaRhoPhi、phi、viscosity 与 eddyViscosity 构造签名一致不要自改再完成类型注册、字典 type 设置与 libs 加载三件套最后用无实质改动的复制版与原模型同设置对拍验证行为一致。
返回列表