写下本文主要为了增进对OF的理解,消化http://xiaopingqiu.github.io/2016/03/12/RTS1/和https://openfoam.top/simpleRTS/#%E5%9F%BA%E7%B1%BB%E6%A8%A1%E5%9E%8B%E7%B1%BB%E5%88%ABreactionrateflamearea的内容。
OpenFOAM 中大部分求解器都包含多个模型,比如一个sprayFoam既要包括连续相的燃烧模型,又要包括粒子的蒸发模型,喷雾模型,这些模型可能又会细分。从 C++ 的角度来看,其实这些模型都是以类来表示的。一般来说,基类用作接口,hashTable就是在基类定义的,派生类则可能是一个具体的模型。
接下来,本文以OpenFOAM-7为基础,以sprayFoam中的lagrangian子模型stochasticCollisionModel的接口为例,说明sprayFoam里lagrangian库的子模型的接口。
子模型StochasticCollision in sprayFoam的接口
首先,sprayFoam里的关于粒子的运动都是用parcels这个对象来表述的,比如在主程序里可以找到parcels.evolve()等语句,而parcels是basicSprayCloud类的,basicSprayCloud的声明如下
namespace Foam { typedef SprayCloud < ReactingCloud < ThermoCloud < KinematicCloud < Cloud < basicSprayParcel > > > > > basicSprayCloud; }
说明parcels具有SprayCloud, ReactingCloud, ThermoCloud, KinematicCloud等Cloud的属性,而stochasticCollisionModel则是属于KinematicCloud的一个子模型。具体的过程如下所示:
KinematicCloud.H里定义了stochasticCollisionModel_,代码如下:
//- Stochastic collision model
autoPtr<StochasticCollisionModel<KinematicCloud<CloudType>>> stochasticCollisionModel_;
而在KinematicCloud的构造函数里,则调用了setModels()函数,setModels()则选择了KinematicCloud的各个子模型,比如:
template<class CloudType>
void Foam::KinematicCloud<CloudType>::setModels()
{
...
stochasticCollisionModel_.reset
(
StochasticCollisionModel<KinematicCloud<CloudType>>::New
(
subModelProperties_,
*this
).ptr() // Bu 2022/1/5 : New() returns a temporary object, which is converted by .ptr() to a pointer as an argument to function reset()
);
...
}
reset()的定义在src\OpenFOAM\memory\autoPtr\autoPtrI.H里,根据下面代码,可知reset()即把指针p赋给ptr_,即把上面StochasticCollisionModel<KinematicCloud<CloudType>>::New( , ).ptr()返回的指针赋给了stochasticCollisionModel_。故关键在于弄懂StochasticCollisionModel<KinematicCloud<CloudType>>::New。
//- If object pointer already set, delete object and set to given pointer
inline void reset(T* = nullptr);
template<class T>inline void Foam::autoPtr<T>::reset(T* p) { if (ptr_) { delete ptr_; } ptr_ = p; }
//defination of ptr_
template<class T>class autoPtr
{
//- Pointer to object
mutable T* ptr_;
}
提起New函数,就不得不介绍一下OpenFOAM里的RTS机制(RunTimeSelection)!RTS机制是OpenFOAM根据用户指定的关键字来选择对应的模型,通过selector即New函数来进行模型选择,通过"虚构造函数"的方式来实现通过基类类型的指针调用派生类的功能。可见,这里有可能是接口所在。(参考http://xiaopingqiu.github.io/2016/06/25/thermophysics1/的思路)。
这里,附上一张自己总结的思维导图,记录了RTS涉及到的函数的位置以及作用,可与下文对比着看。
RTS思维导图
RTS在本例中,Base基类指的是StochasticCollisionModel,Derived派生类指的是ORourkeCollision或者TrajectoryCollision,其中TrajectoryCollision还是ORourkeCollision的派生类,本例派生类仅取TrajectoryCollision进行说明。
根据http://xiaopingqiu.github.io/2016/03/12/RTS1/博客中记录的,RTS 机制的实现跟几个函数的调用有关:declareRunTimeSelectionTable,defineRunTimeSelectionTable,defineTypeNameAndDebug,addToRunTimeSelectionTable。规律可以总结如下:
基类类体里调用TypeName和declareRunTimeSelectionTable两个函数,类体外面调用defineTypeNameAndDebug,defineRunTimeSelectionTable和addToRunTimeSelectionTable三个函数;基类中需要一个静态New函数作为 selector。
派生类类体中需要调用TypeName函数,类体外调用defineRunTimeSelectionTable和addToRunTimeSelectionTable两个宏函数。
但其实并不一定每个模型的调用都是用的这些函数,比如本例中用到的就用defineTemplateRunTimeSelectionTable来代替defineRunTimeSelectionTable的作用。理解RTS的核心问题在于哪个函数实现了什么样的作用。下面通过代码理解每个函数的作用。
对基类BaseClass:
首先,基类头文件(src\lagrangian\intermediate\submodels\Kinematic\StochasticCollision\StochasticCollisionModel\StochasticCollisionModel.H)中部分代码如下所示:
public:
//- Runtime type information
TypeName("collisionModel");
//- Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
StochasticCollisionModel,
dictionary,
(
const dictionary& dict,
CloudType& owner
),
(dict, owner)
);
也就是说,在基类头文件里调用了两个宏函数 TypeName 和 declareRunTimeSelectionTable。
1.宏函数TypeName()的定义在src/OpenFOAM/db/typeInfo/typeInfo.H和className.H里,代码如下:
//- Declare a ClassName() with extra virtual type info
#define TypeName(TypeNameString) \
ClassName(TypeNameString); \
virtual const word& type() const { return typeName; }
//- Add typeName information from argument \a TypeNameString to a class.
// Also declares debug information.
#define ClassName(TypeNameString) \
ClassNameNoDebug(TypeNameString); \
static int debug
//- Add typeName information from argument \a TypeNameString to a class.
// Without debug information
#define ClassNameNoDebug(TypeNameString) \
static const char* typeName_() { return TypeNameString; } \
static const ::Foam::word typeName
由此可知,TypeName()的作用即令typeName_()返回TypeNameString的值。
2.宏函数declareRunTimeSelectionTable的定义在src/OpenFOAM/db/runTimeSelection/construction/runTimeSelectionTables.H中,declareRunTimeSelectionTable的形参对应基类头文件的参数可知,autoPtr=autoPtr, baseType=StochasticCollisionModel, argNames=dictionary, argList=( const dictionary& dict, CloudType& owner), parList=(dict, owner),代码如下:
//- Declare a run-time selection
#define declareRunTimeSelectionTable(autoPtr,baseType,argNames,argList,parList)\
\
/* Construct from argList function pointer type */ \
typedef autoPtr<baseType> (*argNames##ConstructorPtr)argList; \ //Bu 2022/1/2 : create a function pointer
\
/* Construct from argList function table type */ \
typedef HashTable<argNames##ConstructorPtr, word, string::hash> \ //Bu 2022/1/2 : the value of HashTable is argNames##ConstructorPtr, the key of HashTable is word
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(); \ //Bu 2022/1/2 : create hash table
\
/* Table destructor called from the table add function destructor */ \
static void destroy##argNames##ConstructorTables(); \ //Bu 2022/1/2 : delete hash table
\
/* Class to add constructor from argList to table */ \
template<class baseType##Type> \
class add##argNames##ConstructorToTable \
{