Skip to content

Commit 91b53b5

Browse files
Update notebook.json
1 parent fd9c4b4 commit 91b53b5

File tree

1 file changed

+177
-7
lines changed

1 file changed

+177
-7
lines changed
Lines changed: 177 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,177 @@
1-
{
2-
"ServerApp": {
3-
"jpserver_extensions": {
4-
"notebook": true
5-
}
6-
}
7-
}
1+
import numpy as np
2+
from matplotlib import pyplot as pl
3+
from matplotlib import animation
4+
from scipy.fft import fft, ifft # modern FFT module
5+
6+
class Schrodinger(object):
7+
def __init__(self, x, psi_x0, V_x, k0=None, hbar=1, m=1, t0=0.0):
8+
self.x, psi_x0, self.V_x = map(np.asarray, (x, psi_x0, V_x))
9+
N = self.x.size
10+
assert self.x.shape == (N,)
11+
assert psi_x0.shape == (N,)
12+
assert self.V_x.shape == (N,)
13+
14+
self.hbar = hbar
15+
self.m = m
16+
self.t = t0
17+
self.dt_ = None
18+
self.N = len(x)
19+
self.dx = self.x[1] - self.x[0]
20+
self.dk = 2 * np.pi / (self.N * self.dx)
21+
22+
self.k0 = -0.5 * self.N * self.dk if k0 is None else k0
23+
self.k = self.k0 + self.dk * np.arange(self.N)
24+
25+
self._set_psi_x(psi_x0)
26+
self.compute_k_from_x()
27+
28+
self.x_evolve_half = None
29+
self.x_evolve = None
30+
self.k_evolve = None
31+
32+
def _set_psi_x(self, psi_x):
33+
self.psi_mod_x = (psi_x * np.exp(-1j * self.k[0] * self.x)
34+
* self.dx / np.sqrt(2 * np.pi))
35+
36+
def _get_psi_x(self):
37+
return (self.psi_mod_x * np.exp(1j * self.k[0] * self.x)
38+
* np.sqrt(2 * np.pi) / self.dx)
39+
40+
def _set_psi_k(self, psi_k):
41+
self.psi_mod_k = psi_k * np.exp(1j * self.x[0] * self.dk * np.arange(self.N))
42+
43+
def _get_psi_k(self):
44+
return self.psi_mod_k * np.exp(-1j * self.x[0] * self.dk * np.arange(self.N))
45+
46+
def _get_dt(self):
47+
return self.dt_
48+
49+
def _set_dt(self, dt):
50+
if dt != self.dt_:
51+
self.dt_ = dt
52+
self.x_evolve_half = np.exp(-0.5j * self.V_x / self.hbar * dt)
53+
self.x_evolve = self.x_evolve_half * self.x_evolve_half
54+
self.k_evolve = np.exp(-0.5j * self.hbar / self.m * (self.k ** 2) * dt)
55+
56+
psi_x = property(_get_psi_x, _set_psi_x)
57+
psi_k = property(_get_psi_k, _set_psi_k)
58+
dt = property(_get_dt, _set_dt)
59+
60+
def compute_k_from_x(self):
61+
self.psi_mod_k = fft(self.psi_mod_x)
62+
63+
def compute_x_from_k(self):
64+
self.psi_mod_x = ifft(self.psi_mod_k)
65+
66+
def time_step(self, dt, Nsteps=1):
67+
self.dt = dt
68+
if Nsteps > 0:
69+
self.psi_mod_x *= self.x_evolve_half
70+
71+
for _ in range(Nsteps - 1):
72+
self.compute_k_from_x()
73+
self.psi_mod_k *= self.k_evolve
74+
self.compute_x_from_k()
75+
self.psi_mod_x *= self.x_evolve
76+
77+
self.compute_k_from_x()
78+
self.psi_mod_k *= self.k_evolve
79+
self.compute_x_from_k()
80+
self.psi_mod_x *= self.x_evolve_half
81+
self.compute_k_from_x()
82+
self.t += dt * Nsteps
83+
84+
# Gaussian wave packet
85+
def gauss_x(x, a, x0, k0):
86+
return ((a * np.sqrt(np.pi)) ** -0.5) * np.exp(-0.5 * ((x - x0) / a) ** 2 + 1j * x * k0)
87+
88+
# Square barrier potential
89+
def theta(x):
90+
x = np.asarray(x)
91+
y = np.zeros(x.shape)
92+
y[x > 0] = 1.0
93+
return y
94+
95+
def square_barrier(x, width, height):
96+
return height * (theta(x) - theta(x - width))
97+
98+
# Simulation parameters
99+
dt = 0.01
100+
N_steps = 50
101+
t_max = 120
102+
frames = int(t_max / float(N_steps * dt))
103+
104+
hbar = 1.0
105+
m = 1.9
106+
107+
N = 2 ** 11
108+
dx = 0.1
109+
x = dx * (np.arange(N) - 0.5 * N)
110+
111+
V0 = 1.5
112+
L = hbar / np.sqrt(2 * m * V0)
113+
a = 3 * L
114+
x0 = -60 * L
115+
V_x = square_barrier(x, a, V0)
116+
V_x[x < -98] = 1E6
117+
V_x[x > 98] = 1E6
118+
119+
p0 = np.sqrt(2 * m * 0.2 * V0)
120+
dp2 = p0 ** 2 / 80
121+
d = hbar / np.sqrt(2 * dp2)
122+
123+
k0 = p0 / hbar
124+
v0 = p0 / m
125+
psi_x0 = gauss_x(x, d, x0, k0)
126+
127+
S = Schrodinger(x=x, psi_x0=psi_x0, V_x=V_x, hbar=hbar, m=m, k0=-28)
128+
129+
# Plotting setup
130+
fig = pl.figure()
131+
xlim = (-100, 100)
132+
klim = (-5, 5)
133+
134+
ax1 = fig.add_subplot(211, xlim=xlim, ylim=(-0.2 * V0, 1.2 * V0))
135+
psi_x_line, = ax1.plot([], [], c='r', label=r'$|\psi(x)|$')
136+
V_x_line, = ax1.plot([], [], c='k', label=r'$V(x)$')
137+
center_line = ax1.axvline(0, c='k', ls=':', label=r"$x_0 + v_0t$")
138+
title = ax1.set_title("")
139+
ax1.legend(prop=dict(size=12))
140+
ax1.set_xlabel('$x$')
141+
ax1.set_ylabel(r'$|\psi(x)|$')
142+
143+
ymin = abs(S.psi_k).min()
144+
ymax = abs(S.psi_k).max()
145+
ax2 = fig.add_subplot(212, xlim=klim, ylim=(ymin - 0.2 * (ymax - ymin), ymax + 0.2 * (ymax - ymin)))
146+
psi_k_line, = ax2.plot([], [], c='r', label=r'$|\psi(k)|$')
147+
ax2.axvline(-p0 / hbar, c='k', ls=':', label=r'$\pm p_0$')
148+
ax2.axvline(p0 / hbar, c='k', ls=':')
149+
ax2.axvline(np.sqrt(2 * V0) / hbar, c='k', ls='--', label=r'$\sqrt{2mV_0}$')
150+
ax2.legend(prop=dict(size=12))
151+
ax2.set_xlabel('$k$')
152+
ax2.set_ylabel(r'$|\psi(k)|$')
153+
154+
V_x_line.set_data(S.x, S.V_x)
155+
156+
# Animation functions
157+
def init():
158+
psi_x_line.set_data([], [])
159+
V_x_line.set_data([], [])
160+
center_line.set_data([], [])
161+
psi_k_line.set_data([], [])
162+
title.set_text("")
163+
return (psi_x_line, V_x_line, center_line, psi_k_line, title)
164+
165+
def animate(i):
166+
S.time_step(dt, N_steps)
167+
psi_x_line.set_data(S.x, 4 * abs(S.psi_x))
168+
V_x_line.set_data(S.x, S.V_x)
169+
center_line.set_data([x0 + S.t * p0 / m] * 2, [0, 1])
170+
psi_k_line.set_data(S.k, abs(S.psi_k))
171+
title.set_text("t = %.2f" % S.t)
172+
return (psi_x_line, V_x_line, center_line, psi_k_line, title)
173+
174+
anim = animation.FuncAnimation(fig, animate, init_func=init,
175+
frames=frames, interval=30, blit=True)
176+
177+
pl.show()

0 commit comments

Comments
 (0)