Professional Documents
Culture Documents
Solution of The Time-Dependent Schrödinger Equation Using The Crank-Nicolson Algorithm With MPI On A 2-D Regular Cartesian Grid
Solution of The Time-Dependent Schrödinger Equation Using The Crank-Nicolson Algorithm With MPI On A 2-D Regular Cartesian Grid
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 1 / 13
Time-dependent Schrödinger Equation
Schrödinger Equation in 2-D for an electron in a given potential
∂ p̂ 2 p̂y2
i~|ψ(t, x)i = Ĥ(p̂, x̂) |ψ(t, x)i , Ĥ = x + + V̂ (x, y ) (1)
∂t 2m 2m
Attempt to simply discretize the differential operators,
n+1 n
ψj,l − ψj,l
∂t ψ(t, x) ≈ ,
∆t
n+1 n+1 n+1
p̂ 2 ~2 2 ~2 ψj+1,l − 2ψj,l + ψj−1
ψ(t, x) = − ∇ ψ(t, x) ≈ − + ...
2m 2m 2m (∆x)2
is – as the von Neumann stability analysis shows – unconditionally stable.
However, each solution of Schrödinger’s equation has to fulfill a continuity
equation for the probability w (t, x) d3 x = ψ ∗ ψ d3 x to find the electron
within a volume d3 x around x,
~
∂t w (t, x) + ∇ · j = 0, j = [ψ ∗ (∇ψ) − (∇ψ ∗ )ψ] (2)
2im
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 2 / 13
From the continuity equation follows the conservation of the norm of the
wave function:
Z Z Z Z
d
d3 x w (t, x) = d3 x ∂t w (t, x) = − d3 x ∇ · j (t, x) = − dS · j (t, x)
dt
Z Z
SE
d3 x kw (0, x)k2 = 1 −→ d3 x kw (t, x)k2 = 1 (3)
R3 R3
The normalization of the wave function ψ(t, x) is however not conserved by the fully
implicit discretization as this method is not unitary ⇒ a discretization preserving the
hermiticity of the Hamiltonian is needed that maintains the normalization of the
wavefunction.
The temporal evolution of the wave function can be expressed using the unitary
time-evolution operator Û(t):
|ψ(t + ∆t, x)i ' Û(t) |ψ(t, x)i , Û(t) = exp(−iĤt/~) (4)
With the time-evolution operator one can find the explicit Forward-Time Centered-Space
n+1 n
(FTCS) scheme ψj,l = (1 − iĤ∆t)ψj,l and the implicit Backward-Time scheme
n+1 n
(1 + iĤ∆t)ψj,l = ψj,l . Neither scheme is unitary and thus violates probability
conservation.
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 3 / 13
A finite-difference approximation of exp(−iĤ∆t/~) that is unitary was
found by Cayley:
iĤ∆t
1−
exp(−iĤ∆t/~) = 2~
+ O((∆t)2 )
iĤ∆t
1+ 2~
i i
(4) ⇒ 1 + Ĥ∆t |ψ(t + ∆t, x)i = 1 − Ĥ∆t |ψ(t, x)i (5)
2~ 2~
This is exactly the Crank-Nicolson scheme for the Schrödinger equation.
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 4 / 13
Discretization
n into
By substituting the 2-D discrete wave function ψ(t; x, y ) → ψj,l
Eq. (5) and considering the Hamiltonian in the form
~2 ∂ 2 ~2 ∂ 2
Ĥ = |p̂ = −i~∇| = − − + V̂ (x, y )
2m ∂x 2 2m ∂y 2
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 5 / 13
Rewrite Eq. (6) in matrix-form. Assign a short-hand notation for the prefactors of the wave
function at the next time step at various spatial grid points:
i∆t ~2
n+1 1 1 i∆t
ψj,l : bj,l = 1 + + + Vj,l
~ 2m (∆x)2 (∆y )2 2~
n+1 i∆t ~2 1
ψj−1,l : c=−
2~ 2m (∆x)2
n+1
ψj+1,l : a=c
n+1 i∆t ~2 1
ψj,l+1 : d =−
2~ 2m (∆x)2
n+1
ψj,l−1 : e=d
and for the RHS:
i∆t ~2
n 1 1 i∆t
ψj,l : fj,l = 1 − + − Vj,l
~ 2m (∆x)2 (∆y )2 2~
n i∆t ~2 1
ψj+1,l : g =
2~ 2m (∆x)2
n
ψj−1,l : h=g
n i∆t ~2 1
ψj,l+1 : k=
2~ 2m (∆y )2
n
ψj,l−1 : p=k
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 6 / 13
LHS of the discretized Schrödinger Equation
i = 1 + (j − 1)(L − 1) + l − 1 for j = 0, 1, . . . , J; l = 0, 1, . . . , L
ψ n+1
b1,1 d 0 a 0 0 0 0 0
1
e b1,2 d 0 a 0 0 0 0 ψ2n+1
ψ3n+1
0 e b1,3 0 0 a 0 0 0
n+1
c 0 0 b2,1 d 0 a 0 0 ψ4
n+1
0 c 0 e b2,2 d 0 a 0 ψ5 = r
n+1
0 0 c 0 e b2,3 0 0 a ψ6
n+1
0 0 0 c 0 0 b3,1 d 0
ψ7
0 0 0 0 c 0 e b3,2 d n+1
ψ8
0 0 0 0 0 c 0 e b3,3 ψ9n+1
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 7 / 13
RHS of the discretized Schrödinger Equation
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 8 / 13
After vectorization, the discretized Schrödinger Equation simplifies to
Pseudo-code:
for n in range(N):
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 9 / 13
Setting up the matrices in Python
# Build the main diagonal
b_main_diag = [] # coefficient matrix of LHS
f_main_diag = [] # coefficient matrix of RHS
for j in range(J-1):
for l in range(J-1):
b_main_diag.append(b[j,l]); f_main_diag.append(f[j,l])
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 10 / 13
Setting-up the RHS in Python
for n in range(Nt):
if n == 0:
psi_n_mat = psi_0
# Rewrite matrix psi_jl as a vector psi_i
psi_n_vec = np.empty(((J-1)**2,), dtype=complex)
for j in range(J-1):
for l in range(J-1):
i = ind(j,l)
psi_n_vec[i] = psi_n_mat[j,l]
else:
psi_n_vec = psi_np1_vec
RHS = np.dot(B,psi_n_vec)
r = RHS
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 11 / 13
LU decomposition; finally to be parallelized as Fortran code
# LU decomposition:
P, L, U = scipy.linalg.lu(A)
LU = L + U
nA = np.size(A, 0)
y = np.zeros((nA,), dtype=complex)
x = np.zeros((nA,), dtype=complex)
r = np.dot(np.linalg.inv(P),r)
psi_np1_vec = x
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 12 / 13
Parallelizing the code
Peter Leitner & Stefan Hofmeister Crank-Nicolson using MPI Wednesday, May 10, 2017 13 / 13