Python/SciPy 中带有 Crank-Nicolson 的薛定谔/扩散方程

计算科学 有限差分 Python
2021-12-13 15:27:21

我试图使问题尽可能详细。我有一个为薛定谔方程编写的非常简单的求解器,但具有虚时间,它基本上将其转换为扩散方程(带有潜在项)。该方法在此页面上有很好的记录,我基本上几乎完全按照这些步骤进行操作。这是链接:

http://jkwiens.com/2010/01/02/finite-difference-heat-equation-using-numpy/

以及相应的 Python 代码:

http://jkwiens.com/heat-equation-using-finite-difference/

这是我的代码:

import scipy as sp
from scipy import integrate, sparse, linalg
import scipy.sparse.linalg
import pylab as pl

nx = 8000
dx = 0.0025
dt = 0.00002
niter = 20
nonlin = 0.0
gridx = sp.zeros(nx)
igridx = sp.array(range(nx))
psi = sp.zeros(nx)
pot = sp.zeros(nx)
depth = 0.01

# Set up grid, potential, and initial state
gridx = dx*(igridx - nx/2)
pot = depth*gridx*gridx
psi = sp.pi**(-1/4)*sp.exp(-0.5*gridx*gridx)

# Normalize Psi
#psi /= sp.integrate.simps(psi*psi, dx=dx)

# Plot parameters
xlimit = [gridx[0], gridx[-1]]
ylimit = [0, 2*psi[nx/2]]

# Set up diagonal coefficients
Adiag = sp.empty(nx)
Asup = sp.empty(nx)
Asub = sp.empty(nx)
bdiag = sp.empty(nx)
bsup = sp.empty(nx)
bsub = sp.empty(nx)
Adiag.fill(1 - dt/dx**2)
Asup.fill(dt/(2*dx**2))
Asub.fill(dt/(2*dx**2))
bdiag.fill(1 + dt/dx**2)
bsup.fill(-dt/(2*dx**2))
bsub.fill(-dt/(2*dx**2))

# Construct tridiagonal matrix
A = sp.sparse.spdiags([Adiag, Asup, Asub], [0, 1, -1], nx, nx)
b = sp.sparse.spdiags([bdiag, bsup, bsub], [0, 1, -1], nx, nx)

# Loop through time
for t in range(0, niter) :
    # Calculate effect of potential and nonlinearity
    psi *= sp.exp(-dt*(pot + nonlin*psi*psi))

    # Calculate spacial derivatives
    psi = sp.sparse.linalg.bicg(A, b*psi)[0]

    # Normalize Psi
    psi /= sp.integrate.simps(psi*psi, dx=dx)

    # Output figures
    pl.plot(gridx, psi)
    pl.plot(gridx, psi*psi)
    pl.plot(gridx, pot)
    pl.xlim(xlimit)
    pl.ylim(ylimit)
    pl.savefig('outputla/fig' + str(t))
    pl.clf()

nonlin变量只是非线性的一个额外术语(稍后我将求解非线性薛定谔方程),但如果我将其设置为零,那么它就无关紧要了。

我现在的问题是空间运算符没有做任何事情(它应该扩散得相当快),最终整个事情都爆炸了(典型的不稳定性......线条变得锯齿状,最终情节看起来很疯狂)。

我已经检查了我能想到的一切,我完全不知道为什么会这样。我已经改变了线性求解器,密集矩阵而不是稀疏矩阵,系数Ab是正确的(我认为..它们与博客链接不同,因为 Schro. eq. 有一个i术语,所以会发生一些负正号交换......这个在下面引用的论文中提到)。

另外,这是一篇描述计算的论文(但我不使用递归关系,只是一个运算符):http ://arxiv.org/abs/0904.3131

1个回答

正在工作,但速度很慢。您的时间步长比您的网格分隔小 125 倍。鉴于所有其他常数都是统一的,您的细胞交叉时间为 125 个时间步长。需要很长时间才能看到变化。

例如,如果您更改dt0.001,则图 1 和图 19 之间应该有明显的差异。当然,只能比较交替帧,这是试图对薛定谔方程进行去复杂化的奇怪产物。

的“时间步长”中前进(注意符号!)。将您拥有的三对角矩阵与空间差分矩阵进行比较, 将此方法和典型的 Crank-Nicolson 方法应用于 结果 iΔt

+2x2A(2112112).
itψ=(2x2+V)ψ
(IiΔt2(Δx)2A)ψn+1=(I+iΔt2(Δx)2A)ψn.

要么更改dt矩阵中所有条目的符号Ab,要么为了快速修复,在您的定义中添加一个负号dt(同时使其更大 - 无需采取如此小的时间步长)。然后你实际上确实看到了数值稳定的扩散。如所写,您的代码正在反向运行扩散方程,因此爆炸并不意外。