参考:
感谢原作者们的无私引路和宝贵工作。
前置:
OpenFOAM开发编程基础01 输入输出 | 𝓐𝓮𝓻𝓸𝓼𝓪𝓷𝓭 (aerosand.cn)
OpenFOAM 初学者很难不注意到求解器总是有几个固定的头文件,包括 setRootCase.H
,createTime.H
和 createMesh.H
。网络上找到的代码解析常常只有一句注释介绍功能,也许无法消除困惑感。
本文同样从 C++ 开始,简单介绍主函数参数,在此基础上讨论 setRootCase.H
头文件。
建立本文的项目文件夹并进入
1 2 3 4 // terminal cd /home/aerosand/aerosand/ofsp mkdir 02_args cd 02_args
C++ 实现
主函数参数
我们在初学 C++ 的时候,主函数的参数列表一般留空,即有如下形式
1 2 3 4 5 ... int main () { ... }
当进一步深入 C++ 开发时,了解到主函数的更一般写法为
1 2 3 4 ... int main (int argc, char *argv[]) {}int main (int argc, char **argv) {}
argc
即 argument count
的缩写,保存程序运行时传递给主函数的参数个数
argv
即 argument vector
的缩写,保存程序运行时传递给主函数的具体参数的字符型指针,每个指针都指向一个具体的参数。
argv[0]
指向程序运行时的全路径名称
argv[1]
指向程序运行时命令行中执行程序名后第一个字符串
argv[2]
指向程序运行时命令行中执行程序名后第二个字符串
其他以此类推
项目实现
新建项目 02_arg/02_01_args/
主源码 src/main.cpp
如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> int main (int argc, char *argv[]) { std::cout << "Number of arguments = " << argc << std::endl; for (int i=0 ; i<argc; ++i) { std::cout << "Argument " << i << ": " << argv[i] << std::endl; } return 0 ; }
终端直接编译运行
运行结果如下
1 2 Number of arguments = 1 Argument 0: ./output/main
如果运行时增加参数,例如
1 2 // terminal ./output/main hi hey hello
运行结果如下
1 2 3 4 5 Number of arguments = 4 Argument 0: ./output/main Argument 1: hi Argument 2: hey Argument 3: hello
基于主函数参数列表的了解,下面讨论 OpenFOAM 中的主函数参数等内容。
OpenFOAM 实现
应用准备
1 2 3 4 5 // terminal foamNewApp 02_02_args cd 02_02_args cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity debug_case code .
文件结构如下
1 2 3 4 5 6 7 8 9 |- 02_02_args/ |- debug_case/ |- 0/ |- constant/ |- system/ |- Make/ |- files |- options |- 02_02_args.C
以后非特别情况不再赘述文件结构。
脚本和说明
新建脚本
1 2 // terminal code _appmake.sh _appclean.sh _caserun.sh _caseclean.sh README.md
脚本内容和说明文档略。
setRootCase.H
先看一下主源码中的头文件 setRootCase.H
1 2 3 // termianl find $FOAM_SRC -iname setRootCase.H // $FOAM_SRC/OpenFOAM/include/setRootCase.H
代码具体为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Foam::argList args (argc, argv) ; if (!args.checkRootCase ()) { Foam::FatalError.exit (); } #include "foamDlOpenLibs.H"
代码讨论
该 H 文件检查了该应用的参数是否正确
构造参数列表的对象 args
(所以此 H 文件需要放在所有的参数代码等后面)
如果参数列表检查不通过,则报错退出
argList
类是一个非常基础的类,具有很多的成员数据和成员方法。我们大概挑几处代码作为切入点简单了解一下 argList
类。
1 2 3 // terminal find $FOAM_SRC -iname argList.H // /usr/lib/openfoam/openfoam2306/src/OpenFOAM/global/argList/argList.H
打开 argList.H
,内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ... class argList { ... public : ... argList ( int & argc, char **& argv, bool checkArgs = argList::argsMandatory (), bool checkOpts = true , bool initialise = true ); ... ...
方法的实现较为复杂,对于现阶段来说,基础类没有必要去深入讨论代码的实现部分,目前只需要做到心里有数、看到不那么陌生即可。
在上一篇文章的讨论中,也可以深入看一下 OpenFOAM 的 IOdictionary
类,终端使用命 find $FOAM_SRC -iname IOdictionary.H
,可以找到对应的构造函数原型。也可以查找到 IOobject.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 #include "fvCFD.H" int main (int argc, char *argv[]) { argList::addNote ( "Demonstrates how to handle command line options.\n\n" "Application arguments:\n" "----------------------\n" " mathLib - Eigen/GSL/Armodillo/BLAS\n" " level - computation speedup\n" ); #include "setRootCase.H" #include "createTime.H" Info<< nl; runTime.printExecutionTime (Info); Info<< "End\n" << endl; return 0 ; }
编译后查看帮助信息
1 2 // terminal 02_02_args -help
终端输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Usage: 02_02_args [OPTIONS] Options: -case <dir> Case directory (instead of current directory) -decomposeParDict <file> Alternative decomposePar dictionary file -parallel Run in parallel -doc Display documentation in browser -help Display short help and exit -help-full Display full help and exit Demonstrates how to handle command line options. Application arguments: ---------------------- mathLib - Eigen/GSL/Armodillo/BLAS level - computation speedup Using: OpenFOAM-2306 (2306) - visit www.openfoam.com Build: _fbf00d6b-20230626 Arch: LSB;label=32;scalar=64
可以看到我们自定义的帮助信息。
应用参数
应用参数(arguments)在执行应用命令时是强制需要的,下一节的应用选项(option)是可选的。
给主源码增加应用参数如下
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 #include "fvCFD.H" int main (int argc, char *argv[]) { argList::addNote ( "Demonstrates how to handle command line options.\n\n" "Application arguments:\n" "----------------------\n" " mathLib - Eigen/GSL/Armodillo/BLAS\n" " level - computation speedup\n" ); argList::validArgs.append ("mathLib" ); argList::validArgs.append ("level" ); #include "setRootCase.H" #include "createTime.H" #include "createMesh.H" const word args1 = args[1 ]; const scalar args2 = args.get <scalar>(2 ); Info<< "Solver setup: " << nl << " use : " << args1 << nl << " speedup : " << args2 << nl << nl << endl; Info<< nl; runTime.printExecutionTime (Info); Info<< "End\n" << endl; return 0 ; }
终端运行是必须要提供相应类型的参数
编译后运行
1 2 3 // terminal blockMesh -case debug_case 02_02_args -case debug_case GSL 2
结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Create time Create mesh for time = 0 Solver setup: use : GSL speedup : 2 ExecutionTime = 0 s ClockTime = 0 s End
应用选项
应用选项在运行时可写可不写。
主源码如下
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include "fvCFD.H" int main (int argc, char *argv[]) { argList::addNote ( "Demonstrates how to handle command line options.\n\n" "Application arguments:\n" "----------------------\n" " mathLib - Eigen/GSL/Armodillo/BLAS\n" " level - computation speedup\n" ); argList::validArgs.append ("mathLib" ); argList::validArgs.append ("level" ); argList::addOption ( "dict" , "word" , "Use addtional dictionary (just for example)" ); argList::addOption ( "nPrecision" , "label" , "Set the precision level (just for example)" ); argList::addBoolOption ( "log" , "output the log" ); #include "setRootCase.H" #include "createTime.H" #include "createMesh.H" const word args1 = args[1 ]; const scalar args2 = args.get <scalar>(2 ); Info<< "Solver setup: " << nl << " use : " << args1 << nl << " speedup : " << args2 << nl << nl << endl; fileName _dict("./system/myDict" ); if (args.found ("dict" )) { args.readIfPresent ("dict" ,_dict); Info<< "Reading myDict " << endl; } Info<< "Dictionary from " << _dict << nl << endl; label _nPrecision(6 ); args.readIfPresent ("nPrecision" ,_nPrecision); Info<< "Precision is " << _nPrecision << endl; const bool _log = args.found ("log" ); if (_log) { Info<< "Output the logs" << endl; } Info<< nl; runTime.printExecutionTime (Info); Info<< "End\n" << endl; return 0 ; }
编译运行应用
1 2 3 // terminal blockMesh -case debug_case 02_02_args -case debug_case GSL 2 -dict ../constant/myDict -nPrecision 12
运行结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Create time Create mesh for time = 0 Solver setup: use : GSL speedup : 2 Reading myDict Dictionary from "../constant/myDict" Precision is 12 ExecutionTime = 0 s ClockTime = 0 s End
如果运行应用如下
1 02_02_args -case debug_case GSL 2 -dict ../constant/myDict -log
运行结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Create time Create mesh for time = 0 Solver setup: use : GSL speedup : 2 Reading myDict Dictionary from "../constant/myDict" Precision is 0 Output the logs ExecutionTime = 0.01 s ClockTime = 0 s End
应用选项 -dict
也有默认值,可以尝试省略并运行应用。
通过使用不同的应用选项,看到各行源代码的效果。
小结
从 C++ 基础出发, 简单讨论了主函数运行时的帮助、参数和选项。虽然上面的开发都是仅停留在表面做做样子,但目的也是使读者对 OpenFOAM 中运行应用的命令行方法有了一些了解,以后也可以在此基础上深入。更深入的开发见后续讨论。
本文基本搞明白了 OpenFOAM 求解器中必备的 setRootCase.H
到底是什么,那么 createTime.H
头文件到底是什么呢?
Copyright Notice: 此文章版权归aerosand.cn所有,如有转载,请注明来自原作者