一.问题介绍
考虑一维热传导方程:
(1)
其中a是正常数,是给定的连续函数。按照定解条件的不同给法,可将方程(1)的定解问题分为两类:
第一类、初值问题(也称Cauthy问题):求具有所需次数偏微商的函数,满足方程(1)()和初始条件:
(2)
第二类、初边值问题(也称混合问题):求具有所需次数偏微商的函数,满足方程(1)()和初始条件:
(3)
及边值条件
(4)
假定在相应区域光滑,并且在满足相容条件,使上述问题有唯一充分光滑的解。
二.区域剖分
考虑边值问题(1),(4)的差分逼近。去空间步长和时间步长,其中N,M都是正整数。用两族平行直线:
将矩形域分割成矩形网格,网格节点为。以表示网格内点集合,即位于开矩形G的网点集合;表示所有位于闭矩形的网点集合; =--是网格界点集合。
三.离散格式
第k+1层值通过第k层值明显表示出来,无需求解线性代数方程组,这样的格式称为显格式。
第k+1层值不能通过第k层值明显表示出来,而由线性代数方程组确定,这样的格式称为隐格式。
1.向前差分格式
(5)
,
,,
其中j = 1,2,…,N-1,k = 1,2,…,M-1。以表示网比。则方程(5)可以改写为:
易知向前差分格式是显格式。
2.向后差分格式
(6)
, ,
其中j = 1,2,…,N-1,k = 1,2,…,M-1,易知向前差分格式是显格式。
3.六点对称格式(Grank-Nicolson格式)
将向前差分格式和向后差分格式作算术平均,即得到六点对称格式:
(7)
=
利用和边值便可逐层求到。六点对称格式是隐格式,由第k层计算第k+1层时需解线性代数方程组(因系数矩阵严格对角占优,方程组可唯一求解)。
将其截断误差于(=)展开,则得
= 。
4.Richardson格式
(8) ,
或
(9) 。
这是三层显示差分格式。截断误差阶为。为了使计算能够逐层进行,除初值外,还要用到,这可以用前述二层差分格式计算(为保证精度,可将[0,]分成若干等份)。
四.格式稳定性
通过误差估计方程
(1) 可知对任意的r ,Richardson格式都不稳定,所以Richardson格式绝对不稳定。
(2) 当时,向前差分格式趋于稳定;当时,向前差分格式的误差无限增长。因此向前差分格式是条件稳定。
(3) 向后差分格式和六点对称格式都绝对稳定,且各自的截断误差阶分别为和。
五.数值例子
例1 令f ( x ) = 0和a = 1,可求得u(x,t)一个解析解为u ( x , t ) =exp ( x + t )。
1.用向前差分格式验证得数值结果如下:
请输入n的值(输入0结束程序):
2
请输入m的值(输入0结束程序):
17
xj tk 真实值x[i][k] 近似值u[i][k] 误差err[i][k]
0.333333 0.055556 1.475341 1.473867 0.001474
0.666667 0.055556 2.059004 2.056947 0.002057
0.333333 0.111111 1.559623 1.557037 0.002586
0.666667 0.111111 2.176630 2.173719 0.002911
0.333333 0.166667 1.8721 1.5619 0.003102
0.666667 0.166667 2.300976 2.297385 0.003591
0.333333 0.222222 1.742909 1.739373 0.003536
0.666667 0.222222 2.432425 2.428445 0.003981
0.333333 0.277778 1.842477 1.8387 0.003831
0.666667 0.277778 2.571384 2.567048 0.004337
0.333333 0.333333 1.947734 1.943620 0.004114
0.666667 0.333333 2.718282 2.713651 0.004630
0.333333 0.3888 2.059004 2.054632 0.004372
0.666667 0.3888 2.873571 2.8684 0.004927
0.333333 0.444444 2.176630 2.171992 0.004638
0.666667 0.444444 3.037732 3.032512 0.005220
0.333333 0.500000 2.300976 2.296068 0.004908
0.666667 0.500000 3.211271 3.205744 0.005526
0.333333 0.555556 2.432425 2.427233 0.005193
0.666667 0.555556 3.394723 3.388878 0.005845
0.333333 0.611111 2.571384 2.5654 0.005491
0.666667 0.611111 3.588656 3.582475 0.006181
0.333333 0.666667 2.718282 2.712476 0.005805
0.666667 0.666667 3.793668 3.787133 0.006535
0.333333 0.722222 2.873571 2.867434 0.006137
0.666667 0.722222 4.010392 4.003483 0.006908
0.333333 0.777778 3.037732 3.031243 0.0088
0.666667 0.777778 4.239496 4.232193 0.007303
0.333333 0.833333 3.211271 3.204411 0.006859
0.666667 0.833333 4.4816 4.473969 0.007721
0.333333 0.8888 3.394723 3.387472 0.007251
0.666667 0.8888 4.737718 4.729556 0.008162
0.333333 0.944444 3.588656 3.580991 0.007665
0.666667 0.944444 5.008373 4.999745 0.008628
当n等于2和m等于17时最大误差为0.008628
其中r = 1/2,格式是稳定的。
2. 用向后差分格式验证得数值结果如下:
请输入n的值(输入0结束程序):
6
请输入m的值(输入0结束程序):
6
xj 真实值x[i] 近似值u[i] 误差err[i]
第1层结果 时间节点Tk=0.142857
0.142857 1.330712 1.335002 0.0042
0.285714 1.535063 1.542358 0.007295
0.428571 1.770795 1.779949 0.009154
0.571429 2.042727 2.052524 0.009797
0.714286 2.3518 2.365346 0.0027
0.857143 2.718282 2.724256 0.005974
第1层的最大误差是0.009797
第2层结果 时间节点Tk=0.285714
0.142857 1.535063 1.541797 0.006734
0.285714 1.770795 1.782424 0.011629
0.428571 2.042727 2.057345 0.014618
0.571429 2.3518 2.3715 0.015477
0.714286 2.718282 2.732070 0.013788
0.857143 3.135715 3.144633 0.0019
第2层的最大误差是0.015477
第3层结果 时间节点Tk=0.428571
0.142857 1.770795 1.779324 0.008529
0.285714 2.042727 2.057518 0.014791
0.428571 2.3518 2.375010 0.018592
0.571429 2.718282 2.737884 0.019602
0.714286 3.135715 3.153041 0.017326
0.857143 3.617251 3.628337 0.011086
第3层的最大误差是0.019602
第4层结果 时间节点Tk=0.571429
0.142857 2.042727 2.052888 0.010161
0.285714 2.3518 2.374062 0.0174
0.428571 2.718282 2.740457 0.022175
0.571429 3.135715 3.159058 0.023343
0.714286 3.617251 3.637827 0.020576
0.857143 4.172734 4.185851 0.013117
第4层的最大误差是0.023343
第5层结果 时间节点Tk=0.714286
0.142857 2.3518 2.368276 0.011857
0.285714 2.718282 2.738880 0.020598
0.428571 3.135715 3.161600 0.025886
0.571429 3.617251 3.4485 0.027234
0.714286 4.172734 4.196716 0.023982
0.857143 4.813520 4.828788 0.015268
第5层的最大误差是0.027234
第6层结果 时间节点Tk=0.857143
0.142857 2.718282 2.732017 0.013735
0.285714 3.135715 3.159578 0.0238
0.428571 3.617251 3.7240 0.0299
0.571429 4.172734 4.204278 0.031544
0.714286 4.813520 4.841287 0.027767
0.857143 5.552708 5.570378 0.017670
第6层的最大误差是0.031544
当n等于6时最大误差为0.031544
3. 用六点对称格式验证数值结果如下:
请输入n的值(输入0结束程序):
6
请输入m的值(输入0结束程序):
6
xj 真实值x[i] 近似值u[i] 误差err[i]
第1层结果 时间节点Tk=0.142857
0.142857 1.330712 1.330988 0.000276
0.285714 1.535063 1.535522 0.000459
0.428571 1.770795 1.771368 0.000573
0.571429 2.042727 2.043350 0.000623
0.714286 2.3518 2.357004 0.000585
0.857143 2.718282 2.718692 0.000410
第1层的最大误差是0.000623
第2层结果 时间节点Tk=0.285714
0.142857 1.535063 1.535424 0.000361
0.285714 1.770795 1.771435 0.0000
0.428571 2.042727 2.043538 0.000810
0.571429 2.3518 2.357268 0.000849
0.714286 2.718282 2.719016 0.000734
0.857143 3.135715 3.136162 0.000447
第2层的最大误差是0.000849
第3层结果 时间节点Tk=0.428571
0.142857 1.770795 1.771233 0.000438
0.285714 2.042727 2.043476 0.000749
0.428571 2.3518 2.357355 0.000937
0.571429 2.718282 2.719268 0.000986
0.714286 3.135715 3.136592 0.000877
0.857143 3.617251 3.617825 0.000574
第3层的最大误差是0.000986
第4层结果 时间节点Tk=0.571429
0.142857 2.042727 2.043222 0.000495
0.285714 2.3518 2.357287 0.000869
0.428571 2.718282 2.719377 0.001095
0.571429 3.135715 3.136867 0.001153
0.714286 3.617251 3.618261 0.001010
0.857143 4.172734 4.173365 0.000631
第4层的最大误差是0.001153
第5层结果 时间节点Tk=0.714286
0.142857 2.3518 2.356999 0.000581
0.285714 2.718282 2.719284 0.001003
0.428571 3.135715 3.136973 0.001258
0.571429 3.617251 3.618573 0.001322
0.714286 4.172734 4.173900 0.001166
0.857143 4.813520 4.814271 0.000751
第5层的最大误差是0.001322
第6层结果 时间节点Tk=0.857143
0.142857 2.718282 2.7145 0.000663
0.285714 3.135715 3.136871 0.001157
0.428571 3.617251 3.618705 0.001455
0.571429 4.172734 4.174265 0.001531
0.714286 4.813520 4.814867 0.001347
0.857143 5.552708 5.553559 0.000851
第6层的最大误差是0.001531
当n等于6时最大误差为0.001531
4.用Richardson格式验证数值结果如下:
请输入n的值(输入0结束程序):
5
请输入m的值(输入0结束程序):
5
xj tk 真实值x[i][k] 近似值u[i][k] 误差err[i][k]
0.166667 0.166667 1.395612 1.396080 0.000468
0.333333 0.166667 1.8721 1.9481 0.000760
0.500000 0.166667 1.947734 1.94 0.000915
0.666667 0.166667 2.300976 2.301888 0.000912
0.833333 0.166667 2.718282 2.7149 0.000667
0.166667 0.333333 1.8721 1.5540 0.003182
0.333333 0.333333 1.947734 1.944806 0.002928
0.500000 0.333333 2.300976 2.297583 0.003393
0.666667 0.333333 2.718282 2.713600 0.004682
0.833333 0.333333 3.211271 3.204099 0.007171
0.166667 0.500000 1.947734 1.988145 0.040411
0.333333 0.500000 2.300976 2.291621 0.009355
0.500000 0.500000 2.718282 2.707514 0.010768
0.666667 0.500000 3.211271 3.195685 0.015586
0.833333 0.500000 3.793668 3.907779 0.114111
0.166667 0.666667 2.300976 1.214156 1.086820
0.333333 0.666667 2.718282 3.293822 0.575541
0.500000 0.666667 3.211271 3.1907 0.0463
0.666667 0.666667 3.793668 5.400692 1.607024
0.833333 0.666667 4.4816 1.545878 2.935811
0.166667 0.833333 2.718282 35.747074 33.028792
0.333333 0.833333 3.211271 -24.211361 27.422631
0.500000 0.833333 3.793668 31.083927 27.290259
0.666667 0.833333 4.4816 -69.1509 74.373198
0.833333 0.833333 5.294490 95.1481 .854401
附录1
#include #include #include #define Max_N 1000 double u[Max_N][Max_N],b[Max_N],a[Max_N],c[Max_N],f[Max_N], err[Max_N][Max_N],x[Max_N][Max_N],y[Max_N],beta[Max_N],Err[Max_N]; int n,m; //将空间区间【0,1】分为n等份;时间区间【0,1】分为m等份 void catchup() { int i; beta[1]=c[1]/b[1]; for(i=2;i y[1]=f[1]/b[1]; for(i=2;i<=n;i++) y[i]=(f[i]-a[i]*y[i-1])/(b[i]-a[i]*beta[i-1]); u[n][1]=y[n]; for(i=n-1;i>0;i--) u[i][1]=y[i]-beta[i]*u[i+1][1]; } int main() //一维热传导方程的向前差分格式 { int k,i; double h,t,r; double pi=3.1415627; printf("请输入n的值(输入0结束程序):\\n"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):\\n"); while(scanf("%d",&m)&&m&&n) //u(x,t)=exp(x+t),u(x,0)=exp(x),f(x)=0,x属于[0,1],t属于[0,1],a=1. { h=1.0/(n+1); t=1.0/(m+1); r=t/(h*h); for(i=0;i<=n+1;i++)//初值条件 { u[i][0]=exp(i*h); } for(k=0;k<=m+1;k++)//边值条件 { u[0][k]=exp(k*t); u[n+1][k]=exp((n+1)*h+k*t); } printf("xj tk 真实值x[i][k] 近似值u[i][k] 误差err[i][k]\\n"); for(k=1;k<=m;k++) { for(int j=1;j<=n;j++) { u[j][k]=r*u[j+1][k-1]+(1-2*r)*u[j][k-1]+r*u[j-1][k-1]; } } double T=0; for(k=1;k<=m;k++) { for(i=1;i<=n;i++) { x[i][k]=exp(i*h+k*t); err[i][k]=x[i][k]>u[i][k]?x[i][k]-u[i][k]:u[i][k]-x[i][k]; printf("%lf %lf %lf %lf %lf\\n",i*h,k*t,x[i][k],u[i][k],err[i][k]); if(err[i][k]>T) T=err[i][k]; } } printf("当n等于%d和m等于%d时最大误差为%lf\\n",n,m,T); printf("请输入n的值(输入0结束程序):"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):"); } system("PASUE"); return 0; } 附录2 #include #include #include #define Max_N 1000 double u[Max_N],b[Max_N],a[Max_N],c[Max_N],f[Max_N],err[Max_N], x[Max_N],y[Max_N],beta[Max_N],Err[Max_N]; int n,m; //将空间区间【0,1】分为n等份;时间区间【0,1】分为m等份 void catchup() { int i; beta[1]=c[1]/b[1]; for(i=2;i y[1]=f[1]/b[1]; for(i=2;i<=n;i++) y[i]=(f[i]-a[i]*y[i-1])/(b[i]-a[i]*beta[i-1]); u[n]=y[n]; for(i=n-1;i>0;i--) u[i]=y[i]-beta[i]*u[i+1]; } int main() //一维热传导方程的六点对称格式 { int k,i; double h,t,r; //int j=0; double pi=3.1415627; printf("请输入n的值(输入0结束程序):\\n"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):\\n"); while(scanf("%d",&m)&&m&&n) //u(x,t)=exp(x+t),u(x,0)=exp(x),f(x)=0,x属于[0,1],t属于[0,1],a=1. { h=1.0/(n+1); t=1.0/(m+1); r=t/(h*h); printf("xj 真实值x[i] 近似值u[i] 误差err[i]\\n"); double M=0; //double temp=0; for(k=1;k<=m;k++) { b[1]=1+2*r; c[1]=-r; a[n]=-r; b[n]=1+2*r; if(k==1) { f[1]=exp(h)+r*exp(t); f[n]=exp(n*h)+r*exp((n+1)*h+t); } else { f[1]=u[1]+r*exp(k*t); f[n]=u[n]+r*exp((n+1)*h+k*t); } for(i=2;i b[i]=1+2*r; a[i]=-r; c[i]=-r; if(k==1) f[i]=exp(i*h); else f[i]=u[i]; } catchup(); printf("第%d层结果 时间节点Tk=%lf\\n",k,k*t); double T=0; //double tem=0; for(i=1;i<=n;i++) { x[i]=exp(i*h+k*t); err[i]=x[i]>u[i]?x[i]-u[i]:u[i]-x[i]; printf("%lf %lf %lf %lf\\n",i*h,x[i],u[i],err[i]); if(err[i]>T) T=err[i]; //tem=tem+err[i]*err[i]*h; } printf("第%d层的最大误差是%lf\\n",k,T); if(T>M) M=T; //temp=temp+tem; } printf("\\n"); //Err[j]=temp; printf("当n等于%d时最大误差为%lf\\n",n,M); //printf("当n等于%d时其二范数为%lf\\n",n,Err[j]); //if(j!=0) printf("log(Err[j-1]/Err[j])=%lf\\n\\n",log(Err[j-1]/Err[j])); //j++; printf("请输入n的值(输入0结束程序):"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):"); } system("PASUE"); return 0; } 附录3 #include #include #include #define Max_N 1000 double u[Max_N],b[Max_N],a[Max_N],c[Max_N],f[Max_N],err[Max_N], x[Max_N],y[Max_N],beta[Max_N],Err[Max_N]; int n,m; //将空间区间【0,1】分为n等份;时间区间【0,1】分为m等份 void catchup() { int i; beta[1]=c[1]/b[1]; for(i=2;i y[1]=f[1]/b[1]; for(i=2;i<=n;i++) y[i]=(f[i]-a[i]*y[i-1])/(b[i]-a[i]*beta[i-1]); u[n]=y[n]; for(i=n-1;i>0;i--) u[i]=y[i]-beta[i]*u[i+1]; } int main() //一维热传导方程的六点对称格式 { int k,i; double h,t,r; //int j=0; double pi=3.1415627; printf("请输入n的值(输入0结束程序):\\n"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):\\n"); while(scanf("%d",&m)&&m&&n) //u(x,t)=exp(x+t),u(x,0)=exp(x),f(x)=0,x属于[0,1],t属于[0,1],a=1. { h=1.0/(n+1); t=1.0/(m+1); r=t/(h*h); printf("xj 真实值x[i] 近似值u[i] 误差err[i]\\n"); double M=0; //double temp=0; for(k=1;k<=m;k++) { b[1]=1+r; c[1]=-r/2; a[n]=-r/2; b[n]=1+r; if(k==1) { f[1]=r/2*exp(2*h)+(1-r)*exp(h)+r/2+r/2*exp(t); f[n]=r/2*exp((n+1)*h)+(1-r)*exp(n*h)+r/2*exp((n-1)*h)+r/2*exp((n+1)*h+t); } else { f[1]=r/2*u[2]+(1-r)*u[1]+r/2*exp((k-1)*t)+r/2*exp(k*t); f[n]=r/2*u[n-1]+(1-r)*u[n]+r/2*exp((n+1)*h+(k-1)*t)+r/2*exp((n+1)*h+k*t); } for(i=2;i b[i]=1+r; a[i]=-r/2; c[i]=-r/2; if(k==1) f[i]=r/2*exp((i+1)*h)+(1-r)*exp(i*h)+r/2*exp((i-1)*h); else f[i]=r/2*u[i+1]+(1-r)*u[i]+r/2*u[i-1]; } catchup(); printf("第%d层结果 时间节点Tk=%lf\\n",k,k*t); double T=0; double tem=0; for(i=1;i<=n;i++) { x[i]=exp(i*h+k*t); err[i]=x[i]>u[i]?x[i]-u[i]:u[i]-x[i]; printf("%lf %lf %lf %lf\\n",i*h,x[i],u[i],err[i]); if(err[i]>T) T=err[i]; //tem=tem+err[i]*err[i]*h; } printf("第%d层的最大误差是%lf\\n",k,T); if(T>M) M=T; //temp=temp+tem; } printf("\\n"); //Err[j]=temp; printf("当n等于%d时最大误差为%lf\\n",n,M); //printf("当n等于%d时其二范数为%lf\\n",n,Err[j]); //if(j!=0) printf("log(Err[j-1]/Err[j])=%lf\\n\\n",log(Err[j-1]/Err[j])); //j++; printf("请输入n的值(输入0结束程序):"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):"); } system("PASUE"); return 0; } 附录4 #include #include #include #define Max_N 1000 double u[Max_N][Max_N],b[Max_N],a[Max_N],c[Max_N],f[Max_N], err[Max_N][Max_N],x[Max_N][Max_N],y[Max_N],beta[Max_N],Err[Max_N]; int n,m; //将空间区间【0,1】分为n等份;时间区间【0,1】分为m等份 void catchup() { int i; beta[1]=c[1]/b[1]; for(i=2;i y[1]=f[1]/b[1]; for(i=2;i<=n;i++) y[i]=(f[i]-a[i]*y[i-1])/(b[i]-a[i]*beta[i-1]); u[n][1]=y[n]; for(i=n-1;i>0;i--) u[i][1]=y[i]-beta[i]*u[i+1][1]; } int main() //一维热传导方程的Richardson格式 { int k,i; double h,t,r; double pi=3.1415627; printf("请输入n的值(输入0结束程序):\\n"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):\\n"); while(scanf("%d",&m)&&m&&n) //u(x,t)=exp(x+t),u(x,0)=exp(x),f(x)=0,x属于[0,1],t属于[0,1],a=1. { h=1.0/(n+1); t=1.0/(m+1); r=t/(h*h); for(i=0;i<=n+1;i++)//初值条件 { u[i][0]=exp(i*h); } for(k=0;k<=m+1;k++)//边值条件 { u[0][k]=exp(k*t); u[n+1][k]=exp((n+1)*h+k*t); } printf("xj tk 真实值x[i][k] 近似值u[i][k] 误差err[i][k]\\n"); b[1]=1+r; c[1]=-r/2; a[n]=-r/2; b[n]=1+r; f[1]=r/2*u[2][0]+(1-r)*u[1][0]+r/2+r/2*u[0][1]; f[n]=r/2*u[n+1][0]+(1-r)*u[n][0]+r/2*u[n-1][0]+r/2*u[n+1][1]; for(i=2;i b[i]=1+r; a[i]=-r/2; c[i]=-r/2; f[i]=r/2*u[i+1][0]+(1-r)*u[i][0]+r/2*u[i-1][0]; } catchup(); for(k=2;k<=m;k++) { for(int j=1;j<=n;j++) { u[j][k]=2*r*(u[j+1][k-1]-2*u[j][k-1]+u[j-1][k-1])+u[j][k-2]; } } for(k=1;k<=m;k++) { for(i=1;i<=n;i++) { x[i][k]=exp(i*h+k*t); err[i][k]=x[i][k]>u[i][k]?x[i][k]-u[i][k]:u[i][k]-x[i][k]; printf("%lf %lf %lf%lf %lf\\n",i*h,k*t,x[i][k],u[i][k],err[i][k]); } } printf("请输入n的值(输入0结束程序):"); if(scanf("%d",&n)) printf("请输入m的值(输入0结束程序):"); } system("PASUE"); return 0; }