本文摘要:(由ai生成)
2022年8月,CFD Direct在OpenFOAM中引入模块求解器,以类的形式编写,提高了代码的灵活性和可维护性。OpenFOAM通过面向对象方法减少求解器数量,简化用户选择。模块求解器通过foamRun或foamMultiRun部署,提供通用求解算法,简化多流体和固体区域耦合解决方案,允许通过配置文件选择物理模型,使CFD解决方案更清晰。
2022年8月,CFD Direct在OpenFOAM的开发版本(OpenFOAM-dev
)引入了modular solvers
(模块求解器)。与OpenFOAM自1993年编写第一个求解器icoFoam
以来一直采用的传统应用程序求解器不同,模块求解器是以类
的形式编写的,它们相较于传统应用程序求解器更易于使用和维护,其源代码结构更为清晰,从而促进了对代码更好的理解。模块求解器的灵活性更高,特别是可以跨多个区域耦合不同流体和固体的模块,这对于任何形式的流动(如多相流)与共轭热传递(CHT)尤为显著。模块求解器可通过foamRun
或foamMultiRun
应用程序部署,前者用于单区域的通用求解算法,后者则用于多区域。此外,还引入了额外的模块和应用程序,以替代现有的数据处理和案例配置工具。
OpenFOAM 最初是作为计算流体动力学的一个通用开发平台而构想的。其创建者Henry Weller利用了 C++ 中的面向对象编程和泛型编程来管理 CFD 中遇到的复杂科学/工程、数学和计算问题。这些编程范式通过减少代码重复来提高维护效率。数据和函数被封装在类中,而函数提供了操作数据的便捷接口。
OpenFOAM 中的大部分代码都是面向对象和泛型的,即包含在 C++ 类和模板中。这些代码分布在众多库中(在 OpenFOAM-v10 版本中约为 120 个),涵盖了大型核心 OpenFOAM
和 finiteVolume
库到小型物理模型库。相比之下,应用求解器则包含了一系列指令,这些指令在迭代求解算法中求解控制方程,并调用各种物理模型(如湍流)。这部分程序代码是过程化的,而非面向对象的。
随着时间的推移,针对不同流动类别(如不可压缩流、可压缩流、多相流等)定制了大量独立的应用求解器。每种类别中都有基准求解器,通常分别针对稳态和瞬态流动。此外,基准求解器还有一些变体,这些变体结合了以下特性:1) 额外的建模功能,如多孔介质、动网格、用于浮力的Boussinesq近似、单旋转和多旋转参考系(SRF和MRF)等;2) 数值方法上的变化,如局部时间步进、方程的不同实现方式、压力-速度耦合中的“一致性”选项等。
从2004年发布OpenFOAM v1.0版本到2011年发布OpenFOAM v2.1版本期间,OpenFOAM应用求解器的数量从41个增加到了82个。虽然这使OpenFOAM在CFD领域得到广泛的应用,但求解器数量的激增也带来了一些问题。用户经常在众多求解器间难以抉择,而且随着模拟中引入新特性,他们不得不在不同的求解器之间切换。当没有现成的求解器能够包含他们所需的特定功能组合时,他们还面临着编写自定义求解器的艰巨任务。代码重复现象普遍存在,一旦某个应用的代码发生变化,而其又未在其他应用的重复代码中同步更新时,此时会导致不一致。
为解决此问题,CFD Direct将可选的建模和数值方法从求解器代码中进行了抽离,从而减少求解器的数量,与此同时也减少了未解决的错误数量,用户可以从案例配置文件中选择其所需的选项组合。在此过程中,OpenFOAM的一些大型组件也进行了重大改进,如热物理传输、通用模型和约束以及网格运动、拓扑变化等。
OpenFOAM v10在2022年发布时,求解器数量减少到48个,其接近于2004年的水平。然而与v1.0版本相比,V10版本的求解器包含了大量v1.0中不存在的模型和数值方法。这些新的求解器更加复杂,更难以维护,并且依然存在大量的代码重复。因此,自然而然地转向了面向对象这一经过验证的方法来管理复杂性并减少代码重复。
基本思路是创建一个名为foamRun
的应用程序来描述一个通用的求解算法,其功能可以在一系列模块求解器中定义。这一理念的发展受到了需求驱动,即需要一种通用方法来耦合多个区域中的解,这些区域可能包含不同类型的流体和/或固体。对于单个网格区域的foamRun
应用可以扩展为针对多个网格区域执行相同功能的foamMultiRun
应用。这两个应用程序都包含相同的算法结构,其关键功能如下所示(摘自foamRun.C
)。
while (pimple.run(runTime))
{
solver.preSolve();
adjustDeltaT(runTime, solver);
runTime++;
while (pimple.loop())
{
solver.moveMesh();
solver.fvModels().correct();
solver.prePredictor();
solver.momentumPredictor();
solver.thermophysicalPredictor();
solver.pressureCorrector();
solver.postCorrector();
}
solver.postSolve();
runTime.write();
}
这段代码主要负责以下操作:
preSolve()
: 更改网格拓扑并实现网格间的映射。fvModels().correct()
: 更新 fvModels。moveMesh()
: 实现网格运动。prePredictor()
: 更新流体属性。momentumPredictor()
: 求解动量方程。thermophysicalPredictor()
: 求解能量方程并更新热物理属性。pressureCorrector()
: 求解压力方程。postCorrector()
: 求解动量传输,如湍流模拟和热物理传输问题。postSolve()
: 清理工作,如清除临时数据。上述代码中描述的solver
构成了一系列模块求解器的基类,如下所示。求解器类从基类派生,例如solid
、fluidSolver
等。当从左到右遍历层次结构时,通用算法中的函数(在solver
类中作为虚函数存在)被定义为不同类型流动的描述,例如不可压缩流动、等温流动、多组分流和多相流等。有时根据特定求解器的需求,某些函数可能是空的,例如incompressibleFluid
求解器中的thermophysicalPredictor()
函数,因为其不涉及温度计算。许多功能是从基类继承给派生类的;在某些情况下,创建基类是为了定义一类通用的流体类别,例如VoFSolver
,其功能被基于体积分数方法(VoF)的四个派生求解器所继承。
截止本文撰写之时【更新:2023年5月2日】,OpenFOAM共包含有13个流体求解器、2个薄膜求解器、2个固体求解器和2个其他类型求解器。这些模块求解器旨在替代原有的单独的应用程序求解器。具体替换情况如下:
incompressibleFluid
:取代pimpleFoam
、pisoFoam
和simpleFoam
。isothermalFluid
:使用waveSurfacePressure
边界条件,取代potentialFreeSurfaceFoam
。multicomponentFluid
:取代reactingFoam
和buoyantReactingFoam
。fluid
:取代rhoSimpleFoam
、rhoPimpleFoam
、buoyantFoam
和coldEngineFoam
。multiphaseEuler
:取代multiphaseEulerFoam
。compressibleVoF
:能量守恒的求解器,取代compressibleInterFoam
和cavitatingFoam
。incompressibleVoF
:取代interFoam
。incompressibleMultiphaseVoF
:取代multiphaseInterFoam
。compressibleMultiphaseVoF
:取代compressibleMultiphaseInterFoam
。shockFluid
:取代rhoCentralFoam
。XiFluid
:取代XiFoam
。incompressibleDriftFlux
:取代driftFluxFoam
。incompressibleDenseParticleFluid
:取代denseParticleFoam
。isothermalFilm
:取代 surfaceFilmModels
库。film
:取代 surfaceFilmModels
库。solid
:在 chtMultiRegionFoam
中复 制固体区域。solidDisplacement
:取代 solidDisplacementFoam
和 solidEquilibriumDisplacementFoam
。movingMesh
:取代 moveMesh
。functions
:在时间循环中执行 Function Object;使用 scalarTransport
函数对象复 制 scalarTransportFoam
;而使用 clouds 的 fvModel
,使用 incompressibleFluid
和 isothermalFluid
作为辅助求解器,分别复 制了 particleFoam
和 rhoParticleFoam
。foamMultiRun
模拟CHT,使用一个或多个fluid
求解器和solid
求解器,使chtMultiRegionFoam
变得多余;compressibleInterPhaseThermophysicalTransportModel
使用compressibleVoF
模块求解器实现了CHT。可以通过在case的controlDict
文件中使用solver
关键字来指定模块求解器,例如:
solver incompressibleFluid;
或者可以在执行 foamRun
时使用 -solver
选项来指定求解器,即:
foamRun -solver incompressibleFluid
除了模块求解器外,还创建了两个新的应用程序以取代与应用程序求解器相关的功能。
foamPostProcess
工具:复 制了 postProcess
工具和求解器 -postProcess
选项,用于模块求解器。foamToC
工具:工具替代了用于列出模型及其选项的-list...
选项。通过模块求解器,面向对象的优势现在已经扩展到了OpenFOAM的求解器组件。与应用求解器以过程化方式呈现方程、算法和模型接口不同,模块求解器是围绕在foamRun
/foamMultiRun
应用程序中包含的通用算法构建的。方程和接口在类层次结构的不同级别被引入。特定流动类型的求解器包含的代码几乎只与该特定类型有关。例如,fluid
求解器的特点是在thermophysicalPredictor()
函数中求解能量方程,其功能大部分继承自isothermalFluid
求解器。
使用面向对象的方法后,可以更清楚地看到CFD求解涉及时间、空间(网格)以及定义流体/固体状态的物理场/属性。foamRun
/foamMultiRun
应用程序负责初始化时间和空间,并通过时间循环推进时间演化。moveMesh()
函数负责空间演化。每个模块求解器代表一种流体/固体类型,并负责在foamRun
/foamMultiRun
中预定义的函数中初始化和演化该流体/固体状态。求解器开发的重点放在了针对特定流动类型的状态属性演化上,如多相流中的相分数。
模块求解器对于跨多个流体和/或固体区域的耦合求解提供了明显的优势
。与为每种流体和固体类型的组合编写特定的应用求解器不同,foamMultiRun
允许在任意数量的网格区域上使用任何模块求解器。这已经被迅速用于计算具有多种多相流的共轭传热。用户不再需要面对数量众多的求解器进行选择,且在切换稳态和瞬态求解时不再需要更改求解器。物理模型可以通过案例配置文件进行选择,包括通过起始时间目录中的p_rgh
压力场自动激活的浮力。
最后,在第一个求解器应用程序icoFoam编写 30 年后,OpenFOAM 中的求解器抓住了其软件设计的精髓。正如Andy Warhol曾经说过:“人们总是说时间会改变一切,但实际上你必须自己去改变它们。”
(完)