最近在进行计算的时候,为了提高并行效率,我决定手动进行OpenFOAM并行网格的划分。一般来说,提高并行效率可以从两个方面着手:
一般来说,如果网格比较简单,可以轻易使用simple方法划分,如果网格比较复杂,可以用scotch方法划分(关于各划分方法可以查看这篇文章)。但是对于一个几何结构比较简单但是网格分布不均匀的网格,使用simple和scotch都不太好获得比较好的划分结果,因此我决定自己进行手动划分。
网上关于手动划分并行区域的教程有很多,主要可以参考:
CFD中国帖子1
CFD中国帖子2
xiaopingqiu的博客文章
CFDonline帖子
通过阅读以上资料我们可以获得手动分区的一般步骤,但这些资料在一些关键步骤上却说的不是很明白,按照这些教程在OF7环境下无法实现较大网格量的手动分解。经过一段时间的摸索,我找到一种行之有效的实现方法:
为了实现手动并行区域的划分,我们首先需要在/system/decomposeParDict中将划分方式修改为manual
,之后需要在manualCoeffs
中指定划分区域的数据文件。关于该数据文件,我们可以在OpenFOAM主文件夹中搜寻“manualDecomposition”,得到一个范例文件:
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: 7
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class labelList;
location "constant";
object cellDecomposition;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
400
(
0
0
...
...
0
0
)
// ************************************************************************* //
这是一个labelList类型的文件,可以看到其中最主要的信息是中间按照网格ID排列的一些列labe值,0就代表我们将其划分到processor0号CPU中,以此类推。我们要做的最主要工作就是生成一个这样的文件。
首先,我们先在decomposeParDict中将划分方式设置为simple,simple的具体划分方式没有影响。之后在算例主目录打开终端并执行decomposePar -cellDist
。该命令执行后会在划分网格的同时在0文件夹中生成一个cellDist标量场。我们把划分得到的没有用的processor0-n的文件夹全部删除,我们主要利用的就是cellDict这个场。通过paraview我们可以发现,cellDist场是将并行划分的结果用一个标量场表达出来,属于0号CPU的网格区域对应的标量值就是0,属于1号CPU的网格区域对应的标量值就是1…以此类推。如果不想使用cellDist场,自己复制一个空白的标量场文件也可以。
接下来我们使用setFields工具对标量场进行赋值,赋值的原则是将想要划分到0号CPU的网格的标量值设置为0,以此类推。下面我们给出一个例子,大家可以使用setField的丰富功能实现复杂区域的划分:
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 1.5 |
| \\ / A nd | Web: http://www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object setFieldsDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defaultFieldValues
(
volScalarFieldValue cellDist 0
//volScalarFieldValue rhoe 1e-11
);
regions
(
boxToCell
{
box (0 0 0)(0.00072 0.003 0.001);
fieldValues
(
volScalarFieldValue cellDist 0
);
}
boxToCell
{
box (0.00072 0 0)(0.00144 0.003 0.001);
fieldValues
(
volScalarFieldValue cellDist 1
);
}
...
...
);
// ************************************************************************* //
执行setFields命令即可对场进行划分,划分后我们可以使用paraview查看一下重新设置的场cellDist场,看看划分结果是否符合我们的预期。
生成的cellDist场
用记事本打开上面得到的cellDist场,我们可以发下如下的文件结构:
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: 7
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format binary;
class volScalarField;
location "0";
object cellDist;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField nonuniform List<scalar>
120000 //网格数目
(...... //标量场信息);
boundaryField
{......}
可以发现,标量场的文件格式与手动划分需要的labelList类型文件有一些区别。需要注意的是,即使我们将cellDist标量场的开头替换为标准的labelList开头,删除文件尾的边界条件信息,也无法让decomposePar工具识别。这个原因在于标量场每一个网格存储的值使用特殊的分隔符进行分隔,而labelList的值是按照回车符进行分隔的。这一特点可以使用记事本打开一个标量场文件和一个labelList文件对比一下直观获得。
开头提到的所有文章都没有给出一种优雅的方式进行文件格式的转换,在这里,我们使用OpenFOAM编程的方式进行文件转换。新建一个空白的C++文件,输入以下代码:
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see .
Application
scalar2Label
codeBy CloudBird, HIT,[email protected]
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
Info<< "Reading scalarField\n" << endl;
volScalarField manualField
(
IOobject
(
"cellDist",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
const volVectorField& center = mesh.C();
labelIOList finalDecomp
(
IOobject
(
"manualDecomposition",
mesh.facesInstance(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE,
false
),
labelList (center.size())
);
Info<< "Making manualDecomposition file\n" << endl;
forAll(center, cellID)
{
finalDecomp[cellID] = manualField[cellID];
}
finalDecomp.write();
Info<< "Done\n" << endl;
return 0;
}
// ************************************************************************* //
将以上文件保存为“scalar2Label.C”,使用wmake进行编译即可。大家也可以直接下载我写好的代码,链接在我的CSDN下载页和本博文对应的资源中。
编译完成后在算例目录下执行scalar2Label
即可将cellDist文件转化为一个manualDecomposition文件,存储在constant文件夹下。之后仅需要在decomposeParDict指定手动分区的文件为manualDecomposition然后执行decomposePar
即可完成手动并行分区的划分。