openFOAM中时间步长计算参数是怎样读进程序的——初步理解框架

内容如题,在阅读完大量的基础代码之后,我们现在可以尝试解读一下chemFOAM中的程序流程。因为内容很多,所以会分好几个子标题讲完。

我们使用openFOAM的过程中,通常是从tutorials中找到对应算例的配置文件,复制到run的文件夹中,然后使用编译好程序运行,而控制则通过配置文件中的参数设置。那么,首先我们需要理解这些控制文件中的参数是怎样读入到程序中。

配置文件的内容

本文以chemFOAM中的氢气燃烧算例为例,对应的文件夹为tutorials/combustion/chemFoam/h2,内容有:

Allclean Allrun chemkin/ constant/ system/ validation/ 

其中文件夹chemkin为程序CHEMKIN中的源码和计算结果,而validation则是将当前求解器和CHEMKIN中结果进行对比的。真正的配置文件位于constant/ system/中,

constant/
chemistryProperties  initialConditions  thermophysicalProperties
燃烧的求解器和参数   燃烧初值             组分等性质的配置
system/
controlDict  fvSchemes    fvSolution
时间参数     pde方程设置  各个部分的求解器

其中,我们比较关注的时间参数位于controlDict中,内容如下:

/*--------------------------------*- C++ -*----------------------------------*\\
  =========                 |
  \\\\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\\\    /   O peration     | Website:  https://openfoam.org
    \\\\  /    A nd           | Version:  7
     \\\\/     M anipulation  |
\\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    location    "system";
    object      controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

application     chemFoam;

startFrom       startTime;

startTime       0;

stopAt          endTime;

endTime         0.001;

deltaT          1e-05;

maxDeltaT       1;

adjustTimeStep  on;

writeControl    adjustableRunTime;

writeInterval   5e-04;

purgeWrite      0;

writeFormat     ascii;

writeCompression off;

timeFormat      general;

timePrecision   6;

runTimeModifiable yes;

DebugSwitches
{
    SolverPerformance   0;
}

// ************************************************************************* //

内容分别为文件抬头,FoamFile的文件版本(这个不能删除,程序中会检查版本),以及真正的控制参数设置。每个参数的设置形式为key parameter,即关键字加内容的组合。而具体的含义基本上看关键字就可以看明白,比如说startFrom就是指从哪个时间点开始计算,如果是0就是从头开始,如果非零就是续算的。

chemFOAM中初始化时间参数的位置

首先我们需要解释一下,文件的配置文件的范例位于turtorial\\中,而编译好的求解器的顶层源码在application文件夹中,比如当前这个求解器的路径位于applications/solvers/combustion/chemFoam,其内容包括:

dyfluid@dyfluid:~/OpenFOAM/OpenFOAM-7/applications/solvers/combustion/chemFoam ls
chemFoam.C              hEqn.H                   setDeltaT.H
createBaseFields.H      Make/                     solveChemistry.H
createControls.H        output.H                 thermoTypeFunctions.H
createFieldRefs.H       pEqn.H                   YEqn.H
createFields.H          readControls.H
createSingleCellMesh.H  readInitialConditions.H

其中Make给定了当前这个求解器依赖的基础源码,这个在之前的帖子中有介绍:
https://blog.csdn.net/qq_40583925/article/details/106639854
其他代码中,chemFoam.C为最顶层,其他代码也为执行代码,只不过通过.H的形式添加到代码中,增加可读性,chemFoam.C的源码这里大概对框架进行说明:

注释文件头
一系列基础类的.H文件添加
//********************************************//
int main(int argc, char *argv[])
{
       argList::noParallel();
       类对象的创建
       以及计算参数的读取(Time的参数就是在这个位置被读取的)
       //******************************************//
       Info<< "\\nStarting time loop\\n" << endl;
       while (runTime.run())
       {   可以在计算过程中在这个位置控制时间步长参数
           runTime++;
           Info<< "Time = " << runTime.timeName() << nl << endl;
  
           燃烧的求解,Y,h,p这一系列热学参数的更新

           #include "output.H" 
          Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
            << "  ClockTime = " << runTime.elapsedClockTime() << " s"
            << nl << endl;
    }
    Info << "Number of steps = " << runTime.timeIndex() << endl;
    Info << "End" << nl << endl;
    return 0;
}

具体是类对象创建的哪个文件看名字就可以猜到,是createTime.H,其内容如下:

Foam::Info<< "Create time\\n" << Foam::endl;

Foam::Time runTime(Foam::Time::controlDictName, args);

嗯…就两行,第一行输出到终端告诉用户选择要创建时间,然后使用了类Foam::Time的构造函数Time(Foam::Time::controlDictName, args);,而创建的类对象的是runTime

两个输入值的内容这里大概描述一下,第一个其实可以猜到,是要读取的数据所在的Dictionary的名称。而第二个则是用户在终端键入的配置参数,是int main(int argc, char *argv[])的两个输入参数写进一个类之后得到的args,其中argc代表终端键入的选项个数,例如chemFOAM就是args=1,后者是键入的选项的字符串存储。

这两个输入参数的详细内容,会在后面解释,这里先了解到通过这个输入,程序可以找到正确的配置文件中正确的{ }中的内容读取。

chemFOAM计算过程中更新时间参数

没错,在计算过程中,如果修改了时间的配置参数,比如修改了更大的步长,程序也可以实时更新对应的时间步长,具体的实现在while循环中的第一个文件readControls.H,内容如下:

runTime.controlDict().lookup("adjustTimeStep") >> adjustTimeStep;
maxDeltaT = readScalar(runTime.controlDict().lookup("maxDeltaT"));

嗯…又只有两行,runTime就是前面创建的Foam::Time类的对象,对象中内置了函数controlDict(),他返回了Foam::Time类中内置的另外一个类对象unwatcedIOdictionary controlDict_,这个类对象又具有lookup()这个函数(套娃现场)。

lookup的具体实现后面再介绍,这里可以很容易的猜到,就是检索配置文件中的adjustTimeStep关键字,然后读取其中的内容,然后将文件流导入adjustTimeStep变量中。注意这里的>>其实是经过运算符重定义的,OpenFOAM的代码中几乎对所有的类的IO输入都进行了与运算符重定义。

第二个则使用了readScalar这个函数,它位于src/OpenFOAM/primitives/Scalar/Scalar.C中,输入为一个文件流,函数创建了一个Scalar rs对象,然后将文件流>>rs,然后返回rs,就是说这个函数的返回值是一个Scalar对象,然后通过=赋值给maxDeltaT,这里的=也是经过运算符重定义的。

总之就是,读取的核心句式为runTime.controlDict().lookup("keyWord"),通过输入关键字,让程序读取对应关键字的内容,返回一个文件流供操作。

src中的源码才是核心

我们可以看到如果只读turtorial\\application\\这两个文件夹,虽然不难猜出代码的具体含义,但是细节的实现并不了解。这就需要我们阅读src\\这个文件夹中的内容,不过我们也并不需要读取其中全部的内容。只要通过Make\\中的配置文件,找到依赖的源码阅读即可。嘛,但是这也有上千个源码。

这篇到这里为止~尽量一篇不要超过5000字,之前阅读Essential C++一次写太多自己都看不过来。更详细的实现会在后续更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片