OpenFOAM-11模块化

模块化

OpenFOAM-11与之前的版本最大的区别在于代码大量的模块化。OpenFOAM从1.1版本开始,相应的算法均采用单独求解器的方式进行并列。比如不可压缩稳态单相流动求解器为simpleFoam,不可压缩瞬态单相流动求解器为pisoFoam。在OpenFOAM-11开始,大部分求解器不再采用相应的名称来命名。比如之前simpleFoam以及pisoFoam的算例,均采用foamRun求解器来运行。在foamRun求解器代码中,会依据相应的算法进行调整。这在代码层次的改动是相当大的。OpenFOAM-11可以认为是一次彻底的改变。官方将这次改动的原因解释为更加的贴近多物理场的特性,对于多物理场的耦合更加的成熟。当然这里面也存在商业上的原因。

对于不接触OpenFOAM代码,纯粹就是使用的OpenFOAM用户来说,OpenFOAM-11同时保留以往的用户习惯。比如老用户也可以使用simpleFoam来运行相应的算例。OpenFOAM-11版本之前的一些求解器,被归纳到了legacy文件夹中(比如dnsFoam等)。

对于使用OpenFOAM进行开发的用户来说。OpenFOAM-11的改变是适中的。OpenFOAM-11中所有求解器,仅仅区分为单计算域求解器foamRun以及多计算域求解器foamMultiRun。在OpenFOAM-11之前则存在数十个求解器。将这数十个求解器处理成两个模块化的求解器,这里面的代码工作量是非常大的。同时,在进行自己的代码开发的时候,顶层foamRun以及foamMultiRun没有什么可以改动,这两个求解器更像一个壳子把各个模块在求解器顶层连接起来而已。因此在代码开发的时候,需要直接渗入到类/库的开发,因为用户并不能够。这无异于继续增加了OpenFOAM的使用难度。

可以预见的是自OpenFOAM-11以后,OpenFOAM基金会发布的OpenFOAM版本与ESI集团OpenCFD团队发布的OpenFOAM-v版本,在相应的代码结构基础上,由于代码的整合更加困难,因此将会有更大的区别,两家将更将具有相应的特色。

foamRun

由于OpenFOAM-11仅仅存在2个求解器。那么本文就从代码层面来介绍第一个求解器foamRun,来理解一下OpenFOAM-11的模块化思想以及编程处理。在foamRun求解器中,存在3个文件,分别为foamRun.C、setDeltaT.H、setDeltaT.C,后面两个文件很明显的是用来处理时间步长的文件。因此foamRun求解器最重要的文件,或者说唯一一个文件就是foamRun.C。

foamRun的官方描述为:

用于执行OpenFOAM的求解器模块,其可以有两种方式来运行,要么是附加命令参数的形式,要么是在controlDict里面提供相应的参数直接运行。速度压力耦合的处理采用PIMPLE,可以灵活的在瞬态、稳态、拟瞬态之间进行任意的切换。

foamRun的核心流程为,建立solver一个类型,这个solver具体是一个什么类型,需要用户指定。比如用户如果通过下面的方式来运行:

foamRun -solver incompressibleFluid

则表示foamRun程序会调用incompressibleFluid这个类型的算法。如果用户在controlDict里面指定了具体的类型,那么直接运行foamRun即可:

foamRun 

因为整个求解器的代码很短(因为主要算法都处理成库),不妨把整个求解器的核心代码贴出来如下:

int main(int argc, char *argv[])
{
    while (pimple.run(runTime))
    {
        // PIMPLE corrector loop
        while (pimple.loop())
        {
            solver.moveMesh();
            solver.fvModels().correct();
            solver.prePredictor();
            solver.momentumPredictor();
            solver.thermophysicalPredictor();
            solver.pressureCorrector();
            solver.postCorrector();
        }

        solver.postSolve();
    }
    return 0;
}

其中最核心的就是那一套solver.moveMesh()、solver.fvModels().correct()等代码。下面将通过具体的一个类型incompressibleFluid来进行讲述。

实例1:incompressibleFluid

在之前的OpenFOAM版本中,不可压缩流体存在若干的算法以及求解器,比如simpleFoam是不可压缩稳态单相求解器,pimpleFoam是不可压缩瞬态求解器。在OpenFOAM-11中,不可压缩流体的算法都集中在incompressibleFluid这个类库中。并且不再区分瞬态与稳态。在incompressibleFluid这个类库里面,植入了压力速度耦合的关键步骤,在调用的时候进行取舍就可以。

比如solver.preSolve()以及solver.moveMesh()函数,是用来处理动网格功能的。如果求解器需要动网格功能,则此函数执行,若不需要动网格功能,则此函数关闭。类似的,solver.fvModels().correct()用于处理一些特殊的源项,比如附加体积力、多重参考系等功能。若需要此功能,则此函数执行,若不需要此功能,则此函数关闭。

solver.prePredictor()用于处理一些外挂的源项模型,如果没有的话,不执行。

solver.momentumPredictor(),顾名思义用于执行动量预测过程。这部分代码最终调用的为momentumPredictor.C。隶属于incompressibleFluid类库。且momentumPredictor()中植入的算法与之前的版本完全一致。相应的算法可以参考icoFoam解析

solver.thermophysicalPredictor()用于针对温度方程进行求解,incompressibleFluid类型不对此项进行操作。如果需要求解温度,则需要调用fluid等其他模块。

solver.pressureCorrector()用于处理压力修正,是主要的压力速度耦合步骤。相应代码植入在correctPressure.C中。隶属于incompressibleFluid类库。相应的算法可以参考icoFoam解析

solver.postCorrector()用于处理粘度修正,更新湍流粘度求解湍流变量等,被植入在incompressibleFluid.C文件中。其进一步调用momentumTransport湍流模型相关的模块库,因此非常具有普适性。

因此可见,参考icoFoam解析,如果将SIMPLE或者PIMPLE算法分解的话,可以分解为动量预测步骤、压力修正过程、湍流求解几个步骤。这些步骤在OpenFOAM-11中,则被植入到了相应的模块中。然而也显而易见的是,算法还是那个算法,但是代码已经不是以前的代码。

实例2:incompressibleVoF

如果求解器需要调用不可压缩单相流VOF算法,foamRun不需要做任何改动就可以求解,这也就是核心代码模块化的优势。现在以incompressibleVoF为实例,梳理一下foamRun的调用方法。

solver.moveMesh()函数的功能与之前相同。solver.prePredictor()函数需要对密度通量\(\rho\alpha\phi\)进行更新。

solver.momentumPredictor()在incompressibleVOF.H中并没有被植入,而是来自于VoFSolver.H文件中,其中定义的速度方程求解,与interFoam解析中的速度方程无差异。

solver.thermophysicalPredictor()在incompressibleVoF并没有进行植入,因为其是一个不可压缩VOF算法,因此不需要求解热相关方程。

solver.pressureCorrector()用于处理压力修正,是主要的压力速度耦合步骤。相应代码植入在twoPhaseSolver.H中。隶属于twoPhaseSolver类库。相应的算法可以参考interFoam解析,为一个标准的附加重力的压力泊松方程。

solver.postCorrector()用于处理粘湍流粘度求解湍流变量等,被植入在incompressibleVoF.C文件中。其进一步调用momentumTransport湍流模型相关的模块库,从这里可以发现,在将momentumTransport模块化之后,incompressibleFluid以及incompressibleVoF都可以很方便的调用这个库。以此类推,将incompressibleFluid与incompressibleVoF模块化之后,foamRun可以依据不同的工况,调用不同的算法。