Я пытаюсь использовать «метод стрельбы» для решения уравнения Шредингера для достаточно произвольного потенциала в 1D. Но собственные значения, оцененные таким образом в случае потенциалов, которые не имеют жестких границ (где потенциал становится бесконечным), не очень точны по сравнению с аналитическими результатами.
Я думал, что проблему можно решить, создав пространственные сетка более мелкая, но изменение пространственной сетки практически не влияет на собственные значения. оценивается путем решения соответствующего ivp с помощью odeint от scipy - эти функции достаточно точны. Наконец, изменение второй границы, чтобы сделать волновую функцию d ie в более глубокой части классически запрещенной области, также не привело к практическому улучшению собственного значения (изменения, обнаруженные только в 9-м или 10-м разряде десятичной дроби, но сделали волновые функции более низкого энергетического состояния расходятся в конечных точках, чтобы усугубить ситуацию).
Я не могу найти, что изменить, чтобы получить более точные собственные значения. Граничное условие или размер шага? Моя реализация go была неправильной, или это из-за ошибок округления или других «Python вещей»?
Пример - потенциал Морзе (https://en.wikipedia.org/wiki/Morse_potential)
import numpy as np
from scipy.integrate import odeint,simps
from scipy.optimize import bisect
from math import e,floor
xe,lam=1.0,6.0 # parameters for potential
def V(x):return (lam**2)*(e**(-2*(x-xe))-2*(e**-(x-xe))) # morse potential definition
bound1,bound2,bval1,bval2=0,xe+15,0,0 # Bval,Bval2=wavefunction values at x=bound1,bound2
X=np.linspace(bound1,bound2,1000) # region of integration
Erange=np.geomspace(-(lam**2),-0.0001,100) # region of Energy level searching
def func(y,x): # utility function for returning RHS of the differential equation
psi,phi=y # psi=eigenfunction,phi=spatial derivative of psi
return np.array([phi,-(E-V(x))*psi])
def ivp(f,initial1,initial2,X): # solves an ivp with odeint
y0=np.array([initial1,initial2])
return odeint(f,y0,X)[:,0]
def psiboundval(E1): # finds out value of eigenfunction at bound2 for energy E1,by solving ivp
global E;E=E1
S=ivp(func,bval1,E1,X)
return S[(len(S))-1]-bval2
def shoot(Erange): # finds out accurate eigenvalues from approximate ones in Erange by bisect
global E
Y=np.array([psiboundval(E) for E in Erange])
eigval=np.array([bisect(psiboundval,Erange[i],Erange[i+1]) for i in np.where(np.diff(np.signbit(Y)))[0]])
return eigval
print "Numerical results:",shoot(Erange)
print "Analytical results:",[-(lam-n-0.5)**2 for n in range(0,int(floor(lam-0.5)+1))]
Выход
>>> Numerical results: [-30.24833663 -20.24320174 -12.23610971 -6.23177902 -2.23431356
-0.24381032]
Analytical results: [-30.25, -20.25, -12.25, -6.25, -2.25, -0.25]
Для состояний с более высокой энергией наблюдается снижение точности. Желательно, чтобы точность была как минимум до 4-го знака после запятой (если не больше) для всех состояний.