前言
今天閱讀了一本說明書,《gdbOF: A Debugging Tool for OpenFOAM》
受himryangzz影片啟發去讀相關內容,在此對himryangzz表示感謝
希望本篇文章能為需要gdb除錯of的人節約時間
文章前言:
文章前言說of確實做的很不錯,但除錯者需要對of類的結構有較好的理解
gdbOF正是為了解決該問題而存在的,內建的一些宏可以讓of除錯更容易,一些資料結構類看起來更透明簡單
總而言之,文章介紹說gdbOF內建的這些宏很實用
那我們看看王婆賣的什麼瓜
第一章:
- 在 WM_PROJECT DIR/etc/bashrc可設定$WM_COMPILE_OPTION為除錯模式
#- Optimised, debug, profiling:
# WM_COMPILE_OPTION = Opt | Debug | Prof
export WM_COMPILE_OPTION=Opt
也可這樣設定為debug模式和opt模式
alias of_version_debug='source /opt/openfoam_version/etc/bashrc WM_COMPILE_OPTION=Debug'
alias of_version='source /opt/openfoam_version/etc/bashrc'
installgdbOF.sh在執行時會檢查是否在debug狀態
可能有小夥伴發現自己的debug模式會報錯,找不到一些連結庫這樣,這是由於apt install導致的,需要改為編譯安裝,類似cmake加-g也可
第二章:
講了下用gdb怎麼更好的把結果輸出出來
例如書中提及的第一個指令,
$(gdb) p *v@v_size
我們稍微改一下就是壓力場所有的數值
寫到這裡已經可以讓很多做of的人期待書內後面的內容了
書裡說如果我們需要快速的提取我們想要的資訊,那麼就需要我們對openfoam的繼承樹很瞭解
那麼就拿p下手,瞭解下相關繼承樹
gdb列印出來這樣
這東西不能多看,看多了精神容易出問題
我們之前部落格也提過p是volScalarFiel類,構造方法是這樣的
template<class Type, template<class> class PatchField, class GeoMesh>
Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
(
const IOobject& io,
const Mesh& mesh
)
:
Internal(io, mesh, dimless, false),
timeIndex_(this->time().timeIndex()),
field0Ptr_(nullptr),
fieldPrevIterPtr_(nullptr),
boundaryField_(mesh.boundary())
{
readFields();
// Check compatibility between field and mesh
if (this->size() != GeoMesh::size(this->mesh()))
{
FatalIOErrorInFunction(this->readStream(typeName))
<< " number of field elements = " << this->size()
<< " number of mesh elements = " << GeoMesh::size(this->mesh())
<< exit(FatalIOError);
}
readOldTimeIfPresent();
if (debug)
{
InfoInFunction
<< "Finishing read-construction of" << endl << this->info() << endl;
}
能看到初始化了很多東西,下面展開看下初始化了什麼
Internal(io, mesh, dimless, false),
timeIndex_(this->time().timeIndex()),
field0Ptr_(nullptr),
fieldPrevIterPtr_(nullptr),
boundaryField_(mesh.boundary())
這次你再看gdb列印那些爛東西,我們對比一下
對勁了對勁了,
非常對勁!
我們們再說說
$(gdb) p *v@v_size
要展示什麼資料,是內部面的壓力場的資料,為什麼這麼說
因為我用gdb中開啟p的地址,指向的是內部場
那這麼看我們可以暢所欲為的抽取所有資料了,
其實本來就可以的,但是gdbOF好就好在為你指明瞭要抽取哪些
比如說邊介面資料書內的提示是
$(gdb) p *(vSF.boundaryField_.ptrs_.v_[0].v_)@(vSF.boundaryField_.ptrs_.v_[0].size_)
書內解釋說vSF是volScalarField的縮寫,那p剛好符合要求,輸入即可看到邊界場的值
比如說我們開啟這個boundary,
FoamFile
{
version 2.0;
format ascii;
class polyBoundaryMesh;
location "constant/polyMesh";
object boundary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
3
(
movingWall
{
type wall;
inGroups List<word> 1(wall);
nFaces 20;
startFace 760;
}
fixedWalls
{
type wall;
inGroups List<word> 1(wall);
nFaces 60;
startFace 780;
}
frontAndBack
{
type empty;
inGroups List<word> 1(empty);
nFaces 800;
startFace 840;
}
)
有3個patch那麼UList就應該是三維,Ulist[2]是frontAndBack,因為是empty,按理說就應該是沒有資料
確實是如此
繼續回頭看書上內容,讀到這裡已經非常驚喜了
這得省多少勁
但也不必過於樂觀,目前這個測試案例比較簡單,具體除錯時候不一定碰到什麼問題
書上繼續說以上都是甜頭,接下來我們內建整合的一些宏更有用,比如說ppatchesvalueslimits,pinternalvalueslimits.,ppatchlist等
書上也提及了一個問題,就是of有時候程式碼跳轉不過去,確實是有這個問題的,書上說,碰見這樣的你就一步步走吧
這裡gdbOF也提供了便利,step, next and finish這些宏也內建好了
第三章:
書中提及,在of中矩陣的顯示是個難題,gdb採用了c風格的程式碼顯示,遍歷顯示倒是好寫,但效能太差,of這種大矩陣沒法用
這點gdbOF利用python做出了改進,分別介紹了pfvmatrixfull和pfvmatrixsparse的虛擬碼。
這裡額外說一句啊,其實很贊同matlab的矩陣表達方式的,非常快,而且向量化程式設計寫法可以讓速度提升一大截,以後看看有沒有機會把matlab 植入到of中
看他們虛擬碼的意思貌似是收集一部分資料自己進行LU分解,之前我也讀過一些論文說ofLU分解效率不大行的,可能gdbOF給出了python版本的解決方案
** Structure of gdbOF Command pfvmatrixsparse.**
1. Get parameters
2. Get upper and lower arrays with gdb
3. Redirect data to aux file
4. Format aux files: gdb format → python format
5. Call python script to assemble the matrix
(a) Read aux files
(b) Do lduAddressing for sparse matrix
(c) Generate sparse file header
6. Format aux files: python format → gdb format
7. Show in output or/and save file in octave format adding the header to the body
這裡簡述一下庫中其他程式功能
pfindCell用於找位置,在此基礎上pinternalvalueslimits抽取場值以及中心節點資料,pfvmatrix用於觀察為該單元組裝的方程式,psurfacevalues範圍周圍一圈的面值
翻譯不一定準確,最好還是從原始碼上看
gdbOF內還有除錯圖形介面,可能是最近推出來的,但個人還是建議使用gdb配合他們的宏,他們的宏確實是能減少好多使用時間
如果這圖形介面做的和paraFoam似的,我寧可用matlab或python做後處理
第四章:
第四章做了案例演示,gdbOF這個成果他們發表在了論文上,案例演示內容和論文基本一樣
我感覺這樣的案例演示恰恰是of缺少的,像matlab或fluent人家幫助文件都有案例演示,就連c++都有,of的資料結構這麼複雜,每個類的建立或者函式的使用稍微配一個案例,簡單說說即可,
你看查matlab幫助文件的有幾個關心matlab函式過載啥樣,有例子照虎畫貓不更簡單嗎
但是很可惜,開源有利有弊,但絕不討好任何人,
of門檻一下就上去了
案例中很常用pfvmatrixfull這個命令,可以著重去看下
pfindcell的具體使用方法如下:
(gdb)p findce11 0.05 0.45 0.05
RESULTS:
Nearest cell centroid cell number:400
Containing point cell number (-1=out):400
psurfacevalues的具體使用方法如下:
(gdb) psurfacevalues phir 400
internal Face:
$5 = 0
internal Face:
$6 = -0.0045
internal Face:
$7 = 0
empty Face
empty Face
boundary Face:
$8 = 0.0045
附錄:
附錄A展示了LDU分解的虛擬碼
for k : sizeDiag
A[k][k] = diag[k]
end for
for k : sizeAddr
i = lowerAddr[k]
j = upperAddr[k]
A[i][j] = upper[k]
A[j][i] = lower[k]
end for
附錄B說明了volField (volScalarField, volVectorField or volTensorField),與對應的surfaceField區別
前者的內部區域場儲存在體網格中心,後者儲存在體網格交介面
比如說看下面這個虛擬碼,intFieldValue以及patchFieldValue的獲取方式值得借鑑
l = myVolField.internalField.size_
i = 0
while(i<l)
intFieldValue = myVolField.internalField.v_[i]
//do something
i++
l = myVolField.boundaryField.ptrs_.size_
while(i<l)
patch = myVolField.boundaryField.ptrs_.v_[i]
l2 = patch.size_
j = 0
while(j<l2)
patchFieldValue = patch.v_[j]
//do something
j++
i++
附錄C介紹了在面網格上的資料如何查詢
大概意思是找到和查詢面最近的點,然後用體的值估計,因為體的值和麵的值相關
虛擬碼如下所示:(這裡對patch面分別做了處理)
cellIndex = mesh.searchCellIndex(point)
for f : nFaces
fieldFaceValue = false
if isInternalFace(f)
if owner[f]==cellIndex || neighbour[f]==cellIndex
fieldFaceValue = field.internalField[f]
else
if owner[f]==cellIndex
patchIndex = whichPatch(f)
f_local = whichFace(f,patchIndex)
fieldFaceValue = field.boundaryField[patchIndex][f_local]
if(fieldFaceValue)
//do something with fieldFaceValue
end for
附錄D是gdbOF命令列查詢表,不一一展示了,有興趣的查文件
結語
有一說一,這些宏確實能提高開發效率
這要是能整合在code或vim外掛裡就更好了,
如果我這邊做好了會在部落格裡分享下,
後續如果對ofgdb宏有更多自己的看法也會分享
其他
本週塞爾維亞天王諾瓦克德約科維奇世界第一共計378周,超過格拉夫的377周,名副其實的世界第一,???
喜悅之情難以言表
2023-02-27 21:08:22 星期一,寫到這裡記錄一下當前時刻
每當處於逆境時,自己會選擇看一些德約集錦或是穿上德約衣服球鞋拿著德約球拍奔赴球場
從2012年開始,粉了十年
論文致謝一定會有德約科維奇名字
逆境之王諾瓦克德約科維奇,在此表示祝賀
一起探索openfoam也是相當有趣的一件事,非常歡迎私信討論
指正的價值要比打賞更重要,下面是個人聯絡方式,希望能結交到志同道合的朋友