Python Forum
odeint to solve Schrodinger equation
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
odeint to solve Schrodinger equation
#11
I have a lot more work to do on it and probably won't touch it tonight. You can check my GitHub for my progress.

In V(), what is the conditional supposed to do? As written, that conditional will never be true because Vpot never changes (plus, the function should not reference a global for this purpose).

With the number of globals that are invoked, I'm leaning toward creating a class to encompass everything. That would potentially resolve a lot of issues.
Reply
#12
the condition was something I hastily added to be able to plot the potential function on multiple figures without getting doubles.

I almost got the new code to work it runs and finds energy, though it is supposed to get 7 energy levels and its not being able to do that, I am running it with finer steps so maybe it will get things right.


from pylab import *
from scipy.integrate import solve_ivp
from scipy.optimize import brentq
import numpy as np
import itertools

a=1
B=4
L= B+a
Vmax= 50
Vpot = False

N = 1000                  # number of points to take
psi = np.zeros([N,2])     # Wave function values and its derivative (psi and psi')
psi0 = array([0,1])   # Wave function initial states
Vo = 50
E = 0.0                   # global variable Energy  needed for Sch.Eq, changed in function "Wave function"
b = L                     # point outside of well where we need to check if the function diverges
x = linspace(-B-a, L, N)    # x-axis
def V(x):
    '''
    #Potential function in the finite square well.
    '''
    if -a <=x <=a:
        val = Vo
    elif x<=-a-B:
        val = Vmax
    elif x>=L:
        val = Vmax
    else:
        val = 0
    if Vpot==True:
          if -a-B-(10/N) < x <= L+(1/N):
             Ypotential.append(val)
             Xpotential.append(x)
    return val
 
def SE(z, p):
    state0 = p[1]
    state1 = 1.0*(V(z) - E)*p[0]
    return array([state0, state1])
 
def Wave_function(energy):
    global E
    E = energy
    #        odeint(func, y0, t)
    #     solve_ivp(fun, t_span, y0)
    psi = solve_ivp(SE, [-B-a, L], psi0, max_step = ((B+a+L)/(N*2)))
    return psi.y[0,-1]
 
def find_all_zeroes(x,y):
    """
    Gives all zeroes in y = Psi(x)
    """
    all_zeroes = []
    s = np.sign(y)
    for i in range(len(y)-1):
        if s[i]+s[i+1] == 0:
            zero = brentq(Wave_function, x[i], x[i+1])
            all_zeroes.append(zero)
    return all_zeroes

        
def main():
    # main program        
 
    en = linspace(0, Vo, 100000)   # vector of energies where we look for the stable states
 
    psi_b = []      # vector of wave function at x = b for all of the energies in en
    
    for e1 in en:
        psi_b.append(Wave_function(e1))     # for each energy e1 find the the psi(x) at x = b
        
    print(len(psi_b))
    E_zeroes = find_all_zeroes(en, psi_b)   # now find the energies where psi(b) = 0 
 
    # Print energies for the bound states
    print ("Energies for the bound states are: ")
    for E in E_zeroes:
        print ("%.2f" %E)

    # Plot wave function values at b vs energy vector
    f1 = figure(1)
    plot(en/Vmax,psi_b)
    title('Values of the $\Psi(b)$ vs. Energy')
    xlabel('Energy, $E/V_0$')
    ylabel('$\Psi(x = b)$', rotation='horizontal')
    for E in E_zeroes:
        plot(E/Vmax, [0], 'go')
        annotate("E = %.2f"%E, xy = (E/Vmax, 0), xytext=(E/Vmax, 30))
    grid()
    f1.show()

    
#z = (Wave_function(2))  
    
if __name__ == "__main__":
    main()
* edit
on further inspection I found out that solve_ivp is not solving for the span -B-a to B+a, but 0 to B+a

I'm abandoning part of the code because I am switching solve_ivp to solve_bvp, this way I might be able to remove find_all_zeroes.

here is what I did so far (to get Wave_function to work). I'm still trying to understand solve_bvp, but I think it might be better.
from scipy.integrate import solve_bvp
from pylab import *
import numpy as np

## dimentions         _
## |       :       |   | Vmax
## |    ___:___    |   |        _
## |___|       |___|  _| Vmin   _|- Vb
##-B  -A   0   A   B*Alpha
## \______/|\______/
##     Po       Pf

Vmax = 55
Vmin = 0
Vb = 50
A = 1
B = 4
alpha = 1
Po = -A-B
Pf = A+B*alpha
psi_b = array([0,1])   # Wave function boundry [first dir, secound dir]

N = 1000 #steps
psi = np.zeros([N,2])
x = linspace(Po, Pf, N)    # x-axis


def V(z):
    '''
    #Potential function in the finite square well.
    '''
    val=[]
    for i in z:
        if -A <=i <= A:
            val.append( Vb)
        elif i<=Po:
            val.append( Vmax)
        elif i>=Pf:
            val.append(Vmax)
        else:
            val.append(Vmin)
    return val

def boundary_conditions(psi_Po, psi_pf):
    return (psi_b)

def SE(z, p, E):
    state0 = p[1]
    state1 = 1.0*(V(z) - E)*p[0]
    return np.array([state0, state1])

def Wave_function(energy,psi):
    y_ = np.zeros((2, x.size))
    psi = solve_bvp(SE(x, psi, y_), boundary_conditions, x, y_)
    print(len(psi.y))
    return psi.y

def pltPotentail():
    plot(x,V(x))    

def main():
    en = linspace(0, Vb, 10)   # vector of energies where we look for the stable states
    figure(1)
    pltPotentail()
    Wave_function(0,psi)
    show()
if __name__ == "__main__":
    main()
this is the plot I get, as you can see despite passing x to the solver it is not using the span but the number of elements and everything is flat.
[Image: mnv9Kq]

edit/update. I broke the solver even more now because I'm trying to pass psi and energy to SE so I can remove that last global. progress is very slow because I still don't really understand how solve_bvp works. I'm asking more specifically how to use solve_bvp on stackoverflow (site isn't really helpful but its worth a shot). I'm starting to agree with the idea of writing a class.
Reply
#13
I've put a little bit of work into it this morning. I changed V() into a closure and removed the Vpot conditional. If you really need that conditional, we need to figure out a better way to implement it. The calls to V() have been updated too, which also forced an update to SE and odeint.

The global variables have been moved into the main() function.

My version should still provide the results you got previously; these are all technical fixes to the syntax and code layout.
Reply
#14
thanks, I'll update my code according to yours. I'm still trying to figure out how to change the solution, for some reason I'm trying to develop the code using solve_ivp and solve_bvp at the same time. The first one that looks like it is going forward will be used, solve_ivp seems easier to use, so I can control things much better.
Reply
#15
I don't think solve_ivp is going to go forward. I am plotting graphs with it but there are two problems 1 its not symmetric and 2 the first derivative of the function is not continuous.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Mukhanov equation + odeint Messier087 0 1,615 Mar-28-2020, 04:03 PM
Last Post: Messier087
  Odeint to solve Mukhanov equation Messier087 4 2,562 Feb-17-2020, 05:05 PM
Last Post: Messier087
  Can't find a way to solve this nonlinear equation Alex009988 2 2,649 Aug-16-2019, 01:50 AM
Last Post: scidam
  python odeint keeps giving me size of array error kiyoshi7 1 6,137 Nov-01-2018, 02:03 AM
Last Post: j.crater

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020