simpop

普通会员

OpenFOAM常用类的一些总结

OpenFOAM 常用类的一些总结
OpenFOAM 中有许多类,每个类的功能都很强大,这也使它面向对象设计得以实现。 对于程序,最常用到的,也是最底层的就是数据,在 OpenFOAM 中引入了三类基础数据 类型:标量 scalar, 向量 vector, 张量 tensor.这三个中数据类型,也是 FOAM 中最基础的三个 类。(还有一个比较重要的就是 bool 和 label,前者就是是非型,及对错型,只不过是更扩展一 些,后者是标签型数据,相当于 c 中的整型。关于更多的其它数据类型可以参看目 录..\src\OpenFOAM\primitives 里面) 在上述数据类的基础上,增加场(field)的概念,就引入了标量场 scalarField, 向量场 vectorField, 张量场 tensorField。实际上这三个类又是 field 类的 typedef, 如 typedef field<scalar> saclarField。这些场类中都有对应的成员函数进行加减乘除运算,还有复杂的点积叉积等。说到 这 field class,其实他就像是一个数据存放的区域一样, 存放上 scalar, 那它成了标量场 scalarField。 这些类中可以有接口实现数据的计算。从 field 类中又派生出了 FieldField 类,这个就是说场中 场类,其实这个主要用于边界条件类的一个基类。因为边界条件算是网格类场中的一个特殊的 场,后面会介绍。 比 field 类高一点的就是几何场类 GeometricField class, 其相比 field class 多了纪录场位置 的相关信息。说到这里请大家注意他和 polyMesh class 的区别,后者只是纪录网格的结构,如 点的位置、 面的组成、 体的组成等等, polyMesh class 中对应有 pointMesh, surfaceMesh, volMesh 等类,从字面上很容易理解其处理和记录网格点、网格面、网格体等信息。而 GeometricField 类,其则是记录了在什么样的网格上有量 a 的相关信息或数据。它包括了内部区域、边界区域 (GeometricBoundaryField class)、网格、尺度单位、计算的先前时间阶的值等。在该类中有 常用的三种(实际上还有其他的许多,可以参看 OpenFOAM 网上说明):volScalarField 体标 量场,volVectorField 体向量场,volTensorField 体张量场。这里说的场与 field 有所不同,这里 指的是网格区域上所对应的数据信息。上述的 vol 就是指 ployMesh 中的 volMesh,如 volscalarField 类来说:见下例 volScalarField p ( IOobject ( "p",

runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ), mesh ); 看过老苏博客的朋友肯定都知道这是什么意思,这是读入标量压力场文件,把压力值存储到网 格体中心。为加深对 GeometricField 类的理解,贴张 PG 中的图片:

OpenFOAM 中有许多类,每个类的功能都很强大,这也使它面向对象设计得以实现。 对于程序,最常用到的,也是最底层的就是数据,在 OpenFOAM 中引入了三类基础数据类型: 标量 scalar, 向量 vector, 张量 tensor.这三个中数据类型,也是 FOAM 中最基础的三个类。(还

有一个比较重要的就是 bool 和 label,前者就是是非型,及对错型,只不过是更扩展一些,后者 是标签型数据,相当于 c 中的整型。关于更多的其它数据类型可以参看目 录..\src\OpenFOAM\primitives 里面) 在上述数据类的基础上, 增加场 (field) 的概念, 就引入了标量场 scalarField, 向量场 vectorField, 张量场 tensorField.实际上这三个类又是 field 类的 typedef,如 typedef field<scalar> saclarField。 这些场类中都有对应的成员函数进行加减乘除运算, 还有复杂的点积叉积等。 说到这 field class, 其实他就像是一个数据存放的区域一样,存放上 scalar,那它成了标量场 scalarField。这些类中 可以有接口实现数据的计算。从 field 类中又派生出了 FieldField 类,这个就是说场中场类,其 实这个主要用于边界条件类的一个基类。因为边界条件算是网格类场中的一个特殊的场,后面 会介绍。 比 field 类高一点的就是几何场类 GeometricField class, 其相比 field class 多了纪录场位置的相 关信息。说到这里请大家注意他和 polyMesh class 的区别,后者只是纪录网格的结构,如点的 位置、 面的组成、 体的组成等等, polyMesh class 中对应有 pointMesh,surfaceMesh,volMesh 等类, 从字面上很容易理解其处理和记录网格点、网格面、网格体等信息。而 GeometricField 类,其 则是记录了在什么样的网格上有量 a 的相关信息或数据。它包括了内部区域、边界区域 (GeometricBoundaryField class)、网格、尺度单位、计算的先前时间阶的值等。在该类中有 常用的三种(实际上还有其他的许多,可以参看 OpenFOAM 网上说明):volScalarField 体标量 场,volVectorField 体向量场,volTensorField 体张量场。这里说的场与 field 有所不同,这里指的 是网格区域上所对应的数据信息。上述的 vol 就是指 ployMesh 中的 volMesh,如 volscalarField 类来说:见下例 volScalarField p ( IOobject ( "p", runTime.timeName(), mesh, IOobject::MUST_READ,

IOobject::AUTO_WRITE ), mesh ); 看过老苏博客的朋友肯定都知道这是什么意思,这是读入标量压力场文件,把压力值存储到网 格体中心。为加深对 GeometricField 类的理解,贴张 PG 中的图片:

除了体的向量标量张量场外,还有面标量场 surfaceScalarField、面向量场 surfaceVectorField、 面张量场 surfaceTensorField。看下面的例子: surfaceScalarField phi ( IOobject (

"phi", runTime.timeName(), mesh ), fvc::interpolate(alpha)*phia + fvc::interpolate(beta)*phib );这里的 phi 既是一个面向量场对象,他用来是纪录单元体面上流过的通量值。 除了常用到的标量向量张量的几何场外, 还有一些特殊量的场: surfaceSymmTensor 面对称张量 几何场、体球面张量场等等。几何场里面还有一个比较重要的类就是 GeometricBoundaryField, 用来专门对边界进行处理的一个类。 如果说数据场类是处理数据的基础,那么时间类则是控制计算步进必不可少的一部分。Time class 在进行瞬态计算,用它跟踪时间阶,并使时间按一定步长或者变步长累加,及输出计算参 数, 计算时间等。 见下例: (相关说明见老苏博客: OpenFOAM>>solver>>incompressible>>icoFoam 的说明) Info<< "\nStarting time loop\n" << endl; for (runTime++; !runTime.end(); runTime++) { Info<< "Time = " << runTime.timeName() << nl << endl; //…… runTime.write(); Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" << nl << endl; 谈到时间大家很容易想到的就是空间,time and space 是 cfd 中非常重要的概念,在离散过程中 时间和空间都需要进行离散 (非稳态情况) , 与空间相关的类其实上面已经提到: ployMesh class,

在这不在累述。 需要附加说明的是边界条件类: 边界条件在 OpenFOAM 被定义作为场的一个完 整部分而不是场上额外附加的。在 fvMatrix 类中并入了 patch 用来定义区域的外部边界。每一 个 patch 有一个边界条件, 再由 fvm 用合适的方式进行操作处理。 patch 有多种类型: calculated, fixed value, fixed gradient, zero gradient, symmetry, cyclic 等。这些类型都继承于基类 patchField。 在求解之前,需要对偏微分方程组进行离散,转化为线性方程组[A][x]=[b]的形式。其中[x]就 是我们所要求的量,他也就是咱们前面介绍的 GeometricField 类,而[A]代数方程的系数,他就 是我们下面所要提到的 fvMatrix 类。 对于偏微分方程的每一项, OpenFOAM 应用两个类来离散: finiteVolumeMethod 和 finiteVolumeCalculus,分别用 typedef 声明为 fvm 和 fvc. fvm 是计算隐 式导数从而返回 fvMatrix,而 fvc 是计算显式导数或者其它隐式计算返回 geometricField,该类 不存储私有数据,仅是执行操作从一个量 map 到另外一个量上。对于偏微分方程,其中有很多 种导数形式:拉普拉斯、时间导数、二阶时间导数、对流项、散度、梯度、梯度梯度平方、旋 度、源等,在 OpenFOAM 中的表示见下图:

离散化时空之后,就是解方程,其实求解方程的过程主要分成如下几部:1.离散偏微分方程, 2.线性化方程组,3.对应不同的倒数格式选择差分格式,4.求解系数矩阵,5.解方程。在这就涉 及到了一个重要的部分:矩阵。Matrix 是 OpenFOAM 中的一个模板类,他是一个用来存储及运 算标量张量等类型数据的 2 维矩阵。这个矩阵类有点像数学上的矩阵一样。对于应用于数值求 解矩阵,OpenFOAM 引入了 fvMatrix 类,这个就是有限体积(finite volume)矩阵类,他是一 个特殊的矩阵类型,应用于求解有限体积标量方程组,该类成员函数可以实现给定相应场的求 解、通量的计算、残差的计算和控制、方程松弛因子的实现,方程中心系数(central coefficient, 公共成员函数 A())和 H 操作源(H operation source,成员函数 H())的计算、设定计算参考等。 在此需要提到的是 fvMesh 类, 该类和 GoeMesh 类差不多, 不同之处在于 fvMesh 类它包含相应 网格信息和拓扑结构的同时,还对网格进行实时更新(动网格的时候)。这些更新包括删除单 元体面等,并按要求重新定位并计算新的信息。下面举一些关于 fvMatrix 应用的例子:(选自 icoFoam)

fvVectorMatrix UEqn ( fvm::ddt(U) + fvm::div(phi, U) //div,散度是代表某量通过单元体的面积分,此处 phi 为一个通量场, 该场的值被记录在单元体的面上,而 U 就是由通量所输运的量,而该速度值则被记录在单元体 中心点上。 - fvm::laplacian(nu, U) );//源项可以使显式的,在离散时进入方程的右端,当源项为隐式的时候他进入方程的系数 矩阵中。 solve(UEqn == -fvc::grad(p));//关于==,一直有所疑问,听老苏分析挺有道理,最近你看到 一篇文章上说==的定义是用来表示数学意义上的方程左右两端的等于,这个运算符为了使其有 最低的的运算优先级所以采用了==,而非=,同时也强调了方程两端得等的概念,而非赋值。 在 OpenFOAM 中,对==的操作实际上是形式上的,而非实质上有什么运算,它自动重排方程 各项:所有隐式项写进方程矩阵中,而所有显式项则归于方程的 b 中。 volScalarField rUA = 1.0/UEqn.A(); U = rUA*UEqn.H(); pEqn.setReference(pRefCell, pRefValue); pEqn.solve(); 例子中 fvVectorMatrix 为一向量有限体积矩阵类,OpenFOAM 中定义 typedef fvMatrix<Vector> fvVectorMatrix,其他的还有标量、张量等。其他关于上述程序的说明参看老苏博客。 再看如下例子: fvMatrixScalar rhoEq ( fvm::ddt(rho)+fvc::div(phi)

);//此处是一个关于质量守恒方程的求解,对于 phi 为密度与速度的积,而此时采用 fvc 即表示 速度通量在方程中作为已知量,出现在方程的 b 项中,它是计算前一时间阶的值。 说了一些常用的类,下面介绍一些比较基础底层的类:IOdictionary,argList,IOobject, IOdictionary 类是继承于 regIOobject 类和 dictionary 类,其主要作于是读入和写入数据。如读 取 PISO 控制参数,或读入 transportProperties 参数等等。 它派生出许多类: 1. basicThermo(用于基本热力学参数读取和计算) 2. LESModel(大涡模拟模型控制参数) 3. RASModel (RAS 模型控制参数) 4. fvSchemes (离散格式参数) 5. motionSolver (动网格控制参数) 6. radiationModel (辐射模型控制参数) 7. solution (求解方程控制参数) 8. SRFModel (SRF 模型控制参数) 9. tolerances (方程残差控制) 10. transportModel (输运模型参数) 见下例: IOdictionary transportProperties //在 transportProperties 字典中读入参数 ( IOobject (

"transportProperties", runTime.constant(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE ) ); IOobject 类:读入写入数据,他与 IOdictionary 不同之处在于后者是读取一个文件中的一个字 典“{}”之内的数据,而 IOobject 则是读入整个文件,如读入压力场,速度场等,并且有读入写 出的控制参数,见上例中的“MUST_READ,NO_WRITE”等等。(老苏博客中有详细介绍,在 此不多说了) argList 类:读入外部命令参数的一个类,如在命令窗口键入 icoFoam -case <dir>,则对目录 dir 执行 icoFoam 计算,其参数有:-case 选择一个 case 目录替代当前工作目录;-parallel 指定并行 计算参数; -doc 显式该程序文档; -srDoc 在浏览器里显示该程序的源文件; -help 显示改程 序的使用方法 dimensionSet 类是对基本类型的单位设定,并检查其正确性。 tmp 类是管理临时对象的一个类。

OpenFOAM 的程序开发初步
一.OpenFOAM 应用的类型: 使用 OpenFOAM 进行 CAE 模拟的,大致可分为三种类型: 1)直接利用 OpenFOAM 的标准的求解器进行模拟,把 OpenFOAM 替代商业软件来使用, OpenFOAM 已基本具有这样的功能和人气,与 Fuent,Star-CD 等相比较,OpenFOAM 显然 具有更高的求解效率和灵活性。 2)用户自定义求解器,即利用 OpenFOAM 的基本类库,如 finiteVolume,OpenFOAM 库来按 照自己的求解流程来编写针对某类应用的求解器。用户需要开发的求解器就是类似于在

OpenFOAM 的 applications 中所看到的标准求解器 icoFOAM,simpleFOAM 等。显然这一需 求是非常大的,从 OpenFOAM 问世以来,已有很多用户定义了自己的求解器。这类需求的特 点是,并不需要特别关心,离散和求解的最底层的知识,如时间项离散,空间项离散等,关注 的重点是求解的步骤或者流程。在编程中,通常是顶层的求解流程的开发,在多数情况下可以 不编译 OpenFOAM 的 finiteVolume 和 OpenFOAM 库。这种顶层的求解器的开发,是我们以 前常常忽略的,或者是以前没有能力做到的。需要指出的是,商业软件中的所谓 udf,user subroutine 和这是不可相比的。 3)用户自己定义离散方法等。对于研究离散格式、代数求解器等人来说,更关注时间项 ddt,扩 散项 Laplacian,对流项 div 是如何离散的,能否有更高效更高精度的离散方法,这需要修改 finiteVolume 库和 OpenFOAM 库中对应的代码。尤其是对流项,尽管 OpenFOAM 已经提供了 基于 NVD 和 TVD 的模板和 40 多种有名的高阶高精度格式,但可以预见,这仍然是不够的, 毕竟对流项的离散仍然是目前 CFD 的重点研究方向。 可以肯定的是, 目前有很多人关注类型 2 的应用, 毕竟将 OpenFOAM 当成 Fluent 或 Star-CCM 来使用,并不见得方便。但是将 OpenFOAM 作为类库来构建自己的求解器,这是其它软件无 法实现的。 二.OpenFOAM 程序开发的基本知识 2.1OpenFOAM 的基本术语 重要的环境变量: $WM_PROJECT_USER_DIR ―― OpenFOAM 的用户目录 $FOAM_TUTORIALS $ FOAM _SRC $ FOAM_APP $ FOAM_APPBIN $ FOAM_RUN 重要的 shell: run src app util = cd to $FOAM_RUN = cd to $FOAM_SRC = cd to $FOAM_APP = cd to $FOAM_APP/utilities ------OpenFOAM 的算例目录 ------OpenFOAM 库的源程序目录 ------ OpenFOAM 的求解器目录 ------- OpenFOAM 的求解器执行文件目录 ------用户的算例目录

sol tut

= cd to $FOAM_APP/solvers = cd to $FOAM_TUTORIALS

求解器的基本文件结构 appName +appName.C 包含求解器源代码的目录 求解器主程序

+CreateFields.H 场变量的声明和初始化 +Make/ +files +options 编译指令 编译需要的源程序文件和生成的目标文件 编译选项,如链接库等

appName/appName.C 是求解器的主程序 appName/createFields.H 声明变量,并从文件中读入初值,如 p,物性。 appName/Make/files 所有源程序的名称,一个文件一行,最后一行是目标代码的名称和存放 位置,EXE=$(FOAM_USER_APPBIN)/appName appName/Make/options 设定查找头文件和库的路径,EXE_INCS,和需要链接的库 EXE_LIBS 算例的基本文件结构 case/ +0/ +constant/ +polyMesh/ +transportProperties/ +system/ +controlDict +fvSchemes +fvSolutions 具体而言 case/0 case/constant/polyMesh 每个需求解的变量需要一个文件设定其初始边界条件 网格数据,如 owner neighbour points faces boundary 算例目录 包含初始和边界条件 包含初次读入后,不随时间变化的数据 包含多面体网格数据 包含物性数据 包含计算控制和离散格式设定 包含计算控制,如时间步长等 包含离散格式设定 包含代数求解器或 SIMPLE,PISO 算法设定

case/system/transportProperties 物性数据 case/system/controlDict 设定起始终止时间,时间步长,输出控制

case/system/fvSchemes case/system/fvSolution

设定程序用到的每个微分算子的离散格式 为每个变量选择代数方程求解器/收敛精度及 PISO 等算法设定

三.OpenFOAM 程序开发的理论知识 作求解开发,必须能写出需要求解的控制方程及其定解条件,并且对于如何求解方程或方程组 的步骤已经明确。 这些流体力学、传热学以及相关的理论是必需的,所谓连续介质力学中的数学模型,控制方程 和定解条件就是表示它的语言。 在这里是不可能说清楚的,这要看个人的功底了。 四 .OpenFOAM 程序开发的最简单的例子 下面采用 OpenFOAM 来开发一个用户自己的求解器。主要是利用 OpenFOAM 的标准求解器 icoFoam,用户不需要写任何代码,只为为了熟悉 OpenFOAM 程序开发的环境和步骤。 步骤: 1) 将 icoFoam 目录拷贝到新的目录

可采用下面的 Linux 的命令实现: 到 OpenFOAM 的 incompressible 目录 cd applications/incompressible cp –r icoFoam myicoFoam 以上只是复制目录 icoFoam 到新的位置,并且新目录名为 myicoFoam cd myicoFoam 进入新的目录,查看一下,可以看到里面的文件和 icoFoam 中是否一样 2) 原文件改名,并且删除依赖文件

将 icoFoam.C 改名 myicoFoam.C mv icoFoam.C myicoFoam.C 删除依赖文件 rm icoFoam.dep 3) 修改编译文件 files 和 options

进入 Make 目录,打开 files 文件, 将 icoFoam.C 源程序文件名

EXE = $(FOAM_APPBIN)/icoFoam 可执行文件名 修改为 myicoFoam.C 源程序文件名

EXE = $(FOAM_APPBIN)/myicoFoam 可执行文件名 此例中 options 不需修改,可以打开看看 EXE_INC = \ 头文件包含

-I$(LIB_SRC)/finiteVolume/lnInclude EXE_LIBS = \ 链接库 -lfiniteVolume 4)删除原来的 obj 文件 rm –rf linuxGccDPOpt cd .. 5)编译 wmake 6) 检验一下 到 tutorial 目录,检验一下 myicoFoam . cavity 六.OpenFOAM 程序开发――例子一:在 icoFoam 中加入温度场求解 准备: 能量控制方程: dT/dt+div(den*U*T)=div(a gradT) 在壁面上给定值条件。 需要解决的问题: a)如何创建标量场,T b) 如何创建物性,a c)如何定义温度方程,并求解 d) 如何在算例中设定 T 和 a e)如何设定 T 的离散格式 f)如何设定 T 的求解器的收敛标准等 步骤:

1)创建程序需要的新物性和新变量场 打开 myicoFoam.C 可以看到,程序开始运行时调用 CreateFields.H,创建变量场。 打开 CreateFields.H,可以看到程序首先从 transportProperties 文件中读入物性, Info<< "Reading transportProperties\n" << endl; IOdictionary transportProperties ( IOobject ( "transportProperties", 从字典文件 transportProperties 读入

runTime.constant(), //transportProperties 文件位于目录 runTime.constant()中 mesh, 网格对象

IOobject::MUST_READ, IOobject::NO_WRITE ) ); 创建了 Iodictionary 类型对象 transportProperties dimensionedScalar nu ( transportProperties.lookup("nu") ); 创建有量纲标量 nu,nu 通过从字典 transportProperties 查找”nu”来赋值 可以加上新方程需要的物性 dimensionedScalar DT ( transportProperties.lookup("DT") ); 创建有量纲标量 DT,DT 通过从字典 transportProperties 查找”DT”来赋值 此外还要从 createFields 中读入 p,U 场,我们要加入的新的变量场为温度场 T,最快的加入温 度场的方法是拷贝 p 场的代码,修改为 Info<< "Reading field T\n" << endl; volScalarField T ( IOobject //首先读入热扩散率 //首先读入粘性系数

( "T", runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ), mesh ); 这样,创建了新的 vol 标量场 T,从文件 T 中读入。 对于 T 的创建具体解释如下: a)创建了标量场 T b)T 通过读(IOobject::MUST_READ)在 runTime.timeName()目录下名称为“T”的文件创建, 在开 始计算时,runTime.timeName()是 contorlDict 中设定的 startTime 值决定的。 c)T 将自动写入(IOobject::AUTO_WRITE)计算结果到 runTime.timeName()目录中, runTime.timeName()随迭代是变化的,写入控制由 contorlDict 中设定。 d)T 是定义在 mesh 对象上的, 这意味着 T 在内部 cell 上有值 internalField, 在边界上还需要边 界条件,这与 polyMesh/boundary 中要一致。 2)在求解器中加入新的求解方程 下一步回到 myicoFoam.C 加入新的微分方程,由于温度场依赖于速度场,可放在 PISO 循 环后面。 # include "continuityErrs.H" U -= rUA*fvc::grad(p); U.correctBoundaryConditions(); // Add the temperature equation fvScalarMatrix Teqn 温度是标量方程 ( fvm::ddt(T) + fvm::div(phi, T) 要用到界面流量

- fvm::laplacian(DT, T) 扩散项

); TEqn.solve(); 3)编译 wmake 4)在算例中加入新方程的初始和边界条件 4.1 拷贝一个 cavity 算例到 mycavity 4.2 修改 transportProperties 字典文件,设定 DT cd constant 修改 transportProperties 文件,前面已提到 DT 要从该字典文件读入。设定 DT=0.002m2/s DT DT [0 2 -1 0 0 0 0] 0.002; 求解

4.3 修改 T 文件,设定初始值和边界 cd 0 进入 0 目录 拷贝一个 T 文件 cp p T 修改 T 文件为 FoamFile { version format class object } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // dimensions [0 0 0 1 0 0 0]; 初始内部点为 300℃ 2.0; ascii; volScalarField; T;

internalField uniform 300; movingWall { type fixedValue;

value uniform 350.; }

边界为 350℃

fixedWalls { type fixedValue; 边界为 300℃

value uniform 300.;

5)修改离散格式和代数求解器求解控制文件 A 进入 system 目录 由于温度方程有非稳态项,对流项,扩散项,分别要在 ddt,div,laplacian 中设置 打开 fvSchemes 文件,添加 divSchemes { default div(phi,U) div(phi,T) } laplacianSchemes { default none; none; Gauss upwind; Gauss upwind;

laplacian(nu,U) Gauss linear corrected; laplacian(DT,T) Gauss linear corrected; laplacian((1|A(U)),p) Gauss linear corrected; } 在 fvSolution 中设置代数求解器选项 T PBiCG { preconditioner DILU; tolerance relTol }; 注意 T 方程形成的矩阵是非对称的,不要用 PCG 和 DIC 0; 1e-06;

6)运行 myicoFoam . mycavity 七.OpenFOAM 程序开发――求解器的详细分析 1 进入 icoFoam 目录 可以看到 createFields.H icoFoam.C icoFoam.dep Make/ Make/为 wmake 编译所需的文件 IcoFoam.C 为主程序文件,它包含 createFields.H 编辑 icoFoam.C 可以看到 icoFoam.C 首先引入的头文件为 fvCFD.H。 所以你可以看到,在编译选项 options 中 EXE_INC = \ -I$(LIB_SRC)/finiteVolume/lnInclude //fvCFD.H 的存放目录 EXE_LIBS = \ -lfiniteVolume //需要链接的库

找到 fvCFD.H,编辑,可以看出这些是主程序必须的类库 #ifndef fvCFD_H #define fvCFD_H #include "parRun.H" #include "Time.H" #include "fvMesh.H" #include "fvc.H" #include "fvMatrices.H" #include "fvm.H" #include "linear.H" #include "calculatedFvPatchFields.H" #include "fixedValueFvPatchFields.H" #include "adjustPhi.H" #include "findRefCell.H" 时间类 网格类 fvc 类 fvMatrix 类 fvm 类

#include "mathematicalConstants.H" #include "OSspecific.H" #include "argList.H" #ifndef namespaceFoam #define namespaceFoam using namespace Foam; #endif #endif 再看看 icoFoam 的程序体,了解一下求解程序的结构 #include "fvCFD.H" ――――――――――――――――(头文件) 通常位于 main 函数前,是程序所需的类的定义 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { ―――――――――――――――(包含文件) # include "setRootCase.H" # include "createTime.H" # include "createMesh.H" ―――――――――――包含文件通常是程序片断,如创建时间、创建网格等 ―――――――――――――――(求解器代码)―――――― # include "createFields.H" 需要根据应用,单独写的代码,如"createFields.H"和 Main,以及 Ueqn,pEqn 等 ――――――――――――――――――――――――――――――――――――― # include "initContinuityErrs.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 。。。。。 } 八.OpenFOAM 程序开发――求解器的详细分析 2 a.场变量的定义

引用前面的温度场 Info<< "Reading field T\n" << endl; volScalarField T ( IOobject ( "T", runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ), mesh ); 例如 volScalarField CO2 ( IOobject ( "CO2", runTime.timeName(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE ), mesh, // Optional declaration, this can be done by accessing a file in "case/0/" ,量纲可在文件中读 // dimensionedScalar("zero", dimensionSet(1,-1,-3,0,0,0,0), value) ); b.场变量的使用

场变量有定义在内部 cell 上的值,也有边界上的值 例如给组分限值 Example of a mass fraction limiter used in this project: // Initialize the variable Y_i for use in a loop scalarField& CO2Internal = CO2.internalField(); 引用内部点 // Loop for all mesh points 遍历内部点 forAll(CO2, celli) { // Limits the mass fraction to a positive number if (CO2Internal[celli] < 0.0) { CO2Internal[celli] = 0.0; } // Limits the mass fraction to max 1.0 if (CO2Internal[celli] > 1.0) { CO2Internal[celli] = 1.0; } } c.定义输运方程 OpenFOAM 定义方程时要选择一种类型的 fvMatrix,有 fvScalarMatrix 和 fvVectorMatrix 离散格式在 case/system/fvSchemes.中设定 // Define a ScalarMatrix as a object fvScalarMatrix CO2Eqn 定义系数矩阵 ( fvm::div(phi, CO2) 对流项离散 fvm::div

- fvm::laplacian(turbulence->nuEff(),CO2) 扩散项离散 fvm::div == S_CO2 ); // Apply underrelaxation to the equation 源项

// Under relaxation factors defined in file: fvSolution CO2Eqn.relax(); 松弛 CO2Eqn.solve(); 求解

运用 OpenFOAM 编译器 wmake 编译自己的程序
本文将 OpenFoam 的编译系统介绍一下, 并给出了如何在 OpenFOAM 下编译“hello world”程序。 OpenFOAM 用的编译器是 gcc,他并不是直接运用该编译器,而是将该编译器进行了包装,也 就是 wmake。OpenFOAM 中的头文件通常为 H 结尾,而代码文件是以 C 为扩展名,应当注意, 这里的 C 为大写的,如果写成小写,wmake 会出现编译错误,尽管你编写的代码没有错误。 运用 wmake 编译程序,程序所在的文件夹结构必须为如下形式

Make 所在的文件夹中放有主程序和在主程序用到的所有头文件, 这里面的代码文件和头文件名 字任意。Make 文件夹里面有两个文件 files 和 options,这两个文件的名字不能改变。 files 文件主要干两件事 (1)指定哪些文件需要编译,这里的文件是代码文件,也就是.C 文件,而不包括.H 文件 (2)指定你要编译的类型,是编译成库,还是编译成可执行文件,以及编译成的库文件或者可 执行文件的名字。 下面是 icoFoam 的 Make 文件夹下的 files 文件的内容 icoFoam.C EXE = $(FOAM_APPBIN)/icoFoam 要编译的代码文件直接将名字写到里面就行了,如果有多个代码文件,直接一个一个列在上面 就行了。 下面为编译程序类型 EXE=,说明要编译成可执行文件,等号右面为编译后的文件放在什么地 方。这一行也可以不写,他会将编译的可执行文件放到当前文件夹,名字为 OpenFOAM.out.

如果你要编译成库的话请采用”“LIB= ...”等号后面放编译的库文件所在的目录, 一般编译库文件 命名为 lib...,这是一个习惯,而非规定。 options 文件也是干两件事 (1) 指定编译的头文件所在的目录, 如果说所用的头文件在当前文件夹或者标准 C++的头文件, 无需指定。 (2)指定编译当前程序所用到的库。 下面为 icoFoam 下的 options 文件的内容 EXE_INC = \ -I$(LIB_SRC)/finiteVolume/lnInclude EXE_LIBS = \ -lfiniteVolume EXE_INC=用于所运用到的头文件所在的目录,EXE_LIB 用来指定所有到的库。注意这里的库 为 OpenFOAM 中的库或者你自己写的库,C++的标准库无需在这添加。 因此如果你不使用 OpenFOAM 中的库,而是自己独立编写 C++程序,并且所有的头文件都在 当前的根目录,options 里无需指定任何东西。 下面是一个简单的“Hello world”c++程序,按照我说的方法试一试? 第 1 步:建立一个目录,用于编译当前的 Hello world 程序? 下面为当根目录建立一个 hello 的文件夹,并进入 hello 文件夹。 cd //进入根目录 mkdir hello //建立文件夹,名为 hello cd hello //进入 hello

第 2 步: 建立 Make 文件夹,并进入 Make 建立 files 和 options 文件 mkdir Make cd Make //建立 Make 文件夹

//进入 Make

touch files //创建 files 文件 touch options //创建 options 文件 cd.. //退出 Make 文件夹 第 3 步:建立程序文件 hello.C, 打开 hello.C 进行编程序 touch hello.C //创建 hello.C kate hello.C //打开 hello.C

输入如下代码 #include"iostream" using namespace std ; int main () { cout<<"hello world"<<endl; } 关闭 kate 第 4 步:在 files 指定编译文件,hello.C cd Make //进入 Make kate files //打开 files 将下面的东西输入进去 hello.C EXE=hello 关闭 kate 第 5 步:程序编译 cd .. //退出 Make 文件夹 wmake //编译程序 第 6 步:看结果 ./hello

残差问题探讨
在实际的流体模拟中通常以残差作为收敛的判据,有时候为什么残差永远降不下来呢?到底求 得的数据是否可信呢?今天我们聊聊残差问题。 在 CFD 计算过程中有两种残差一种是外残差一种是内残差。 残差是当前时刻的时刻的收敛数据 带入到下一个时刻的方程中而引起的残差,而内残差是求解代数方程中引起的残差。

外残差: 对于方程 f(x,t)=0 在 t_0 时刻有收敛解 x_0, 则 f(x_0,t=t_0)=0; 当用 t0 时刻的结果代 入到 t1 时刻的方程时,通常并不能满足方程,即 f(x_0, t = t_1) = r !=0; 这里的残差 r 称为外残 差。 内残差:在 cfd 计算中通常将方程转化为代数方程 Ax=b;当得到某个解 A*x_0-b = r1; 这里的 r1 ->0 时,认为 Ax=b 收敛。 这里的 r1 为内残差。 对于稳态问题:只有当 r->0 时,才被认为收敛,也就是(x_1 - x_0)->0. 也就是我们在 cfd 计算 中通常见到的那个残差,fluent 及其 pyFoam 输出残差图就是这个 r。r 常被作为收敛判据。 对于非稳态问题, 下一时刻的求解结果用于和当前的求解结果不一样 (时变的, 也就是非稳态) , 这时候 r 并不是很小,对于特定的问题,这个 r 永远不可能很小(因为是非稳态问题),所以对于 非稳态问题外残差 r 不能作为收敛判据。 无论是稳态还是非稳态,都必须是代数方程 Ax=b 收敛,r1->0 时,是必须满足的。但是在稳态 计算中,由于某一个迭代的结构没有意义,这时候为了减少计算量通常给定一定的迭代次数, 而并不是设定 r1 必须满足一定的限制。这是 fluent 采用的一种手段。而对于非稳态问题,由于 我们关心某一个时刻的值,这时候必须是 r1->0,使得求解的代数方程收敛,因此 r1 才是作为 非稳态问题的收敛判据。 在 openfoam 中两个残差都有,外残差就是你在迭代过程中的输出屏幕上看到的那个 initial residual, 而内残差就是求解某一个方程迭代一定后的那个残差, 内残差 r1, 可以通过在 fvSolution 里面的代数方程求解器中设定,relTol(相对残差)tol(绝对残差)。两者的区别不用说了吧。 外残差只对稳态的求解器有,就是 fvSolution 下的 Simple 字典下的 convergence,可以通过下 面方法设置 Simple { convergence } 1e-6;

当所有方程残差外残差小于 1e-6 时,认为收敛,求解器停止计算。

OpenFOAM 中非均匀初始场的设定
采纳网友的建议, 这次讨论 OpenFOAM 中非均匀初始场设置问题。 对于 openfoam 非均匀场初 始化现成程序有两个: 1)OpenFOAM 自带功能 setFields 2) 社区中的 funkySetFields. 下面介绍一 下两者的使用。 1 setFields 的使用 使用 setFields 只需要将 system 文件夹中建立 setFieldsDict,然后在其中设置相应的参数,设置 完后,在 case 根目录下利用控制台输入 setFields 就可以了。下面介绍一下 interFoam 算例中的 setFieldsDict.该字典位置在 OpenFOAM-1.6/tutorials/multiphase/interFoam/laminar/damBreak/system/setFieldsDict ,文件中的 内容为 FoamFile //文件头 { version format class location object } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // defaultFieldValues //用来设定场的默认值 ( volScalarFieldValue alpha1 0 ); // 设置场 alpha1 的默认值 2.0; ascii; dictionary; "system"; setFieldsDict;

regions //设置 alpha1 不为 0 的区域 ( boxToCell // 方形区域内的 cell

{ box (0 0 -1) (0.1461 0.292 1); //方形区域的边界,两点 xyz 最小点和 xyz 最大点 fieldValues ( volScalarFieldValue alpha1 1 //用来 alpha1 场在上面 box 区域内的值的大小 ); } ); setFields 对于规则区域定值使用比较方便,但是很难实现比较复杂内部场的设置,比如满足 某种关系式的内部场设置。 2 funkySetFields 的使用 用来设定比较复杂的内部场。 可以指定满足一定条件的关系式的初始场。 2.1 软件的获取 funkySetFields 在官方或者 dev 版本里面都没有该功能, 可以通过下面命令获取。 运行下面的 命令需要你的电脑安装 svn。 svn checkout //用来指定定值

https://openfoam-extend.svn.sourceforge.net/svnroot/openfoam-extend/trunk/Breeder_1.6/utilities/pos tProcessing/FunkySetFields/

2.2 软件的安装 该软件安装比较简单,直接进入该文件夹,并运行 Allwmake ./Allwmake 2.3 使用 2.3.1 常用关键字
field //用来指定要修改的场 expression_r //用来指定表达式 condition //用来指定上述表达式应当满足的条件 keepPatches //用来说明是否保持原来边界条件,最好加上,不加的话,funkySetField 会给所有 边界为 0 梯度 create //用来说明是否是新建场 valuePatches //用来指定那些定值边界由临近内部节点值给定

dimension //用来指定新建立场的单位 time //用来指定 funkySetField 所指定的时间点 应当指出,上述关键字可以直接在控制台上输,也可以写在名字为 funkySetFieldsDict(类

似于 setFieldsDict)中。 2.3.2 使用方法 方法 1 直接在控制台输入

直接进入你要初始话的 case 中,输入类似于下面的命令。如上面的 setField 也可以通过 下面的 funkySetFields 命令来实现 funkySetFields -time 0 -keepPatches -field alpha1 -expression_r "1" -condition

"pos().x <= 0.1461 && pos().y <= 0.292" 注意比较长的式子用单引号或者双引号隔开。 上述关键字没有次序要求。 方法 2 使用 funkySetFieldsDict 字典

方法和上面 setFields 差不多,在 system 文件夹中建立 funkySetFieldsDict 字典文件, 对于上面表达式可以通过下面字典文件实现。 expression_rs ( alpha { field alpha1; expression_r "1"; //操作的场 //表达式 // 设置 alpha1,名字任意 //设置复杂内部边界入口

condition "pos().x <= 0.1461 && pos().y <= 0.292" ;//执行上述表达式的条件 keepPatches } pressure1 { field p; //指定操作场 //执行表达式子,无条件 //设置压力,名字任意 true; //是否保持以前边界

expression_r "10.*(0.1-pos().y)"; } pressure2

{ field p; 指定表达式 //表达式子 //条件

expression_r "p+U&U";

condition "pos().x > (max(pos().x)-min(pos().x))/2"; } );

从上面可以看出,使用 funkySetFieldsDict 可以实现更为复杂内部场,且可以同时对多个 场进行操作 2.3.3 表达式中的常用支持 也许你已经注意到, 上面例子中 condition 和 expression_r 使用了表达式, funkySetFields 中你可以使用下列常用的操作符或者函数
1) C++基本操作符 +,-,*,/,%, <,>,<=,>=,!=,==, &&,||,? : 2)OpenFOAM 定义的向量操作符 &,^ 3)圆周率常量 pi 4)标量函数 pow,log,exp,sqr,sqrt,sin,cos,tan 5)OpenFOAM 中的一些函数 mag:求模 grad :求标量梯度 curl :求向量旋度 snGrad:表面法向剃度 div :向量场散度 laplaction :求一个场的 laplacian 项目 min,max :标量场的最值 pos :网格中心位置矢量 fpos :面中心位置矢量

face :表面法向量场 area:表面面积场 vol :网格单元体积场 deltaT :时间步长 time :当前时间 setFields 和 funkySetField 可以实现比较复杂的内部场初始化,而对于复杂的边界场,你要自定 义边界条件了。

使用 OpenFOAM 的基本流程
任何 CFD 软件的使用无非通过 3 个基本步骤: 前处理,CFD 计算,后处理 前处理主要包括:网格的生成,物理参数的设定,初始边界条件的设定,求解控制设定,方程 求解方法的选择,离散格式的选择。

网格生成:
OpenFOAM 带有自己的网格生成功能 blockMesh,他可以生成块结构化网格,使用比较简单, 但对于复杂几何,该功能实施比较复杂。 可以采用其网格软件如:gridgen,pointwise,gambit,icemcfd,tetgen,gmesh,ansys 等生成网 格, 通过网格转换功能将其转换为 openfoam 可识别的网格。 我本人通常采用 gridgen 生成 fluent 网格,再采用 fluentMeshToFaom 功能转换为 openfoam 可识别网格。

物理参数的设置:
OpenFOAM 中的物理参数文件都在当前 case 文件夹里面的 constant 文件夹中,里面常用的 文件通常常有 environmentalProperties:设定环境参数,重力加速度 transportProperties:传输相关参数,比如黏性,密度,对于非牛顿流体的黏性模型及其参数 等 LESProperties:大涡模型及其相关的模型参数 RASProperties: 雷诺时均模型及其相关模型参数 thermodynamicProperties:热物理相关参数 这些文件的名字由 solver 里面定义,可以任意更改,上面书写是 openfoam 中的一个惯例, 至于如何更改,请参看 solver 说明。

初始边界条件的设定:
初始条件和边界条件设定都在 case 文件夹中的 0 文件夹中,在 Openfoam 中,每个求解变量都 有自己的单独的求解文件,下面以/OpenFOAM/OpenFOAM-1.5/tutorials/icoFoam/cavity/0/p 压力 文件为例进行说明 FoamFile { version format class object } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // //场的单位,应当注意这里的压强单位并非实际压强,而是压强除去密度(p/rho)的单位 //因为 openfoam 对动量方程直接求解的速度 dimensions [0 2 -2 0 0 0 0]; 2.0; //版本号 ascii; //存储形式二进制或者 ascii volScalarField;//场的类型,体心标量场 p; //场的名字 //文件头

//初始条件:内部场为均匀场,所有全为 0,如果不均匀场则采用 setField 或者 funkySetField 对 初始场进行//设置,如何使用这些功能,以后再说明。 internalField uniform 0; //边界条件 boundaryField { movingWall { type } fixedWallsm //边界名字 { type } frontAndBack //边界名字 zeroGradient;//边界条件为第二类边界条件,梯度为 0 zeroGradient; //边界条件为第二类边界条件,梯度为 0 //边界名字

{ //空边界条件,说明求解是二维流动,这个在 openFOAM 是独有的,如果遇到该类边界,该边 界不参与方程离//散,也就是什么都不做。 type } } empty;

求解控制设定:
文件为 system/controlDict,典型的 controlDict 文件如下 //文件头 FoamFile { version format class object } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // //当前 case 所用求解器的名字 application icoFoam; //程序从什么时候开始执行,startTime 开始 startFrom startTime; 2.0; ascii; dictionary; controlDict;

//startTime 设定为 0,即从 0 时刻开始执行 startTime 0;

//程序什么时候结束,endTime 结束 stopAt endTime;

//程序结束时间 endTime 0.5;

//当前算例的时间步长 deltaT 0.005;

//以什么方式写文件,按照时间步长写(也可以为 runTime,即按照时间来些)

writeControl

timeStep;

//20 个时间步长,20*timeStep 写一次; (如果按照时间来写的话为 1) writeInterval 20;

//写过程是否覆盖,如果 0 则不覆盖,大于 0 为覆盖,比如:2,case 文件家中只有输出文件 比 如 6 和 7,//当算到 8 时候,会覆盖 6,9 会覆盖 8,以此类推 purgeWrite 0;

//写的格式 ascii 或者 binary writeFormat ascii;

//文件写入精度 writePrecision 6; //是否对生成数据进行压缩,压缩的话会战较少空间。uncompressed/compressed; writeCompression uncompressed; //时间文件夹格式:fixed m.ddddd(d 的个数取决于下面的 timePrecision) ,scientific :采用科学 计数//法,general:科学计数法指数小于-4 用指数,大于-4 用小数 timeFormat general;

//时间文件夹精度 timePrecision 6;

//在求解过程中是否允许修改以上参数 runTimeModifiable yes;

方程求解方法的选择:
文件为 system/fvSolution,典型的文件为 //文件头 FoamFile { version format class object } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 2.0; ascii; dictionary; fvSolution;

solvers //方程求解器 { p PCG //压力采用预条件共轭梯度法(主要用于求解对称矩阵) { preconditioner tolerance relTol }; U PBiCG //速度采用预条件双共轭梯度法(主要用于反对称矩阵) { preconditioner tolerance relTol }; } PISO //piso 控制参数 { nCorrectors 2;//修正次数 DILU; //预测器,对角不完全 LU 1e-05;//残差 0; //迭代容差 DIC; //预测器,对角不完全 Cholesky 方法

1e-06; //参差 0; //迭代容差

nNonOrthogonalCorrectors 0;//非正交修正次数 pRefCell pRefValue } 如果对求解器不明白,可以参看相关理论,或者直接找到一个差不多的 case 进行复制。 0;//压力参考 cell 的 index 0;//压力参考值

离散格式的选择:
文件:system/fvSchemes,典型文件 //文件头 FoamFile { version format 2.0; ascii;

class object }

dictionary; fvSchemes;

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // //非稳态格式 ddtSchemes { default } gradSchemes //梯度离散 { default grad(p) } divSchemes //散度离散 { default div(phi,U) } laplacianSchemes //拉普拉斯项离散 { default none; //拉普拉斯项离散,必须指定 none; //散度的离散(必须指定没有默认值) Gauss linear;//梯度离散采用高斯方法,线性插值 Gauss linear; //压力的梯度离散 Euler; //默认采用欧拉离散,其他格式以后介绍

Gauss linear;//对流项离散,高斯理论,采用线性插值

laplacian(nu,U) Gauss linear corrected; //扩散项离散采用高斯理论,采用线性插值,并带有非 //网格正交修正 laplacian((1|A(U)),p) Gauss linear corrected;//压力方程离散采用高斯理论,线性插值,带有非// 网格正交修正 } interpolationSchemes //插值格式 { default linear; //默认线性插值

interpolate(HbyA) linear;//线性插值 } snGradSchemes//梯度发法向分量 { default } fluxRequired //是否计算流律 { default no; //默认不计算 corrected;//默认带有非正交修正

p;//压力需要计算,因为需要利用压力流律修正速度 } CFD 计算: 设定上述参数后,直接在 case 文件中,在控制台中输入相应求解器的名字即可。如果参数设置 有误,会得到提示。 后处理: openfoam 推荐的后处理软件为 paraview, 当然你可以运用 foamToTecplot 功能将其转换为 tecplot 格式运用 tecplot 进行处理,或者运用 foamDataToFluent 转化为 fluent 格式进行后处理,所有支 持的转化在/OpenFOAM-1.5/applications/utilities/postProcessing/dataConversion 文件夹中。

Windows 下 OpenFOAM 开发及使用环境配置指南
OpenFOAM 是一款优秀的开源 CFD 软件, 其实更应该称作是一个程序库, 用户可以在其平台上进行 源码级开发. 目前 OpenFOAM 已经拥有大量的 CFD 求解器可供使用. 更重要的是, 它是完全免费的. 更更重要的是, 我们可以在其提供的 CFD 类库(网格, 场, 离散算法)基础上任意进行二次开发, 从而 配置出适用于自己的 CFD 程序. 更更更重要的是, 我们可以在不违背 GPL 协议的前提下任意分发 软件, 不存在使用其他盗版商业软件的违法问题(虽然这每时每刻都在发生, 也许你的 Windows 就 是盗版...). Anyway, 无论从哪个角度来讲, OpenFOAM 都是 "FREE" 的. 尤其对于科学研究来讲, OpenFOAM 非常适合开发 CFD 模型,在面向对象的设计体系下, 代码重用和模型扩充会为你的科研 积累增色不少. OpenFOAM 的开发源于 Linux, 这对只熟悉 Windows 的用户来说是个噩耗, 尤其在中国更多的人 习惯于使用 Windows. 作为研究人员 , 可以花上几个星期去钻研 Linux, 从而适应在 Linux 下的

OpenFOAM 开发及使用. 然而如果你把自己的程序交付给别人使用时, 让他在早已习惯于 Windows 的情况下去重新学习另一个操作系统, 恐怕还是太费劲儿了点儿. 即便是自己研究之用, 有时一些 前后处理软件我们已经习惯了使用 Windows 版本, 在不同系统之间切换还是一件烦人的事情(有朝 一日在学界 TeX 取代了 MS Word 时或许就不用切换了). 另外更多的情况是, 你的实验室里大多数机器跑的都是 Windows, 如果你要把 OpenFOAM 程序 放到上面运行, 那麻烦也来了...总而言之, 我们还需要一个 Windows 版本的 OpenFOAM. 一些人在这方面做了工作. 早在 OpenFOAM 还处于 1.2 版本时, 便有人将其通过 Cygwin 移植到 Windows 下. 到今天发展到 1.7 版本, 虽然断断续续, 但总有人在做. Cygwin 是 Windows 下的模拟 Linux 环境 , 可以进行程序开发 , 但得到的程序需要依赖于 Cygwin 环境运行 , 当然也可以脱离 Cygwin 环境, 将程序(exe, dll)打包然后移植到其他计算机上,但必须带上 cygwin1.dll, 因为程序对 Windows 的一些调用都是通过 cygwin1.dll 实现的, 这也就加大了计算的开销, 对讲求效率的 CFDer 来说, 绝不是一个好消息. 但 Cygwin 的一个好处是可以在 Windows 下进行程序开发, 这对使用 Windows 从事科研工作的人是个好消息. 另一套解决方案是在 Linux 下通过交叉编译得到 Windows 下可执行的 OpenFOAM 程序, 交叉 编 译环境采用 MinGW. MinGW 可以看做一个平台, 也可以看做 gcc 的一个版本, 它可以使你在 A 操 作 系 统 上 编 译 得 到 B 操 作 系 统 的 程 序 . Symscape (http://www.symscape.com) 和 blueCAPE (http://www.bluecape.com.pt) 公司在这方面做了大量的 port 工作,他们的产品分别是 OpenFlow 和 blueCFD. 他们在提供有偿服务的同时,也公开了其 port 方案和相应的的 patch, 尤其是 blueCAPE 的 Bruno Santos 还在 OpenFOAMWiki 上维护了一个相当全面详细的页面(见后参考链接). 这种采 用交叉编译得到的 OpenFOAM 由于不存在 Cygwin 这一层的调用,因此其运行速度较之前一种解决 方案会有所提升. 但是这种方案下的缺点是显而易见的, 开发过程还只能在 Linux 下进行, 系统切换 仍然是个问题. 如果能在 Windows 下利用 Cygwin 环境进行开发, 同时编译的程序又能脱离 Cygwin 运行, 那是再 好不过了. 这样可以在一个操作系统下同时进行开发/调试和运行, 就像 Windows 的 native 程序一样, 不失为在 Windows 下使用 OpenFOAM 的最理想目标了. Cygwin + MinGW 为这种目标的实现提供了 可能. 在 Wyldckat(Bruno Santos @blueCAPE 的 OpenFOAMWiki ID)的 wiki 页面上描述了该解决方 案, 但对于 OpenFOAM 的编译过程, 主要还是针对在 Linux 下利用 MinGW 进行交叉编译的情况. 对 于 Cygwin 下的 MinGW 编译, 需要有一些修改的地方,本文把这些实现的细节做一总结描述, 作为该 wiki 的补充, 主要目的还是给中国的用户/同行做些参考, 尤其是对于年轻的研究生/博士生, 作为科 研的主力军, 深入到 OpenFOAM 这样的专业软件中做些扎实的研究还是有益的, 能让你在方法层面

更加深刻地理解 CFD, 至少比拿 Fluent 算点东西就发 paper, 凑合着混毕业要好得多. 需要说明的是, 这种配置/开发/运行方案也有一个不足, 就是编译出来的程序在 Cygwin 环境下 无法运行, 而需要在 Windows 的命令行(或 bat 文件)来使用. 对习惯了使用 Cygwin/Linux 的人来说 有点不爽, 好在 MinGW 的开发者提供了 MSYS 环境, 经过简单的配置,我们可以在 Windows 下按 Linux 的习惯来运行程序. 这样, Cygwin+MinGW 做开发, MSYS 作运行环境,打造出一个 Windows 下开发及使用 OpenFOAM 的 CFD 环境. 基本环境: ~~~~~~~~ 操作系统:Windows 7 Ultimate 32 bit Linux 环境:Cygwin 1.7 32bit OpenFOAM: 1.6 并行环境:MPICH2 配置过程: ~~~~~~~~ 1. Install Cygwin (国内镜像 www.cygwin.cn) (1) 除基本安装外,还需安装以下包: autoconf automake binutils bison byacc diffutils patch doxygen flex gcc-core gcc-g++ git make python readline texinfo wget w3m (2) 其余建议安装包: bzip2 gitk liblzma rxvt vim 2. 修改注册表, 使系统区分大小写 (1) HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\ kernel\ObCaseInsensitive 设为 0. (2) 重启系统使应用生效. 3. 配置 Cygwin (1) 启动 Cygwin, home/<user>目录将依据当前 Windows 用户创建. 若用户名存在空格, 则需要在 Cygwin 根目录下的 /etc/passwd 中将映射名改为无空格的用户名标识, 并重启 Cygwin. (2) 在 Cygwin Shell 中输入 mkdir OpenFOAM echo export TEMP=/tmp >> ~/.bashrc

echo export TMP=/tmp >> ~/.bashrc 以创建 OpenFOAM 安装目录并使 TEMP/TMP 变量有效. (3) 在 Windows 中建立文件夹, 用于 mount OpenFOAM 及 tmp 目录: 在/etc/fstab 中添加 <of_dir> /home/<user>/OpenFOAM ntfs binary,posix=1 0 0 <tmp_dir> ntfs binary,posix=1 0 0 其中<of_dir> 为 OpenFOAM 的实际安装目录, <tmp_dir>为实际临时目录. patch 命令的运行依赖/tmp 目录. - NOTE: 将以上目录设在根目录下比较方便, 且保持命名简洁易记. (4) 重启 Cygwin 使修改生效. 输入 ln -s /usr/bin/cpp /lib/cpp 以使 wmake 正确运行. 4. 安装 OpenFOAM (1) 下载 OpenFOAM-1.6.General.gtgz, ThirdParty-1.6.General.gtgz 解压到安装目录 tar xzf OpenFOAM-1.6.General.gtgz tar xzf ThirdParty-1.6.General.gtgz (2) 下载 PatchesNBatches.tar.gz 并解压到$HOME/OpenFOAM 目录. 在该目录下运行命令 patch -p0 < pnb/OpenFOAM-1.6_patch patch -p0 < pnb/ThirdParty-1.6_patch (3) 修改脚本, 配置 OpenFOAM 环境 (3a)在$HOME/.bashrc 文件中添加下面一行: source $HOME/OpenFOAM/OpenFOAM-1.6/etc/bashrc-mingw32 使 OpenFOAM 配置随 Cygwin 启动生效. bashrc-mingw32 中需将 case $WM_ARCH in Linux)中的"Linux)"改为"*)", 以使 Cygwin 能够假冒 Linux. (当然也可以加入 Cygwin 选项, 但会涉及到一些需要适应 OpenFOAM 的规则配置, 如 wmake rule 等, 不建议使用. 这种假冒策略是一个 trick, 如果仅是本人在 cygwin 下使 用, 这种做法足够, 且可将源码修改降至最低. 至于考虑平台可移植性的通用性设置, 则应 该是 OpenFOAM 发布者该做的事情) (3b)重启 Cygwin, 发现有编译器未安装的警示信息, 不用理会, 这是因为 OpenFOAM 认为编译器是 mingw32, 有错误提示是正常的. 我们需要做的检查当前系统是否含有 gcc(用 gcc -v 命令, 我的版本是 3.4.4)

(3c)运行以下 chmod 命令以使新 patch 的 script 文件正确运行 chmod 744 $WM_THIRD_PARTY_DIR/build-mingw32 chmod 744 $WM_THIRD_PARTY_DIR/build-mingw-w32 chmod 744 $WM_THIRD_PARTY_DIR/build-mingw-w64 chmod 744 $WM_THIRD_PARTY_DIR/build-mingw-w64-45 chmod 744 $WM_THIRD_PARTY_DIR/makeGcc44 chmod 744 $WM_THIRD_PARTY_DIR/get-mpich2 chmod 744 $WM_PROJECT_DIR/src/Allclean chmod 744 $WM_PROJECT_DIR/applications/utilities/parallelProcessing/Allwmake chmod 744 $WM_PROJECT_DIR/bin/tutowin chmod 744 $WM_PROJECT_DIR/bin/foamDiff chmod 744 $WM_PROJECT_DIR/bin/backupSourceFolder chmod 744 $WM_PROJECT_DIR/bin/backupFullFolder (3d)下载 mpich2-1.1.1p1-win-ia32.msi 文件, 安装 32 位 MPICH2 1.1.1p1, 将安装 目录下的 bin, include 和 lib 文件夹拷贝至 ThirdParty-1.6/mpich2-1.1.1p1. (3e)修改 bashrc-mingw32:将 WM_GETMPICH2 设为 DONTGETMPICH2 重启 Cygwin 使编译 mingw32 的环境设置生效. (4) 编译 mingw 交叉编译器 mingw32 (4a)将 ThirdParty-1.6/build-mingw32 脚本中以下变量对应的文件下载到 ThirdParty-1.6/mingwcc/source 目录(手动创建).当然也可以下载这些 package 的最新版本, 但需注意要同时在脚本中修改相应的名字. BINUTILS_ARCHIVE="binutils-2.19.1-src.tar.gz" MINGW_ARCHIVE="mingwrt-3.15.2-mingw32-dev.tar.gz" W32API_ARCHIVE="w32api-3.13-mingw32-dev.tar.gz" REGEX_ARCHIVE="mingw-libgnurx-2.5.1-bin.tar.gz" REGEX2_ARCHIVE="mingw-libgnurx-2.5.1-dev.tar.gz" (4b)针对 Cygwin 环境修改 build-mingw32 脚本: * BUILD=`uname -m`-$WM_ARCH-gnu 改为 BUILD=`uname -m`-pc-cygwin * do_gmp, do_mpfr 函数中将--host=$TARGET 改为--host=$BUILD * do_mpfr 函数中--enable-thread-safe 改为--disable-thread-safe

(4c)在 ThirdParty-1.6 目录下输入命令 ./build-mingw32 GCC-4.3.3 运行脚本, 等待命令完成. (约数小时, 期间若有 tar 错误或者 no file or directory 错误, 不用理会.) (5) 配置 wmake 编译环境. (5a)建立 flex++链接: 将 alias flex++='flex -+' 命令加入到 OpenFOAM-1.6/etc/alias.sh 中 (5b)修改 wmake rules. (我们现在的平台是"linux", 编译器是 mingw32, 因此要改 的是 OpenFOAM-1.6/wmake/rules/linuxmingw32 文件夹中的内容) * mplibMPICH 中-lmpich 改为-lmpi, 删除-lrt * general 中删除 include $(GENERAL_RULES)/byacc include $(GENERAL_RULES)/btyacc++ 加入 include $(GENERAL_RULES)/version include $(GENERAL_RULES)/bison (5c)修改 zlib 配置. 将 ThirdParty-1.6/zlib/Make 目录拷贝至 ThirdParty-1.6/gcc-4.3.3/zlib (5d)重启 Cygwin, 使修改生效 (6) 到 OpenFOAM-1.6 目录, wclean all && ./Allwmake, 完成.

********************************************************************************* 参考链接: ~~~~~~~~ http://openfoamwiki.net/index.php/Tip_Using_Cygwin_for_cross-compiling_OpenFOAM http://openfoamwiki.net/index.php/Tip_Cross_Compiling_OpenFOAM_1.6_in_Linux_For_Windows_ with_MinGW https://trac.handbrake.fr/wiki/CygWin http://www.bluecape.com.pt/ (blueCAPE) http://www.symscape.com/ (OpenFlow)

http://ftp.twaren.net/Unix/GNU/gnu/ http://heanet.dl.sourceforge.net/sourceforge/mingw 注意事项: ~~~~~~~~ *** <*>表示依赖于用户系统的一些变量, 用户需根据自己的系统配置来设定. *** Cygwin 只有 32 位的安装版本, 因此对 gmp, mpfr, gcc 的编译过程来说, 系统都是 i686, 而不是 x86_64, 在 Cygwin 中输入 uname -m 可确认这点 *** 以上配置过程请按顺序进行 *** 如格式不齐, 请拷贝到 txt 文档中用等宽字体查看本文档 文件下载: ~~~~~~~~ OpenFOAM-1.6.General.gtgz: http://downloads.sourceforge.net/foam/OpenFOAM-1.6.General.gtgz?use_mirror=mesh ThirdParty-1.6.General.gtgz: http://downloads.sourceforge.net/foam/ThirdParty-1.6.General.gtgz?use_mirror=mesh PatchesNBatches.tar.gz: http://openfoamwiki.net/images/e/e2/PatchesNBatches.tar.gz mpich2-1.1.1p1-win-ia32.msi: http://www.mcs.anl.gov/research/projects/mpich2/downloads/tarballs/1.1.1p1/mpich2-1.1.1p1-win-ia32.m si mingw 相关文件: http://heanet.dl.sourceforge.net/sourceforge/mingw