参考:

感谢原作者们的无私引路和宝贵工作。

前置:
OpenFOAM开发编程基础02 主函数参数列表类初步 | 𝓐𝓮𝓻𝓸𝓼𝓪𝓷𝓭 (aerosand.cn)

本文简单介绍 OpenFOAM 中的 Time 类,在此基础上讨论了 createTime.H 头文件。

建立本文的项目文件夹并进入

1
2
3
4
// terminal 
cd /home/aerosand/aerosand/ofsp
mkdir 03_time
cd 03_time

OFextension 插件使用

十分推荐在 vscode 中安装社区插件 OFextension

参考 OpenFOAM在VS Code下的debug模式调试 - 知乎 (zhihu.com)

配置插件

  1. Ofextension: OFpath 设置正确的 OpenFOAM 安装路径
  2. 使用 vscode 打开用户的开发应用,使用 F1 输入 ofInit 初始化配置

代码编写

在应用开发中,例如本文应用,在主源码中输入 runTime. ,vscode 会自动弹出可选的 runTime 方法(成员函数)。

而且可以在主源码中选中头文件、类等,右键使用 Go to DefinitionGo to Declaration 等,直接跳转查看源代码。

非常推荐此插件,十分方便。注意不要在 OpenFOAM 源文件夹下初始化。

程序调试

  1. 调试算例的文件夹名称保持为 debug_case
  2. userApp/Make/options 中的 EXE_INC = 下的第一行需要添加 -g \ 调试参数
  3. 执行 ofInit 初始化配置
  4. 给代码行打点,进入 vscode 调试界面进行调试

时间类方法

应用准备

1
2
3
4
5
// terminal
foamNewApp 03_01_time
cd 03_01_time
cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity debug_case
code .

脚本和说明

读者可能感受到前几篇文章使用的脚本对每个不同的应用都要重新写,十分繁琐。

我们逐渐介绍一些更方便的脚本写法。

新建脚本

1
2
// terminal
code caserun caseclean

caserun 脚本负责应用编译成功后,调试算例的运行,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
cd "${0%/*}" || exit 1 # Run from this directory
#------------------------------------------------------------------------------

appPath=$(cd `dirname $0`; pwd) # Get application path
appName="${appPath##*/}" # Get application name

blockMesh -case debug_case | tee debug_case/log.mesh
echo "Meshing done."

$appName -case debug_case | tee debug_case/log.run

  • $0 返回当前脚本的绝对路径
  • %xxx 去除 xxx 字符
  • /* 表示 / 及之后的所有字符

不用担心脚本语言,暂时只需要知道使用上述脚本即可,更深入的脚本语言会随着讨论深入而逐渐介绍。

caseclean 脚本负责清理调试算例,还原到初始状态,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
cd "${0%/*}" || exit 1 # Run from this directory
#------------------------------------------------------------------------------

appPath=$(cd `dirname $0`; pwd)
appName="${casePath##*/}"

cd debug_case

rm -rf log.*
foamCleanTutorials
echo "Cleaning Done."

这两个脚本自动获取应用路径和应用名称,所以也适合后续讨论的其他应用使用,只需要复制使用即可。注意,上述写法不适合 .sh 文件格式,因为脚本语言的语法会导致上述脚本中的 cd 语句报错。

使脚本生效

1
2
// termianl
chmod +x caserun caseclean

使用方法

1
2
3
// terminal
./caserun
./caseclean

除非特殊强调,以后均使用这两个脚本。

createTime.H

看一下和时间类相关的头文件 createTime.H

1
2
3
// termianl
find $FOAM_SRC -iname createTime.H
// /usr/lib/openfoam/openfoam2306/src/OpenFOAM/include/createTime.H

如果使用 OFextension 可以直接跳转。

内容如下

1
2
3
Foam::Info<< "Create time\n" << Foam::endl;

Foam::Time runTime(Foam::Time::controlDictName, args);

第一行是正常的输出语句。

第二行构造了一个 Foam::Time 类型的 runTime 对象,构造基于 controlDictNameargs

args 需要先创建,所以 createTime.H 要在 setRootCase.H 之后

Time 是一个非常基础的类,具有很多的成员数据和成员方法。我们大概挑几处代码作为切入点简单了解一下 Time 类。

1
2
3
// termianl
find $FOAM_SRC -iname Time.H
// /usr/lib/openfoam/openfoam2306/src/OpenFOAM/db/Time/Time.H

推荐使用 OFextension 插件,直接跳转查看,以后不再赘述。

打开 Time.H ,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
class Time
:
public clock,
public cpuTime,
public TimePaths,
public objectRegistry,
public TimeState
// Time类继承自更多的基类
{
public:
...
private:
...
protected:
...
private:
...
public:
...
// 基于参数的构造函数
inline Time
(
const word& ctrlDictName, // word类型的引用
const argList& args, // argList类型的引用
const bool enableFunctionObjects = true,
const bool enableLibs = true
);
// 找到这个内联函数,就是 createTime.H 第2行的方法原型
// 第3个和第4个形参默认为 true,可以不用传入
...
// Time类的成员函数
virtual dimensionedScalar startTime() const;

virtual dimensionedScalar endTime() const;
...
...

方法的实现较为复杂,对于现阶段来说,基础类没有必要去深入讨论代码的实现部分,目前只需要做到心里有数、看到不那么陌生即可。

主源码

在主源码中使用时间类方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "fvCFD.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

int main(int argc, char *argv[])
{
#include "setRootCase.H"
// #include "createTime.H"
Foam::Info<< "Create time\n" << Foam::endl;
Foam::Time runTime(Foam::Time::controlDictName, args);
// 这两行就是 createTime.H

Info<< "Case name : " << runTime.caseName() << endl;
Info<< "Root path : " << runTime.rootPath() << endl;
Info<< "Path : " << runTime.path() << endl;
Info<< "Time path : " << runTime.timePath() << endl;
Info<< "Controdict : " << runTime.controlDict() << endl;
Info<< "Format : " << runTime.writeFormat() << endl;
Info<< "Version : " << runTime.writeVersion() << endl;
Info<< "Start time : " << runTime.startTime() << endl;
Info<< "End time : " << runTime.endTime() << endl;
Info<< "Time step : " << runTime.deltaT() << endl;

Info<< "# set end time = 10" << endl;
runTime.setEndTime(10);

Info<< "# set deltaT = 1" << endl;
runTime.setDeltaT(1);

Info<< "Start time : " << runTime.startTime() << endl;
Info<< "End time : " << runTime.endTime() << endl;
Info<< "Time step : " << runTime.deltaT() << endl;


while (runTime.loop())
{
Info<< "Time: " << runTime.timeName() << endl;
runTime.write();
}

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Info<< nl;
// runTime.printExecutionTime(Info);
// 展开成员函数 printExecutionTime() 的主要内容
Info<< "Execution time: " << runTime.elapsedCpuTime() << " s" << endl;
Info<< "Clock time: " << runTime.elapsedClockTime() << " s" << endl;

Info<< "End\n" << endl;

return 0;
}


// ************************************************************************* //

编译运行

通过终端编译运行此应用

1
2
3
4
// terminal
wmake
./caseclean
./caserun

运行结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Create time

Case name : "debug_case"
Root path : "/home/aerosand/aerosand/ofsp/03_timeMesh/03_01_time"
Path : "/home/aerosand/aerosand/ofsp/03_timeMesh/03_01_time/debug_case"
Time path : "/home/aerosand/aerosand/ofsp/03_timeMesh/03_01_time/debug_case/0"
Controdict :
{
application icoFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.5;
deltaT 0.005;
writeControl timeStep;
writeInterval 20;
purgeWrite 0;
writeFormat ascii;
writePrecision 6;
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable true;
}

Format : ascii
Version : 2.0
Start time : startTime [0 0 1 0 0 0 0] 0
End time : endTime [0 0 1 0 0 0 0] 0.5
Time step : deltaT [0 0 1 0 0 0 0] 0.005
# set end time = 10
# set deltaT = 1
Start time : startTime [0 0 1 0 0 0 0] 0
End time : endTime [0 0 1 0 0 0 0] 10
Time step : deltaT [0 0 1 0 0 0 0] 1
Time: 1
Time: 2
Time: 3
Time: 4
Time: 5
Time: 6
Time: 7
Time: 8
Time: 9
Time: 10

Execution time: 0 s
Clock time: 0 s
End


小结

加上之前的讨论,我们已经大体理解 OpenFOAM 应用中常见的 setRootCase.HcreateTime.H 头文件,下一篇将讨论最后一个必备头文件 createMesh.H