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()
:
|
|