OpenFOAM開發編程基礎02 主函數參數列表類初步

參考:

  • https://github.com/UnnamedMoose/BasicOpenFOAMProgrammingTutorials
  • https://www.topcfd.cn/simulation/solve/openfoam/openfoam-program/
  • https://www.tfd.chalmers.se/~hani/kurser/OS_CFD/
  • https://github.com/ParticulateFlow/OSCCAR-doc/blob/master/openFoamUserManual_PFM.pdf
  • https://www.youtube.com/watch?v=KB9HhggUi_E&ab_channel=UCLOpenFOAMWorkshop
  • http://dyfluid.com/#
  • https://ss1.xrea.com/penguinitis.g1.xrea.com/study/OpenFOAM/index.html

感謝原作者們的無私引路和寶貴工作。

OpenFOAM 初學者很難不注意到求解器總是有幾個固定的頭文件,包括 setRootCase.HcreateTime.HcreateMesh.H 。網絡上找到的代碼解析常常只有一句注釋介紹功能,也許無法消除困惑感。

更新和勘誤詳見 aerosand.cn。

本文同樣從 C++ 開始,簡單介紹主函數參數,在此基礎上討論 setRootCase.H 頭文件。

建立本文的項目文件夾并進入

// terminal 
cd /home/aerosand/aerosand/ofsp
mkdir 02_args
cd 02_args

C++ 實現

主函數參數

我們在初學 C++ 的時候,主函數的參數列表一般留空,即有如下形式

...
int main() // 省略參數列表
{
 ...
}

當進一步深入 C++ 開發時,了解到主函數的更一般寫法為

...
int main(int argc, char *argv[]) {}
// 或者
int main(int argc, char **argv) {}
  • argcargument count 的縮寫,保存程序運行時傳遞給主函數的參數個數
  • argvargument vector 的縮寫,保存程序運行時傳遞給主函數的具體參數的字符型指針,每個指針都指向一個具體的參數。
    • argv[0] 指向程序運行時的全路徑名稱
    • argv[1] 指向程序運行時命令行中執行程序名后第一個字符串
    • argv[2] 指向程序運行時命令行中執行程序名后第二個字符串
    • 其他以此類推

項目實現

新建項目 02_arg/02_01_args/

主源碼 src/main.cpp 如下所示

#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;
}

終端直接編譯運行

// terminal
make run

運行結果如下

Number of arguments = 1
Argument 0: ./output/main

如果運行時增加參數,例如

// terminal
./output/main hi hey hello

運行結果如下

Number of arguments = 4
Argument 0: ./output/main
Argument 1: hi
Argument 2: hey
Argument 3: hello

基于主函數參數列表的了解,下面討論 OpenFOAM 中的主函數參數等內容。

OpenFOAM 實現

應用準備

// terminal
cd /home/aerosand/aerosand/ofsp/02_args/
foamNewApp 02_02_args
cd 02_02_args
cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity debug_case
code .

文件結構如下

|- 02_02_args/
|- debug_case/
|- 0/
|- constant/
|- system/
|- Make/
|- files
|- options
|- 02_02_args.C

以后非特別情況不再贅述文件結構。

腳本和說明

新建腳本

// terminal
code _appmake.sh _appclean.sh _caserun.sh _caseclean.sh README.md

腳本內容和說明文檔略。

setRootCase.H

先看一下主源碼中的頭文件 setRootCase.H

// termianl
find $FOAM_SRC -iname setRootCase.H
// $FOAM_SRC/OpenFOAM/include/setRootCase.H

代碼具體為

// Construct from (int argc, char* argv[]),
// - use argList::argsMandatory() to decide on checking command arguments.
// - check validity of the options

Foam::argList args(argc, argv)// 構造argList類型的args變量
if (!args.checkRootCase()) // 如果檢查應用參數(算例路徑)錯誤
{
    Foam::FatalError.exit(); // 報錯退出
}

// User can also perform checks on otherwise optional arguments.
// Eg,
//
//  if (!args.check(true, false))
//  {
//      Foam::FatalError.exit();
//  }

// Force dlOpen of FOAM_DLOPEN_LIBS (principally for Windows applications)
#include "foamDlOpenLibs.H" // 兼容性處理,無需深究

代碼討論

  • 該 H 文件檢查了該應用的參數是否正確
  • 構造參數列表的對象 args (所以此 H 文件需要放在所有的參數代碼等后面)
  • 如果參數列表檢查不通過,則報錯退出

argList 類是一個非常基礎的類,具有很多的成員數據和成員方法。我們大概挑幾處代碼作為切入點簡單了解一下 argList 類。

// terminal
find $FOAM_SRC -iname argList.H
// /usr/lib/openfoam/openfoam2306/src/OpenFOAM/global/argList/argList.H

打開 argList.H ,內容如下

...
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 中的構造函數原型。

主源碼

幫助信息

#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;
}


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

編譯后查看幫助信息

// terminal
02_02_args -help

終端輸出

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)是可選的。

給主源碼增加應用參數如下

#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" // 構造OpenFOAM的argList類型的args對象
    #include "createTime.H"

    #include "createMesh.H"

 // args第0參數是程序名本身
    const word args1 = args[1]; // args第1參數就是增補的第1個參數
    const scalar args2 = args.get<scalar>(2); // 增補的第2個參數


 // 顯示參數
    Info<< "Solver setup: " << nl
        << "    use     : " << args1 << nl
        << "    speedup : " << args2 << nl
        << nl << endl;

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

    Info<< nl;
    runTime.printExecutionTime(Info);

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

    return 0;
}


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

終端運行是必須要提供相應類型的參數

編譯后運行

// terminal
blockMesh -case debug_case
02_02_args -case debug_case GSL 2

結果為

Create time

Create mesh for time = 0

Solver setup:
   use     : GSL
   speedup : 2



ExecutionTime = 0 s  ClockTime = 0 s

End

應用選項

應用選項在運行時可寫可不寫。

主源碼如下

#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"
    );

 // 應用參數要在 setRootCase.H 構造 args 之前
    argList::validArgs.append("mathLib");
    argList::validArgs.append("level");

 // 應用選項也要在 setRootCase.H 構造 args 之前
    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"
    );

 // setRootCase.H 將構造argList類型的args對象
    #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;

 // 創建_dict并給默認初始值
    fileName _dict("./system/myDict");
    if (args.found("dict"))
    {
        args.readIfPresent("dict",_dict);
        // 如果使用了 -dict 選項,則使用 -dict 后的值
        // 也許會有同學疑問上面這句代碼為什么能讀取 -dict 后的值并傳給 _dict
        // 建議先不要深究,以后熟悉C++了可以翻閱OpenFOAM更底層的源代碼
        Info<< "Reading myDict " << endl;
    }
    Info<< "Dictionary from " << _dict << nl << endl;

 // 創建 label 類型的對象并給默認初始值
    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;
    }
    // 只要使用 -log 選項,就會執行一些方法,比如這里的輸出


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

    Info<< nl;
    runTime.printExecutionTime(Info);

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

    return 0;
}


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

編譯運行應用

// terminal
blockMesh -case debug_case
02_02_args -case debug_case GSL 2 -dict ../constant/myDict -nPrecision 12

運行結果為

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

如果運行應用如下

02_02_args -case debug_case GSL 2 -dict ../constant/myDict -log

運行結果為

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 頭文件到底是什么呢?

文章來源: Aerosand

登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP