Crank-Nicolson隐式方法解线性双曲型方程

Crank-Nicolson隐式方法解线性双曲型方程
Crank-Nicolson方法在抛物型方程里面比较常用,双曲型方程例子不多,该方法是二阶精度,无条件稳定,然而,数值震荡比较明显,特别是时间演化比较大以及courant数比较大的时候。
对于这类方程的隐式解法,系数矩阵是三对角矩阵,每次固定时间t,通过解方程的方法解出来下一个时间步上的函数值,比如X方向分了N个格点,去掉边界条件,每个时间步N-2个未知数,构成三对角矩阵。如果采用追赶法求解,courant数需要小于2
网上的例子不多,我这里写了一下,供大家参考
在这里插入图片描述
CN方法离散成差分方程组,注意对于边界条件旁边的未知数边界项需要移动到等式右边
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
这里外边界直接采用精确解作为边界条件

import matplotlib
import math
matplotlib.use('TkAgg')
import numpy as np  
import matplotlib.pyplot as plt


def catchup(n,a0,b0,c0,F0):             #输入三个对角线上的值a,b,c,F0是等号右边的向量
#注意,追赶法要求:|b1|>|c1|,|bn|>|an|, |bi|>|ai|+|ci|

    m = np.zeros(F0.size, dtype=float)#中间变量
    xx = np.zeros(F0.size, dtype=float)
    for i in range(1, n): #正序,追
        m[i] = a0[i]/b0[i-1]#          a0是左副对角线,c0是右副对角线

        b0[i] = np.copy(b0[i]) - m[i]*c0[i-1]#b是主对角线
        F0[i] = np.copy(F0[i]) - m[i]*F0[i-1]
    xx[-1] = F0[-1]/b0[-1]
    for j in range (n-2, -1, -1):#倒序,赶
        xx[j] = (F0[j]-c0[j]*xx[j+1])/b0[j]
    return xx


def CN(x,t,a0,u):#Cranck-Nicolson格式
    n = (x.size-2)#  x方向未知数数量,x方向有两个边界作为已知条件,因此未知数是格点数-2
    m = t.size-1   #t方向未知数量,t方向未知数-1

    courant = a0*(t[2]-t[1])/(x[2]-x[1])#courant数,虽然CN算法对courant数没有限制,但追赶法有限制
    if courant > 2:
        print('courant number is too large',courant )
    #由于追赶法要求三条对角线|bi|>|ai|+|ci|,对应从courant<2
    print('courant=',courant)

    b = np.zeros(n, dtype=float)#方程组的系数矩阵,b是主对角线,ac是两条副对角线,这是一个三对角矩阵
    a = np.zeros(n, dtype=float)
    c = np.zeros(n, dtype=float)
    f = np.zeros(n, dtype=float)#差分方程等号的右边,和对角线上元素数量一致

    for j in range (0,m):

        for i in range(0,n): #对三条对角线分别赋值,对方程组等号右边f也赋值,注意第一行和最后一行需要额外+-courant/4.*u[m+1,0]
            b[i] = 1.#     主对角线
            if i >0:   
                a[i] = -1.*courant/4.
            if i<(n-1):
                c[i] =courant/4.
            f[i] = u[j,i+1]-courant/4.*(u[j,i+2]-u[j,i])

        '''#这里是系数矩阵,实际上不需要,可以打印出来看一下
        A = np.zeros((n,n),dtype=float)
        for i in range(0,n):         
            A[i,i] = 1.#     主对角线
            if i >0:
                A[i-1,i] = -1.*courant/2.
            if i<(n-1):
                A[i,i+1] =courant/2.
            f[i] = u[j,i+1]-courant/4.*(u[j,i+2]-u[j,i])
            f[0] = np.copy(f[0])+courant/4.*u[j+1,0]
            f[-1] = np.copy(f[-1])-courant/4.*u[j+1,-1]
        aa,bb,cc,=get_tridiagonal2(A,f)
        dd=np.copy(f)
        '''

        #u[m+1,-1] = u[m,-1]#+((t[2]-t[1])/(x[2]-x[1]))*(u[m,-1]-u[m,-2])
        f[0] =  u[j,1]-courant/4.*(u[j,2]-u[j,0])+courant/4.*u[j+1,0]#对方程组等号右边f首元素单独赋值(见公式)
        f[-1] = np.copy(f[-1])-courant/4.*u[j+1,-1]#对方程组等号右边f末元素单独赋值(见公式)
        
        result = catchup(n, a, b, c, f)#采用追赶法,只需输入三条对角线和方程右边
        u[j+1, 1:(result.size+1)] = np.copy(result)
    return u

def plot(x, t, result):
    plt.figure()
    plt.plot(x, result[-1,:])
    plt.show()
    plt.close()

    plt.figure()
    plt.contourf(x, t, result, 50, cmap = 'jet')
    plt.colorbar()
    plt.savefig('CN.png')
    plt.show()
    plt.close()
    return 0


#初始化
a0 = 250.
x = np.linspace(0., 400., 200)
t = np.linspace(0., 0.5, 200)

u = np.zeros((t.size,x.size), dtype=float)
u[0,:] = 100.*np.cos(math.pi*x/60.)
u[:,0] = 100.*np.cos(math.pi*(0.- a0*t)/60.)#100.*np.cos(-1.*math.pi*a0*t/60.)
u[:,-1] = 100.*np.cos(math.pi*(x[-1] - a0*t)/60.)

result = CN(x, t, a0, u)

plot(x, t, result)

在这里插入图片描述

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值