OpenFOAM 中 function object 的实现
Contents
OpenFOAM 中的 function object 是其提供的比较灵活的数据处理功能,可以在数值计算的同时进行数据处理,OpenFOAM 将其称为运行时数据处理。
在 OpenFOAM 5.0 以后,function object 的整个框架进行了代码重构。本文以 OpenFOAM 6 对象,分析 function object 框架的实现原理。
Time 类
OpenFOAM 通过 Time 类实现 function object。
Time 是 OpenFOAM 中描述时间的基本类,通常用 while (runTime.run()) 或 while (runTime.loop()) 来实现时间步的循环。这两种方法的区别是:runTime.run() 需要手动增加时间步,而 runTime.loop() 自动增加时间步。这可以从 Time::run() 的定义中看出来:
|
|
loop() 函数先调用 run(),然后执行 operator++() ,将时间步加一。
Time 类的头文件中也给出了这两个函数的使用示例,在 runTime.run() 循环中需要手动执行 runTime++。
Time::run()
|
|
Time::loop()
|
|
function object 功能的实现
Time 类中有一个类型为 functionObjectList 的成员变量 functionObjects_,这个变量中存储了从 controlDict 中读取的所有 function objects.
每次执行 runTime.run() 时,functionObjects_ 的一些成员函数将被执行,函数执行的流程图如下:
st=>start: 开始
e=>end: 结束
funcObjsStart=>operation: functionObjects_.start():>https://github.com/OpenFOAM/OpenFOAM-6/blob/master/src/OpenFOAM/db/Time/Time.C#L820[blank]
funcObjsExec=>operation: functionObjects_.execute():>https://github.com/OpenFOAM/OpenFOAM-6/blob/master/src/OpenFOAM/db/Time/Time.C#L824[blank]
funcObjsEnd=>operation: functionObjects_.end():>https://github.com/OpenFOAM/OpenFOAM-6/blob/master/src/OpenFOAM/db/Time/Time.C#L808[blank]
runTimeLoop=>operation: 进入runTime.loop():>https://github.com/OpenFOAM/OpenFOAM-6/blob/master/src/OpenFOAM/db/Time/Time.C#L836[blank]
runTimeWrite=>inputoutput: 执行runTime.write()
(实际调用regIOobject::write())
cond1=>condition: 是否是第一个时间步?:>https://github.com/OpenFOAM/OpenFOAM-6/blob/master/src/OpenFOAM/db/Time/Time.C#L818[blank]
cond2=>condition: 是否结束计算?:>https://github.com/OpenFOAM/OpenFOAM-6/blob/master/src/OpenFOAM/db/Time/Time.C#L805[blank]
st->runTimeLoop->cond1
cond1(yes,right)->funcObjsStart->cond2
cond1(no)->funcObjsExec->cond2
cond2(yes,down)->funcObjsEnd->e
cond2(no)->runTimeWrite(right)->runTimeLoop
调用流程的具体步骤归纳如下:
- 在第一个时间步内,执行
functionObjects_.start(); - 在随后的时间步内,执行
functionObjects_.execute(); - 在最后一个时间步内,依次执行
functionObjects_.execute()和functionObjects_.end()。
这些涉及到的成员函数主要作用如下:
functionObjectList::start(): 调用read(),从 controlDict 中读取关键词functions对应的条目,并初始化自身(functionObjectList继承自PtrList<functionObject>,是一个由多个functionObject组成的列表)。functionObjectList::execute(): 遍历所有 function objects 对象,并调用每个对象的execute()和write()方法。functionObjectList::end(): 遍历所有 function objects 对象,并调用每个对象的end()方法。
functionObjectList::read()
先看 functionObjectList::read() 中构造 function objects 的相关代码:
|
|
如果字典文件中有 writeControl 或 outputControl (outputControl 是旧版本用的关键词,为了兼容性而保留的),则构造 functionObjects::timeControl 对象(注意这里的 functionObjects 是命名空间);否则,调用 functionObject 的 New 函数,利用 RTS 构造其派生类对象。
timeControl 是一个在 functionObjects 命名空间 下,派生自 functionObject 的类。该类提供了与时间相关的操作,类中还封装了另一个 functionObject 对象 foPtr_,foPtr_为实际要执行的 function object。
以时间平均 fieldAverage 这个 function object 为例说明。下面是其在 controlDict 中的配置:
fieldAverage1
{
type fieldAverage;
libs ("libfieldFunctionObjects.so");
writeControl writeTime;
...
当读取到关键词 writeControl 后,将构造一个 functionObject::timeControl 对象。在构造这个对象时,成员变量 foPtr_ 也会被初始化,利用 RTS 构造 foPtr_:
|
|
functionObject 的主要成员函数
我们再来看 functionObject 的三个成员函数 execute()、write() 和 end() 。
前两个是纯虚函数,必须在派生类中重新实现:
|
|
最后一个 end() 函数注释中写的默认调用 execute() 是错误的,end() 默认是一个什么都不做的空函数:
|
|
上面注释中提到在 post-processing 模式中 execute() 和 write() 将分别被 executeControl 和 writeControl 覆盖。由于所有的 postProcess function object 都有 writeControl 关键词(参考 etc/caseDicts/postProcessing 目录下的示例),这些 function object 对象均为 functionObjects::timeControl 类型,该类重写了 execute() 和 write(),使其通过字典文件中的 executeControl 和 writeControl 关键词来控制 function object 执行和写入的行为和频率。如只有 executeControl_.execute() 为真时才会执行实际 function object 的成员函数 foPtr_->execute():
|
|