OpenFOAM-3.0 的湍流模型(四)
OpenFOAM-3.0 的湍流模型(四)
转自:https://xiaopingqiu.github.io/,侵删
仅仅觉得都挺有用的,所以转发一下。仅仅是想做个备份,希望不要某天淹没在互联网的长河里
最后来看一个小问题:OpenFOAM-3.0 中的湍流模型是怎么编译的。在这之前,湍流模型的编译很直观,将需要编译的湍流模型的代码的 .C 文件写到 Make/files 里就好了。可是,在 OpenFOAM-3.0 里,很多湍流模型代码的 .C 文件并没有写到 Make/files 里,而是在 makeTurbulenceModels.C里类似这样写
1 | #include "mykEpsilon.H" |
然后在 Make/files 里写的是这个 makeTurbulenceModels.C 文件。为什么呢?
这里来分析一下这个问题。
这个问题,说起来也简单,不过我经过很多摸索从想明白。其实,这个问题用一个概念就可以解释清楚:条件编译。
条件编译常用于头文件,格式如下
1 | //filename: kEpsilon.H |
这样能避免头文件重复引用的导致变量或者类重复定义的问题,原因在于,第一次 #include "kEpsilon.H" 时,会触发 #define kEpsilon_H 的操作,之后如果代码中再出现 #include "kEpsilon.H" 则 #ifndef kEpsilon_H 将不再成立,所以, #ifndef ... #endif 之间的内容将不会再度被引入。
OpenFOAM 的模板类中,还常见的一种用法是
1 | #ifdef NoRepository |
这个怎么理解呢? 本来也不难理解,无非就是如果定义了宏 NoRepository 则在头文件里将类的具体定义部分也引入到头文件里。问题是,翻遍 OpenFOAM 的 src 目录下的源码,也找不到 NoRepository 的定义。经过搜索,原来这个 NoRepository 是通过 g++ 的 -D 选项来定义的!在编译过程中,使用
1 | g++ -c -DNoRepository ... |
相当于进行了 #define NoRepository 1 的操作,所以, #ifdef NoRepository 这个条件是满足的。
OpenFOAM 中,编译选项的定义在 wmake/rules 下,具体的定义取决于你用的编译器,以 linux64Gcc/c++ 为例
1 | c++WARN = -Wall -Wextra -Wno-unused-parameter -Wold-style-cast -Wnon-virtual-dtor |
可见这里的确是使用了 -DNoRepository 选项。
为什么要在头文件里 #include "kEpsilon.C" 呢?这就涉及到模板类的实例化的问题。这篇文章详细地探讨了模板类实例化过程中会遇到的问题,以及解决的办法。简单地说,模板类不是一种类型,而是一种模板,模板类通过代入模板参数来实例化,以得到具体的类(这个具体的类就可以看作是一种“数据类型”了)。在示例化过程中,编译器不光需要模板类的声明部分,还需要知道模板类的成员函数的具体定义部分,所以,如果在进行模板类声明的地方只包含了模板类的声明部分(一般是头文件),那实例化就会失败,编译器会报类似“undefined reference to …” 的错误。
cfd-online 上的这个帖子也探讨了关于 NoRepository 的问题。
最后,makeTurbulenceModels.C 里的 #include "kEpsilon.H",其实相当于也 #include "kEpsilon.C",而且,要注意这里 include 进来的是一个模板类,是用来建立实例化的模型的!实例化的过程,在 makeRASModel(kEpsilon) 里,详细的参考前一篇,看看这个宏函数的展开,就知道模型参数是怎么代入进去来得到实例化的湍流模型类的。