def calculate_HEOM(reorg_energy): print reorg_energy system_hamiltonian = np.array([[100., 20.], [20., 0]]) cutoff_freq = 53. temperature = 300. hs = HierarchySolver(system_hamiltonian, environment(reorg_energy, beta, K), beta, N=trunc_level) hs.init_system_dm = init_state HEOM_history, time = hs.calculate_time_evolution(time_step, duration) return HEOM_history
class DQDHEOMModelSparse(): def __init__(self, Gamma_L, Gamma_R, bias, T_c, environment=[], beta=1., K=0, tc=True, trunc_level=5, \ dissipator_test=False): self.system_dimension = 3 self.bias = bias self.T_c = T_c self.Gamma_L = Gamma_L self.Gamma_R = Gamma_R self.jump_operators = np.array([np.array([[0, 0, 0], [1., 0, 0], [0, 0, 0]]), np.array([[0, 0, 1.], [0, 0, 0], [0, 0, 0]])]) self.jump_rates = np.array([self.Gamma_L, self.Gamma_R]) self.beta = beta self.environment = environment self.filter = False self.K = K self.tc = tc self.heom_solver = HierarchySolver(self.system_hamiltonian(), self.environment, \ self.beta, self.jump_operators, self.jump_rates, N=trunc_level,\ num_matsubara_freqs=self.K, temperature_correction=self.tc, \ dissipator_test=dissipator_test) self.truncation_level = trunc_level #self.heom_solver.truncation_level = self.truncation_level self.dv_pops = np.zeros(self.system_dimension**2 * self.heom_solver.number_density_matrices()) self.dv_pops[:self.system_dimension**2] = np.array([1., 0, 0, 0, 1., 0, 0, 0, 1.]) def system_hamiltonian(self): return np.array([[0, 0, 0], [0, self.bias/2., self.T_c], [0, self.T_c, -self.bias/2.]]) def heom_matrix(self): self.heom_solver = HierarchySolver(self.system_hamiltonian(), self.environment, \ self.beta, self.jump_operators, self.jump_rates, N=self.truncation_level, \ num_matsubara_freqs=self.K, temperature_correction=self.tc) #self.heom_solver.truncation_level = self.truncation_level return sp.csr_matrix(self.heom_solver.construct_hierarchy_matrix_super_fast()) def jump_matrix(self): if not self.filter: heom_dim = self.heom_solver.number_density_matrices() * self.heom_solver.system_dimension**2 else: heom_dim = self.heom_solver.num_dms * self.heom_solver.system_dimension**2 LJ = sp.lil_matrix((heom_dim, heom_dim), dtype='complex128') LJ[0,8] = self.Gamma_R return LJ
def calculate_HEOM(reorg_energy): system_hamiltonian = np.array([[100., 20.], [20., 0]]) cutoff_freq = 53. temperature = 300. init_state = np.array([[1., 0], [0, 0]]) time_step = 0.00005 duration = 5. hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature) HEOM_history, time = hs.hierarchy_time_evolution(init_state, 18, time_step, duration) return HEOM_history
def HEOM_calculation(hamiltonian): reorg_energy = 100. cutoff_freq = 53. temperature = 300. init_state = np.array([[1., 0], [0, 0]]) duration = 5. time_step = 0.00005 hs = HierarchySolver(hamiltonian, reorg_energy, cutoff_freq, temperature) HEOM_history, time = hs.hierarchy_time_evolution(init_state, 18, time_step, duration) return HEOM_history
class SRLHEOMModel(): def __init__(self): self.hamiltonian = np.array([[100.,8.],[8.,0]]) self.jump_operators = np.array([np.array([[0, 0],[1., 0]]), np.array([[0, 1.],[0, 0]])]) self.Gamma_L = 1. self.Gamma_R = 1.#e-4 self.jump_rates = np.array([self.Gamma_L, self.Gamma_R]) self.dt = 1.e4 self.hs = HierarchySolver(self.hamiltonian, 35., 40., temperature=300., jump_operators=self.jump_operators, jump_rates=self.jump_rates) self.hs.truncation_level = 4 self.hm = self.hs.construct_hierarchy_matrix_super_fast().tolil() #print self.hm.todense() self.init_ss_vector = spla.eigs(self.hm.tocsc(), k=1, sigma=0, which='LM', maxiter=1000)[1] def hm_chi(self, chi): new_hm = self.hm.copy() # sys_dim = self.hs.system_dimension # for i in range(self.hs.number_density_matrices()): # print 'i = ' + str(i*sys_dim**2) # print 'j = ' + str((i+1)*sys_dim**2 - 1) # new_hm[i*sys_dim**2,(i+1)*sys_dim**2 - 1] *= np.exp(chi) new_hm[0,3] *= np.exp(chi) return new_hm # define cumulant generating function def cumulant_generating_function(self, chi): W = self.hm_chi(chi).tocsc() ss = spla.eigs(W, k=1, sigma=0, which='LM', maxiter=1000, v0=self.init_ss_vector)[1] #ss = spla.svds(W, k=1, which='SM', maxiter=10000, v0=self.init_ss_vector)[0] ss /= np.trace(self.hs.extract_system_density_matrix(ss)) dv_pops = np.zeros(4 * self.hs.number_density_matrices()) dv_pops[:4] = np.array([1., 0, 0, 1.]) #ss = utils.stationary_state_svd(W.todense(), dv_pops) return np.log(dv_pops.dot(spla.expm(W.multiply(self.dt)).dot(ss))) def zero_frequency_noise(self): CGF_dd = ndt.Derivative(self.cumulant_generating_function, n=2, method='central') return CGF_dd(0)[0] / self.dt def mean(self): ss = spla.eigs(self.hm_chi(0).tocsc(), k=1, sigma=0, which='LM', v0=self.init_ss_vector)[1] #ss = spla.svds(self.hm_chi(0).tocsc(), k=1, which='SM', maxiter=10000, v0=self.init_ss_vector)[0] ss = self.hs.extract_system_density_matrix(ss) ss /= np.trace(ss) return self.Gamma_R * ss[1,1] def fano_factor(self): return self.zero_frequency_noise() / self.mean()
def __init__(self, Gamma_L, Gamma_R, bias, T_c, environment=[], beta=1., K=0, tc=True, trunc_level=5, \ dissipator_test=False): self.system_dimension = 3 self.bias = bias self.T_c = T_c self.Gamma_L = Gamma_L self.Gamma_R = Gamma_R self.jump_operators = np.array([np.array([[0, 0, 0], [1., 0, 0], [0, 0, 0]]), np.array([[0, 0, 1.], [0, 0, 0], [0, 0, 0]])]) self.jump_rates = np.array([self.Gamma_L, self.Gamma_R]) self.beta = beta self.environment = environment self.filter = False self.K = K self.tc = tc self.heom_solver = HierarchySolver(self.system_hamiltonian(), self.environment, \ self.beta, self.jump_operators, self.jump_rates, N=trunc_level,\ num_matsubara_freqs=self.K, temperature_correction=self.tc, \ dissipator_test=dissipator_test) self.truncation_level = trunc_level #self.heom_solver.truncation_level = self.truncation_level self.dv_pops = np.zeros(self.system_dimension**2 * self.heom_solver.number_density_matrices()) self.dv_pops[:self.system_dimension**2] = np.array([1., 0, 0, 0, 1., 0, 0, 0, 1.])
def construct_heom_matrix(self): if not self.no_mode: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.v * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.c * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (), ()] else: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (), ()] jump_operators = [self.excitation_op(), self.deexcitation_op(), \ self.forward_secondary_CT_op(), self.backward_secondary_CT_op(), \ self.drain_lead_op(), self.source_lead_op()] jump_rates = np.array([self.gamma_ex, self.gamma_deex, self.forward_secondary_CT, self.backward_secondary_CT, \ self.Gamma_R, self.Gamma_L]) self.solver = HierarchySolver(self.el_hamiltonian(), environment=env, beta=self.beta, \ jump_operators=jump_operators, jump_rates=jump_rates, \ N=self.N, num_matsubara_freqs=self.K, temperature_correction=True) return self.solver.construct_hierarchy_matrix_super_fast()
def __init__(self): self.hamiltonian = np.array([[100.,8.],[8.,0]]) self.jump_operators = np.array([np.array([[0, 0],[1., 0]]), np.array([[0, 1.],[0, 0]])]) self.Gamma_L = 1. self.Gamma_R = 1.#e-4 self.jump_rates = np.array([self.Gamma_L, self.Gamma_R]) self.dt = 1.e4 self.hs = HierarchySolver(self.hamiltonian, 35., 40., temperature=300., jump_operators=self.jump_operators, jump_rates=self.jump_rates) self.hs.truncation_level = 4 self.hm = self.hs.construct_hierarchy_matrix_super_fast().tolil() #print self.hm.todense() self.init_ss_vector = spla.eigs(self.hm.tocsc(), k=1, sigma=0, which='LM', maxiter=1000)[1]
class PhotocellModel(object): def __init__(self, delta_E, J, drude_reorg_energy, drude_cutoff, mode_freq, mode_S, mode_damping, CT_scaling, temperature=300., N=6, K=0, v=1., no_mode=False): ''' Parameters... delta_E: unshifted electronic energy splitting in site basis J: electronic coupling drude_reorg_energy: reorg energy due to Drude bath drude_cutoff: relaxation parameter of the Drude bath mode_freq: frequency of the mode mode_S: Huang-Rhys factor of the mode mode_damping: damping constant for the mode CT_scaling: the scaling parameter for the CT state reorg energy temperature N: number of tiers to use with HEOM K: number of Matsubara terms to use in correlation function expansion with HEOM v: the scaling parameter for the excited state reorg energy no_mode: whether to include the mode in the spectral density or not ''' self.el_dim = 5 # the dimension of the electronic system self.delta_E = delta_E # 100. self.J = J # 5. #evals,evecs = np.linalg.eig(H) self.T = temperature # 300. # temperature in Kelvin self.beta = 1. / (utils.KELVIN_TO_WAVENUMS * self.T ) # the inverse temperature in wavenums self.drude_reorg_energy = drude_reorg_energy # 35. self.drude_cutoff = drude_cutoff # 40. self.no_mode = no_mode self.mode_freq = mode_freq # 342. self.mode_S = mode_S # 0.0438 self.mode_damping = mode_damping # 10. self.mode_reorg_energy = self.mode_freq * self.mode_S self.total_reorg_energy = ( self.drude_reorg_energy + self.mode_reorg_energy ) if not self.no_mode else self.drude_reorg_energy self.v = v # scaling of site 1 reorg energy (in case we want to vary it too) self.c = CT_scaling # scaling of CT state reorg energy self.N = N # truncation level self.K = K # num Matsubara terms ''' Where did I take the following parameters from? ''' self.n_ex = 6000 # number of photons in the 'hot' bath self.gamma = 1.e-2 # bare transition rate between ground and excited states self.gamma_ex = self.gamma * self.n_ex # rate from ground to excited state self.gamma_deex = self.gamma * (self.n_ex + 1. ) # rate from excited to ground state self.secondary_CT_energy_gap = 300. self.bare_secondary_CT = 1. #0.0025 # rate from CT1 to CT2 self.n_c = utils.planck_distribution(self.secondary_CT_energy_gap, self.T) self.forward_secondary_CT = (self.n_c + 1) * self.bare_secondary_CT self.backward_secondary_CT = self.n_c * self.bare_secondary_CT self.Gamma_L = 1. # 0.025 # the rate from left lead to populate ground state self.Gamma_R = 1. # rate from CT2 state to right lead # set up environment depending on no_mode if not self.no_mode: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.v * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.c * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (), ()] else: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (), ()] # I think this dummy solver is set up so we can get info about the size of hierarchy # etc using methods from HierarchySolver before actually creating the hierarchy matrix self.dummy_solver = HierarchySolver(self.el_hamiltonian(), env, self.beta, N=self.N, num_matsubara_freqs=self.K) def el_hamiltonian(self): ''' The electronic Hamiltonian. We can ignore the energies of ground, CT2 and empty states as there is no coherent evolution between them. We take into account the relative energies through the incoherent rates instead. ''' H = np.zeros((self.el_dim, self.el_dim)) H[1:3, 1:3] = np.array([[self.delta_E / 2., self.J], [self.J, -self.delta_E / 2.]]) + np.diag([ self.v * self.total_reorg_energy, self.c * self.total_reorg_energy ]) return H def excitation_op(self): ''' Operator to take the system from ground state to site 1 (excited state) transformed to the electronic eigenstate basis. ''' op = np.zeros((self.el_dim, self.el_dim)) op[1, 0] = 1. # eigenstate basis evals, evecs = np.linalg.eig(self.el_hamiltonian()[1:3, 1:3]) transform = np.eye(self.el_dim, dtype='complex128') transform[1:3, 1:3] = evecs return np.dot(transform.T, np.dot(op, transform)) def deexcitation_op(self): ''' Operator to take the system from site 1 (excited state) to ground state transformed to the electronic eigenstate basis. ''' op = np.zeros((self.el_dim, self.el_dim)) op[0, 1] = 1. # eigenstate basis evals, evecs = np.linalg.eig(self.el_hamiltonian()[1:3, 1:3]) transform = np.eye(self.el_dim, dtype='complex128') transform[1:3, 1:3] = evecs return np.dot(transform.T, np.dot(op, transform)) def forward_secondary_CT_op(self): op = np.zeros((self.el_dim, self.el_dim)) op[3, 2] = 1. return op def backward_secondary_CT_op(self): op = np.zeros((self.el_dim, self.el_dim)) op[2, 3] = 1. return op def drain_lead_op(self): op = np.zeros((self.el_dim, self.el_dim)) op[4, 3] = 1. return op def source_lead_op(self): op = np.zeros((self.el_dim, self.el_dim)) op[0, 4] = 1. return op def construct_heom_matrix(self): if not self.no_mode: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.v * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.c * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (), ()] else: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (), ()] jump_operators = [self.excitation_op(), self.deexcitation_op(), \ self.forward_secondary_CT_op(), self.backward_secondary_CT_op(), \ self.drain_lead_op(), self.source_lead_op()] jump_rates = np.array([self.gamma_ex, self.gamma_deex, self.forward_secondary_CT, self.backward_secondary_CT, \ self.Gamma_R, self.Gamma_L]) self.solver = HierarchySolver(self.el_hamiltonian(), environment=env, beta=self.beta, \ jump_operators=jump_operators, jump_rates=jump_rates, \ N=self.N, num_matsubara_freqs=self.K, temperature_correction=True) return self.solver.construct_hierarchy_matrix_super_fast() def jump_matrix(self): dim = self.dummy_solver.M_dimension() jop = sp.csr_matrix((dim, dim)) jop[:self.el_dim**2, :self.el_dim**2] = self.Gamma_R * np.kron( self.drain_lead_op(), self.drain_lead_op()) return jop def dv_pops(self): dv_pops = np.zeros(self.dummy_solver.system_dimension**2 * self.dummy_solver.number_density_matrices()) dv_pops[:self.dummy_solver.system_dimension**2] = np.eye( self.dummy_solver.system_dimension).flatten() return dv_pops def update_Gamma_R(self, Gamma_R): self.Gamma_R = Gamma_R self.solver.jump_rates[-2] = Gamma_R
[1., 0, 0], [0, 0, 0]]), np.array([[0, 0, 1.], [0, 0, 0], [0, 0, 0]])]) jump_rates = np.array([0.1, 0.0025]) K = 4 environment = [] if mode_params: # assuming that there is a single identical mode on each site environment = [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K), UBOscillator(mode_params[0][0], mode_params[0][1], mode_params[0][2], beta, K=K)), \ (OBOscillator(reorg_energy, cutoff_freq, beta, K=K), UBOscillator(mode_params[0][0], mode_params[0][1], mode_params[0][2], beta, K=K))] else: environment = [(), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K),), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K),)] hs = HierarchySolver(system_hamiltonian, environment, beta, jump_ops, jump_rates, num_matsubara_freqs=K, temperature_correction=True) hs.truncation_level = 7 hm = hs.construct_hierarchy_matrix_super_fast() print 'hierarchy matrix shape: ' + str(hm.shape) print hs.dm_per_tier() np.savez('DQD_heom_matrix_N7_K4.npz', hm=hm) import scipy.sparse.linalg as spla np.set_printoptions(precision=6, linewidth=150, suppress=True) v0 = np.zeros(hm.shape[0]) v0[0] = 1./3 v0[4] = 1./3 v0[8] = 1./3 evals,evec = spla.eigs(hm.tocsc(), k=1, sigma=0, which='LM', v0=v0)#, ncv=100)
beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) init_state = np.array([[1., 0], [0, 0]]) trunc_level = 30 K = 0 #hs = HierarchySolver(system_hamiltonian, 1., cutoff_freq, temperature) def environment(reorg_energy, beta, K): return [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K),), \ (OBOscillator(reorg_energy, cutoff_freq, beta, K=K),)] hs = HierarchySolver(system_hamiltonian, environment(1., beta, K), beta, N=trunc_level) # error function for least squares fit def residuals(p, y, pops1, pops2): k12, k21 = p return y - (-k12 * pops1 + k21 * pops2) def fit_func(t, k01, k10): time_propagator = np.zeros((2, 2)) time_propagator[0, 0] = -k01 time_propagator[0, 1] = k10 time_propagator[1, 1] = -k10 time_propagator[1, 0] = k01
CT2_empty_rate = 25.e-3 * utils.EV_TO_WAVENUMS empty_ground_rate = 25.e-3 * utils.EV_TO_WAVENUMS # jump_rates = np.array([excitation_rate, deexcitation_rate, chl_CT1_rate, CT1_chl_rate, \ # phe_CT1_rate, CT1_phe_rate, CT1_CT2_rate, CT2_CT1_rate, CT2_empty_rate, empty_ground_rate]) jump_rates = np.array([excitation_rate, deexcitation_rate]) for i in range(6): jump_rates = np.append(jump_rates, [forward_exciton_CT_rates[i], backward_exciton_CT_rates[i]]) #jump_rates[2:] *= 0.1 jump_rates = np.append(jump_rates, [CT1_CT2_rate, CT2_CT1_rate, CT2_empty_rate, empty_ground_rate]) single_mode_params = []#[(342., 342.*0.4, 100.)] #print jump_rates #jump_rates = np.zeros(18) hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature, jump_operators=jump_operators, jump_rates=jump_rates, underdamped_mode_params=single_mode_params) hs.truncation_level = 6 init_state = np.zeros((10, 10)) init_state[0,0] = 1. init_state = np.dot(site_exciton_transform, np.dot(init_state, site_exciton_transform.T)) hs.init_system_dm = init_state dm_history, time = hs.calculate_time_evolution(0.01, 5.) # transform back to exciton basis exciton_dm_history = np.zeros((dm_history.shape[0], dm_history.shape[1], dm_history.shape[2])) for i,dm in enumerate(dm_history): exciton_dm_history[i] = np.dot(site_exciton_transform.T, np.dot(dm, site_exciton_transform)) np.savez('../../data/PSIIRC_HEOM_incoherent_rates_slow_jump_rates_data.npz', exciton_dm_history=exciton_dm_history, \ time=time, reorg_energy=reorg_energy, cutoff_freq=cutoff_freq, temperature=temperature, \ site_exciton_transform=site_exciton_transform, jump_rates=jump_rates) # np.savez('../../data/PSIIRC_HEOM_incoherent_rates_mode_data.npz', exciton_dm_history=exciton_dm_history, \
'''Ed's params''' electronic_coupling = 92. system_hamiltonian = np.array([[1042., electronic_coupling], [electronic_coupling, 0]]) reorg_energy = 110. cutoff_freq = 100. #53.08 temperature = 300. # Kelvin beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) fig,ax1 = plt.subplots() mode_params = [] K = 0 environment = [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K),), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K),)] hs = HierarchySolver(system_hamiltonian, environment, beta, num_matsubara_freqs=K, temperature_correction=True) hs.truncation_level = 12 print 'Calculating time evolution...' start = tutils.getTime() init_state = np.array([[0,0],[0,1.]]) init_state = np.dot(hs.system_evectors.T, np.dot(init_state, hs.system_evectors)) hs.init_system_dm = init_state dm_history, time = hs.calculate_time_evolution(time_step, duration) exciton_dm_history = hs.transform_to_exciton_basis(dm_history) end = tutils.getTime() print 'Calculation took ' + str(tutils.duration(end, start)) # convert time in inverse wavenums to picoseconds
# site-CT couplings couplings = np.array([[0,150.,-42.,-55.,-6.,17.,0,0], [0,0,-56.,-36.,20.,-2.,0,0], [0,0,0,7.,46.,-4.,70.,0], [0,0,0,0,-5.,37.,0,0], [0,0,0,0,0,-3.,70.,0], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,40.], [0,0,0,0,0,0,0,0]]) system_hamiltonian = np.diag(average_site_CT_energies) + couplings + couplings.T system_hamiltonian = system_hamiltonian[:6,:6] reorg_energy = 35. cutoff_freq = 300. temperature = 300. mode_params = []#[(342., 342.*0.4, 100.)] hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature, underdamped_mode_params=mode_params) init_state = np.zeros(system_hamiltonian.shape) init_state[0,0] = 1. # exciton basis init_state = np.dot(hs.system_evectors, np.dot(init_state, hs.system_evectors.T)) # transform to site basis for HEOM calculation #dm_history, time = hs.converged_time_evolution(init_state, 6, 6, time_step, duration) hs.init_system_dm = init_state hs.truncation_level = 8 dm_history, time = hs.calculate_time_evolution(time_step, duration) exciton_dm_history = hs.transform_to_exciton_basis(dm_history) end_time = tutils.getTime() print 'Calculation took ' + str(tutils.duration(end_time, start_time)) # print 'Calculating steady state...'
system_hamiltonian = np.array([[100., electronic_coupling], [electronic_coupling, 0]]) reorg_energy = 100. cutoff_freq = 53.08 temperature = 300. # Kelvin beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) mode_params = [] #[(200., 0.25, 10.)] init_state = np.array([[1., 0], [0, 0]]) K_values = range(4) dm_histories = np.zeros((len(K_values) + 1, duration / time_step + 1, 2, 2), dtype='complex128') for i in K_values: hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, beta, underdamped_mode_params=mode_params, \ num_matsubara_freqs=i, temperature_correction=True) print 'Calculating for K = ' + str(i) start = tutils.getTime() hs.init_system_dm = init_state hs.truncation_level = 9 dm_history, time = hs.calculate_time_evolution(time_step, duration) dm_histories[i] = dm_history end = tutils.getTime() print 'Calculation took ' + str(tutils.duration(end, start)) '''Now calculate for K = 0 but include temperature correction''' hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, beta, underdamped_mode_params=mode_params, \ num_matsubara_freqs=0, temperature_correction=True)
def heom_matrix(self): self.heom_solver = HierarchySolver(self.system_hamiltonian(), self.environment, \ self.beta, self.jump_operators, self.jump_rates, N=self.truncation_level, \ num_matsubara_freqs=self.K, temperature_correction=self.tc) #self.heom_solver.truncation_level = self.truncation_level return sp.csr_matrix(self.heom_solver.construct_hierarchy_matrix_super_fast())
# print 'Started calculating HEOM dynamics for reorg_energy = ' + str(reorg_energy) + 'cm-1 at ' + str(tutils.getTime()) # hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature) # init_state = np.zeros(system_hamiltonian.shape) # init_state[0,0] = 1. # exciton basis # init_state = np.dot(hs.system_evectors, np.dot(init_state, hs.system_evectors.T)) # transform to site basis for HEOM calculation # dm_history, time = hs.converged_time_evolution(init_state, truncation_level, truncation_level, time_step, duration) # exciton_dm_history = hs.transform_to_exciton_basis(dm_history) # np.savez('../../data/PSIIRC_HEOM_dynamics_reorg_energy_'+str(int(reorg_energy))+'_wavenums.npz', exciton_dm_history=exciton_dm_history, \ # time=time, init_state=init_state, reorg_energy=reorg_energy, cutoff_freq=cutoff_freq, temperature=temperature, \ # system_hamiltonian=system_hamiltonian) # try different cutoff freqs reorg_energy = 35. cutoff_freq_values = [40., 70., 100.] temperature = 300. for cutoff_freq in cutoff_freq_values: print 'Started calculating HEOM dynamics for cutoff_freq = ' + str(cutoff_freq) + 'cm-1 at ' + str(tutils.getTime()) hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature) init_state = np.zeros(system_hamiltonian.shape) init_state[0,0] = 1. # exciton basis init_state = np.dot(hs.system_evectors, np.dot(init_state, hs.system_evectors.T)) # transform to site basis for HEOM calculation dm_history, time = hs.converged_time_evolution(init_state, truncation_level, truncation_level, time_step, duration) exciton_dm_history = hs.transform_to_exciton_basis(dm_history) np.savez('../../data/PSIIRC_HEOM_dynamics_cutoff_freq_'+str(int(cutoff_freq))+'_wavenums.npz', exciton_dm_history=exciton_dm_history, \ time=time, init_state=init_state, reorg_energy=reorg_energy, cutoff_freq=cutoff_freq, temperature=temperature, \ system_hamiltonian=system_hamiltonian) print 'Calculations finished'
# init_state = np.dot(hs.system_evectors, np.dot(init_state, hs.system_evectors.T)) # transform to site basis for HEOM calculation # dm_history, time = hs.converged_time_evolution(init_state, truncation_level, truncation_level, time_step, duration) # exciton_dm_history = hs.transform_to_exciton_basis(dm_history) # np.savez('../../data/PSIIRC_HEOM_dynamics_reorg_energy_'+str(int(reorg_energy))+'_wavenums.npz', exciton_dm_history=exciton_dm_history, \ # time=time, init_state=init_state, reorg_energy=reorg_energy, cutoff_freq=cutoff_freq, temperature=temperature, \ # system_hamiltonian=system_hamiltonian) # try different cutoff freqs reorg_energy = 35. cutoff_freq_values = [40., 70., 100.] temperature = 300. for cutoff_freq in cutoff_freq_values: print 'Started calculating HEOM dynamics for cutoff_freq = ' + str( cutoff_freq) + 'cm-1 at ' + str(tutils.getTime()) hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature) init_state = np.zeros(system_hamiltonian.shape) init_state[0, 0] = 1. # exciton basis init_state = np.dot(hs.system_evectors, np.dot(init_state, hs.system_evectors.T) ) # transform to site basis for HEOM calculation dm_history, time = hs.converged_time_evolution(init_state, truncation_level, truncation_level, time_step, duration) exciton_dm_history = hs.transform_to_exciton_basis(dm_history) np.savez('../../data/PSIIRC_HEOM_dynamics_cutoff_freq_'+str(int(cutoff_freq))+'_wavenums.npz', exciton_dm_history=exciton_dm_history, \ time=time, init_state=init_state, reorg_energy=reorg_energy, cutoff_freq=cutoff_freq, temperature=temperature, \ system_hamiltonian=system_hamiltonian) print 'Calculations finished'
jump_operators[3] = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1., 0]]) # CT2 backward jump_operators[4] = np.array([[0, 0, 0, 0], [0, 0, 0, 1.], [0, 0, 0, 0], [0, 0, 0, 0]]) # CT2 forward jump_operators[5] = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1., 0, 0]]) # irreversible transfer to ground state jump_operators[6] = np.array([[0, 0, 0, 1.], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) jump_rates = np.array([1., 1.1, 2., 2.1, 0.8, 0.82, 0.2]) hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature, jump_operators=jump_operators, jump_rates=jump_rates) # start_time = tutils.getTime() # print 'Calculating steady state...' # steady_state = hs.calculate_steady_state(6,6) # print steady_state # # end_time = tutils.getTime() # print 'Calculation took ' + str(tutils.duration(end_time, start_time)) start_time = tutils.getTime() print 'Calculating time evolution...' dm_history, time = hs.hierarchy_time_evolution(np.array([[0, 0, 0, 0], [0, 1., 0, 0],
[0, 0, 0, 1.], [0, 0, 0, 0], [0, 0, 0, 0]]) # CT2 forward jump_operators[5] = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1., 0, 0]]) # irreversible transfer to ground state jump_operators[6] = np.array([[0, 0, 0, 1.], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) jump_rates = np.array([1., 1.1, 2., 2.1, 0.8, 0.82, 0.2]) hs = HierarchySolver(system_hamiltonian, reorg_energy, cutoff_freq, temperature, jump_operators=jump_operators, jump_rates=jump_rates) # start_time = tutils.getTime() # print 'Calculating steady state...' # steady_state = hs.calculate_steady_state(6,6) # print steady_state # # end_time = tutils.getTime() # print 'Calculation took ' + str(tutils.duration(end_time, start_time)) start_time = tutils.getTime() print 'Calculating time evolution...' dm_history,time = hs.hierarchy_time_evolution(np.array([[0, 0, 0, 0],[0, 1., 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]]), 8, 8, 0.005, 15., sparse=True) end_time = tutils.getTime() print 'Calculation took ' + str(tutils.duration(end_time, start_time)) print time.shape
np.array([[0, 0, 1.], [0, 0, 0], [0, 0, 0]]) ]) jump_rates = np.array([0.1, 0.0025]) K = 4 environment = [] if mode_params: # assuming that there is a single identical mode on each site environment = [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K), UBOscillator(mode_params[0][0], mode_params[0][1], mode_params[0][2], beta, K=K)), \ (OBOscillator(reorg_energy, cutoff_freq, beta, K=K), UBOscillator(mode_params[0][0], mode_params[0][1], mode_params[0][2], beta, K=K))] else: environment = [(), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K), ), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K), )] hs = HierarchySolver(system_hamiltonian, environment, beta, jump_ops, jump_rates, num_matsubara_freqs=K, temperature_correction=True) hs.truncation_level = 7 hm = hs.construct_hierarchy_matrix_super_fast() print 'hierarchy matrix shape: ' + str(hm.shape) print hs.dm_per_tier() np.savez('DQD_heom_matrix_N7_K4.npz', hm=hm) import scipy.sparse.linalg as spla np.set_printoptions(precision=6, linewidth=150, suppress=True) v0 = np.zeros(hm.shape[0]) v0[0] = 1. / 3
def __init__(self, delta_E, J, drude_reorg_energy, drude_cutoff, mode_freq, mode_S, mode_damping, CT_scaling, temperature=300., N=6, K=0, v=1., no_mode=False): ''' Parameters... delta_E: unshifted electronic energy splitting in site basis J: electronic coupling drude_reorg_energy: reorg energy due to Drude bath drude_cutoff: relaxation parameter of the Drude bath mode_freq: frequency of the mode mode_S: Huang-Rhys factor of the mode mode_damping: damping constant for the mode CT_scaling: the scaling parameter for the CT state reorg energy temperature N: number of tiers to use with HEOM K: number of Matsubara terms to use in correlation function expansion with HEOM v: the scaling parameter for the excited state reorg energy no_mode: whether to include the mode in the spectral density or not ''' self.el_dim = 5 # the dimension of the electronic system self.delta_E = delta_E # 100. self.J = J # 5. #evals,evecs = np.linalg.eig(H) self.T = temperature # 300. # temperature in Kelvin self.beta = 1. / (utils.KELVIN_TO_WAVENUMS * self.T ) # the inverse temperature in wavenums self.drude_reorg_energy = drude_reorg_energy # 35. self.drude_cutoff = drude_cutoff # 40. self.no_mode = no_mode self.mode_freq = mode_freq # 342. self.mode_S = mode_S # 0.0438 self.mode_damping = mode_damping # 10. self.mode_reorg_energy = self.mode_freq * self.mode_S self.total_reorg_energy = ( self.drude_reorg_energy + self.mode_reorg_energy ) if not self.no_mode else self.drude_reorg_energy self.v = v # scaling of site 1 reorg energy (in case we want to vary it too) self.c = CT_scaling # scaling of CT state reorg energy self.N = N # truncation level self.K = K # num Matsubara terms ''' Where did I take the following parameters from? ''' self.n_ex = 6000 # number of photons in the 'hot' bath self.gamma = 1.e-2 # bare transition rate between ground and excited states self.gamma_ex = self.gamma * self.n_ex # rate from ground to excited state self.gamma_deex = self.gamma * (self.n_ex + 1. ) # rate from excited to ground state self.secondary_CT_energy_gap = 300. self.bare_secondary_CT = 1. #0.0025 # rate from CT1 to CT2 self.n_c = utils.planck_distribution(self.secondary_CT_energy_gap, self.T) self.forward_secondary_CT = (self.n_c + 1) * self.bare_secondary_CT self.backward_secondary_CT = self.n_c * self.bare_secondary_CT self.Gamma_L = 1. # 0.025 # the rate from left lead to populate ground state self.Gamma_R = 1. # rate from CT2 state to right lead # set up environment depending on no_mode if not self.no_mode: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.v * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), UBOscillator(self.mode_freq, self.c * self.mode_S, self.mode_damping, beta=self.beta, K=self.K)), (), ()] else: env = [(), (OBOscillator(self.v * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (OBOscillator(self.c * self.drude_reorg_energy, self.drude_cutoff, beta=self.beta, K=self.K), ), (), ()] # I think this dummy solver is set up so we can get info about the size of hierarchy # etc using methods from HierarchySolver before actually creating the hierarchy matrix self.dummy_solver = HierarchySolver(self.el_hamiltonian(), env, self.beta, N=self.N, num_matsubara_freqs=self.K)
# system_hamiltonian = np.array([[1042., electronic_coupling], [electronic_coupling, 0]]) # reorg_energy = 110. # cutoff_freq = 100. #53.08 # temperature = 300. # Kelvin # beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) # mode_params = [] #[(1111., 0.0578, 50.)] K = 0 environment = [] if mode_params: # assuming that there is a single identical mode on each site environment = [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K), UBOscillator(mode_params[0][0], mode_params[0][1], mode_params[0][2], beta, K=K)), \ (OBOscillator(reorg_energy, cutoff_freq, beta, K=K), UBOscillator(mode_params[0][0], mode_params[0][1], mode_params[0][2], beta, K=K))] else: environment = [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K),), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K),)] hs = HierarchySolver(system_hamiltonian, environment, beta, num_matsubara_freqs=K, temperature_correction=False) #hs = HierarchySolverNonRenorm(system_hamiltonian, environment, beta, num_matsubara_freqs=K, temperature_correction=False) hs.truncation_level = 30 print 'Calculating time evolution...' start = tutils.getTime() init_state = np.array([[1.,0],[0,0]]) #init_state = np.dot(hs.system_evectors.T, np.dot(init_state, hs.system_evectors)) hs.init_system_dm = init_state dm_history, time = hs.calculate_time_evolution(time_step, duration) #exciton_dm_history = hs.transform_to_exciton_basis(dm_history) end = tutils.getTime() print 'Calculation took ' + str(tutils.duration(end, start))
[electronic_coupling, 0]]) reorg_energy = 110. cutoff_freq = 100. #53.08 temperature = 300. # Kelvin beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) fig, ax1 = plt.subplots() mode_params = [] K = 0 environment = [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K), ), (OBOscillator(reorg_energy, cutoff_freq, beta, K=K), )] hs = HierarchySolver(system_hamiltonian, environment, beta, num_matsubara_freqs=K, temperature_correction=True) hs.truncation_level = 12 print 'Calculating time evolution...' start = tutils.getTime() init_state = np.array([[0, 0], [0, 1.]]) init_state = np.dot(hs.system_evectors.T, np.dot(init_state, hs.system_evectors)) hs.init_system_dm = init_state dm_history, time = hs.calculate_time_evolution(time_step, duration) exciton_dm_history = hs.transform_to_exciton_basis(dm_history) end = tutils.getTime()
mode_params = [] # [(200., 0.25, 10.)] """Ed's PE545 params""" # electronic_coupling = 92. # system_hamiltonian = np.array([[1042., electronic_coupling], [electronic_coupling, 0]]) # reorg_energy = 100. # cutoff_freq = 140. #53.08 # temperature = 300. # Kelvin # beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) # mode_params = [] #[(1111., 0.0578, 10.)] hs = HierarchySolver( system_hamiltonian, reorg_energy, cutoff_freq, beta, underdamped_mode_params=mode_params, num_matsubara_freqs=1, temperature_correction=True, sites_to_couple=np.array([1, 1]), ) hs.truncation_level = 11 print hs.system_dimension ** 2 * hs.number_density_matrices() print "Calculating time evolution..." start = tutils.getTime() init_state = np.array([[1.0, 0], [0, 0]]) # init_state = np.dot(hs.system_evectors.T, np.dot(init_state, hs.system_evectors)) # print init_state
system_hamiltonian = np.array([[100., 20.], [20., 0]]) cutoff_freq = 53.08 temperature = 300. beta = 1. / (utils.KELVIN_TO_WAVENUMS * temperature) init_state = np.array([[1., 0], [0, 0]]) trunc_level = 30 K = 0 #hs = HierarchySolver(system_hamiltonian, 1., cutoff_freq, temperature) def environment(reorg_energy, beta, K): return [(OBOscillator(reorg_energy, cutoff_freq, beta, K=K),), \ (OBOscillator(reorg_energy, cutoff_freq, beta, K=K),)] hs = HierarchySolver(system_hamiltonian, environment(1., beta, K), beta, N=trunc_level) # error function for least squares fit def residuals(p, y, pops1, pops2): k12, k21 = p return y - (-k12*pops1 + k21*pops2) def fit_func(t, k01, k10): time_propagator = np.zeros((2,2)) time_propagator[0,0] = -k01 time_propagator[0,1] = k10 time_propagator[1,1] = -k10 time_propagator[1,0] = k01 time_step = t[1] - t[0] dynamics = te.liouvillian_time_evolution(np.array([1,0]), time_propagator, t[-1], time_step, wave_nums=False) return dynamics[:,0]