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
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
    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()
Exemple #4
0
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],
    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)
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
Exemple #7
0
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, \
Exemple #8
0
# 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...'
Exemple #9
0
# 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))
Exemple #10
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
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)
#     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'