问题描述
求解如下方程
的间断初值问题称为激波管问题也叫黎曼问题。
该问题描述的是无粘理想气体在中一根管道中由压力或者速度驱动在突变的初始条件下的变化过程。
通过求解通量的雅各比矩阵
其中
其中
对于该方程存在一个特殊关系
以守恒变量表示的守恒形式和非守恒形式的方程之间满足雅各比矩阵
即
且
任何与
相似的矩阵
以及相应的可逆变换
满足
于是根据原变量
通过原变量形式的方程可以很容易计算出矩阵
的特征值,从而得到与
相似的对角阵,将方程解耦,得到三个方程。分别求出三个方程的特征线并对应三个变量,沿三条特征线三个变量的值不发生改变,这三个变量称为黎曼不变量。
问题求解
一根两端封闭的管道内左右两侧有不同的气体,中间以一物体将两侧气体分隔开,左侧气体满足
右侧气体满足
这里以二阶迎风的通量差分格式计算。
由原变量表达的方程中空间导数项的系数矩阵
的特征值为
分别表示三个黎曼不变量的传播速度,其中本问题中显然一定有亚音速的区域,因此必然有
通量分裂的方法有很多,这里使用Lax-Friedrichs分裂
前面提到了雅各比矩阵的特征值是
那么根据当地的
可以很容易计算出三个特征值的值,找到三者中模最大的特征值
然后构造新的雅各比矩阵
这样必然有
且
的全部特征值大于0,
于是得到分裂的守恒方程
式中第二项表示向右传播的信息,第三项表示向左传播的信息,分别使用
和
时间使用单步推进。
具体代码如下
#include <iostream> #include <vector> #include <cmath> #define gamma 1.4 const int NE=100,//空间点数 NS=1000, SKIP_STEP=10;//时间步数 const double rb=-5,l=10,//计算域左边界,计算域长度 dt=0.005,//时间步长 dx=l/NE; using namespace std; void F(vector<double> &_F,double w1,double w2,double w3) { double u=w2/w1,t=u*w2; _F[0]=w2; _F[1]=(3-gamma)*t/2+(gamma-1)*w3; _F[2]=(1-gamma)/2*u*t+gamma*u*w3; } void F_div(vector<double>::iterator &f,const vector<double> &F,double w1,double w2,double w3) { *f=F[0]; f++; *f=F[1]; f++; *f=F[2]; f++; } double max(double x1,double x2) { if(x1>x2) return x1; else return x2; } void advance(vector<double>& w1,vector<double>& w2,vector<double>& w3,vector<double>& F_p,vector<double>& F_m) { vector<double> tF(3,0); double l=0; vector<double>::iterator f_p=F_p.begin(),f_m=F_m.begin(); for(int i=0;i<w1.size();i++) { F(tF,w1[i],w2[i],w3[i]); double u=w2[i]/w1[i],p=(gamma-1)*(w3[i]-w2[i]*w2[i]/w1[i]/2),c=sqrt(gamma*p/w1[i]); l=max(max(abs(u+c),abs(u-c)),l); F_div(f_p,tF,w1[i],w2[i],w3[i]); F_div(f_m,tF,w1[i],w2[i],w3[i]); } for(int i=0;i<w1.size();i++) { F_p[3*i]+=l*w1[i]; F_m[3*i]-=l*w1[i]; F_p[3*i+1]+=l*w2[i]; F_m[3*i+1]-=l*w2[i]; F_p[3*i+2]+=l*w3[i]; F_m[3*i+2]-=l*w3[i]; } f_p=F_p.begin()+3,f_m=F_m.begin()+3; w1[1]=w1[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[1]=w2[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[1]=w3[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; for(int i=2;i<w1.size()-2;i++) { w1[i]=w1[i]-0.25*(3*(*f_p)-4*(*(f_p-3))+*(f_p-6))*dt/dx +0.25*(*(f_m+6)-4*(*(f_m+3))+3*(*(f_m)))*dt/dx; f_p++; f_m++; w2[i]=w2[i]-0.25*(3*(*f_p)-4*(*(f_p-3))+*(f_p-6))*dt/dx +0.25*(*(f_m+6)-4*(*(f_m+3))+3*(*(f_m)))*dt/dx; f_p++; f_m++; w3[i]=w3[i]-0.25*(3*(*f_p)-4*(*(f_p-3))+*(f_p-6))*dt/dx +0.25*(*(f_m+6)-4*(*(f_m+3))+3*(*(f_m)))*dt/dx; f_p++; f_m++; } w1[w1.size()-2]=w1[w1.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[w2.size()-2]=w2[w2.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[w3.size()-2]=w3[w3.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w1[0]=w1[1]; w2[0]=-w2[1]; w3[0]=w3[1]; w1[w1.size()-1]=w1[w1.size()-2]; w2[w2.size()-1]=-w2[w2.size()-2]; w3[w3.size()-1]=w3[w3.size()-2]; } struct val { const vector<double> &w1,&w2,&w3; val(const vector<double>& _w1,const vector<double>& _w2,const vector<double>& _w3):w1(_w1),w2(_w2),w3(_w3){}; }; void init(vector<double> &w1,vector<double> &w2,vector<double> &w3) { int i=1; for(;i<w1.size()/2;i++) { w1[i]=1; w2[i]=0; w3[i]=2/(gamma-1); } for(;i<w1.size()-1;i++) { w1[i]=1; w2[i]=0; w3[i]=1/(gamma-1); } w1[0]=w1[1]; w2[0]=-w2[1]; w3[0]=w3[1]; w1[w1.size()-1]=w1[w1.size()-2]; w2[w2.size()-1]=-w2[w2.size()-2]; w3[w3.size()-1]=w3[w3.size()-2]; } ostream& operator<<(ostream& out,const val& Q) { for(int i=1;i<Q.w1.size()-1;i++) { double rho=Q.w1[i],u=Q.w2[i]/Q.w1[i],p=(gamma-1)*(Q.w3[i]-Q.w2[i]*Q.w2[i]/Q.w1[i]/2); out<<i*dx+rb-dx<<'t'<<rho<<'t'<<u<<'t'<<p<<'n'; } return out; } int main() { vector<double> w1(NE+3),w2(NE+3),w3(NE+3),F_p(3*NE+9),F_m(3*NE+9); val Q(w1,w2,w3); init(w1,w2,w3); cout<<w1.size()-2<<'t'<<NS/SKIP_STEP<<'t'<<rb<<'t'<<l<<'n'; cout<<Q<<'n'; for(int i=0;i<NS;i++) { advance(w1,w2,w3,F_p,F_m); if(i%SKIP_STEP==0)cout<<Q<<'n'; } }
计算结果如下
蓝线是压力,黑线是密度,红线是速度
由于我也没有激波管解析解的结果。所以也没办法判断具体结果差多少,不过从网上看到的一些激波管问题的解来看基本规律应该没有太大的问题,不过由于二阶迎风格式的耗散较小,因此间断处有一些震荡。
要想消除震荡可以利用限制器在间断附近使用耗散更大的低阶通量或者使用ENO和WENO格式来抑制震荡。
现在先测试一下一阶格式,使用如下advance函数
void advance(vector<double>& w1,vector<double>& w2,vector<double>& w3,vector<double>& F_p,vector<double>& F_m) { vector<double> tF(3,0); double l=0; vector<double>::iterator f_p=F_p.begin(),f_m=F_m.begin(); for(int i=0;i<w1.size();i++) { F(tF,w1[i],w2[i],w3[i]); double u=w2[i]/w1[i],p=(gamma-1)*(w3[i]-w2[i]*w2[i]/w1[i]/2),c=sqrt(gamma*p/w1[i]); l=max(max(abs(u+c),abs(u-c)),l); F_div(f_p,tF,w1[i],w2[i],w3[i]); F_div(f_m,tF,w1[i],w2[i],w3[i]); } for(int i=0;i<w1.size();i++) { F_p[3*i]+=l*w1[i]; F_m[3*i]-=l*w1[i]; F_p[3*i+1]+=l*w2[i]; F_m[3*i+1]-=l*w2[i]; F_p[3*i+2]+=l*w3[i]; F_m[3*i+2]-=l*w3[i]; } f_p=F_p.begin()+3,f_m=F_m.begin()+3; w1[1]=w1[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[1]=w2[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[1]=w3[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; for(int i=2;i<w1.size()-2;i++) { w1[i]=w1[i]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[i]=w2[i]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[i]=w3[i]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; } w1[w1.size()-2]=w1[w1.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[w2.size()-2]=w2[w2.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[w3.size()-2]=w3[w3.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w1[0]=w1[1]; w2[0]=-w2[1]; w3[0]=w3[1]; w1[w1.size()-1]=w1[w1.size()-2]; w2[w2.size()-1]=-w2[w2.size()-2]; w3[w3.size()-1]=w3[w3.size()-2]; }
结果如下
可以看到使用高耗散的低阶格式间断处的震荡就可以被抑制住。但是耗散非常明显。
这里使用限制器来抑制间断震荡,首先相邻确定差分的比值根据信息的传播方向分成两个方向的比值
限制器函数
格式如下
这里做了一个简化,直接令
用
即
具体的advance函数如下
void advance(vector<double>& w1,vector<double>& w2,vector<double>& w3,vector<double>& F_p,vector<double>& F_m) { vector<double> tF(3,0); double l=0; vector<double>::iterator f_p=F_p.begin(),f_m=F_m.begin(); for(int i=0;i<w1.size();i++) { F(tF,w1[i],w2[i],w3[i]); double u=w2[i]/w1[i],p=(gamma-1)*(w3[i]-w2[i]*w2[i]/w1[i]/2),c=sqrt(gamma*p/w1[i]); l=max(max(abs(u+c),abs(u-c)),l); F_div(f_p,tF,w1[i],w2[i],w3[i]); F_div(f_m,tF,w1[i],w2[i],w3[i]); } for(int i=0;i<w1.size();i++) { F_p[3*i]+=l*w1[i]; F_m[3*i]-=l*w1[i]; F_p[3*i+1]+=l*w2[i]; F_m[3*i+1]-=l*w2[i]; F_p[3*i+2]+=l*w3[i]; F_m[3*i+2]-=l*w3[i]; } f_p=F_p.begin()+3,f_m=F_m.begin()+3; w1[1]=w1[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[1]=w2[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[1]=w3[1]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; for(int i=2;i<w1.size()-2;i++) { double r_p=(w1[i]-w1[i-1])/(w1[i-1]-w1[i-2]), r_m=(w1[i+2]-w1[i+1])/(w1[i+1]-w1[i]); if(w1[i-1]==w1[i-2]) r_p=0; if(w1[i+1]==w1[i]) r_m=0; w1[i]=w1[i]-phi(r_p)*0.25*(3*(*f_p)-4*(*(f_p-3))+*(f_p-6))*dt/dx -(1-phi(r_p))*0.5*(*(f_p)-*(f_p-3))*dt/dx +phi(r_m)*0.25*(*(f_m+6)-4*(*(f_m+3))+3*(*(f_m)))*dt/dx -(1-phi(r_m))*0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; r_p=(w2[i]-w2[i-1])/(w2[i-1]-w2[i-2]), r_m=(w2[i+2]-w2[i+1])/(w2[i+1]-w2[i]); if(w2[i-1]==w2[i-2]) r_p=0; if(w2[i+1]==w2[i]) r_m=0; w2[i]=w2[i]-phi(r_p)*0.25*(3*(*f_p)-4*(*(f_p-3))+*(f_p-6))*dt/dx -(1-phi(r_p))*0.5*(*(f_p)-*(f_p-3))*dt/dx +phi(r_m)*0.25*(*(f_m+6)-4*(*(f_m+3))+3*(*(f_m)))*dt/dx -(1-phi(r_m))*0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; r_p=(w3[i]-w3[i-1])/(w3[i-1]-w3[i-2]), r_m=(w3[i+2]-w3[i+1])/(w3[i+1]-w3[i]); if(w3[i-1]==w3[i-2]) r_p=0; if(w3[i+1]==w3[i]) r_m=0; w3[i]=w3[i]-phi(r_p)*0.25*(3*(*f_p)-4*(*(f_p-3))+*(f_p-6))*dt/dx -(1-phi(r_p))*0.5*(*(f_p)-*(f_p-3))*dt/dx +phi(r_m)*0.25*(*(f_m+6)-4*(*(f_m+3))+3*(*(f_m)))*dt/dx -(1-phi(r_m))*0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; } w1[w1.size()-2]=w1[w1.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w2[w2.size()-2]=w2[w2.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w3[w3.size()-2]=w3[w3.size()-2]-0.5*(*(f_p)-*(f_p-3))*dt/dx-0.5*(*(f_m+3)-*(f_m))*dt/dx; f_p++; f_m++; w1[0]=w1[1]; w2[0]=-w2[1]; w3[0]=w3[1]; w1[w1.size()-1]=w1[w1.size()-2]; w2[w2.size()-1]=-w2[w2.size()-2]; w3[w3.size()-1]=w3[w3.size()-2]; }
计算结果如下
对比前面一阶格式和二阶格式可以看到,使用限制器之后二阶格式的间断震荡被明显抑制住了,而耗散也没有一阶格式那么明显。
- 点赞
- 收藏
- 分享
-
- 文章举报
原文始发于:计算流体力学简介(八)——激波管问题
主题测试文章,只做测试使用。发布者:sys234,转转请注明出处:http://www.cxybcw.com/92454.html