当前位置: 首页 > 工具软件 > OpenFOAM > 使用案例 >

openfoam学习心得——openfoam编程进阶

管弘
2023-12-01

openfoam学习心得——openfoam编程重新学

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对象。

 类似资料: