目录
一、研究目标
二、理论推导
三、算例实现
四、结论
一、研究目标
我们已经在专栏中介绍了椭圆型偏微分方程的五点菱形差分格式,这里我们继续以该方法为背景,探讨如何提高五点法的精度,即从二阶精度提升到四阶精度。
研究目标现继续以矩形区域内的Poisson方程的边值问题:
二、理论推导
提高差分格式精度的一种有效方法是紧差分,即引入中间函数,对二阶偏导数进行更精细的逼近。
与五点菱形差分法类似,首先进行矩形区域的剖分,然后将原方程弱化,使其仅在离散节点处成立。在利用差商代替微商之前,引入中间函数,令
原方程在离散节点处满足
又有,当 有界时,
从而有
也就是
由二维抛物型偏微分方程紧交替方向隐格式方法介绍中算子公式
可知公式(3)为
同理可得
将算子作用到公式(2)上,有
然后将公式(4)、(5)一起代入公式(6),可得
用数值解代替精确解并忽略高阶项,可得紧差分格式:
该格式的局部截断误差为,将公式(7)中第1式整理化简,利用记号
可得
该紧格式每一步计算都涉及9个点,所以公式(7)称为九点紧差分格式。
该格式无法写成线性方程组的形式,只能写成
其中,
记
则原数值格式可以简写为
其中,
,
且
为解该方程组,将未知量按照下标拉长成一个列向量,并写出块矩阵形式,为
上述方程组的高斯-赛德尔迭代公式为:
其中,,加括号的上标k表示迭代次数。
三、算例实现
采用九点紧差分格式求解椭圆型方程边值问题:
已知该问题精确解为。分别取步长和,输出6个节点和处的数值解和误差。要求在各节点处最大误差的迭代误差限为。
代码如下:(采用Gauss-Seidel迭代)
include <cmath>
#include <stdlib.h>
#include <stdio.h>
#define pi 3.14159265359int main(int argc, char* argv[])
{int m,n,i,j,k;double xa,xb,ya,yb,dx,dy,alpha,beta,gamma,err,maxerr;double *x,*y,**u,**g,**temp,kexi,eta1,eta2;double leftboundary(double y);double rightboundary(double y);double bottomboundary(double x);double topboundary(double x);double f(double x, double y);double **Gij(double *x, double *y, int m, int n);double exact(double x, double y);xa=0.0;xb=2.0;ya=0.0;yb=1.0;m=64;n=32;printf("m=%d, n=%d.\n",m,m);dx=(xb-xa)/m;dy=(yb-ya)/n;beta=1.0/(dx*dx);gamma=1.0/(dy*dy);kexi=beta+gamma;eta1=10*beta-2*gamma;eta2=10*gamma-2*beta;x=(double*)malloc(sizeof(double)*(m+1));for(i=0;i<=m;i++)x[i]=xa+i*dx;y=(double*)malloc(sizeof(double)*(n+1));for(j=0;j<=n;j++)y[j]=ya+j*dy;u=(double**)malloc(sizeof(double*)*(m+1));temp=(double**)malloc(sizeof(double*)*(m+1));for(i=0;i<=m;i++){u[i]=(double*)malloc(sizeof(double)*(n+1));temp[i]=(double*)malloc(sizeof(double)*(n+1));}for(j=0;j<=n;j++){u[0][j]=leftboundary(y[j]);u[m][j]=rightboundary(y[j]);}for(i=1;i<m;i++){u[i][0]=bottomboundary(x[i]);u[i][n]=topboundary(x[i]);}for(i=1;i<m;i++){for(j=1;j<n;j++)u[i][j]=0.0;}g=Gij(x,y,m,n);for(i=0;i<=m;i++){for(j=0;j<=n;j++)temp[i][j]=u[i][j];}k=0;do{maxerr=0.0;for(i=1;i<m;i++){for(j=1;j<n;j++){temp[i][j]=(g[i][j]-kexi*(u[i-1][j-1]+temp[i-1][j+1]+u[i+1][j-1]+temp[i+1][j+1])-eta1*(u[i-1][j]+temp[i+1][j])-eta2*(u[i][j-1]+temp[i][j+1]))/(-20*kexi);err=temp[i][j]-u[i][j];if(err>maxerr)maxerr=err;u[i][j]=temp[i][j];}}k=k+1;}while(maxerr>0.5*1e-10);printf("k=%d.\n",k);k=m/4;for(i=k;i<m;i=i+k){printf("(%.2f,0.25), y=%f, err=%.4e.\n",x[i],u[i][n/4],fabs(exact(x[i],y[n/4])-u[i][n/4]));}k=m/4;for(i=k;i<m;i=i+k){printf("(%.2f,0.50), y=%f, err=%.4e.\n",x[i],u[i][n/2],fabs(exact(x[i],y[n/2])-u[i][n/2]));}for(i=0;i<=m;i++){free(u[i]);free(temp[i]);}free(u);free(temp);free(x);free(y);return 0;
}double leftboundary(double y)
{return sin(pi*y);
}
double rightboundary(double y)
{return exp(1.0)*exp(1.0)*sin(pi*y);
}
double bottomboundary(double x)
{return 0.0;
}
double topboundary(double x)
{return 0.0;
}
double exact(double x, double y)
{return exp(x)*sin(pi*y);
}
double f(double x, double y)
{return (pi*pi-1)*exp(x)*sin(pi*y);
}
double **Gij(double *x, double *y, int m, int n)
{int i,j;double temp1,temp2,temp3,**ans;ans=(double**)malloc(sizeof(double*)*(m+1));for(i=0;i<=m;i++)ans[i]=(double*)malloc(sizeof(double)*(n+1));for(i=1;i<m;i++){for(j=1;j<n;j++){temp1=f(x[i-1],y[j-1])+10*f(x[i],y[j-1])+f(x[i+1],y[j-1]);temp2=f(x[i-1],y[j])+10*f(x[i],y[j])+f(x[i+1],y[j]);temp3=f(x[i-1],y[j+1])+10*f(x[i],y[j+1])+f(x[i+1],y[j+1]);ans[i][j]=-(temp1+temp3+10*temp2)/12.0;}}return ans;
}
相同的问题,与五点菱形差分法计算结果进行了对比,结果如下:
当时,计算结果如下:
+++++++++++++九点紧差分格式++++++++++++++
m=32, n=16.
k=747.
(0.50,0.25), y=1.165829, err=6.7140e-06.
(1.00,0.25), y=1.922127, err=1.1487e-05.
(1.50,0.25), y=3.169047, err=1.4319e-05.
(0.50,0.50), y=1.648731, err=9.4951e-06.
(1.00,0.50), y=2.718298, err=1.6245e-05.
(1.50,0.50), y=4.481709, err=2.0250e-05.
+++++++++++++五点菱形差分格式++++++++++++
m=32,n=16.
k=887
(0.50,0.25), y=1.169343, err=3.5207e-03.
(1.00,0.25), y=1.928138, err=6.0228e-03.
(1.50,0.25), y=3.176531, err=7.4986e-03.
(0.50,0.50), y=1.653700, err=4.9790e-03.
(1.00,0.50), y=2.726799, err=8.5175e-03.
(1.50,0.50), y=4.492294, err=1.0605e-02.
当时,计算结果如下:
+++++++++++++九点紧差分格式++++++++++++++
m=64, n=32.
k=2790.
(0.50,0.25), y=1.165822, err=4.1552e-07.
(1.00,0.25), y=1.922116, err=7.1227e-07.
(1.50,0.25), y=3.169034, err=8.9066e-07.
(0.50,0.50), y=1.648722, err=5.8773e-07.
(1.00,0.50), y=2.718283, err=1.0074e-06.
(1.50,0.50), y=4.481690, err=1.2597e-06.
+++++++++++++五点菱形差分格式++++++++++++
m=64,n=32.
k=3315
(0.50,0.25), y=1.166702, err=8.7958e-04.
(1.00,0.25), y=1.923620, err=1.5048e-03.
(1.50,0.25), y=3.170908, err=1.8751e-03.
(0.50,0.50), y=1.649965, err=1.2439e-03.
(1.00,0.50), y=2.720410, err=2.1281e-03.
(1.50,0.50), y=4.484341, err=2.6518e-03.
四、结论
从计算结果可知,对于九点紧差分格式来说,当步长减半时,误差减小为约1/16,可见其数值格式是四阶收敛的。同时,与五点菱形差分格式相比,九点紧差分法迭代步数更少,同时计算精度更高!