def evolve(self, psi0, dt=0.001, Nt=1, t0=0., nout=1, coordinates='linear'): psi = psi0 t = t0 x = self.x nx = len(x) dx = x[1] - x[0] vmat = self.v nac = self.nac # momentum k-space k = 2.0 * np.pi * scipy.fftpack.fftfreq(nx, dx) if coordinates == 'linear': print('The nuclear coordinate is linear.') elif coordinates == 'curvilinear': raise NotImplementedError('Kinetic energy operator for curvilinear\ coordinates has not been implemented.') fig, ax = plt.subplots() for j in range(Nt // nout): for i in range(nout): t += dt psi = rk4(psi, hpsi, dt, x, k, vmat, nac) #output_tmp = density_matrix(psi) #f.write('{} {} {} {} {} \n'.format(t, *rho)) #purity[i] = output_tmp # ax.plot(x, np.abs(psi[:,0]) + 0.1 * j) ax.plot(x, np.abs(psi[:, 1])) return psi
def _propagator(H, dt, Nt): """ compute the resolvent for the multi-point correlation function signals U(t) = e^{-i H t} Parameters ----------- t: float or list times """ # propagator U = identity(H.shape[-1], dtype=complex) # set the ground state energy to 0 print('Computing the propagator. ' 'Please make sure that the ground-state energy is 0.') Ulist = [] for k in range(Nt): Ulist.append(U) U = rk4(U, tdse, dt, H) return Ulist
def _lindblad(H, rho0, c_ops, Nt, dt, e_ops=[], return_result=True): """ time propagation of the lindblad quantum master equation with second-order differencing Input ------- h0: 2d array system Hamiltonian Nt: total number of time steps dt: time step c_ops: list of collapse operators e_ops: list of observable operators rho0: initial density matrix Returns ========= rho: 2D array density matrix at time t = Nt * dt """ nstates = H.shape[-1] # initialize the density matrix rho = rho0 t = 0.0 # first-step # rho_half = rho0 + liouvillian(rho0, h0, c_ops) * dt2 # rho1 = rho0 + liouvillian(rho_half, h0, c_ops) * dt # rho_old = rho0 # rho = rho1 if return_result == False: f_dm = open('den_mat.dat', 'w') fmt_dm = '{} ' * (nstates**2 + 1) + '\n' f_obs = open('obs.dat', 'w') fmt = '{} ' * (len(e_ops) + 1) + '\n' for k in range(Nt): t += dt # rho_new = rho_old + liouvillian(rho, h0, c_ops) * 2. * dt # # update rho_old # rho_old = rho # rho = rho_new rho = rk4(rho, liouvillian, dt, H, c_ops) # dipole-dipole auto-corrlation function #cor = np.trace(np.matmul(d, rho)) # take a partial trace to obtain the rho_el # compute observables observables = np.zeros(len(e_ops), dtype=complex) for i, obs_op in enumerate(e_ops): observables[i] = obs_dm(rho, obs_op) f_obs.write(fmt.format(t, *observables)) f_obs.close() f_dm.close() return rho else: rholist = [] # store density matries result = Result(dt=dt, Nt=Nt, rho0=rho0) observables = np.zeros((Nt, len(e_ops)), dtype=complex) for k in range(Nt): t += dt rho = rk4(rho, liouvillian, dt, H, c_ops) rholist.append(rho) observables[k, :] = [obs_dm(rho, op) for op in e_ops] result.observables = observables result.rholist = rholist return result
def _correlation_2p_1t(H, rho0, ops, c_ops, dt, Nt, method='lindblad', output='cor.dat'): """ compute the time-translation invariant two-point correlation function in the density matrix formalism using quantum regression theorem <A(t)B> = Tr[ A U(t) (B rho0) U^\dag(t)] input: ======== H: 2d array full Hamiltonian rho0: initial density matrix ops: list of operators [A, B] for computing the correlation functions method: str dynamics method e.g. lindblad, redfield, heom args: dictionary of parameters for dynamics Returns ======== the density matrix is stored in 'dm.dat' 'cor.dat': the correlation function is stored """ #nstates = H.shape[-1] # number of states in the system # initialize the density matrix A, B = ops rho = B.dot(rho0) f = open(output, 'w') # f_dm = open('dm.dat', 'w') # fmt = '{} ' * (H.size + 1) + '\n' # format to store the density matrix # dynamics t = 0.0 cor = np.zeros(Nt, dtype=complex) # sparse matrix H = csr_matrix(H) rho = csr_matrix(rho) A = csr_matrix(A) c_ops_sparse = [csr_matrix(c_op) for c_op in c_ops] if method == 'lindblad': for k in range(Nt): t += dt rho = rk4(rho, liouvillian, dt, H, c_ops_sparse) # cor = A.dot(rho).diagonal().sum() tmp = obs_dm(rho, A) cor[k] = tmp # store the reduced density matrix f.write('{} {} \n'.format(t, tmp)) # f_dm.write(fmt.format(t, *np.ravel(rho))) # f_dm.write(fmt.format(t, *np.ravel(rho.toarray()))) else: sys.exit('The method {} has not been implemented yet! Please \ try lindblad.'.format(method)) f.close() # f_dm.close() return cor
def driven_dynamics(ham, dip, psi0, pulse, dt=0.001, Nt=1, e_ops=None, nout=1, \ t0=0.0): ''' Laser-driven dynamics in the presence of laser pulses Parameters ---------- ham : 2d array Hamiltonian of the molecule dip : TYPE transition dipole moment psi0: 1d array initial wavefunction pulse : TYPE laser pulse dt : TYPE time step. Nt : TYPE timesteps. e_ops: list observable operators to compute nout: int Store data every nout steps Returns ------- None. ''' # initialize the density matrix # wf = csr_matrix(wf0).transpose() psi = psi0 nstates = len(psi0) # f = open(fname,'w') fmt = '{} ' * (len(e_ops) + 1) + '\n' fmt_dm = '{} ' * (nstates + 1) + '\n' f_dm = open('psi.dat', 'w') # wavefunction f_obs = open('obs.dat', 'w') # observables t = t0 # f_dip = open('dipole'+'{:f}'.format(pulse.delay * au2fs)+'.dat', 'w') for k1 in range(int(Nt / nout)): for k2 in range(nout): ht = pulse.field(t) * dip + ham psi = rk4(psi, tdse, dt, ht) t += dt * nout # compute observables Aave = np.zeros(len(e_ops), dtype=complex) for j, A in enumerate(e_ops): Aave[j] = obs(psi, A) f_dm.write(fmt_dm.format(t, *psi)) f_obs.write(fmt.format(t, *Aave)) f_dm.close() f_obs.close() return
def _quantum_dynamics(H, psi0, dt=0.001, Nt=1, e_ops=[], t0=0.0, nout=1, store_states=True, output='obs.dat'): """ Quantum dynamics for a multilevel system. Parameters ---------- e_ops: list of arrays expectation values to compute. H : 2d array Hamiltonian of the molecule psi0: 1d array initial wavefunction dt : float time step. Nt : int timesteps. e_ops: list observable operators to compute nout: int Store data every nout steps Returns ------- None. """ psi = psi0 if e_ops is not None: fmt = '{} ' * (len(e_ops) + 1) + '\n' f_obs = open(output, 'w') # observables t = t0 # f_obs.close() if store_states: result = Result(dt=dt, Nt=Nt, psi0=psi0) observables = np.zeros((Nt // nout, len(e_ops)), dtype=complex) psilist = [psi0.copy()] # compute observables for t0 observables[0, :] = [obs(psi, e_op) for e_op in e_ops] for k1 in range(1, Nt // nout): for k2 in range(nout): psi = rk4(psi, tdse, dt, H) t += dt * nout # compute observables observables[k1, :] = [obs(psi, e_op) for e_op in e_ops] # f_obs.write(fmt.format(t, *e_list)) psilist.append(psi.copy()) # f_obs.close() result.psilist = psilist result.observables = observables return result else: # not save states for k1 in range(int(Nt / nout)): for k2 in range(nout): psi = rk4(psi, tdse, dt, H) t += dt * nout # compute observables e_list = [obs(psi, e_op) for e_op in e_ops] f_obs.write(fmt.format(t, *e_list)) f_obs.close() return psi
def driven_dynamics(H, edip, psi0, pulse, dt=0.001, Nt=1, e_ops=None, nout=1, \ t0=0.0, return_result=True): ''' Laser-driven dynamics in the presence of laser pulses Parameters ---------- ham : 2d array Hamiltonian of the molecule dip : TYPE transition dipole moment psi0: 1d array initial wavefunction pulse : TYPE laser pulse dt : TYPE time step. Nt : TYPE timesteps. e_ops: list observable operators to compute nout: int Store data every nout steps Returns ------- None. ''' # initialize the density matrix # wf = csr_matrix(wf0).transpose() psi = psi0.astype(complex) nstates = len(psi0) # f = open(fname,'w') if e_ops is None: e_ops = [] t = t0 # f_dip = open('dipole'+'{:f}'.format(pulse.delay * au2fs)+'.dat', 'w') if return_result: result = Result(dt=dt, Nt=Nt, psi0=psi0) observables = np.zeros((Nt // nout, len(e_ops)), dtype=complex) psilist = [psi0.copy()] # compute observables for t0 observables[0, :] = [obs(psi, e_op) for e_op in e_ops] for k1 in range(1, Nt // nout): for k2 in range(nout): ht = -pulse.field(t) * edip + H psi = rk4(psi, tdse, dt, ht) t += dt * nout # compute observables observables[k1, :] = [obs(psi, e_op) for e_op in e_ops] # f_obs.write(fmt.format(t, *e_list)) psilist.append(psi.copy()) # f_obs.close() result.psilist = psilist result.observables = observables return result else: fmt = '{} ' * (len(e_ops) + 1) + '\n' fmt_dm = '{} ' * (nstates + 1) + '\n' f_dm = open('psi.dat', 'w') # wavefunction f_obs = open('obs.dat', 'w') # observables for k1 in range(int(Nt / nout)): for k2 in range(nout): ht = pulse.field(t) * edip + H psi = rk4(psi, tdse, dt, ht) t += dt * nout # compute observables Aave = np.zeros(len(e_ops), dtype=complex) for j, A in enumerate(e_ops): Aave[j] = obs(psi, A) f_dm.write(fmt_dm.format(t, *psi)) f_obs.write(fmt.format(t, *Aave)) f_dm.close() f_obs.close() return
def adiabatic_2d(x, y, psi0, v, dt, Nt=0, coords='linear', mass=None, G=None): """ propagate the adiabatic dynamics at a single surface :param dt: time step :param v: 2d array potential matrices in 2D :param psi: list the initial state mass: list of 2 elements reduced mass Nt: int the number of the time steps, Nt=0 indicates that no propagation has been done, only the initial state and the initial purity would be the output G: 4D array nx, ny, ndim, ndim G-matrix :return: psi_end: list the final state G: 2d array G matrix only used for curvilinear coordinates """ #f = open('density_matrix.dat', 'w') t = 0.0 dt2 = dt * 0.5 psi = psi0.copy() nx, ny = psi.shape dx = x[1] - x[0] dy = y[1] - y[0] kx = 2. * np.pi * fftfreq(nx, dx) ky = 2. * np.pi * fftfreq(ny, dy) if coords == 'linear': # Split-operator method for linear coordinates psi = x_evolve_2d(dt2, psi, v) for i in range(Nt): t += dt psi = k_evolve_2d(dt, kx, ky, psi) psi = x_evolve_2d(dt, psi, v) elif coords == 'curvilinear': # kxpsi = np.einsum('i, ijn -> ijn', kx, psi_k) # kypsi = np.einsum('j, ijn -> ijn', ky, psi_k) # tpsi = np.zeros((nx, ny, nstates), dtype=complex) # dxpsi = np.zeros((nx, ny, nstates), dtype=complex) # dypsi = np.zeros((nx, ny, nstates), dtype=complex) # for i in range(nstates): # dxpsi[:,:,i] = ifft2(kxpsi[:,:,i]) # dypsi[:,:,i] = ifft2(kypsi[:,:,i]) for k in range(Nt): t += dt psi = rk4(psi, hpsi, dt, kx, ky, v, G) #f.write('{} {} {} {} {} \n'.format(t, *rho)) #purity[i] = output_tmp[4] # t += dt #f.close() return psi
nac = get_nac(x) k = 2.0 * np.pi * scipy.fftpack.fftfreq(nx, dx) psi = np.zeros((nx, nstates), dtype=complex) psi[:, 0] = gwp(x, a=1.0, x0=1.0, k0=0.0) print('Propagation starts ...\n') fig, ax = plt.subplots() for j in range(10): for i in range(nsteps): t += dt psi = rk4(psi, hpsi, dt, x, k, vmat) #output_tmp = density_matrix(psi) #f.write('{} {} {} {} {} \n'.format(t, *rho)) #purity[i] = output_tmp ax.plot(x, np.abs(psi[:,0]) + 0.1 * j) ax.plot(x, psi[:,1].real)
def _redfield(R, rho0, evecs=None, Nt=1, dt=0.005, t0=0, e_ops=[], return_result=True): """ time propagation of the Redfield quantum master equation with RK4 Input ------- R: 2d array Redfield tensor rho0: 2d array initial density matrix Nt: total number of time steps dt: time step e_ops: list of observable operators Returns ========= rho: 2D array density matrix at time t = Nt * dt """ N = rho0.shape[0] # initialize the density matrix if e_ops is None: e_ops = [] # basis transformation if evecs is not None: rho0 = transform(rho0, evecs) e_ops = [transform(e, evecs) for e in e_ops] rho = rho0.copy() rho = dm2vec(rho).astype(complex) # tf = t0 + dt * Nt # result = solve_ivp(rhs, t_span=(t0, tf), y0=rho0, vectorized=True, args=(R, )) t = t0 if return_result == False: f_obs = open('obs.dat', 'w') fmt = '{} ' * (len(e_ops) + 1) + '\n' for k in range(Nt): # compute observables # observables = np.zeros(len(e_ops), dtype=complex) # for i, obs_op in enumerate(e_ops): observables = [obs_dm(rho, e) for e in e_ops] t += dt rho = rk4(rho, rhs, dt, R) # dipole-dipole auto-corrlation function #cor = np.trace(np.matmul(d, rho)) # take a partial trace to obtain the rho_el f_obs.write(fmt.format(t, *observables)) f_obs.close() # f_dm.close() return rho else: rholist = [] # store density matries result = Result(dt=dt, Nt=Nt, rho0=rho0) observables = np.zeros((Nt, len(e_ops)), dtype=complex) for k in range(Nt): t += dt rho = rk4(rho, rhs, dt, R) tmp = np.reshape(rho, (N, N)) rholist.append(transform(tmp, dag(evecs))) observables[k, :] = [obs_dm(tmp, e) for e in e_ops] result.observables = observables result.rholist = rholist return result
def _lindblad_driven(H, rho0, c_ops=None, e_ops=None, Nt=1, dt=0.005, t0=0., return_result=True): """ time propagation of the lindblad quantum master equation with time-dependent Hamiltonian H = H0 + f(t) * H1 - ... Input ------- H: list [H0, [H1, f1(t)]] system Hamiltonian pulse: Pulse object externel pulse Nt: total number of time steps dt: time step c_ops: list of collapse operators e_ops: list of observable operators rho0: initial density matrix Returns ========= rho: 2D array density matrix at time t = Nt * dt """ def calculateH(t): Ht = H[0] for i in range(1, len(H)): Ht += -H[i][1](t) * H[i][0] return Ht nstates = H[0].shape[-1] if c_ops is None: c_ops = [] if e_ops is None: e_ops = [] # initialize the density matrix rho = rho0.copy() rho = rho.astype(complex) t = t0 if return_result == False: f_dm = open('den_mat.dat', 'w') fmt_dm = '{} ' * (nstates**2 + 1) + '\n' f_obs = open('obs.dat', 'w') fmt = '{} ' * (len(e_ops) + 1) + '\n' for k in range(Nt): t += dt Ht = calculateH(t) rho = rk4(rho, liouvillian, dt, Ht, c_ops) # dipole-dipole auto-corrlation function #cor = np.trace(np.matmul(d, rho)) # take a partial trace to obtain the rho_el # compute observables observables = np.zeros(len(e_ops), dtype=complex) for i, obs_op in enumerate(e_ops): observables[i] = obs_dm(rho, obs_op) f_obs.write(fmt.format(t, *observables)) f_obs.close() f_dm.close() return rho else: rholist = [] # store density matries result = Result(dt=dt, Nt=Nt, rho0=rho0) observables = np.zeros((Nt, len(e_ops)), dtype=complex) for k in range(Nt): t += dt Ht = calculateH(t) rho = rk4(rho, liouvillian, dt, Ht, c_ops) rholist.append(rho.copy()) observables[k, :] = [obs_dm(rho, op) for op in e_ops] result.observables = observables result.rholist = rholist return result