16_meshRatio
0. 前言
我们基于前文对网格的讨论,来尝试一个计算网格参数的应用,便于读者练习和理解网格以及 OpenFOAM 项目流程。
本项目代码来自于 Tom Smith 讲义《programming with OpenFOAM》(Tutorial at The 3rd UCL OpenFOAM Workshop)。
本文主要讨论
- 练习网格类方法的使用
- 考虑代码的运行效率
- 复习自定义字典文件的使用
- 编译运行 meshRatio 项目
1. 项目准备
终端输入命令,建立项目
ofsp
foamNewApp ofsp_16_meshRatio
cd ofsp_16_meshRatio
cp -r $FOAM_TUTORIALS/incompressible/simpleFoam/pitzDaily debug_case
code .测试初始求解器,提供脚本和说明。
2. 网格体积比
主源码修改为
#include "fvCFD.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
const scalar c = mesh.C().size();
Info<< "Number of cells = " << c << endl;
// 网格单元数量
const labelListList& neighbour = mesh.cellCells();
// 返回邻单元为新列表
List<scalar> ratios(0); // 声明一个scalar列表且全初始化为0
scalar volumeRatio = 0;
forAll (neighbour, cellI) // 遍历邻单元,其实就是所有单元
{
List<label> n = neighbour[cellI];
// 对每个单元,获得它的邻单元到列表 n
const scalar cellVolume = mesh.V()[cellI];
// 本单元体积
forAll (n, i) // 对于某个本单元,遍历它的邻单元
{
label neighbourIndex = n[i];
scalar neighbourVolume = mesh.V()[neighbourIndex];
// 邻单元体积
if (neighbourVolume >= cellVolume) // 体积比大于 1 的情况
{
volumeRatio = neighbourVolume / cellVolume;
ratios.append(volumeRatio);
// 体积比存入 ratios 列表
// 方便但是效率低
}
}
}
Info<< "Maximum volume ratio = " << max(ratios) << endl;
// 最大体积比
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< nl;
runTime.printExecutionTime(Info);
Info<< "End\n" << endl;
return 0;
}执行 caserun 脚本,或者直接对测试算例划分网格,运行求解器
wmake
blockMesh -case debug_case
ofsp_16_meshRatio -case debug_case终端输出如下
Create time
Create mesh for time = 0
Number of cells = 12225
Maximum volume ratio = 1.49908
ExecutionTime = 0.11 s ClockTime = 0 s
End3. 改进体积比
List 类的 append 方法虽然方便,但是效率很低,因为每一次向 List 添加数据的时候,都要创建一个 n+1 大小的新 List ,将老数据拷贝过去,再加入新数据。在数据量很大的时候,每次添加新数据都有新建再复制的过程,效率非常低。
我们考虑到对于要处理的网格,因为网格确定,所以要计算的体积比总量也是确定的。可以提前声明一个固定大小的 List,分配好内存,后续只需要向其添加数据就行。
改进后主源码如下
#include "fvCFD.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
const scalar c = mesh.C().size();
Info<< "Number of cells = " << c << endl;
const labelListList& neighbour = mesh.cellCells();
/*
* 代码改进如下
*/
label len = mesh.Cf().size(); // 需要的 ratio 的 List 大小
scalar initial = 0;
List<scalar> ratios(len, initial); // 创建固定大小的 List
label counter = 0; // ratios 的序号
scalar volumeRatio = 0;
forAll (neighbour, cellI) // 遍历邻单元
{
List<label> n = neighbour[cellI];
const scalar cellVolume = mesh.V()[cellI];
forAll (n, i)
{
label neighbourIndex = n[i];
scalar neighbourVolume = mesh.V()[neighbourIndex];
if (neighbourVolume >= cellVolume)
{
volumeRatio = neighbourVolume / cellVolume;
ratios[counter] = volumeRatio; // 存储体积比
counter += 1;
}
}
}
Info<< "Maximum volume ratio = " << max(ratios) << endl;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< nl;
runTime.printExecutionTime(Info);
Info<< "End\n" << endl;
return 0;
}终端输入命令,编译运行
终端输出如下
Create time
Create mesh for time = 0
Number of cells = 12225
Maximum volume ratio = 1.49908
ExecutionTime = 0.05 s ClockTime = 0 s
End可以很明显看到运行时间从 0.13s 减少到了 0.06s,效率大大提高。
4. 最大体积比
如果我们只是要获得最大体积比,那么其实我们不需要保存所有的体积比,保存体积比的最大值就够了。
主源码如下
#include "fvCFD.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
const scalar c = mesh.C().size();
Info<< "Number of cells = " << c << endl;
const labelListList& neighbour = mesh.cellCells();
/*
* 代码改进如下
*/
scalar volumeRatio = 0.0;
scalar currentRatio = 0.0;
forAll (neighbour, cellI)
{
List<label> n = neighbour[cellI];
const scalar cellVolume = mesh.V()[cellI];
forAll (n, i)
{
label neighbourIndex = n[i];
scalar neighbourVolume = mesh.V()[neighbourIndex];
if (neighbourVolume >= cellVolume)
{
volumeRatio = neighbourVolume / cellVolume;
if (volumeRatio > currentRatio) // 只存储最大体积比
{
currentRatio = volumeRatio;
}
}
}
}
Info<< "Maximum volume ratio = " << currentRatio << endl;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< nl;
runTime.printExecutionTime(Info);
Info<< "End\\n" << endl;
return 0;
}编译运行项目
终端输出如下
Create time
Create mesh for time = 0
Number of cells = 12225
Maximum volume ratio = 1.49908
ExecutionTime = 0.05 s ClockTime = 0 s
End5. 体积比准则
仅获得体积比还不够,我们可能希望知道测试算例的网格有多少超过了指定的体积比准则。
我们通过 OpenFOAM 的字典来接入体积比准测这一参数。
为测试算例提供字典 /ofsp_16_meshRatio/debug_case/system/volumeRatioDict ,内容如下
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
maxRatio 1.2;用户可以通过字典文件修改参数而不用再次编译项目。
Tip
我们约定
Properties文件放在/userApp/constant文件夹下Dict文件放在/userApp/system文件夹下
主源码如下
#include "fvCFD.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
IOdictionary volumeRatioDict // 建立字典对象
(
IOobject
(
"volumeRatioDict", // 文件名称
runTime.system(), // 文件路径
mesh, // 基于 mesh 构造
IOobject::MUST_READ, // 必读
IOobject::NO_WRITE // 只读不写
)
);
const scalar c = mesh.C().size();
Info<< "Number of cells = " << c << endl;
const labelListList& neighbour = mesh.cellCells();
scalar volumeRatio = 0.0;
scalar currentRatio = 0.0;
label nFail = 0; // 统计超出准测的数量
scalar maxRatio(readScalar(volumeRatioDict.lookup("maxRatio")));
// 从字典读入
forAll (neighbour, cellI)
{
List<label> n = neighbour[cellI];
const scalar cellVolume = mesh.V()[cellI];
forAll (n, i)
{
label neighbourIndex = n[i];
scalar neighbourVolume = mesh.V()[neighbourIndex];
if (neighbourVolume >= cellVolume)
{
volumeRatio = neighbourVolume / cellVolume;
if (volumeRatio > currentRatio)
{
currentRatio = volumeRatio;
}
if (volumeRatio > maxRatio) // 统计超出准测的数量
{
nFail += 1;
}
}
}
}
Info<< "Maximum volume ratio = " << currentRatio << nl
<< "Number of cell volume ratios exceeding " << maxRatio
<< " = " << nFail << nl
<< endl;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< nl;
runTime.printExecutionTime(Info);
Info<< "End\n" << endl;
return 0;
}编译运行项目
终端输出如下
Create time
Create mesh for time = 0
Number of cells = 12225
Maximum volume ratio = 1.49908
Number of cell volume ratios exceeding 1.2 = 532
ExecutionTime = 0.04 s ClockTime = 0 s
End6. 小结
本文继续讨论了网格类的方法,提供了实践案例。读者通过反复练习,可以回顾之前的知识点,克服 OpenFOAM 编程陌生感,方便后续学习。
本文完成讨论
- 练习网格类方法的使用
- 考虑代码的运行效率
- 复习自定义字典文件的使用
- 编译运行 meshRatio 项目