@wudawufanfan
2016-12-27T07:20:11.000000Z
字数 6324
阅读 538
未分类
在此输入正文
import numpy as npfrom matplotlib import pyplot as plfrom matplotlib import animationfrom scipy.fftpack import fft,ifftclass Schrodinger(object):"""Class which implements a numerical solution of the time-dependentSchrodinger equation for an arbitrary potential"""def __init__(self, x, psi_x0, V_x,k0 = None, hbar=1, m=1, t0=0.0):"""Parameters----------x : array_like, floatlength-N array of evenly spaced spatial coordinatespsi_x0 : array_like, complexlength-N array of the initial wave function at time t0V_x : array_like, floatlength-N array giving the potential at each xk0 : floatthe minimum value of k. Note that, because of the workings of thefast fourier transform, the momentum wave-number will be definedin the rangek0 < k < 2*pi / dxwhere dx = x[1]-x[0]. If you expect nonzero momentum outside thisrange, you must modify the inputs accordingly. If not specified,k0 will be calculated such that the range is [-k0,k0]hbar : floatvalue of planck's constant (default = 1)m : floatparticle mass (default = 1)t0 : floatinitial tile (default = 0)"""# Validation of array inputsself.x, psi_x0, self.V_x = map(np.asarray, (x, psi_x0, V_x))N = self.x.sizeassert self.x.shape == (N,)assert psi_x0.shape == (N,)assert self.V_x.shape == (N,)# Set internal parametersself.hbar = hbarself.m = mself.t = t0self.dt_ = Noneself.N = len(x)self.dx = self.x[1] - self.x[0]self.dk = 2 * np.pi / (self.N * self.dx)# set momentum scaleif k0 == None:self.k0 = -0.5 * self.N * self.dkelse:self.k0 = k0self.k = self.k0 + self.dk * np.arange(self.N)self.psi_x = psi_x0self.compute_k_from_x()# variables which hold steps in evolution of theself.x_evolve_half = Noneself.x_evolve = Noneself.k_evolve = None# attributes used for dynamic plottingself.psi_x_line = Noneself.psi_k_line = Noneself.V_x_line = Nonedef _set_psi_x(self, psi_x):self.psi_mod_x = (psi_x * np.exp(-1j * self.k[0] * self.x)* self.dx / np.sqrt(2 * np.pi))def _get_psi_x(self):return (self.psi_mod_x * np.exp(1j * self.k[0] * self.x)* np.sqrt(2 * np.pi) / self.dx)def _set_psi_k(self, psi_k):self.psi_mod_k = psi_k * np.exp(1j * self.x[0]* self.dk * np.arange(self.N))def _get_psi_k(self):return self.psi_mod_k * np.exp(-1j * self.x[0] *self.dk * np.arange(self.N))def _get_dt(self):return self.dt_def _set_dt(self, dt):if dt != self.dt_:self.dt_ = dtself.x_evolve_half = np.exp(-0.5 * 1j * self.V_x/ self.hbar * dt )self.x_evolve = self.x_evolve_half * self.x_evolve_halfself.k_evolve = np.exp(-0.5 * 1j * self.hbar /self.m * (self.k * self.k) * dt)psi_x = property(_get_psi_x, _set_psi_x)psi_k = property(_get_psi_k, _set_psi_k)dt = property(_get_dt, _set_dt)def compute_k_from_x(self):self.psi_mod_k = fft(self.psi_mod_x)def compute_x_from_k(self):self.psi_mod_x = ifft(self.psi_mod_k)def time_step(self, dt, Nsteps = 1):"""Perform a series of time-steps via the time-dependentSchrodinger Equation.Parameters----------dt : floatthe small time interval over which to integrateNsteps : float, optionalthe number of intervals to compute. The total changein time at the end of this method will be dt * Nsteps.default is N = 1"""self.dt = dtif Nsteps > 0:self.psi_mod_x *= self.x_evolve_halffor i in xrange(Nsteps - 1):self.compute_k_from_x()self.psi_mod_k *= self.k_evolveself.compute_x_from_k()self.psi_mod_x *= self.x_evolveself.compute_k_from_x()self.psi_mod_k *= self.k_evolveself.compute_x_from_k()self.psi_mod_x *= self.x_evolve_halfself.compute_k_from_x()self.t += dt * Nsteps####################################################################### Helper functions for gaussian wave-packetsdef gauss_x(x, a, x0, k0):"""a gaussian wave packet of width a, centered at x0, with momentum k0"""return ((a * np.sqrt(np.pi)) ** (-0.5)* np.exp(-0.5 * ((x - x0) * 1. / a) ** 2 + 1j * x * k0))def gauss_k(k,a,x0,k0):"""analytical fourier transform of gauss_x(x), above"""return ((a / np.sqrt(np.pi))**0.5* np.exp(-0.5 * (a * (k - k0)) ** 2 - 1j * (k - k0) * x0))####################################################################### Utility functions for running the animationdef theta(x):"""theta function :returns 0 if x<=0, and 1 if x>0"""x = np.asarray(x)y = np.zeros(x.shape)y[x > 0] = 1.0return ydef square_barrier(x, width, height):return height * (theta(x) - theta(x - width))####################################################################### Create the animation# specify time steps and durationdt = 0.01N_steps = 50t_max = 120frames = int(t_max / float(N_steps * dt))# specify constantshbar = 1.0 # planck's constantm = 1.9 # particle mass# specify range in x coordinateN = 2 ** 11dx = 0.1x = dx * (np.arange(N) - 0.5 * N)# specify potentialV0 = 1.5L = hbar / np.sqrt(2 * m * V0)a = 3 * Lx0 = -60 * LV_x = square_barrier(x, a, V0)V_x[x < -98] = 1E6V_x[x > 98] = 1E6# specify initial momentum and quantities derived from itp0 = np.sqrt(2 * m * 0.2 * V0)dp2 = p0 * p0 * 1./80d = hbar / np.sqrt(2 * dp2)k0 = p0 / hbarv0 = p0 / mpsi_x0 = gauss_x(x, d, x0, k0)# define the Schrodinger object which performs the calculationsS = Schrodinger(x=x,psi_x0=psi_x0,V_x=V_x,hbar=hbar,m=m,k0=-28)####################################################################### Set up plotfig = pl.figure()# plotting limitsxlim = (-100, 100)klim = (-5, 5)# top axes show the x-space dataymin = 0ymax = V0ax1 = fig.add_subplot(211, xlim=xlim,ylim=(ymin - 0.2 * (ymax - ymin),ymax + 0.2 * (ymax - ymin)))psi_x_line, = ax1.plot([], [], c='r', label=r'$|\psi(x)|$')V_x_line, = ax1.plot([], [], c='k', label=r'$V(x)$')center_line = ax1.axvline(0, c='k', ls=':',label = r"$x_0 + v_0t$")title = ax1.set_title("")ax1.legend(prop=dict(size=12))ax1.set_xlabel('$x$')ax1.set_ylabel(r'$|\psi(x)|$')# bottom axes show the k-space dataymin = abs(S.psi_k).min()ymax = abs(S.psi_k).max()ax2 = fig.add_subplot(212, xlim=klim,ylim=(ymin - 0.2 * (ymax - ymin),ymax + 0.2 * (ymax - ymin)))psi_k_line, = ax2.plot([], [], c='r', label=r'$|\psi(k)|$')p0_line1 = ax2.axvline(-p0 / hbar, c='k', ls=':', label=r'$\pm p_0$')p0_line2 = ax2.axvline(p0 / hbar, c='k', ls=':')mV_line = ax2.axvline(np.sqrt(2 * V0) / hbar, c='k', ls='--',label=r'$\sqrt{2mV_0}$')ax2.legend(prop=dict(size=12))ax2.set_xlabel('$k$')ax2.set_ylabel(r'$|\psi(k)|$')V_x_line.set_data(S.x, S.V_x)####################################################################### Animate plotdef init():psi_x_line.set_data([], [])V_x_line.set_data([], [])center_line.set_data([], [])psi_k_line.set_data([], [])title.set_text("")return (psi_x_line, V_x_line, center_line, psi_k_line, title)def animate(i):S.time_step(dt, N_steps)psi_x_line.set_data(S.x, 4 * abs(S.psi_x))V_x_line.set_data(S.x, S.V_x)center_line.set_data(2 * [x0 + S.t * p0 / m], [0, 1])psi_k_line.set_data(S.k, abs(S.psi_k))title.set_text("t = %.2f" % S.t)return (psi_x_line, V_x_line, center_line, psi_k_line, title)# call the animator. blit=True means only re-draw the parts that have changed.anim = animation.FuncAnimation(fig, animate, init_func=init,frames=frames, interval=30, blit=True)# uncomment the following line to save the video in mp4 format. This# requires either mencoder or ffmpeg to be installed on your system#anim.save('schrodinger_barrier.mp4', fps=15, extra_args=['-vcodec', 'libx264'])pl.show()