1、OpenFOAM编程入门:setRootCase都干了些啥?
setRootCase都干了些啥
2、blockMesh > log.blockMesh
运行blockMesh这个命令,并将其output写进log文件里面
可以看blockMesh源代码学习数据的写入
3、mesh.boundaryMesh() 返回polyBoundaryMesh类
polyBoundaryMesh类输出结果
(
movingWall
{
type wall;
inGroups List<word> 1(wall);
nFaces 20;
startFace 760;
}
fixedWalls
{
type wall;
inGroups List<word> 1(wall);
nFaces 60;
startFace 780;
}
frontAndBack
{
type patch;
nFaces 800;
startFace 840;
}
)
**polyPatch类:**
type wall;
inGroups List<word> 1(wall);
nFaces 20;
startFace 760;
**fvboundarymesh类**
**fvPatch类:**
polyPatch可以理解为fvPatch的一个总和,fvpatch用来计算面中心等
4、openfoam Workshop
5、The openfoam technology primer–边界条件与几何场如何结合的
6、 TypeName (“base”)与defineTypeNameAndDebug(AlgorithmBase,0)-必须写类全名
展开为:
ClassName("base");
virtual const word& type() const {return typeName}
再展开:
ClassNameNoDebug("base");
static int debug
virtual const word& type() const {return typeName}
再展开:char*可以指向一个字符串
TypeName ("base")最终展开
static const char* typeName_(){return "base"} //返回classname
virtual const word& type() const {return typeName} //返回typename-虚函数,可被覆盖
static const ::Foam::word typeName
static int debug
这里初始化了两个变量但是没有赋值,下面来看赋值:
defineTypeNameAndDebug(AlgorithmBase,0)
展开为:
defineTypeName(AlgorithmBase)
defineDebugSwitch(AlgorithmBase,0)--debug有关,不深究
展开为:
defineTypeNameWithName(AlgorithmBase,AlgorithmBase::typeName_());
defineDebugSwitch(AlgorithmBase,0)
最后展开为:
const Foam::word AlgorithmBase::TypeName(AlgorithmBase::typeName_())
defineDebugSwitch(AlgorithmBase,0)
咋一看,对于此类类对象,其typeName_()与type()返回值是一样的,但是注意type() 方法是虚函数,固当用指针时,将产生奇效,如下:
autoPtr< incompressible::turbulenceModel > turbulence
turbulence->typeName_() --返回turbulenceModel
turbulence->type() --返回kOmega
7、 RTS机制相关宏函数展开
完整代码请移步:openfoam RTS机制分析
第一个要学习的宏函数如下,顺带学习下如何展开宏函数:
#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); \
} \
} \
\
~add##argNames##ConstructorToTable() \
{ \
destroy##argNames##ConstructorTables(); \
} \
}; \
\
/* Class to add constructor from argList to table */ \
/* Remove only the entry (not the table) upon destruction */ \
template<class baseType##Type> \
class addRemovable##argNames##ConstructorToTable \
{ \
/* retain lookup name for later removal */ \
const word& lookup_; \
\
public: \
\
static autoPtr<baseType> New argList \
{ \
return autoPtr<baseType>(new baseType##Type parList); \
} \
\
addRemovable##argNames##ConstructorToTable \
( \
const word& lookup = baseType##Type::typeName \
) \
: \
lookup_(lookup) \
{ \
construct##argNames##ConstructorTables(); \
argNames##ConstructorTablePtr_->set(lookup, New); \
} \
\
~addRemovable##argNames##ConstructorToTable() \
{ \
if (argNames##ConstructorTablePtr_) \
{ \
argNames##ConstructorTablePtr_->erase(lookup_); \
} \
} \
};
declareRunTimeSelectionTable--一次声明对应一个构造函数
(
autoPtr,
AlgorithmBase,
Word, argNames--word构造、copy构造等
(
const word& algorithmName argList-此构造函数形参数
),
(algorithmName)
)
展开后如下:
上面宏中###是为了区分开参数与非参数
typedef autoPtr< AlgorithmBase > (*WordConstructorPtr)( const word& algorithmName );
函数指针--WordConstructorPtr理解成一个类,其对象就是函数指针
string::hash默认参数,word是key,value是WordConstructorPtr类(或叫函数指针)
typedef HashTable< WordConstructorPtr, word, string::hash > WordConstructorTable;
初始化哈希表指针-静态的,父类、子类对象均可访问此表-所有对象访问的都是同一张表
static WordConstructorTable* WordConstructorTablePtr_;
函数声明
static void constructWordConstructorTables();
static void destroyWordConstructorTables();
template< class AlgorithmBaseType >--类中类
class addWordConstructorToTable --将构造函数添加到Hash表中
{
public:
static autoPtr< AlgorithmBase > New ( const word& algorithmName )
{
给指向基类的指针动态分配内存-指向由word构造生成的基类对象
return autoPtr< AlgorithmBase >(new AlgorithmBaseType (algorithmName));
}
找类中的typename静态名称
addWordConstructorToTable ( const word& lookup = AlgorithmBaseType::typeName )
{
调用前面声明的函数
constructWordConstructorTables();
New函数是一个前面指定好的函数指针类型
if (!WordConstructorTablePtr_->insert(lookup, New))
{
std::cerr<< "Duplicate entry "
<< lookup << " in runtime selection table "
<< "AlgorithmBase" << std::endl;
error::safePrintStack(std::cerr);
}
}
析构函数,因为前面的函数中一旦调用将产生有动态分配的内存
~addWordConstructorToTable()
{
destroyWordConstructorTables();
}
};
类中类
template< class AlgorithmBaseType >
class addRemovableWordConstructorToTable
{
const word& lookup_; 私有成员
public:
静态函数:返回一个基类指针,其指向的可能是别的对象
======植入进哈希表的是一个函数
static autoPtr< AlgorithmBase > New ( const word& algorithmName )
{
return autoPtr< AlgorithmBase >(new AlgorithmBaseType (algorithmName));
}
======植入进哈希表的是一个函数
addRemovableWordConstructorToTable ( const word& lookup = AlgorithmBaseType::typeName )
: lookup_(lookup)
{
constructWordConstructorTables();
WordConstructorTablePtr_->set(lookup, New);
}
=======删除某个哈希表元素
~addRemovableWordConstructorToTable()
{
if (WordConstructorTablePtr_)
{
WordConstructorTablePtr_->erase(lookup_);
}
}
};
上面声明了一个静态数据成员-一张哈希表,key-typename;value是一个函数:此函数的功能是为基类指针复制基类或子类对象。下面的宏将上述静态变量与函数展开。
defineRunTimeSelectionTable(AlgorithmBase, Word)展开后如下:
初始化
AlgorithmBase::WordConstructorTable* AlgorithmBase::WordConstructorTablePtr_ = __null;不至于变成野指针
void AlgorithmBase::constructWordConstructorTables() {
static bool constructed = false;
if (!constructed) {
constructed = true;
初始化哈希表指针-分配了内存
AlgorithmBase::WordConstructorTablePtr_ = new AlgorithmBase::WordConstructorTable;
}
};
如果这个指针不为空指针,就删除堆内存的对象,并设置为空指针
void AlgorithmBase::destroyWordConstructorTables() {
if (AlgorithmBase::WordConstructorTablePtr_) {
delete AlgorithmBase::WordConstructorTablePtr_;
AlgorithmBase::WordConstructorTablePtr_ = __null;
}
};
至此,上述的类变定义完成了,我们也搞清楚了类中每个函数的意思,下面还有一个宏来使用上面定义好的类。
addToRunTimeSelectionTable(AlgorithmBase, AlgorithmBase, Word)展开为:
这里告诉我们如何调用类中类
AlgorithmBase::addWordConstructorToTable< AlgorithmBase > addAlgorithmBaseWordConstructorToAlgorithmBaseTable_;
上面初始化一个类中类对象,在初始化过程中,为基类的哈希表中插入了key-value对,这说明这个表会一直存在。即时再用别的基类对象访问这个表,此表仍然存在相同的数据。第一个AlgorithmBase表示addWordConstructorToTable方法位于基类中,第二个参数AlgorithmBase,代表了插入的key-value的typename函数以及New函数的功能,其返回的是一个基类还是子类对象有此参数指定。可能有点难理解,我们来看其子类。
class AlgorithmNew
:
public AlgorithmBase
{
public:
// Declare the static variable typeName of the class AlgorithmNew.
TypeName ("new");
// Empty constructor.
AlgorithmNew () {};
// Word constructor.
AlgorithmNew (const word& algorithmName) {};
// Make the class callable (function object)
virtual void operator()()
{
Info << "AlgorithmNew::operator()()" << endl;
}
};
defineTypeNameAndDebug(AlgorithmNew, 0);
addToRunTimeSelectionTable(AlgorithmBase, AlgorithmNew , Word);
此时基类的static成员,哈希表中应该是这样的:
AlgorithmBase – New函数–返回基类指针,指针指向的是以word构造生成的AlgorithmBase类对象
AlgorithmNew – New函数–返回基类指针,指针指向的是以word构造生成的AlgorithmNew类对象
再来一个继承:
class AlgorithmAdditional
:
public AlgorithmNew
{
public:
// Declare the static variable typeName of the class AlgorithmAdditional.
TypeName ("additional");
// Empty constructor.
AlgorithmAdditional () {};
// Word constructor.
AlgorithmAdditional (const word& algorithmName) {};
// Make the class callable (function object)
virtual void operator()()
{
// Call base operator explicitly.
AlgorithmNew::operator()();
// Perform additional operations.
Info << "AlgorithmAdditional::operator()()" << endl;
}
};
defineTypeNameAndDebug(AlgorithmAdditional, 0);
addToRunTimeSelectionTable(AlgorithmBase, AlgorithmAdditional , Word)
此时基类的static成员,哈希表中应该是这样的:
AlgorithmBase – New函数–返回基类指针,指针指向的是以word构造生成的AlgorithmBase类对象
AlgorithmNew – New函数–返回基类指针,指针指向的是以word构造生成的AlgorithmNew类对象
AlgorithmAdditional – New函数–返回基类指针,指针指向的是以word构造生成的AlgorithmAdditional 类对象
这个表在编译的时候就已经永恒存在了,可以发现都是以word构造生成的对象,要是我有别的构造呢?如copy构造,原理相同。
注意,表中的New函数是定义在addWordConstructorToTable类中-此类为基类中的类的,在基类中同样有一个New函数,充当selector
static autoPtr< AlgorithmBase > New (const word& algorithmName)
{
输入一个typename--也就是key
WordConstructorTable::iterator cstrIter =
WordConstructorTablePtr_->find(algorithmName);
找不到就报错
// If the Factory Method was not found.
if (cstrIter == WordConstructorTablePtr_->end())
{
FatalErrorIn
(
"AlgorithmBase::New(const word&)"
) << "Unknown AlgorithmBase type "
<< algorithmName << nl << nl
<< "Valid AlgorithmBase types are :" << endl
<< WordConstructorTablePtr_->sortedToc()
<< exit(FatalError);
}
cstrIter()--返回key对应的value,也就是new函数,并传参定义基类指针。
return cstrIter()(algorithmName);
}
从上面代码我们可以学习到,哈希表类中有个迭代器的类中类,()运算符被重载,用来返回key对应的value。
综上学习完毕,RTS机制说直接点就是在基类中生成一个静态的哈希表,基类和子类每编译一次,就往哈希表中加入一个值,其加入值的方法也很精妙,竟然是初始化类中类对象,这个值是永恒的,与求解器运行与否无关,同时基类中还会有一个静态的New函数,用来做选择,看看到底调用哈希表中的哪个函数指针,生成什么类型的对象赋予基类指针。可以猜想定义湍流模型肯定是需要往哈希表中加值的。
8、湍流模型中的RTS分析
1. turbulenceModel 类中
declareRunTimeNewSelectionTable宏-–生成一个哈希表,同时生成往哈希表中插值的类,此时的类中类New函数–也就是此类中哈希表的value返回的是key值所对应类的New函数–选择器:
defineRunTimeSelectionTable宏–这个宏是定义declareRunTimeNewSelectionTable宏中所声明的函数用的
2.RASModel类中
declareRunTimeSelectionTable宏–生成一个哈希表,同时生成往哈希表中插值的类,这个返回的是基类或子类对象。
defineRunTimeSelectionTable(RASModel, dictionary)宏–说明是哈希表中New函数返回的对象是由字典构造生成的。
addToRunTimeSelectionTable(turbulenceModel, RASModel, turbulenceModel)宏–说明将RASModel类添加到turbulenceModel类的哈希表中:
也就是RASModel(类的typename) New—这个函数返回RASModel::New
3、kEpsilon类中
addToRunTimeSelectionTable(RASModel, kEpsilon, dictionary)宏–说明将kEpsilon类添加到RASModel的哈希表中,采用字典构造生成kEpsilon类对象,返回给基类指针。
把类添加到哈希表等同于key=类的typename,value=New函数(属于类中类的New函数),其返回此类对象。某一个类中存在哈希表,则存在select(属于基类的New函数),可以在哈希表中用迭代器来选择函数执行。
故而我们在文件中指定的都是typename–可能与类名相同,也可能不同,一般是一样的。
综上,autoPtr< incompressible::turbulenceModel > turbulence
(
incompressible::turbulenceModel::New(U, phi, laminarTransport)
);运行过程为,turbulenceModel::New根据字典选择RASModel,则调用RASModel中的RASModel::New函数,然后根据字典选择kEpsilon,则在生成kEpsilon对象。