最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

OpenFOAM開發(fā)編程基礎(chǔ)00 基本實現(xiàn)和

2023-08-04 16:08 作者:我這么老實又乖又靦腆  | 我要投稿

參考:

  • 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/OSCCARdoc/blob/master/openFoamUserManual_PFM.pdf

  • https://www.youtube.com/watchv=KB9HhggUi_E&ab_channel=UCLOpenFOAMWorkshop

  • http://dyfluid.com/#


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

前置:

https://aerosand.cn/categories/CFD/

強(qiáng)烈建議在學(xué)習(xí)過計算流體力學(xué)基礎(chǔ)以及有限體積法之后再開始本系列學(xué)習(xí)。至少也要同時開始,不然最后可能很難理解 OpenFOAM 求解器標(biāo)準(zhǔn)算法。


OpenFOAM 是什么呢?引用 wiki 解釋如下

OpenFOAM (for "Open-source Field Operation And Manipulation") is a C++ toolbox for the development of customized numerical solvers, and pre-/post-processing utilities for the solution of continuum mechanics problems, most prominently including computational fluid dynamics (CFD).

我們從簡單的 C++ 程序?qū)崿F(xiàn)開始,簡單了解編譯原理,通過 makefile 逐漸掌控我們的項目,過渡到了解 OpenFOAM 的 Make 實現(xiàn)方式,然后認(rèn)識 OpenFOAM 的基本程序,最后逐漸深入 OpenFOAM 的程序開發(fā)。

鑒于 OpenFOAM 的使用環(huán)境,我們選擇在 ubuntu 22.04 系統(tǒng)環(huán)境中,基于 OpenFOAM 2306 版本進(jìn)行開發(fā),方便起見使用 vscode 工具。

OpenFOAM 的安裝,vscode 的安裝,快捷命令的自定義等討論參見 [OpenFOAM 環(huán)境準(zhǔn)備 | ???????????????? (aerosand.cn)](https://aerosand.cn/posts/20230331145640/)



原生實現(xiàn)


我們使用 C++ 寫一段簡單的 “hello world” 程序。

hello world


對于 OpenFOAM 來說,項目(或者稱為應(yīng)用)寫在任何一個文件夾都可以,放在 `$FOAM_RUN` 路徑下也是為了方便管理。

比如,此學(xué)習(xí)討論中,我把項目放在自建文件夾 `/home/aerosand/aerosand/` 之下,并定義了快捷命令 `asd` 。快捷命令的自定義使用請參考 [OpenFOAM 環(huán)境準(zhǔn)備 | ???????????????? (aerosand.cn)](https://aerosand.cn/posts/20230331145640/)

例如,新建總項目文件夾(`// terminal` 表示下面命令需要在終端輸入執(zhí)行)


(`ofsp` 即 `OpenFoam sharing programming` 的縮寫)

在用戶路徑下,建立本章節(jié)的項目文件夾,例如 `/home/aerosand/aerosand/ofsp/of00_0/` 。

系列討論中可能用戶路徑以后簡寫為 `userApp/`

詳細(xì)操作演示如下


可以使用 `tree` 命令查看文件樹狀結(jié)構(gòu)(命令參考 [OpenFOAM 常用指令 | ???????????????? (aerosand.cn)](https://aerosand.cn/posts/20230331173234/))

最后,我們能看到文件結(jié)構(gòu)為


我們約定在文件表示中,名稱后加了 `/` 的表示文件夾,反之表示文件。

我們分別寫入示例代碼,內(nèi)容如下

類的聲明 `Aerosand.h`

類的實現(xiàn) `Aerosand.cpp`

主源碼 `of00_0.cpp`

雖然我們籠統(tǒng)的把整個過程稱為“編譯”,實際上,在 Linux 系統(tǒng)下,C++ 程序的編譯過程其實分為下面幾個過程。我們將逐步拆解并實現(xiàn)各個環(huán)節(jié)。

編譯過程

預(yù)處理

將程序代碼中包含的 `#include` 文件插入替換到原文件中,在 Linux 系統(tǒng)下生成 `.i` 文件。

`.i` 代表著 intermediate preprocessor output 中間預(yù)處理輸出

我們在終端里通過命令執(zhí)行這一過程

?g++ 的 `-E` 標(biāo)識指定編譯器進(jìn)行預(yù)處理

g++ 的 `-o` 標(biāo)識指定編譯器生成文件的名稱

結(jié)果生成 `Aerosand.i` 和 `of00_0.i` 文件。

編譯

編譯器對預(yù)處理后的 `.i` 文件進(jìn)行進(jìn)一步語法分析,在 Linux 系統(tǒng)下生成 `.s` 文件。

`.s` 代表著 source code written in assembly 匯編語言形式的源文件

終端中執(zhí)行編譯過程

g++ 的 `-S` 標(biāo)識指定編譯器進(jìn)行編譯

結(jié)果生成 `Aerosand.s` 和 `of00_0.s` 文件。

匯編

編譯器把編譯后的 `.s` 文件轉(zhuǎn)換成可以執(zhí)行的機(jī)器指令,在 Linux 系統(tǒng)下生成 `.o` 文件。

`.o` 代表著 object file 目標(biāo)文件

終端中執(zhí)行匯編過程

?g++ 的 `-c` 標(biāo)識指定編譯器進(jìn)行匯編

結(jié)果生成 `Aerosand.o` 和 `of00_0.o` 文件。

動態(tài)庫

當(dāng)項目中有大量“類”的時候,我們希望某些“類”能固定下來提供某種“方法”,這種“方法”就形成一個可以重復(fù)使用的“庫”(library)。當(dāng)其他項目使用這個庫的時候,庫本身無需再次“預(yù)處理”,“編譯”以及“匯編”,僅僅和這個項目鏈接即可。

因為靜態(tài)庫開銷大,浪費空間,更新維護(hù)困難,所以 OpenFOAM 大量使用動態(tài)庫,我們這里也只以動態(tài)庫為例。

動態(tài)庫在**程序編譯**時并不鏈接到目標(biāo)代碼,而僅僅在**程序運行**時才被鏈接載入。不同的程序如果調(diào)用相同的庫,那么內(nèi)存里只需要一份該動態(tài)庫的可分享實例,這樣就大大減少了空間浪費。此外,因為動態(tài)庫僅在程序運行時才被鏈接載入,庫的單獨維護(hù)更新也十分方便。


編譯可以對匯編后的 `.o` 目標(biāo)文件進(jìn)行整理成動態(tài)庫,在 Linux 系統(tǒng)下生成 `.so` 文件。

`.so` 代表著 shared object 共享目標(biāo)

終端中執(zhí)行生成動態(tài)庫命令

g++ 的 `-shared` 標(biāo)識指定生成動態(tài)鏈接庫

g++ 的 `-fPIC` 標(biāo)識指定創(chuàng)建與地址無關(guān)的編譯程序,為了使得結(jié)果可以共享使用

動態(tài)庫文件以 `lib` 開頭

生成 `Aerosand.so` 文件,該文件就是可鏈接的動態(tài)庫。

鏈接

編譯器把所有的目標(biāo)文件以及庫文件都組織成一個可以執(zhí)行的二進(jìn)制文件

使用 `echo` 命令查看原本動態(tài)庫鏈接路徑,可以發(fā)現(xiàn)并不是項目本地路徑。臨時指定動態(tài)庫路徑為當(dāng)前文件夾(臨時指定不影響 OpenFOAM 動態(tài)庫路徑的環(huán)境配置)。

終端中將主源碼目標(biāo)文件和動態(tài)庫鏈接,生成可執(zhí)行文件

g++ 的 `-L` 標(biāo)識緊跟指定的庫的路徑, 使用 `-L.` 表示動態(tài)庫在當(dāng)前路徑

g++ 的 `-l` 標(biāo)識緊跟指定的庫的名稱,使用時省略 `lib` 字段

最終生成 `of00_0` 文件。

需要知道的是,無論是把新開發(fā)的庫放在其他特定路徑下,或者是本項目下,每個項目都可以鏈接使用這個動態(tài)庫,只要指定正確的鏈接路徑。這也是動態(tài)庫“相對獨立”“自由鏈接”的意義所在。

運行

運行結(jié)果為

make 實現(xiàn)

上一節(jié)的編譯過程雖然清晰,但是一步一步的執(zhí)行十分繁瑣。

我們采用 make 來管理我們的開發(fā)項目。目前很多人也會進(jìn)一步的使用 CMake 來管理項目,CMake 更加簡潔高效,不過本質(zhì)上也是基于 make 的。

我們可以為項目提供 makefile 文件通用的描述所有執(zhí)行步驟。這樣只需要簡單執(zhí)行 makefile 文件就可以編譯整個項目,大大方便調(diào)試運行。此外,上面項目的所有代碼文件都放在一起,十分不方便,所以我們對代碼進(jìn)行分類管理。

代碼準(zhǔn)備

我們建立新項目 `/home/aerosand/aerosand/ofsp/of00_1/` 。文件結(jié)構(gòu)如下:

在我們早期開發(fā)中,庫在很多情況下都只是某個項目的特定庫。所以,我們?nèi)匀话寻姸?`類` 形成的 `開發(fā)庫` 作為一個獨立的文件夾放進(jìn)開放項目內(nèi)。開發(fā)庫文件夾內(nèi)有庫自己的 `庫 makefile`。項目根目錄下有項目主源碼,開發(fā)庫文件夾,以及 `項目 makefile` 。文件結(jié)構(gòu)清晰,層次明確。

因為頭文件路徑有變化,主源碼頭文件包含修改為?

其他代碼的內(nèi)容保持不變。

庫 makefile

庫的 makefile 只負(fù)責(zé)庫的編譯,目的是得到動態(tài)庫,方便主程序鏈接使用。

makefile 文件將編譯過程簡化成“編譯”和“鏈接”兩部分,不再展開“預(yù)處理”,“匯編”的過程。編譯過程把源代碼編譯成 `.o` 目標(biāo)文件或者庫文件等中間文件,“鏈接”過程把中間文件鏈接成最后可執(zhí)行程序。

makefile 文件的基本格式為

基于前文對?C++ 項目編譯原理的過程的討論,庫 makefile 可以非常直白的寫成

順序重要。先指定動態(tài)庫的編譯,再指定匯編 `.o` 文件的編譯。

`<support>` 部分不用包括 `.h` 文件

進(jìn)入庫文件夾,執(zhí)行 makefile

清理的時候自行刪除 `.o` 文件和 `.so` 文件即可。

可以看到庫文件夾下生成了我們需要的 `libAerosand.so` 文件。

當(dāng)代碼文件繁多的時候,這么直白的寫 makefile 效率低,不利于維護(hù),我們優(yōu)化 makefile 寫法到通用形式

希望讀者不要對 makefile 的寫法感到擔(dān)心,需要知道的都寫在本文里了,陌生的語法知道可以這么使用即可,不需要花費時間了解原因和原理。

第一段定義了一些命令的宏指代,方便第二段命令的書寫。注意獲取當(dāng)前文件夾名稱 `NAME` 的寫法,獲取當(dāng)前路徑下所有源文件 `SOURCE` 的寫法。

第二段使用宏指代寫了編譯命令,本質(zhì)上和原生寫法沒有什么區(qū)別。

第三段自定義了 `make clean` 命令。注意 `Linux` 系統(tǒng)下常見的類似寫法,例如 `*.so` 指代所有的 `.so` 文件。

動態(tài)庫編譯

結(jié)果生成了動態(tài)庫 `userApp/Aerosand/libAerosand.so` 文件(注意路徑)。

項目 makefile

我們直接寫 makefile 文件

如果主源碼沒有先生成目標(biāo)文件,而是通過 `-c` 標(biāo)識把編譯和鏈接放在一句指令內(nèi)寫完,編譯后的文件將無法執(zhí)行,這是因為 `-c` 標(biāo)識指定的生成文件不能直接運行。

程序編譯(注意要離開庫文件夾, cd 到 `userApp/` 下)

注意,makefile 中的 `make run` 部分臨時指定了動態(tài)庫鏈接路徑。

運行結(jié)果如下

vscode 插件

對于一般的 C++ 項目,推薦使用 vscode 的插件 `C/C++ Project Generator`,操作步驟如下

1. 使用 `F1` 打開快捷命令輸入,使用 `Create C++ project`

2. 彈出窗口中選擇到準(zhǔn)備好的空白項目文件夾,并打開

3. 在 `src/main.cpp` 中開發(fā)主函數(shù)代碼

4. 在 `include/` 路徑下開發(fā)頭文件的定義,在 `src/` 路徑下開發(fā)頭文件的實現(xiàn)

5. 終端使用命令 `make` 編譯此項目,`make run` 編譯并運行,`make clean` 清理項目

6. 也可以使用 `./output/main` 直接運行該程序


wmake 實現(xiàn)

OpenFOAM 并不使用 `make` 管理應(yīng)用,而是使用 `wmake` 管理應(yīng)用。

在理解了 C++ 項目的 `make` 實現(xiàn)方式之后,我們現(xiàn)在可以更加容易的明白 OpenFOAM 提供的 `wmake` 實現(xiàn)方式。

可以找到 OpenFOAM 的 `wmake` 文件夾。

大概掃一眼文件構(gòu)成,總的來說, OpenFOAM 基于原生 的 `make` 發(fā)展了自己的 `wmake` 。OpenFOAM 使用 `Make/files` 和 `Make/options` 實現(xiàn) `wmake` 的編譯管理。

OpenFOAM 約定源代碼后綴為 `.C`,頭文件后綴為 `.H` 。需要理解的是,OpenFOAM “**應(yīng)用層面**” 的 `.H` 文件更多只是為了對主源碼按功能進(jìn)行拆分,方便代碼閱讀和維護(hù),所以并不是真實的頭文件。這和 C++ 開發(fā)層面的頭文件以及 OpenFOAM “**源碼層面**”的頭文件(如 `$FOAM_SRC/OpenFOAM/dimensionSet.H`)不同。

下面討論的都是“源碼層面”的頭文件,不討論“應(yīng)用層面”的頭文件。

代碼準(zhǔn)備

OpenFOAM 中,約定把一個“項目”稱為“應(yīng)用(application)”

建立應(yīng)用(application)`/home/aerosand/aerosand/ofsp/of00_2/` 。進(jìn)入該文件夾,寫入源代碼。

代碼內(nèi)容如下:

Aerosand 庫頭文件

Aerosand 庫源文件

應(yīng)用主源碼

注意每個代碼文件的最后都需要留個一個空白行,否則 OpenFOAM 會警告 `parse error`

類的頭文件不再需要相對路徑

OpenFOAM 提供了 Make 文件來幫助開發(fā),其中

  • `/Make/files` 指定編譯需要的所有源文件和目標(biāo)路徑以及目標(biāo)文件名稱

  • `/Make/options` 指定 application 或者庫所需要包含的頭文件、鏈接的其他庫文件(包含路徑)

類似把 makefile 文件換成了 OpenFOAM 的 Make 文件

硬鏈接

硬鏈接并不需要單獨編譯庫文件,而是將庫文件直接包含在主應(yīng)用上,所以這種情況不需要準(zhǔn)備庫自己的 Make 文件。

代碼文件結(jié)構(gòu)如下

文件 `../userApp/Make/files` 內(nèi)容如下

此應(yīng)用需要“包擴(kuò)”自定義庫 Aerosand。

這里使用“包括”而不是“鏈接”,為了強(qiáng)調(diào) Aerosand 并沒有生成自己的獨立庫文件(如靜態(tài)庫 `.a` 文件或者動態(tài)庫 `.so` 文件)

文件 `userApp/Make/options` 內(nèi)容如下

因為前文臨時定義了庫的鏈接路徑,這里需要可能重啟終端,以恢復(fù) OpenFOAM 的環(huán)境配置。

執(zhí)行編譯

終端輸出信息有三段,對應(yīng)著應(yīng)用編譯的三個過程。

第一段是自定義的 Aerosand 庫編譯得到目標(biāo)文件 `Aerosand.o` (見輸出信息的末尾處)

第二段是主源碼編譯得到目標(biāo)文件 `of00_2.o` (見輸出信息的末尾處)

第三段是鏈接的過程,鏈接自定義庫或者其他的動態(tài)鏈接,最終生成可執(zhí)行文件(見輸出信息的末尾處)。

我們可以直接運行這個應(yīng)用

運行結(jié)果如下

動態(tài)庫

在實際的開發(fā)中,我們還是要使用動態(tài)庫來保證內(nèi)存和效率。

文件結(jié)構(gòu)如下

注意此時的文件結(jié)構(gòu),庫自己單獨擁有一套 `庫 Make`?

庫 Make

為庫創(chuàng)建 Make 文件

文件 `userApp/Aerosand/Make/files` 內(nèi)容如下

注意庫使用 `LIB` 而不是 `EXE`

庫的目標(biāo)路徑結(jié)尾是 `LIBBIN`

因為這個 Aerosand 庫的實現(xiàn)不再進(jìn)一步需要鏈接其他庫,所以 `userApp/Aerosand/Make/options` 直接空置即可。

編譯這個庫

可以通過命令 `cd $FOAM_USER_LIBBIN` 確認(rèn) Aerosand 庫的編譯結(jié)果文件 `libAerosand.so` 的所在位置。

因為庫內(nèi)的類可能會有多個,甚至還有其他子庫,所以庫編譯后會同時在庫的目錄下生成 `lnInclude` 文件夾,`lnInclude` 包含了該庫所有類(/子庫)的聲明( `.H` 文件)或者實現(xiàn) `.C文件` 的快捷方式,方便后續(xù)鏈接的時候可以提供統(tǒng)一路徑??梢詤⒖?OpenFOAM 的 `$FOAM_SRC/OpenFOAM` 庫,可以看到根目錄下有 `lnInclude` 文件夾,其中包含了此庫內(nèi)的所有類(/子庫)的快捷方式。

在終端使用 `find` 命令搜索OpenFOAM源代碼文件的時候往往能看到相近的路徑 `lnInclude/` 下也有一個同名文件,這個就是快捷方式。我們一般選擇打開閱讀本體。

應(yīng)用 Make

因為 Aerosand 庫已經(jīng)被編譯成了動態(tài)庫,所以我們需要在應(yīng)用的 `Make/options` 文件中為應(yīng)用提供動態(tài)庫鏈接。

修改 `userApp/Make/files` 文件

修改 `userApp/Make/options` 文件

標(biāo)識符號

  • `EXE_INC` 指定需要**包含**的庫

    • `-I` 同樣用來指定**包含**“`庫.H`”,從 `lnInclude` 文件夾取得路徑

  • `EXE_LIB` 指定需要**鏈接**的庫

    • `-L` 同樣用來指定**鏈接**“`庫文件.so`”的路徑

    • `-l` 同樣用來指定**鏈接**“`庫文件.so`”的名稱(字母是 link 的 l,不是 include 的 i)

一定要注意路徑,路徑對于成功編譯非常重要。一般指定的路徑都是從本地出發(fā)的(可以從本地路徑出發(fā),定義其他庫的絕對路徑,見下文演示)。

編譯運行

編譯應(yīng)用

此時終端信息分為兩段,第一段將主源碼編譯成目標(biāo)文件,第二段鏈接動態(tài)庫到應(yīng)用,生成可執(zhí)行文件。

可以通過 `cd $FOAM_USER_APPBIN` 確認(rèn)應(yīng)用的可執(zhí)行程序被編譯到了哪里。

運行編譯生成的應(yīng)用程序

運行結(jié)果如下

結(jié)果和前面各種方式實現(xiàn)的結(jié)果相同。


OpenFOAM 類

OpenFOAM 中有大量的類。我們大概了解一些常見的類型/類:

`Switch`

  • OpenFOAM 為了用戶使用簡單方便,大量使用 `Switch` 供用戶選擇。`Switch` 本質(zhì)上一種布爾類型。用戶可以使用 `false` , `off`? , `no` ,? `n`? , `f` 表示否定選項,使用 `true` ,? `on` , `yes` , `y`? , `t` 表示肯定選項

`label`

  • 本質(zhì)上是 OpenFOAM 定義的具有 `INT_SIZE` 大小的 integer data type

`scalar`

  • 本質(zhì)上是 OpenFOAM 定義的具有 `FLOAT_SIZE` 或者 `DOUBLE_SIZE` 大小的 floating-point data type

`vector`

  • 矢量數(shù)據(jù)結(jié)構(gòu)

  • 包含重載后的數(shù)學(xué)運算方法

`tensor`

  • 張量數(shù)據(jù)結(jié)構(gòu)

  • 包含重載后的數(shù)學(xué)運算方法

`dimensionedScalar/*Vector/*Tensor`

  • 具有 OpenFOAM 單位系統(tǒng)的量

  • 包含名稱、單位和取值等成員數(shù)據(jù),以及相應(yīng)的成員方法

`scalar*/vector*/tensorField`

  • 基礎(chǔ)類型的列表值

  • 描述各種場

  • 包含數(shù)據(jù)和方法

`dimensionSet`

  • OpenFOAM 的單位系統(tǒng)

  • `dimensionSet (const scalar mass, const scalar length, const scalar time, const scalar temperature, const scalar moles, const scalar current=0, const scalar luminousIntensity=0)`

  • `[質(zhì)量, 長度, 時間, 溫度, 摩爾, 電流, 光強(qiáng)]`

  • OpenFOAM 也提供很多單位的組合 `$FOAM_SRC/OpenFOAM/dimensionSet/dimensionSets.H`

`tmp<>`

  • OpenFOAM 經(jīng)常見到的處理臨時數(shù)據(jù)的特殊類

  • 因為 C++ 很多時候的內(nèi)存都需要手動管理,所以 OpenFOAM 為開發(fā)者提供此類

`IOobject`

  • 提供接入 OpenFOAM 各種數(shù)據(jù)結(jié)構(gòu)的方法,本身沒有成員數(shù)據(jù)

Vector 類

我們拿出 Vector 類看一下 OpenFOAM 對 Vector 類的實現(xiàn)。

找到 Vector 類,進(jìn)入文件夾,

閱讀 `Vector.H` 的介紹可知,該類是模板化的 3D Vector,繼承自 VectorSpace 并添加了 3 分量的構(gòu)造、分量元素的接口函數(shù)、點積和叉積的方法等。具體到 `Vector.H` 的代碼,可以看到簡單的方法在代碼中直接實現(xiàn),復(fù)雜方法則大量使用內(nèi)聯(lián)函數(shù)(inline funtion)以提高代碼性能。OpenFOAM 特別提供 `VectorI.H` 文件來寫內(nèi)聯(lián)函數(shù)的實現(xiàn)。該類沒有 `.C` 文件,因為所有方法都是通過內(nèi)聯(lián)函數(shù)實現(xiàn)的。其他的文件夾 `/bools` , `/complex` , `/floats` ,`/ints` ,`/lists` 都是 Vector 類對不同基本類型的 `typedef` 。

我們大概看一下 `Vector.H` 代碼

陌生的代碼細(xì)節(jié)可以忽略,或者網(wǎng)上查詢相關(guān)語法。

比如,基于 3 分量的構(gòu)造,其內(nèi)聯(lián)函數(shù)在 `VectorI.H` 中實現(xiàn)如下

?`Vector` 后面加后綴 `I` 用來表示是對內(nèi)聯(lián)函數(shù)的實現(xiàn)

  • 成員數(shù)據(jù) `v_` 和重載的運算符 `[]` 來自父類 `VectorSpace`,查看 `$FOAM_SRC/primitives/VectorSpace/VectorSpace.H`

  • 傳入函數(shù)的參數(shù)為 `vx, vy, vz`,并使用**常引用**提高性能,保證數(shù)據(jù)安全

  • 函數(shù)將 3 分量參數(shù)對應(yīng)傳入類的成員數(shù)據(jù)

  • 模板化的函數(shù),類型為 `Cmpt`

  • 如果我們自己寫也可以參考這種類的架構(gòu)

比如,3 分量的接口函數(shù)因為簡單,就沒有內(nèi)聯(lián)而直接跟在 `Vector.H` 對應(yīng)的聲明中直接實現(xiàn),如下

  • 對常量數(shù)據(jù)和非常量數(shù)據(jù)定義了兩套函數(shù),提高性能

  • 標(biāo)識符 `noexcept` 直接告訴編譯器該函數(shù)不會發(fā)生異常,利于編譯優(yōu)化

比如,標(biāo)量積和矢量積的聲明和實現(xiàn)分別是

聲明如下:

實現(xiàn)如下:

  • `const` 約束輸入?yún)?shù),需要使用常量 vector

  • `const` 約束函數(shù)體,函數(shù)體內(nèi)部不能修改類的成員數(shù)據(jù)

  • 另外聲明 `v1` 作為本類的成員數(shù)據(jù) `v_` 的引用

  • 返回 `v1` 和 `v2` 的計算結(jié)果

根據(jù)類型 `Cmpt` 的不同,就實現(xiàn)了針對不同類型的方法。比如 `Vector<scalar>` 就是 `scalar` 類型的類實現(xiàn)。比如,在 `/Vector/ints/labelVector.H` 文件中說明了這一點,如下

`Vector.H` 的代碼最后還專門提供了 `Traits` 部分來說明該模板類中一些方法的方案。

比如對連續(xù)性的方案

  • 如果 `Cmpt` 是連續(xù)的,那么 `Vector<Cmpt>` 也是連續(xù)的

上面這些代碼介紹主要是為了幫助讀者慢慢熟悉 C++ 語言在 OpenFOAM 中的使用,克服對 C++ 語言的陌生和恐懼,便于讀者理解下文要寫的主源碼。暫時不需要花費更多時間去閱讀更多 OpenFOAM 的源代碼,后續(xù)會有專門的系列文章閱讀和討論代碼。

我們通過一個應(yīng)用來使用 OpenFOAM 的自有類型/類。

OpenFOAM 提供快捷命令

`foamNewApp` 快速建立應(yīng)用模板

文件結(jié)構(gòu)如下

**注意,開發(fā)庫的文件結(jié)構(gòu)與前文稍有不同。因為開發(fā)庫里可能由好幾個類構(gòu)成,開發(fā)庫擁有自己的 Make 文件,集中管理多個類**

開發(fā)庫

頭文件 `myClass.H` 如下

源文件 `myClass.C` 如下

庫 Make

為開發(fā)庫寫 Make 文件

文件 `userApp/myLib/Make/files` 如下

本次開發(fā)庫的實現(xiàn)沒有用到其他庫,所以文件 `userApp/myLib/Make/options` 空置。

將開發(fā)庫編譯成動態(tài)庫

主源碼

如果我們要使用 tensor 類,不僅要包含它的頭文件,還需要包含相關(guān)的庫。

查找 tensor 庫

通過 `ls` 命令我們可以看到 `OpenFOAM` 擁有自己的 Make 文件以及 `lnInclude` ,所以 tensor 類屬于 OpenFOAM 庫。后續(xù)我們需要在應(yīng)用中包含、鏈接 OpenFOAM 庫。

同樣的,我們想要使用 `dimensionedTensor` 和 `tensorField`

可以看到這兩個類也屬于 `OpenFOAM` 庫。

我們包含這些庫,也包含自己的開發(fā)庫

主源碼如下

應(yīng)用 Make?

文件 `userApp/Make/files` 如下

原則上來說,我們應(yīng)該在 `userApp/Make/options` 里面鏈接 `OpenFOAM` 庫。實際上,因為 `OpenFOAM` 庫是最基本的庫,所以,所有的應(yīng)用都默認(rèn)隱含的自動鏈接 `OpenFOAM` 庫,無需再顯式的寫明。

所以,我們只需要在 `userApp/Make/options` 里面鏈接開發(fā)庫。

編譯運行

運行結(jié)果如下

fvCFD.H

在實際開發(fā)中,我們還需要用到更多的和 FVM 相關(guān)的類來離散求解偏微分方程。OpenFOAM 提供 `fvCFD.H` ,其中包含了大部分和 FVM 相關(guān)的頭文件,包括 tensor 類等。使用 `fvCFD.H` 可以減少主源碼要寫的頭文件數(shù)量。

我們找一下 `fvCFD.H` 文件

顯然 `fvCFD.H` 不在 `OpenFOAM 庫` 里,而是在 `finiteVolume 庫` 里,所以需要另外在 `Make/options` 中包含、鏈接。

我們將上述主源碼中的非開發(fā)庫頭文件全部替換成 `fvCFD.H` 。

此時的 `Make/options` 文件應(yīng)修改為(當(dāng)然開發(fā)庫鏈接仍然需要有)

  • `finiteVolume` 被顯式的包含、鏈接

  • `meshTools` 補(bǔ)充了 `finiteVolume` 中涉及的其他庫

重新編譯運行,結(jié)果相同。


OpenFOAM 應(yīng)用

在完全理解了編譯過程的種種,我們使用 OpenFOAM 提供的工具,串一個較為完整的應(yīng)用開發(fā)流程。

創(chuàng)建應(yīng)用

在用戶文件夾下創(chuàng)建應(yīng)用項目,進(jìn)入該應(yīng)用項目

接著可以拷貝一個簡單算例用于開發(fā)過程的測試

準(zhǔn)備腳本

為了方便開發(fā),可以創(chuàng)建腳本文件,我們使用下劃線前綴表明它是一個腳本,區(qū)別于 OpenFOAM 原生文件。下面舉個例子。

`_appmake.sh` 腳本主要負(fù)責(zé)應(yīng)用的編譯,暫時寫入如下內(nèi)容

`_appclean.sh` 腳本主要負(fù)責(zé)應(yīng)用的清理,暫時寫如下內(nèi)容

`_caserun.sh` 腳本主要是負(fù)責(zé)應(yīng)用編譯成功后,調(diào)試算例的運行,暫時寫入如下內(nèi)容

`_caseclean.sh` 腳本主要是負(fù)責(zé)清理應(yīng)用到到編譯前狀態(tài),如果應(yīng)用要修改,那么測試算例也要還原到運行前的狀態(tài),所以暫時寫入如下內(nèi)容

庫的編譯清理也可以類似的創(chuàng)建腳本,這里不多贅述。

我們可以簡單的運行這些腳本,如下所示

說明文件

為了方便后續(xù)開發(fā)和使用,還應(yīng)該準(zhǔn)備說明文件。

寫入需要的開發(fā)備忘、運行步驟、注意事項等內(nèi)容。請不要吝嗇時間,務(wù)必花費一點點時間把問題寫清楚,不然日后轉(zhuǎn)交他人,或者自己重看,都會十分痛苦。

項目結(jié)構(gòu)

所以,應(yīng)用的文件結(jié)構(gòu)如下

主源碼

打開主源碼 `of00.C`

這里我約定

`/* comments */` 寫在代碼功能塊之前,用于正式說明或者介紹此代碼功能塊

`// comments` 寫在具體代碼行附近,用于解釋、標(biāo)記或者想法等

代碼解釋

  • OpenFOAM 文件頭內(nèi)容

    • 文中均省略處理

  • `#include "fvCFD.H"`

    • 包含了所有的 FVM 方法,通常必須

  • `#include "setRootCase.H"`

    • 建立應(yīng)用的參數(shù)列表的類,檢查算例文件結(jié)構(gòu)

    • 使用 `find $FOAM_SRC -name setRootCase.H` 去查閱

  • `#include "createTime.H"`

    • 創(chuàng)建 `time` 類的 `runTime` 對象,需要算例

  • `#include "creatMesh.H"`

    • 求解器應(yīng)用需要該頭文件

    • 創(chuàng)建 `fvMesh` 類的 `mehs` 對象

  • `Info`

    • OpenFOAM 提供的輸出語法,適配 OpenFOAM 多種類型

  • `nl`

    • OpenFOAM 提供的換行符,和 `endl` 類似

    • 本系列約定,當(dāng)存在大段輸出的時候,中間換行用 `nl` ,結(jié)尾處用 `endl`

  • `runTime.printExecutionTime(Info)`

    • 打印時間相關(guān)信息

主源碼開發(fā)

我們在主代碼中添加簡單的內(nèi)容

開發(fā)庫 `myLibrary` 的寫法與上一節(jié)同理。這里不再重復(fù)討論,因為本例用不到,所以我們空置處理。

注意,這里演示了如何鏈接使用其他開發(fā)庫。

我們沒有使用新開發(fā)庫 `myLibrary` ,調(diào)用的依然是上一節(jié)的開發(fā)庫 `myLib` (見 `#include myClass.H`? )。所以,我們需要妥善處理鏈接問題。

應(yīng)用 Make?

默認(rèn)生成的 `userApp/Make/files` 基礎(chǔ)上添加自開發(fā)庫

  • 注意書寫格式,比如標(biāo)識符、行尾的 `\` 換行

    • 原則上可以一行寫完所有語句,雖然有警告,但不是不行

    • 為了方便維護(hù),使用換行符 `\` 來換行,換行符 `\` 前面多加空格無所謂,后面如果有空格會有警告

  • `EXE_INC`

    • 以 `-I` 標(biāo)識開頭列出所有需要包含的頭文件的路徑

    • `$(LIB_SRC)` 是環(huán)境變量

    • 可以等同替換為 `-I$(FOAM_SRC)/finiteVolume/lnInclude`

    • 或者直接寫成絕對地址 `-I/usr/lib/openfoam/openfoam2306/src/finiteVolume/lnInclude`

    • 開發(fā)庫的調(diào)用是相對地址 `../of00_3/myLib/lnInclude`

  • `EXE_LIBS`

    • 小寫 `-l` 標(biāo)識列出庫的名字

    • 大寫 `-L` 標(biāo)識列出庫的路徑

查看默認(rèn)生成的 `userApp/Make/file`,其內(nèi)容不需要修改。

編譯運行

編譯并運行該應(yīng)用

  • 編譯時會警告 mesh 未使用,我們確實沒有使用,這不影響

運行結(jié)果如下

以后的運行結(jié)果不再贅述 OpenFOAM 標(biāo)準(zhǔn)輸出信息。


小結(jié)

到此為止,我們應(yīng)該清楚明白了 OpenFOAM 應(yīng)用開發(fā)的邏輯和架構(gòu)。

希望這樣的介紹能讓讀者感受到“清晰”和“連續(xù)”。

在實際開發(fā)中,開發(fā)庫可以是用戶自定義邊界條件,也可以是一些用戶工具等等。后續(xù)會逐漸討論OpenFOAM求解器的各個部分。


OpenFOAM開發(fā)編程基礎(chǔ)00 基本實現(xiàn)和的評論 (共 條)

分享到微博請遵守國家法律
重庆市| 普兰店市| 霸州市| 竹北市| 金昌市| 博客| 安泽县| 越西县| 晋中市| 康保县| 平潭县| 府谷县| 东台市| 宜章县| 玉龙| 邹城市| 武安市| 黄梅县| 新野县| 无锡市| 长武县| 荆门市| 仁化县| 寻乌县| 南阳市| 海南省| 乌兰察布市| 固阳县| 仁化县| 文山县| 察雅县| 彭水| 黎城县| 调兵山市| 镇平县| 内江市| 桃园县| 海阳市| 常熟市| 永登县| 越西县|