目录
一、研究目标
二、理论推导
三、算例实现
一、研究目标
前面我们已经介绍了二阶双曲型方程显式、隐式差分格式,可否像抛物型方程一样,构建更高精度的差分格式。接下来我们介绍紧差分格式。这里继续以非齐次二阶双曲型偏微分方程的初边值问题为研究对象:
公式(1)中u表示一个与时间t和位置x有关的待求波函数,及方程右端项函数都是已知函数,是非零常数。
二、理论推导
第一步:网格剖分。对矩形求解域进行等距剖分,即
第二步:弱化原方程。将原来的连续方程离散到网格节点上成立,得到离散方程:
第三步:对偏导数进行更高精度近似。由泰勒公式(固定时间t不变):
将上面两式相加可得
有
类似的有
将上面两式相加后除以2得
从而
现令
及
则公式(3)可写作
整理可得
由于原双曲型方程为,也即
公式(4)可改写为
再利用中心差商近似
上式中用数值解代替精确解并忽略高阶项,可得
其中,。
联合初边值条件,可得到以下紧差分格式:
其中,局部截断误差为,关于时间t是二阶的,关于空间x是四阶的。
三、算例实现
紧差分格式计算双曲型偏微分方程初边值问题:
已知其精确解为。分别取步长为和,给出节点处的数值解和误差。
代码如下:
#include <cmath>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
int i,j,k,m,n;
double a,h,r,tau,pi,c1,c2;
double *x,*t,**u,*a1,*b,*c,*d,*ans;
double phi(double x);
double ddphi(double x);
double psi(double x);
double alpha(double t);
double beta(double t);
double f(double x, double t);
double exact(double x, double t);
double *chase_algorithm(double *a, double *b, double *c, double *d, int n);
m=200;
n=50;
a=1.0;
pi=3.14159265359;
h=pi/m;
tau=1.0/n;
r=a*tau/h;
r=r*r;
printf("r=%.4f.\n",r);
x=(double*)malloc(sizeof(double)*(m+1));
for(i=0;i<=m;i++)
x[i]=i*h;
t=(double*)malloc(sizeof(double)*(n+1));
for(k=0;k<=n;k++)
t[k]=k*tau;
u=(double **)malloc(sizeof(double*)*(m+1));
for(i=0;i<=m;i++)
u[i]=(double*)malloc(sizeof(double)*(n+1));
for(i=0;i<=m;i++)
u[i][0]=phi(x[i]);
for(k=1;k<=n;k++)
{
u[0][k]=alpha(t[k]);
u[m][k]=beta(t[k]);
}
for(i=1;i<m;i++)
u[i][1]=(r*u[i-1][0]+2*(1-r)*u[i][0]+r*u[i+1][0]+tau*tau*f(x[i],t[0])+2*tau*psi(x[i]))/2.0;
a1=(double*)malloc(sizeof(double)*(m-1));
b=(double*)malloc(sizeof(double)*(m-1));
c=(double*)malloc(sizeof(double)*(m-1));
d=(double*)malloc(sizeof(double)*(m-1));
ans=(double*)malloc(sizeof(double)*(m-1));
c1=1.0-6*r;
c2=10.0+12*r;
for(k=1;k<n;k++)
{
for(i=1;i<m;i++)
{
d[i-1]=(-c1)*(u[i-1][k-1]+u[i+1][k-1])-c2*u[i][k-1]+2*(u[i-1][k]+10*u[i][k]+u[i+1][k])+tau*tau*(f(x[i-1],t[k])+10*f(x[i],t[k])+f(x[i+1],t[k]));
a1[i-1]=c1;
b[i-1]=c2;
c[i-1]=a1[i-1];
}
d[0]=d[0]-c1*u[0][k+1];
d[m-2]=d[m-2]-c1*u[m][k+1];
ans=chase_algorithm(a1,b,c,d,m-1);
for(i=0;i<m-1;i++)
u[i+1][k+1]=ans[i];
}
free(ans);
k=4*n/5;
j=m/10;
for(i=j;i<=m/2;i=i+j)
printf("(x,t)=(%.2f,%.2f),y=%f,error=%.4e.\n",x[i],t[k],u[i][k],fabs(u[i][k]-exact(x[i],t[k])));
free(a1);free(b);free(c);free(d);free(x);free(t);
return 0;
}
double phi(double x)
{
return sin(x);
}
double psi(double x)
{
return sin(x);
}
double alpha(double t)
{
return 0.0;
}
double beta(double t)
{
return 0.0;
}
double f(double x, double t)
{
return 2*sin(x)*exp(t);
}
double exact(double x, double t)
{
return sin(x)*exp(t);
}
double *chase_algorithm(double *a, double *b, double *c, double *d, int n)
{
int i;
double *ans,*g,*w,p;
ans=(double*)malloc(sizeof(double)*n);
g=(double*)malloc(sizeof(double)*n);
w=(double*)malloc(sizeof(double)*n);;
g[0]=d[0]/b[0];
w[0]=c[0]/b[0];
for(i=1;i<n;i++)
{
p=b[i]-a[i]*w[i-1];
g[i]=(d[i]-a[i]*g[i-1])/p;
w[i]=c[i]/p;
}
ans[n-1]=g[n-1];
i=n-2;
do
{
ans[i]=g[i]-w[i]*ans[i+1];
i=i-1;
}while(i>=0);
free(g);free(w);
return ans;
}
当时,计算结果如下:
r=1.6211.
(x,t)=(0.31,0.80),y=0.687686,error=4.3538e-05.
(x,t)=(0.63,0.80),y=1.308057,error=8.2815e-05.
(x,t)=(0.94,0.80),y=1.800386,error=1.1398e-04.
(x,t)=(1.26,0.80),y=2.116481,error=1.3400e-04.
(x,t)=(1.57,0.80),y=2.225400,error=1.4089e-04.
当时,计算结果如下:
r=0.4053.
(x,t)=(0.31,0.80),y=0.687727,error=2.7423e-06.
(x,t)=(0.63,0.80),y=1.308135,error=5.2162e-06.
(x,t)=(0.94,0.80),y=1.800493,error=7.1794e-06.
(x,t)=(1.26,0.80),y=2.116607,error=8.4399e-06.
(x,t)=(1.57,0.80),y=2.225532,error=8.8743e-06.
从计算结果可知,当时间步长减小为原来的1/4、空间步长减小为原来的1/2时,误差减小为原来的1/16。