計算流體力學簡介(五)——通量差分

基本原理

守恆型方程
ut+fx=0\frac{\partial u}{\partial t}+\frac{\partial f}{\partial x}=0
使用空間中心差分離散
uit+fi+12fi12Δx=0\frac{\partial u_i}{\partial t}+\frac{f_{i+\frac{1}{2}}-f_{i-\frac{1}{2}}}{\Delta x}=0
其中i+12i+\frac{1}{2}i12i-\frac{1}{2}表示網格點ii與兩側網格點i+1i+1i1i-1的中點。構造函數fi+12=g(uik,,ui,,ui+l)f_{i+\frac{1}{2}}=g(u_{i-k},\cdots,u_i,\cdots,u_{i+l})(fi12=f(i1)+12f_{i-\frac{1}{2}}=f_{(i-1)+\frac{1}{2}})使得g(ui+12,,ui+12)=f(ui+12)g(u_{i+\frac{1}{2}},\cdots,u_{i+\frac{1}{2}})=f(u_{i+\frac{1}{2}})則稱函數gg構造出的fi+12f_{i+\frac{1}{2}}爲數值通量。利用uit+fi+12fi12Δx=0\frac{\partial u_i}{\partial t}+\frac{f_{i+\frac{1}{2}}-f_{i-\frac{1}{2}}}{\Delta x}=0進行時間離散推進得到的格式爲守恆型差分格式。而構造函數gg即是對通量ff的重構,因此這個方法稱爲通量重構。
這個方法保證了通量在網格單元的交界面(i+12i+\frac{1}{2})兩側始終是相等的,不會因爲網格離散而產生數值散度,從而在網格交界面上出現非物理的源和匯。

對流方程

ut+ux=0\frac{\partial u}{\partial t}+\frac{\partial u}{\partial x}=0
初場爲u0(x)=ex2x[5,5]u_0(x)=e^{-x^2},x\in[-5,5]週期邊界
ui+12=ui+ui+12u_{i+\frac{1}{2}}=\frac{u_i+u_{i+1}}{2},時間推進使用歐拉單步推進,得到離散方程
uin+1uinΔt+ui+1n+uin2uin+ui1n2Δx=0\frac{u_i^{n+1}-u_i^n}{\Delta t}+\frac{\frac{u_{i+1}^n+u_i^n}{2}-\frac{u_i^n+u_{i-1}^n}{2}}{\Delta x}=0化簡之後我們可一看到就是前面提到的一階中心差分的格式,根據前面一階中心差分格式的分析可以知道這個格式不穩定,需要添加人工粘性,這裏就不解這個方程了。

Burgers方程

利用通量重構求解
ut+uux=0\frac{\partial u}{\partial t}+u\frac{\partial u}{\partial x}=0
初場爲u0(x)=ex2x[5,5]u_0(x)=e^{-x^2},x\in[-5,5]週期邊界
f(u)=u22f(u)=\frac{u^2}{2}
同樣使用上面的離散方法進行離散得到
uin+1=uinΔt4Δx((ui+1n)2(ui1n)2)u_i^{n+1}=u_i^n-\frac{\Delta t}{4\Delta x}((u_{i+1}^n)^2-(u_{i-1}^n)^2)
具體代碼如下

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
const int NE=32,//空間點數
NS=100;//時間步數
const double rb=-5,l=10,//計算域左邊界,計算域長度
dt=0.1,//時間步長
dx=l/NE;
void init_guass(vector<double> &u0)//設置高斯函數初場
{
    for(int i=0;i<u0.size();i++) 
	{
		u0[i]=exp(-pow((l*double(i)/(NE-1)+rb),2));
	}
}
void advance(vector<double>& u)
{
    vector<double> t(u);
    for(int i=1;i<u.size()-1;i++)
    {
        u[i]=t[i]-0.25*(t[i+1]*t[i+1]-t[i-1]*t[i-1])*dt/dx;
    }
    int i=0;
    u[i]=t[i]-0.25*(t[i+1]*t[i+1]-t[u.size()-1]*t[u.size()-1])*dt/dx;
    i=u.size()-1;
    u[i]=t[i]-0.25*(t[0]*t[0]-t[i-1]*t[i-1])*dt/dx;
}
ostream& operator<<(ostream& out,const vector<double>& A)
{
        for(int j=0;j<A.size()-1;j++)
        {
            out<<A[j]<<'\t';
        }
        out<<A[A.size()-1];
    return out;
}
int main()
{
    vector<double> u(NE+1);
    init_guass(u);
    cout<<NE+1<<'\t'<<NS<<'\t'<<rb<<'\t'<<l<<'\n';
    cout<<u<<'\n';
    for(int i=0;i<NS;i++)
    {
        advance(u);
        cout<<u<<'\n';
    }
    return 0;
}

在這裏插入圖片描述
可以看到計算髮散了,從前面對流方程可以看到以這種單元兩側的平均值作爲通量點的值實際上是一種中心差分格式,那麼顯示推進必然不穩定,必須添加人工粘性。因此這裏考慮使用迎風格式來進行計算。
fi+12=ui2f_{i+\frac{1}{2}}=u_{i}^2則得到推進公式爲
uin+1=uin+Δt2Δx((uin)2(ui1n)2)u_i^{n+1}=u_i^n+\frac{\Delta t}{2\Delta x}((u_i^n)^2-(u_{i-1}^n)^2)
得到advance函數爲

void advance(vector<double>& u)
{
    vector<double> t(u);
    for(int i=1;i<u.size()-1;i++)
    {
        u[i]=t[i]-0.5*(t[i]*t[i]-t[i-1]*t[i-1])*dt/dx;
    }
    int i=0;
    u[i]=t[i]-0.5*(t[i]*t[i]-t[u.size()-1]*t[u.size()-1])*dt/dx;
}

計算結果如下
在這裏插入圖片描述
可以看到使用迎風的通量重構即可得到穩定的顯式推進格式,並且結果也基本上沒有明顯問題。
這裏使用更高階格式嘗試一下。
fi+12=fi+12fiΔx+O(Δx)fi=fifi1=fifiΔx+O(Δx)f_{i+\frac{1}{2}}=f_i+\frac{1}{2}f_i'\Delta x+O(\Delta x)\\ f_i=f_i\\ f_{i-1}=f_i-f_i'\Delta x+O(\Delta x)
可以得到
fi+12=3fifi12f_{i+\frac{1}{2}}=\frac{3f_i-f_{i-1}}{2}
於是有新的推進格式
uin+1=uinΔt4Δx(3(uin)24(ui1n)2+(ui2n)2)u_i^{n+1}=u_i^n-\frac{\Delta t}{4\Delta x}(3(u_i^n)^2-4(u_{i-1}^n)^2+(u_{i-2}^n)^2)
得到新的advance函數爲

void advance(vector<double>& u)
{
    vector<double> t(u);
    for(int i=1;i<u.size()-1;i++)
    {
        u[i]=t[i]-0.25*(3*t[i]*t[i]-4*t[i-1]*t[i-1]+t[i-2]*t[i-2])*dt/dx;
    }
    int i=0;
    u[i]=t[i]-0.25*(3*t[i]*t[i]-4*t[u.size()-1]*t[u.size()-1]+t[u.size()-2]*t[u.size()-2])*dt/dx;
    i=1;
    u[i]=t[i]-0.25*(3*t[i]*t[i]-4*t[i-1]*t[i-1]+t[u.size()-1]*t[u.size()-1])*dt/dx;
}

計算結果如下
在這裏插入圖片描述
可以看到間斷部分更加尖銳,更貼近真解,不像之前那樣間斷的拐角處比較光滑。但是可以看到在間斷結束的位置有一個向下的小尖峯,這是使用高階耗散(高於二階的耗散)時總會出現的一個現象,具體產生的原因我也不是很清楚,似乎類似於吉布斯現象。

發佈了23 篇原創文章 · 獲贊 9 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章