有了上一篇博文的基础,就可以来填一个坑了,即分析 OpenFOAM 中湍流模型框架中的 RTS 。上一篇博文,使用的程序比较简单,这里通过一个实际使用 RTS 机制的例子来加深对 RTS 的理解。
经过前面对那段简单代码的分析,可以知道, declareRunTimeSelectionTable
宏函数的主要功能是声明了一个 hashTable
,并定义了一个指向这个hashTable
的指针, 然后还声明了几个辅助的类。 defineRunTimeSelectionTable
这个宏函数的主要作用是对 declareRunTimeSelectionTable
中的 hashTable
指针进行了初始化。 addToRunTimeSelectionTable
的主要作用是将当前类的类名以及返回当前类的对象的一个函数分别作为 hashTable
的 key 和 value 插入到 hashTable
中。下面来看这些宏函数在湍流模型框架中是怎么使用的。
1. turbulenceModel 类
类体中,调用 declareRunTimeNewSelectionTable
宏函数1
2
3
4
5
6
7
8
9
10
11
12
13 declareRunTimeNewSelectionTable
(
autoPtr,
turbulenceModel,
turbulenceModel,
(
const volVectorField& U,
const surfaceScalarField& phi,
transportModel& transport,
const word& turbulenceModelName
),
(U, phi, transport, turbulenceModelName)
);
注意这里用的是 declareRunTimeNewSelectionTable
!与 declareRunTimeSelectionTable
区别在于,declareRunTimeNewSelectionTable
这个宏函数定义的插入到 hashTable
中的那个函数,返回值不是派生类的对象,而是派生类中的 New
函数的返回值!1
2
3
4
5
6
7
8
9
10
11
12
13
14static autoPtr< baseType > New##baseType argList \
{ \
return autoPtr< baseType >(baseType##Type::New parList.ptr()); \
}
......
if \
( \
!argNames##ConstructorTablePtr_->insert \
( \
lookup, \
New##baseType \
) \
) \
这说明,这里的派生类 RASModel
将不会作为一个具体的湍流模型来使用。而是用来选择 RAS
类型的具体湍流模型的一个跳板。
类体外,调用1
2defineTypeNameAndDebug(turbulenceModel, 0);
defineRunTimeSelectionTable(turbulenceModel, turbulenceModel);
注意,这里没有调用 addToRunTimeSelectionTable
宏函数, turbulenceModel
类是基类,也不会作为具体的湍流模型来调用,所以不需要将它自己添加到 hashTable
。
2. RASModel
turbulenceModel
类下一层的派生类是 RASModel
和 LESModel
。先来看 RASModel
,这个类类体里调用了 declareRunTimeSelectionTable
。1
2
3
4
5
6
7
8
9
10
11
12
13declareRunTimeSelectionTable
(
autoPtr,
RASModel,
dictionary,
(
const volVectorField& U,
const surfaceScalarField& phi,
transportModel& transport,
const word& turbulenceModelName
),
(U, phi, transport, turbulenceModelName)
);
类体外调用了1
2
3defineTypeNameAndDebug(RASModel, 0);
defineRunTimeSelectionTable(RASModel, dictionary);
addToRunTimeSelectionTable(turbulenceModel, RASModel, turbulenceModel);
根据前面的分析,这里 RASModel 又创建了一个新的 hashTable
, 用的是 declareRunTimeSelectionTable
和 defineRunTimeSelectionTable(RASModel, dictionary);
,同时,RASModel类 本身又添加到了 turbulenceModel
中建立的 hashTable
里: addToRunTimeSelectionTable(turbulenceModel, RASModel, turbulenceModel);
RASModel
类之下的派生类,就是具体的湍流模型了,这里以 kEpsilon
模型为例:
- kEpsilon
具体的湍流模型,如kEpsilon
,只需要添加到上面基类中创建的hashTable
中,就能保证其能被调用到。1
addToRunTimeSelectionTable(RASModel, kEpsilon, dictionary);
这里是添加到了 RASModel 中创建的 hashTable
里。
3. LESModel
LESModel
类也是继承自 turbulenceModel
的,所以其处理方法跟 RASModel
是一样的。不过 LES
类的模型的继承关系略比 RAS
类的复杂一点(参看这篇中的 LES 模型继承关系图)。在这个图中,中间层的 GenEddyVisc
等4个虚线框中的类不是作为具体的湍流模型来调用的,这里有必要看一下这样的中间类在 RTS 机制中是怎么处理的。检查这几个类的代码,可以发现 GenEddyVisc
和 GenSGSStress
中只是在类体外调用了 defineTypeNameWithName(GenEddyVisc, "GenEddyVisc");
, scaleSimilarity
在类体中调用了 TypeName
,类体外调用了 defineTypeNameAndDebug
,DESModel
中没有任何处理。可见这些类只是对 typeName
做了处理,并没有调用 addToRunTimeSelectionTable
。
同 RASModel
一样, LESModel
之下派生的具体的湍流模型则需要调用 addToRunTimeSelectionTable
来将自己添加到 LESModel
中定义的 hashTable
中。
由上可知,湍流模型的调用过程大致是这样的:
求解器里创建一个 turbulenceModel
类型的 autoPtr
,并调用 turbulenceModel::New
来初始化。 turbulenceModel::New
从 turbulenceProperties 文件中读取关键字,假设读取到 simulationType 为 RASModel
,则 turbulenceModel::New
的 cstrIter()
返回的是 RASModel::New
,于是 cstrIter()(U, phi, transport, turbulenceModelName)
则是在调用 RASModel::New
。然后, RASModel::New
从 RASProperties 文件里读取关键字,并根据读取到的内容,从 RASModel
类中创建的 hashTable
里查找对应的湍流模型,假设从 RASProperties 中读取到的是 kEpsilon
, 则返回一个 kEpsilon
模型的对象。最终结果是,求解器里创建的turbulenceModel
类型的 autoPtr
指向了 kEpsilon
类的对象,这就实现了对 kEpsilon
模型的调用。