OpenFOAM 中的 Run Time Selection

以一个很简单的例子分析 OpenFOAM 中的 Run Time Selection,如有错误,欢迎指正!

本文内容主要是为了消化 Giskard 博客 而作,在此致谢!
首先简单说下 RTS 的功能:就是在 solver 中创建模型对象的时候,可以使用基类中的 New 函数创建一个基类的指针,然后在 case 的字典文件中选择所需的子模型(派生类),即运行时选择(Run Time Selection)。这对代码的要求就是,通过给定模型的名字(从字典中获取),然后能获取该模型的对象,这就是 New 函数的功能。

代码路径:

\src\OpenFOAM\db\runTimeSelection\construction
\src\combustionModels\FSD\reactionRateFlameAreaModels

基类(模型类别):reactionRateFlameArea

  • 基类体内调用:TypeName("reactionRateFlameArea");

  • 基类体内调用 declareRunTimeSelectionTable(详细代码见本文末尾),作用如下:

    • HashTable 起别名,argNames##ConstructorTable,并创建一个该类的指针 argNames##ConstructorTablePtr_
    • 定义add##argNames##ConstructorToTable,模板是 baseType##Type。该类的 New 函数很关键,返回基类指针,指向一个临时 new 的对象,对象类型是 baseType##Type。该类的构造函数也很关键,它向 argNames##ConstructorTablePtr_insert 一组 key and value:baseType##Type::typeNameNew 函数。

    所以关键在于创建 add##argNames##ConstructorToTable 的对象时它的模板是什么类型。如果模板是基类,那么往哈希表中 insert 的是基类的 typeName返回指向基类对象的基类指针的 New 函数。如果模板是派生类,那么往哈希表中 insert 的是派生类的 typeName返回指向派生类对象的基类指针的 New 函数

declareRunTimeSelectionTable
(
autoPtr,
reactionRateFlameArea,
dictionary,
(
const word modelType,
const dictionary& dict,
const fvMesh& mesh,
const combustionModel& combModel
),
(modelType, dict, mesh, combModel)
);
  • 基类体内申明了函数
static autoPtr<reactionRateFlameArea> New
(
const dictionary& dict,
const fvMesh& mesh,
const combustionModel& combModel
);
  • 基类体外调用了
defineTypeNameAndDebug(reactionRateFlameArea, 0);
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary);

reactionRateFlameAreaNew.C 文件中定义了 New 函数,这个函数在 FSD 的构造函数里调用,用于创建本文所说的基类指针。

Foam::autoPtr<Foam::reactionRateFlameArea> Foam::reactionRateFlameArea::New
(
const dictionary& dict,
const fvMesh& mesh,
const combustionModel& combModel
)
{
word reactionRateFlameAreaType
(
dict.lookup("reactionRateFlameArea")
);

Info<< "Selecting reaction rate flame area correlation "
<< reactionRateFlameAreaType << endl;

dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(reactionRateFlameAreaType);

const label tempOpen = reactionRateFlameAreaType.find('<');

const word className = reactionRateFlameAreaType(0, tempOpen);

return autoPtr<reactionRateFlameArea>
(cstrIter()(className, dict, mesh, combModel));
}
//cstrIter 是那个 declareRunTimeSelectionTable 里边定义的 New 函数。
//它的形参列表是 declareRunTimeSelectionTable 的 argList(第四个参数)。
//它创建一个基类指针,指向派生类的一个对象,同时该对象被构造,构造函数的实参列表是 parList(第五个参数)。
// 这里给它的实参是 (className, dict, mesh, combModel)
//className===relaxation(从字典中读取的), dict===FSDCoeffs, combModel===FSD

派生类(具体模型):relaxation

派生类体内调用:TypeName("relaxation");

defineTypeNameAndDebug(relaxation, 0);
addToRunTimeSelectionTable
(
reactionRateFlameArea,
relaxation,
dictionary
);

派生类调用 addToRunTimeSelectionTable 的时候,创建了一个 baseType::add##argNames##ConstructorToTable<thisType> 类的对象,这里 thisTyperelaxation,作为类的模板传入 。我们可以看到,当我们把派生类的类名作为 add 的模板时,New 函数返回的是指向派生类对象的基类指针。而这个 New 函数在 add 的构造函数中随同**派生类的 typeName **被插入到哈希表中。

//- Add to hash-table of functions with typename as the key
#define addToRunTimeSelectionTable (baseType,thisType,argNames)
/* Add the thisType constructor function to the table */ \
baseType::add##argNames##ConstructorToTable<thisType> \
add##thisType##argNames##ConstructorTo##baseType##Table_

declareRunTimeSelectionTable 细节展示:

//- Declare a run-time selection
#define declareRunTimeSelectionTable(autoPtr,baseType,argNames,argList,parList)\
\
/* Construct from argList function pointer type */ \
typedef autoPtr<baseType> (*argNames##ConstructorPtr)argList; \
\
/* Construct from argList function table type */ \
typedef HashTable<argNames##ConstructorPtr, word, string::hash> \
argNames##ConstructorTable; \
\
/* Construct from argList function pointer table pointer */ \
static argNames##ConstructorTable* argNames##ConstructorTablePtr_; \
\
/* Table constructor called from the table add function */ \
static void construct##argNames##ConstructorTables(); \
\
/* Table destructor called from the table add function destructor */ \
static void destroy##argNames##ConstructorTables(); \
\
/* Class to add constructor from argList to table */ \
template<class baseType##Type> \
class add##argNames##ConstructorToTable \
{ \
public: \
\
static autoPtr<baseType> New argList \
{ \
return autoPtr<baseType>(new baseType##Type parList); \
} \
\
add##argNames##ConstructorToTable \
( \
const word& lookup = baseType##Type::typeName \
) \
{ \
construct##argNames##ConstructorTables(); \
if (!argNames##ConstructorTablePtr_->insert(lookup, New)) \
{ \
std::cerr<< "Duplicate entry " << lookup \
<< " in runtime selection table " << #baseType \
<< std::endl; \
error::safePrintStack(std::cerr); \
} \
} \
}; \

第一次使用自己的 RTS

文章作者: Yan Zhang
文章链接: https://openfoam.top/simpleRTS/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 OpenFOAM 成长之路
微信打赏给博主更多动力吧~