用有限差分和牛顿法解非线性微分方程(边值问题)-python

最近师兄让我解一个微分方程,我随口就答应下来了。结果仔细研究以后发现是个大坑。方程式一个复杂的非线性方程,而且是边值问题(知道两个端点的值)。微分方程的初值问题(知道一个端点的值和导数)相对简单,因为可以降阶,但边值问题不能降阶,相对麻烦一些,先上方程:
( 1 − μ 2 ) T ′ ′ ( μ ) + v ( v − 1 ) T ( μ ) − ( 1 − μ 2 ) 2 T ( μ ) T ′ ′ ( μ ) M 2 T ( μ ) − 1 − 2 / v = 0 (1-\mu^2)T''(\mu)+v(v-1)\sqrt{T(\mu)}-(1-\mu^2)^2T(\mu)T''(\mu)M^2T(\mu)^{-1-2/v}=0 (1μ2)T(μ)+v(v1)T(μ) (1μ2)2T(μ)T(μ)M2T(μ)12/v=0
边界条件是
T ( 1 ) = 0 和 T ( 0 ) = 1 T(1)=0和T(0)=1 T(1)=0T(0)=1
这个方程我没解出来,知道好的算法的小伙伴麻烦在下面留言.
如果只有前面两项,会容易一点
( 1 − μ 2 ) T ′ ′ ( μ ) + v ( v − 1 ) T ( μ ) = 0 (1-\mu^2)T''(\mu)+v(v-1)\sqrt{T(\mu)}=0 (1μ2)T(μ)+v(v1)T(μ) =0
v是参数,取1的时候有解析解 T = 1 − μ T=1-\mu T=1μ
边值问题一般用有限差分法和打靶法,这里我用的是有限差分。
μ \mu μ区间[0,1]上分成n等分,步长h,T在i点的二阶导数可以表示成
T i ′ ′ = ( T i + 1 − 2 T i + T i − 1 ) / h 2 T_{i}''=(T_{i+1}-2T_{i}+T_{i-1})/h^2 Ti=(Ti+12Ti+Ti1)/h2
T在每个点上的值作为未知数,这样每个点上都有一个未知数,一共有n个点,端点已知,就是n-2个未知数。把上面这个式子带到待求的微分方程里面,每个点上列一个方程,有n-2个方程。如果是线性方程,可以直接用追赶法,高斯-赛的尔法等来解,由于这个方程是非线性的,这里我用牛顿法来解。关于牛顿法见我上一篇文章:python 实现(拟)牛顿法解非线性方程组
https://blog.csdn.net/zry1318/article/details/86033518

import math
import numpy as np  
from numpy import * 
import matplotlib.pyplot as plt

def Fun(x,num):                       #方程组在这里
    i  =  num
    f  =  np.zeros((i),dtype = float)
    ddT0 = (x[1]-2*x[0]+T0)/h/h#  待求函数二阶导数,先列靠近左边界点的方程
    muj10 = 1.-mu[1]*mu[1] # 1-mu*mu
    f[0]  = muj10*ddT0+vi*(vi-1.)*x[0]**0.5

    ddTn = (T1-2*x[i-1]+x[i-2])/h/h#  待求函数二阶导数,靠近右边界点的方程
    muj1n = 1.-mu[i]*mu[i] # 1-mu*mu
    f[i-1]  = muj1n*ddTn+vi*(vi-1.)*x[i-1]**0.5

    for j in range(1, i-1):#边界点知道,j从1开始
        ddT = (x[j+1]-2*x[j]+x[j-1])/h/h#  待求函数T(mu)的二阶导数
        muj1 = 1.-mu[j]*mu[j] # 1-mu*mu

        f[j]  =  muj1*ddT+vi*(vi-1.)*x[j]**0.5
    return f

def dfun(x,num):                         #计算雅可比矩阵的逆矩阵
    df  =  np.zeros((num,num),dtype = float)
    dx  =  0.000001                           # 
    x1  =  np.copy(x)
    for i in range(0,num):              # 求导数,i是列,j是行
        for j in range(0,num):
            x1  =  np.copy(x)
            x1[j]  =  x1[j]+dx           #x+dx
            df[i,j]  =  (Fun(x1,num)[i]-Fun(x,num)[i])/dx   #f(x+dx)-f(x)/dx
    df_1  =  np.linalg.inv(df)                              #计算逆矩阵
    return df_1

def Newton(x,num):
               
    x1  =  np.copy(x)
    i  =  0
    delta  =  np.copy(x)
#    dfun0 = dfun(x,num)          #也可以使用简化牛顿法
    while(np.max(abs(delta)) > 1.e-6 and i < imax):  #控制循环次数
        print(i)
        x1  =  x-dot(dfun(x,num),Fun(x,num))  #公式
        mask=x1<0
        x1[mask]=x_stand[mask]
        delta  =  x1-x                     #比较x的变化
        x  =  x1
        i  =  i+1
        print(x)
    if i == imax:
        print('error: i>imax, no solution')
    print('i = ',i)
    return x


mu = np.arange(0.0, 1.01,  0.05)   #自变量
h = mu[1]-mu[0]#步长,线性
MM = 0.0#   M^2
vi =  1.
T0 = 1.#边界条件,
T1 = 0.
imax = 10000#最大迭代次数
yy = 1.-mu    #精确解
x_stand = yy[1:-1]
num  = mu.size-2                      # 方程未知数的个数
x  =  np.ones((num),dtype = float)/2.#初始值
a  =  Newton(x,num)

print('imax = ',imax)
print('note: if i  =  imax, the code did not find solution')
print('final result = ',a)
plt.figure(0) # 创建图表1    

#print(yy)  
a2  =  np.zeros((mu.size),dtype = float)
a2[0] = 1
a2[1:-1] = a

plt.plot(mu, a2,'r' ) #绘制数据散点图,用plt.sc  atter(x,y)
print(a2)
print(yy)
plt.plot(mu, yy,'b' ) #绘制数据散点图,用plt.sc  atter(x,y)

plt.xlabel('$\mu$')     #设置X轴的文字   
plt.ylabel('T')  
#plt.savefig('Figure_T.png') 
plt.show() #显示图片

v=1的时候,数值解与解析解重合
在这里插入图片描述
v=2的时候,结果如下
在这里插入图片描述

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
非线性薛定谔方程可以用离散化的差分方法来求。下面是一种基于Crank-Nicolson方法的差分求非线性薛定谔方程的Matlab代码: ```matlab % 初始化参数 L = 20; % 区域长度 N = 512; % 空间离散点数 dx = L / N; % 离散步长 x = linspace(-L/2, L/2, N); % 离散空间网格 dt = 0.01; % 时间步长 t = 0; % 初始时间 T = 10; % 总时间 c0 = 0.4; % 初始波包中心位置 sigma0 = 2; % 初始波包宽度 k0 = 0.2; % 初始波包波数 gama = 1; % 非线性系数 % 初始化波函数 psi = exp(-((x-c0)/sigma0).^2 + 1i*k0*x); % 建立差分矩阵 I = eye(N); D2 = (circshift(I, [0 -1]) - 2*I + circshift(I, [0 1])) / dx^2; % 二阶导差分矩阵 D1 = (circshift(I, [0 -1]) - circshift(I, [0 1])) / (2*dx); % 一阶导差分矩阵 % 迭代求 while t < T % 计算线性项 psi_x = D1 * psi; psi_xx = D2 * psi; V = gama * abs(psi).^2; Lpsi = -0.5*psi_xx + V.*psi; % 计算非线性项 psi_abs2 = abs(psi).^2; NLpsi = gama * (psi_abs2 .* psi); % 使用Crank-Nicolson方法求 A = I - 0.5i*dt*Lpsi; B = I + 0.5i*dt*Lpsi; psi = B \ (A * psi - 0.5i*dt*NLpsi); % 更新时间 t = t + dt; end % 画出结果 figure; plot(x, abs(psi).^2); xlabel('x'); ylabel('|psi|^2'); ``` 这个代码使用了Crank-Nicolson方法求非线性薛定谔方程,其中使用了二阶导差分矩阵和一阶导差分矩阵来离散化空间导数,然后用差分矩阵和Crank-Nicolson方法求时间演化。最终的结果是一个波函数的模方随着时间演化的图像。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值