Lecture 14
Lecture 14
df ( x) d 2 f ( x) d n1 f ( x) d n f ( x)
F x, f ( x), , 2
,...., n 1
n
dx dx dx dx
specifies n known boundary conditions at a and b, to solve this equation on an
interval of x ∈ [a, b].
• For the second-order case, since the boundary condition can be either be a value
of f (x) or a value of the derivative f’(x), we can have several different cases for the
specified values.
• For example, we can have the boundary condition values specified as:
1. Two values of f (x), that is, f (a) and f (b) are known.
2. Two derivatives of f(x), that is, f’(a) and f’(b) are known.
3. Mixed conditions from the above two cases are known: that is, either f (a) and
f’(b) are known, or f’(a) and f (b) are known.
To get the particular solution, we need two boundary conditions. The second-order
ODE boundary value problem is also called the “Two-Point Boundary-Value
Problem.”
Finite difference method
In this method we will turn the function ψ(x) into a vector, which is a list in Python,
and the operator of the differential equation into a matrix. We then end up with a
matrix eigen equation, which we can diagonalize to get our answer.
Discretization:
•The process of discretization is simply turning our continuous space x, into a discrete
number of steps, N , and our function into an array of size N .
• We thus have N values xi , which have a stepsize h x xi 1 xi
• Size of N is important. Too large a number will slow down our computation and
require too much computer memory, too small a number and the answers we compute
will not be sufficiently accurate. A common practice is to start with a small
number and then increase it until the accuracy is acceptable.
Forward and Backward first order differential
d f ( x x) f ( x) f ( x h) f ( x)
Forward: f ( x) lim x0 o( h)
dx x h
d f ( x x) f ( x x) f ( x h) f ( x h)
Central: f ( x) lim x0 O(h 2 )
dx 2x 2h
f 0' 1 1 0 . . f 0
'
f1 0 1 1 . . f1
. 1 . . . . . .
h
. . .
'
N 1
f 1 f N 1
We note that the last entry in the matrix will not be correct because there is no element
for N. We can fix this up by taking the backward derivative at the last point.
Second order Differential
d2 f ' ( x) f ' ( x x)
f ( x) lim x 0
dx 2
x
f ( x x) 2 f ( x) f ( x x)
lim x 0
x 2
f ( x h) 2 f ( x ) f ( x h)
h2
In the discrete space we can write f i '' ( f i 1 2 f i f i 1 ) / h 2
As a matrix equation we can write as:
f 0'' 2 1 0 0 f 0
''
f1 1 2 1 0 1 f
f '' 1 0 1 2 1 f
2 h2 2
. . . .
''
N 1
f 1 2 f N 1
Note that at both ends of our array we will get an inaccurate answer unless we do
some fixup. The fix up in this case is to use the same elements as the row below (at
the start) or the row above (at the end), so we get
f 0'' f1''
f N'' 1 f N'' 2
Solving the Schrödinger Equation
2 2
h d
Hˆ ( x) E ( x), Hˆ 2
V
2m dx
The matrix for the potential is simply the values of the potential on the diagonal of the
matrix
Vi j Vi
Writing out the matrix for we get:
2 1 0 0 V0 0 0
2
1 2 1 0 0 V1 0
h 0 0 V
H 0 1 2 1
2mh 2 2
. . .
VN 1
1 2
import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as scl
hbar=1
m=1
N = 512
a = 1.0
x = np.linspace(-a/2.,a/2.,N)
# We want to store step size, this is the reliable way:
h = x[1]-x[0] # Should be equal to 2*np.pi/(N-1)
V = 0.*x
Mdd = 1./(h*h)*(np.diag(np.ones(N-1),-1) -2* np.diag(np.ones(N),0) + np.diag(np.ones(N-1),1))
H = -(hbar*hbar)/(2.0*m)*Mdd + np.diag(V)
E,psiT = np.linalg.eigh(H) # This computes the eigen values and eigenvectors
psi = np.transpose(psiT) # We take the transpose of psiT to the wavefunction vectors can
accessed as psi
plt.figure(figsize=(10,7))
for i in range(5):
if psi[i][N-10] < 0: # Flip the wavefunctions if it is negative at large x, so plots are more
consistent.
plt.plot(x,-psi[i]/np.sqrt(h),label="$E_{}$={:>8.3f}".format(i,E[i]))
else:
plt.plot(x,psi[i]/np.sqrt(h),label="$E_{}$={:>8.3f}".format(i,E[i]))
plt.title("Solutions to the Infinite Square Well")
plt.legend()
plt.show()
Finite square well with bound state
Now, the potential is different, in that it has a small area which is not zero but some
negative value, here –V0.
For our calculation to be approximately correct, we need to make sure that our entire
calculation space, from -a/2 to a/2 is much larger than the well, which is from -
b/2 to b/2.
We also need a large N , the number of steps in our space, so that the resulting wave
function is smooth in the area of the well.
Python Code
import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as scl
hbar=1
m=1
N = 4097
a = 200.0
b = 2.
x = np.linspace(-a/2.,a/2.,N)
h = x[1]-x[0] # Should be equal to 2*np.pi/(N-1)
V0 = -6.
V=np.zeros(N)
for i in range(N):
if x[i]> -b/2. and x[i]< b/2.:
V[i]= V0
Mdd = 1./(h*h)*(np.diag(np.ones(N-1),-1) -2* np.diag(np.ones(N),0) + np.diag(np.ones(N-1),1))
H = -(hbar*hbar)/(2.0*m)*Mdd + np.diag(V)
E,psiT = np.linalg.eigh(H) # This computes the eigen values and eigenvectors
psi = np.transpose(psiT) # We take the transpose of psiT to the wavefunction vectors can
accessed as psi[n]
plt.figure(figsize=(10,7))
plt.xlim((-5*b,5*b))
plt.plot(x,V/(-V0),color="Gray",label="V(x) scaled to 1")
for i in range(5):
if E[i]<0:
if psi[i][N-10] < 0:
plt.plot(x,-psi[i]/np.sqrt(h),label="$E_{}$={:>8.3f}".format(i,E[i]))
else:
plt.plot(x,psi[i]/np.sqrt(h),label="$E_{}$={:>8.3f}".format(i,E[i]))
plt.title("Solutions to the Finite Square Well")
plt.legend()
plt.savefig("Finite_Square_Well_WaveFunctions.pdf")
plt.show()
Few things about the states:
1. Particle exists only in discrete states and is associated with the corresponding
energy in each state. The states are orthonormal. One state can not be represented
as a linear combination of other states.
2. We see that in the first state (ground state) most likely to find the particle is in the
center of the well. But if you give the particle a bit of energy and it jumps into the
second state (excited state) you will find it most likely between center and edges.
3. There is a non-zero probability of finding a particle outside the well. The
phenomenon is called quantum tunnelling.
Harmonic Oscillator wave function using finite difference method in Python
Algorithm
The Schrodinger equation for one dimensional quantum system is given as
h 2 d 2
2
V ( x) ( x) E ( x)
2m dx
For simplicity, we use a system of units such that m=1, hbar=1. Hence, our equation become,
1 d 2
2
V ( x) ( x) E ( x)
2 dx
Using second order centred derivative formula, we can discretized the above equation as follows:
1 j 1 2 j j 1
2
V j j E j
2 h
Let’s suppose we want to solve this equation in the region xꞓ(a,b), then We can create
N+1 grid points such that x0 = a , xN=b .
Since, the particle is confined in the region xꞓ(a,b), this leads to the following boundary
Conditions:
0 0
N 0
Thus, we need only to compute for the remaining N-1 grid points, that is j=1,2,3,…..N-1.
To illustrate, consider N=5, then we have
0 0
5 0
This means we need to compute ψj for j=1,2,3,4.
2 1 0 0 H= T+V
1 1 2 1 0
T 2
2h 0 1 2 1
4. Diagonalize H to obtain
0 1 2
0 eigenvalues(energies) and eigenvectors.
V1 0 0 0
0 V2 0 0
V
0 0 V3 0
0 0 0 V
4
Finite difference implementation in Python
# Import necessary libraries
# Create kinetic energy matrix
import numpy as np
T = np.zeros((N-2)**2).reshape(N-2,N-2)
import matplotlib.pyplot as plt
for i in range(N-2):
# Define potential energy function for j in range(N-2):
if i==j:
def Vpot(x): T[i,j]= -2
return x**2 elif np.abs(i-j)==1:
# Enter computational parameters T[i,j]=1
else:
a = -6.0
T[i,j]=0
b = 6.0
N = 1001
# Create potential energy matrix
# Define x grid and step size
V = np.zeros((N-2)**2).reshape(N-2,N-2)
x = np.linspace(a,b,N) for i in range(N-2):
h = x[1]-x[0] for j in range(N-2):
if i==j:
V[i,j]= Vpot(x[i+1])
else:
V[i,j]=0
# Create the Hamiltonian Matrix
H = -T/(2*h**2) + V
# Find eigen values and eigen vectors and sort them in ascending order
val,vec=np.linalg.eig(H)
z = np.argsort(val)
z = z[0:4]
energies=(val[z]/val[z][0])
print(energies)
# plot wavefunctions for first 4 lowest states
plt.figure(figsize=(12,10))
for i in range(len(z)):
y = []
y = np.append(y,vec[:,z[i]])
y = np.append(y,0)
y = np.insert(y,0,0)
plt.plot(x,y,lw=3, label="{} ".format(i))
plt.xlabel('x', size=14)
plt.ylabel('$\psi$(x)',size=14)
plt.legend()
plt.title('normalized wavefunctions for a harmonic oscillator using finite difference
method',size=14)
plt.show()
Output
Energies
[1. 2.99997454 4.99989817 6.99977088]
Shooting Method
• The shooting method was developed with the goal of transforming an ODE
boundary value problem into an equivalent initial value problem.
• With initial value problems, we start at the initial value and march forward to
get the solution.
• The name “shooting method” is analogous with the target shooting: as shown in
Fig.
• We shoot at the target and observe where we hit the target. Based on the errors,
we can adjust our aim and shoot again hoping that we will hit closer to the target.
• We can see from the analogy that the shooting method is an iterative optimization
method.
• Let us see how the shooting method works using the second-order ODE given
f(a) = fa and f(b) = fb, as well as
df ( x) d 2 f ( x)
F x, f ( x),
dx dx 2
Step 1
• We start the whole process by guessing f ‘(a) = α, then, together with f(a) = fa,
we turn the above problem into an initial value problem with two conditions all at
the value x = a.
Step 2
• We can use a Runge–Kutta method, to integrate to the other boundary b to find
f (b) = fβ. This is called the shooting step.
Step 3
Now we compare the value of fβ with fb. Usually, our initial guess is not good, and
fβ = fb, but what we want is fβ −fb = 0; therefore, we adjust our initial guesses
and repeat the process until the error is acceptable, at which time we can stop.
This is the iterative step.
• Finding the best guess to obtain fβ −fb = 0 is a root-finding problem and can be
tedious, but it does offer a systematic way to search for the best guess. Since fβ is a
function of α, the problem becomes finding the root of g(α) −fb = 0.