偏微分方程算法之二阶双曲型方程隐式差分法

目录

一、研究目标

二、理论推导

三、算例实现


一、研究目标

上篇文章介绍了二阶双曲型方程显式差分格式,由于显格式稳定性要求高,使用范围受限。我们尝试对其进行差分隐格式推导。这里继续以非齐次二阶双曲型偏微分方程的初边值问题为研究对象:

公式(1)中u表示一个与时间t和位置x有关的待求波函数,及方程右端项函数都是已知函数,是非零常数。

二、理论推导

第一步:网格剖分。对矩形求解域进行等距剖分,即

第二步:弱化原方程。将原来的连续方程离散到网格节点上成立,得到离散方程:

第三步:偏导数用差商近似。用二阶中心差商近似公式(2)中的关于时间的二阶偏导数,即

但对空间的二阶偏导数近似采用:

从而

这样原方程可以弱化为:

对初始条件的处理与显格式方法一样,然后用数值解代替精确解并忽略高阶项,可得差分格式为

,可以将公式(3)整理为公式(4)所示的隐格式:

可以将上式写成矩阵形式

该系数矩阵是三对角矩阵,可以使用追赶法求解。

隐式差分的计算过程:

由公式(4)中的初始条件知道第0个时间层的全部信息,同时知道第1个时间层上内部节点的信息,由于所有边界信息已知,所以第1个时间层上的所有节点信息已知。采用追赶法求解线性方程组,先取k=1,就可以解出第2个时间层内点信息,加上边界已知信息,就可以得出第2个时间层上完整信息。再取k=2,以上形式类推,以此完成所有时间层。

三、算例实现

计算双曲型偏微分方程初边值问题:

已知其精确解为。分别取步长为,给出节点处的数值解和误差。

代码如下:


cpp 复制代码
#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;
        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));
        for(k=1;k<n;k++)
        {
                for(i=1;i<m;i++)
                {
                        d[i-1]=r*(u[i-1][k-1]+u[i+1][k-1])/2.0-(1+r)*u[i][k-1]+2*u[i][k]+tau*tau*f(x[i],t[k]);
                        a1[i-1]=-0.5*r;
                        b[i-1]=1.0+r;
                        c[i-1]=a1[i-1];
                }
                d[0]=d[0]+0.5*r*u[0][k+1];
                d[m-2]=d[m-2]+0.5*r*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;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;
}

时,计算结果如下:

bash 复制代码
r=1.6211.
(x,t)=(0.31,0.80),y=0.687689,error=4.1006e-05.
(x,t)=(0.63,0.80),y=1.308062,error=7.7998e-05.
(x,t)=(0.94,0.80),y=1.800393,error=1.0736e-04.
(x,t)=(1.26,0.80),y=2.116489,error=1.2620e-04.
(x,t)=(1.57,0.80),y=2.225408,error=1.3270e-04.
(x,t)=(1.88,0.80),y=2.116489,error=1.2620e-04.
(x,t)=(2.20,0.80),y=1.800393,error=1.0736e-04.
(x,t)=(2.51,0.80),y=1.308062,error=7.7998e-05.
(x,t)=(2.83,0.80),y=0.687689,error=4.1006e-05.

时,计算结果如下:

bash 复制代码
r=1.6211.
(x,t)=(0.31,0.80),y=0.687720,error=1.0308e-05.
(x,t)=(0.63,0.80),y=1.308121,error=1.9607e-05.
(x,t)=(0.94,0.80),y=1.800473,error=2.6987e-05.
(x,t)=(1.26,0.80),y=2.116583,error=3.1725e-05.
(x,t)=(1.57,0.80),y=2.225508,error=3.3358e-05.
(x,t)=(1.88,0.80),y=2.116583,error=3.1725e-05.
(x,t)=(2.20,0.80),y=1.800473,error=2.6987e-05.
(x,t)=(2.51,0.80),y=1.308121,error=1.9607e-05.
(x,t)=(2.83,0.80),y=0.687720,error=1.0308e-05.

从两种不同时空步长的计算结果来看,隐差分格式是二阶收敛的。

相关推荐
Yingye Zhu(HPXXZYY)14 小时前
ICPC 2023 Nanjing R L 题 Elevator
算法
程序员Xu17 小时前
【LeetCode热题100道笔记】二叉树的右视图
笔记·算法·leetcode
笑脸惹桃花17 小时前
50系显卡训练深度学习YOLO等算法报错的解决方法
深度学习·算法·yolo·torch·cuda
阿维的博客日记18 小时前
LeetCode 48 - 旋转图像算法详解(全网最优雅的Java算法
算法·leetcode
GEO_YScsn18 小时前
Rust 的生命周期与借用检查:安全性深度保障的基石
网络·算法
程序员Xu18 小时前
【LeetCode热题100道笔记】二叉搜索树中第 K 小的元素
笔记·算法·leetcode
THMAIL19 小时前
机器学习从入门到精通 - 数据预处理实战秘籍:清洗、转换与特征工程入门
人工智能·python·算法·机器学习·数据挖掘·逻辑回归
Kevinhbr19 小时前
CSP-J/S IS COMING
数据结构·c++·算法
蕓晨20 小时前
set的插入和pair的用法
c++·算法
THMAIL20 小时前
深度学习从入门到精通 - AutoML与神经网络搜索(NAS):自动化模型设计未来
人工智能·python·深度学习·神经网络·算法·机器学习·逻辑回归