flux unity 流体_【游戏流体力学基础及Unity代码(八)】激波捕捉法和RiemannSolver...
本篇介紹各種解決burgers方程的數值方法,相應的代碼可在clatterrr/CFDcodepython找到。
上一章介紹了最簡單的非線性方程,即一維無粘性burgers方程,但我們將它稍微改寫一下
微分項用泰勒展開微分實際上得到了
上式是精確解。但是把右側的值全算出來不現實。如果只取等式右側第一項,就是有限差分(finite difference)形式的迎風格式(Upwind Scheme)。
一階upwind格式的缺點就是舍棄了太多泰勒展開項,所以很不精確。而有限差分法規定每個網格由一個離散的值表示,在處理有關激波的不連續問題時并不那么自然,方便。所以有限體積(finite volume)法便被提了出來,這種方法將一個格子里的值看成連續的,從前到后積分后再除以格子長度就是格子的值,這種方法在處理不連續問題時有很大優勢。比如最簡單的有限體積法下的Lax-Friedrichs方法:
然而這種方法也只有一階精度,并且有一些人工粘性(artifial viscosity)所導致的耗散(disspative)。它看起來像是這樣的。虛線是準確的解,而其它顏色的線是不同情況下的Lax-Friedrhs。人工粘性就像高斯模糊樣,讓尖銳的部分變得平滑了,然而我們要模擬的激波也消失了,這顯然不是一種很好的方法。
所以我們繼續嘗試新方法,即Lax-Wendroff方法:
Lax-Wendroff方法有二階精度,并且人工粘性的影響非常小,二階精度在大多數時候都夠用了。其代碼可在這里找到https://github.com/clatterrr/CFDcodepython/blob/main/RiemannSolver/Burgers1dLaxWendroff.py。與Lax-Wendroff方法很相似的MacCormack方法也經常被使用:
LaxWendroff和MacCormack都是二階精度,看起來很方便好用,然而有著隱藏的問題,那就是振蕩(oscillation)。它看起來像是這樣的,虛線是準確的解,其它顏色則是在不同情況下的LaxWendroff方法,在臨近激波的時候,雖然人工粘性幾乎沒了,但解的跳動非常嚴重,忽上忽下,偏離準確結果非常多。
振蕩出現的原因也非常簡單。比如我們要更新U_i的值,就要考慮它的U_i+1/2和U_i-1/2的值,這兩個值又和U_i-1和U_i+1有關。所以U_i實際上的增加量,就是它自己的斜率,而斜率通過U_i-1和U_i+1計算出來。這就是問題所在。如下圖,黑線是精確的解析解,而藍線是近似的數值解。當U_i是全局最高值,理論上不能再有值比這個值高,而由于U_i-1小于U_i+1導致U_i的斜率為正的話,那么U_i+1/2會比U_i的值還要高,如下圖,紅線就是斜率,紅點就是不該出現的高點,這就造成了振蕩。
關于這個問題,油管上有三個非常不錯的視頻Need For Flux Limiter, Flux Limiters , How Does Flux Limiter Work,這三個視頻的博主是同一人,似乎是MIT的教師,他的有關計算流體力學的其它視頻質量也非常高,推薦關注。
如何消除這種振蕩?Godunov直接采用一種非常簡單的方法,也就是我們小學就學過的分情況討論。比如對于下圖,黑色箭頭所指的位置,半個時間步后的值應該是多少?如果uL和uR都大于零,那么它們都會向右移動,那么結果就是uL。如下圖的左下,淺藍是初始位置,深藍是半個時間步后的位置,深藍畫得有點偏為了方便比較。
最終的五種情況如下:
這樣極大值附近就不會出現比極大值還大的值了,極小值也是如此,振蕩自然也就消失了。這就是一種Total Variation Diminishing方法,簡稱TVD方法,可以用于消除振蕩。另一種分情況討論的方法是Roe方法。標準的Roe方法要先線性化,算出一堆特征值和矩陣,然后再計算f,但本篇并不打算討論這個,所以僅僅用一種簡單的方法代替這個,也就是
上面的a其實就是上篇所說的激波的速度,因此也被稱為Roe Speed。還有一種是HLL方法。
這就是早期人類用數值模擬馴服激波的珍貴方法。【誤】
然而Godunov,Roe和HLL方法的準確度很差,都要先判斷激波兩側的速度然后決定F的值。速度僅僅被劃分為兩個區間,即大于零或小于零,F也只能從一開始就設定好的幾個結果中選一個,因此只有一階精度。能不能不要這么一刀切,而是根據向前速度與向后速度的比例來確定最終的F呢?
我們要繼續嘗試新方法,也就是通量限制器(flux limiter),也叫slop limiter。比如對于之前的LaxWendroff方法,要計算半步長的U,實際上應該用網格中心的U,加上自己斜率乘以網格長的二分之一,向前的斜率由前一格的值減去這一格的值得到,也就是下式
那個phi,就是flux limiter。對于LaxWendroff來說,它永遠是一,因此也導致了振蕩問題,這樣不好。所以要繼續嘗試不同的方法。比如一個叫flux limiter的方法。因此我們先定義向前的斜率與向后的斜率之比為r,用r來決定phi。簡便起見,下面的數學公式用u來代替U - dt\dx*F。
繼續分情況討論,如果r < 0,也就是前后斜率的符號不一樣,那就說明出現了局部最大值或最小值,我們不能讓半步的值比局部最大值還大,也不能比局部最小值還小,那么就定義此時的斜率為零,也就是 phi = 0。如果向前的斜率與向后的斜率符號相同,比如都是正數,但前向的斜率絕對值略小,那么就要注意向前半步的值不能比前一格的值還要大,因為此時前一格可能是局部最大值。所以此時phi = r。如果向前斜率的絕對值比向后的更大,那么此時我們就使用laxWendroff所使用的phi = 1就行了,這就是minmod limiter。下圖紅線代表半步長的值。
表達式可以寫成下面兩種形式:
但實際寫代碼的時候更常使用下面這種函數的形式
除了minmod之外,還可以選擇其它的flux limiter,最常用的如下:
上面的改進是基于LaxWendroff。但也可以使用另一種方法,也就是Monotonic Upstream-centered Scheme for Conservation Laws,簡稱MUSCL。它的就是在計算半步F的時候,不像之前那樣使用此處的半步U,而且同時將而是把相鄰網格所計算的此處的半步值也計算進來。
如下圖,i+1/2處的值,即可以由左邊U_i計算得到U^L,也可以由U_{i+1}計算得到U^R,而MUSCL方法將這兩種值的影響都考慮了進來。
而將兩個值都考慮進來后半步長F的具體算法,仍然可以由godunov或其它的flux limiter算法計算。比如由MUSCL + minmod來計算burgers方程,那么公式如下:
用上面介紹的所有方法解1dBurgers問題的代碼都可以clatterrr/CFDcodepython找到。除了上面這些顯式方法外,還有隱式方法也可以用,比如Runge-Kutta法,本篇不再介紹了。這些方法主要用來解決本系列第四篇提到的Euler方程,第七篇提到的Burgers方程,以及下一篇第九篇提到的淺水波方程。了解這些求解非線性方程的方法之后,就可以開始在unity上模擬了。
另外,我對一些概念理解還不夠深入,所以本篇和代碼可能有一些錯誤。還請大佬們發現后指導我一下。
宣傳:我創建了一個模擬流體交流Q群,歡迎各位喜歡自己編寫代碼模擬流體的小伙伴們入群互相交流學習!群號:1001290801
參考
僅僅看我寫的文章肯定是不夠的,所以我選了一些不錯的書籍列在下面
[1]《Computational Fluid Mechanics and Heat Transfer》 by Anderson, Dale Pletcher, Richard H. Tannehill, John C
[2]《Finite Volume Methods for Hyperbolic Problems》by Randall J. LeVeque
[3]《Handbook of Numerical Methods for Hyperbolic Problems Basic and Fundamental Issues》by Rémi Abgrall and Chi-Wang Shu
[4]《Riemann Solvers and Numerical Methods for Fluid Dynamics A Practical Introduction》 by Eleuterio F. Toro非常經典的書,超級推薦Riemann Solvers and Numerical Methods for Fluid Dynamics
[5]《Numerical Methods for Conservation Laws From Analysis to Algorithm》 by Jan S. Hesthaven
[6]《Solving Hyperbolic Equations with Finite Volume Methods》 by M. Elena Vázquez-Cendón 這書后面有一些代碼可以參考
[7]《Numerical Solution of Hyperbolic Conservation Laws》by John A. Trangenstein
[9]《Exact solution of the Riemann problem for the shallow water equations》
[10]《計算淺水動力學——有限體積法的應用》譚維炎 著
推薦代碼,包括了下一篇的淺水波方程。每一份都是經過精心挑選,簡短而又清晰的適合初學者的代碼~
總結
以上是生活随笔為你收集整理的flux unity 流体_【游戏流体力学基础及Unity代码(八)】激波捕捉法和RiemannSolver...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PCL-MAL 聚己内酯马来酰亚胺
- 下一篇: Grafana的Worldmap插件使用