def absorption(self, e_min, e_max, de, rho_0, t_final, dt, dipole_file='dipole_dipole.dat', is_damped=False): utils.print_banner("CALCULATING LINEAR ABSORPTION SPECTRUM") energies = np.arange(e_min, e_max, de) omegas = energies/const.hbar mu = self.dipole_site mu_rho_0 = np.dot(mu, rho_0) times, mu_rho, x = self.dynamics.propagate(mu_rho_0, 0.0, t_final, dt) Cw = np.zeros(len(omegas)) fdipole = open(dipole_file,'w') t_damp = 0. expi = np.exp(1j*np.outer(omegas,times)) for t, time in enumerate(times): weight = dt - 0.5*dt*(t==0 or t==len(times)-1) Ct = np.trace(np.dot(mu,mu_rho[t])) if is_damped and t > t_damp: Ct *= switch_to_zero(time,t_damp,t_final) fdipole.write('%0.6f %0.6f %0.6f\n'%( time, Ct.real, Ct.imag)) Cw += weight*(expi[:,t]*Ct).real fdipole.close() return energies, Cw
def __init__(self, hamiltonian, method='Redfield', is_secular=False, is_verbose=False): """Initialize the Redfield class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. method : str The weak-coupling method, either 'Redfield', 'TCL2', or 'TC2'. is_secular : bool Flag to indicate the secular approximation. """ assert (method in ['Redfield', 'TCL2', 'TC2']) if is_verbose: utils.print_banner("PERFORMING RDM DYNAMICS WITH METHOD = %s" % (method)) self.ham = hamiltonian self.method = method self.is_secular = is_secular self.is_verbose = is_verbose self.setup()
def __init__(self, hamiltonian, is_verbose=True): """Initialize the Unitary evolution class. Parameters ---------- hamiltonian : HamiltonianSystem An instance of the pyrho HamiltonianSystem class. """ if is_verbose: utils.print_banner("PERFORMING UNITARY DYNAMICS") self.ham = hamiltonian
def __init__(self, hamiltonian, L=1, K=0, K_truncation='Ishizaki-Tanimura', L_truncation='TNL', is_scaled=True): """Initialize the HEOM class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. L : int The "hierarchy depth." L_truncation: str Hierarchy closure type (time-local or time-nonlocal) K : int The Matsubara truncation. K_truncation : str The Matsubara truncation type (or terminator). is_scaled : bool Flag to use scaled ADMs, which are useful for filtering. """ assert (K_truncation in ['None', 'Ishizaki-Tanimura']) assert (L_truncation in ['TNL', 'TL']) utils.print_banner("PERFORMING RDM DYNAMICS WITH " "THE HIERARCHICAL EQUATIONS OF MOTION") self.ham = hamiltonian self.Lmax = L self.Kmax = K self.is_scaled = is_scaled self.L_truncation = L_truncation self.K_truncation = K_truncation print "--- Hierarchy depth, L =", self.Lmax print "--- Using hierarchy closure:", self.L_truncation print "--- Maximum Matsubara frequency, K =", self.Kmax print "--- Using Matsubara truncation scheme:", self.K_truncation # TODO(TCB): Implement filtering. # Scaling makes no difference unless using tolerant filtering if self.is_scaled: print "--- Using Shi et al. scaled ADMs." else: print "--- Using original *unscaled* ADMs." self.initialize_hierarchy_nmats() self.precompute_matsubara()
def __init__(self, ham_sys, ham_sysbath, spec_densities, kT, hbar=1, is_verbose=True, sample_wigner=False): """Initialize the Hamiltonian class. Parameters ---------- ham_sys : np.array The system Hamiltonian in the site basis. ham_sysbath : list of np.arrays The system part of the system-bath operator for each bath. spec_densities : list of functions The spectral density function for each bath. kT : float Thermal energy, kT, in chosen units. hbar : float Reduced Planck constant, hbar, in chosen units. """ # Set these shared constants const.kT = kT const.hbar = hbar if is_verbose: utils.print_banner("INITIALIZING SYSTEM+BATH HAMILTONIAN") self.init_system(ham_sys, is_verbose) self.sample_wigner = sample_wigner self.sysbath = ham_sysbath self.spec_densities = spec_densities assert len(ham_sysbath) == len(spec_densities) self.nbath = len(ham_sysbath) # 'sd' is a list of 'SpecDens' instances that have member # variables lamda, omega_c and member function J(omega) self.sd = [] self.coupling = [] n = 0 for spec_dens in self.spec_densities: self.sd.append(SpecDens(spec_dens)) self.sd[n].write_Jw('Jw%d.dat' % (n)) n += 1
def __init__(self, hamiltonian, dynamics_slow, dynamics_fast, omega_split=None): """Initialize the Hybrid class Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. """ utils.print_banner("PERFORMING RDM DYNAMICS WITH HYBRID METHOD") self.ham = hamiltonian self.dynamics_slow = dynamics_slow self.dynamics_fast = dynamics_fast self.omega_split = omega_split self.setup()
def __init__(self, hamiltonian, L=1, K=0, K_truncation='Ishizaki-Tanimura', L_truncation='TNL'): """Initialize the HEOM class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. L : int The "hierarchy depth." L_truncation: str Hierarchy closure type (time-local or time-nonlocal) K : int The Matsubara truncation. K_truncation : str The Matsubara truncation type (or terminator). """ assert(K_truncation in ['None','Ishizaki-Tanimura']) assert(L_truncation in ['TNL','TL']) utils.print_banner("PERFORMING RDM DYNAMICS WITH " "THE HIERARCHICAL EQUATIONS OF MOTION") self.ham = hamiltonian self.Lmax = L self.Kmax = K self.Nk = K+1 self.L_truncation = L_truncation self.K_truncation = K_truncation print("--- Hierarchy depth, L =", self.Lmax) print("--- Using hierarchy closure:", self.L_truncation) print("--- Maximum Matsubara frequency, K =", self.Kmax) print("--- Using Matsubara truncation scheme:", self.K_truncation) if self.ham.sd[0].sd_type == 'ohmic-exp': self.nlorentz = 3 # number of Lorenztians to fit elif self.ham.sd[0].sd_type == 'cubic-exp': self.nlorentz = 4 # number of Lorenztians to fit elif self.ham.sd[0].sd_type == 'custom': self.nlorentz = len(self.ham.sd[0].pks) # number of Lorenztians as input else: self.nlorentz = 0 self.initialize_hierarchy_nmats() self.precompute_matsubara()
def __init__(self, hamiltonian, nmode=300, ntraj=100): """Initialize the Ehrenfest class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. nmode : int The number of explicit classical modes ntraj : int The number of trajectories over which to average """ utils.print_banner("PERFORMING EHRENFEST DYNAMICS") self.ham = hamiltonian self.nmode = nmode self.ntraj = ntraj
def __init__(self, hamiltonian, L=1, K=0, truncation_type='Ishizaki-Tanimura', is_scaled=True): """Initialize the HEOM class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. L : int The "hierarchy depth." K : int The Matsubara truncation. truncation_type : str The hierarchy truncation type (or terminator). is_scaled : bool Flag to use scaled ADMs, which are useful for filtering. """ assert(truncation_type in ['None','Ishizaki-Tanimura','TL']) utils.print_banner("PERFORMING RDM DYNAMICS WITH " "THE HIERARCHICAL EQUATIONS OF MOTION") self.ham = hamiltonian self.Lmax = L self.Kmax = K self.is_scaled = is_scaled self.truncation_type = truncation_type print "--- Hierarchy depth, L =", self.Lmax print "--- Maximum Matsubara frequency, K =", self.Kmax print "--- Using Matsubara truncation scheme:", self.truncation_type # TODO(TCB): Implement filtering. # Scaling makes no difference unless using tolerant filtering if self.is_scaled: print "--- Using Shi et al. scaled ADMs." else: print "--- Using original *unscaled* ADMs." self.initialize_hierarchy_nmats() self.precompute_matsubara()
def __init__(self, ham_sys, ham_sysbath, spec_densities, kT, hbar=1, is_verbose=True): """Initialize the Hamiltonian class. Parameters ---------- ham_sys : np.array The system Hamiltonian in the site basis. ham_sysbath : list of np.arrays The system part of the system-bath operator for each bath. spec_densities : list of functions The spectral density function for each bath. kT : float Thermal energy, kT, in chosen units. hbar : float Reduced Planck constant, hbar, in chosen units. """ # Set these shared constants const.kT = kT const.hbar = hbar if is_verbose: utils.print_banner("INITIALIZING SYSTEM+BATH HAMILTONIAN") self.init_system(ham_sys, is_verbose) self.sysbath = ham_sysbath self.spec_densities = spec_densities assert len(ham_sysbath) == len(spec_densities) self.nbath = len(ham_sysbath) # 'sd' is a list of 'SpecDens' instances that have member # variables lamda, omega_c and member function J(omega) self.sd = [] n = 0 for spec_dens in self.spec_densities: self.sd.append(SpecDens(spec_dens)) self.sd[n].write_Jw('Jw%d.dat'%(n)) n += 1
def __init__(self, hamiltonian, method='Redfield', is_secular=False, is_verbose=True): """Initialize the Redfield class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. method : str The weak-coupling method, either 'Redfield', 'TCL2', or 'TC2'. is_secular : bool Flag to indicate the secular approximation. """ assert(method in ['Redfield', 'TCL2', 'TC2']) if is_verbose: utils.print_banner("PERFORMING RDM DYNAMICS WITH METHOD = %s"%(method)) self.ham = hamiltonian self.method = method self.is_secular = is_secular self.is_verbose = is_verbose self.setup()
def __init__(self, hamiltonian, dynamics_slow, dynamics_fast, omega_split=None, use_PD=False): """Initialize the Hybrid class Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class. """ raise NotImplementedError utils.print_banner("PERFORMING RDM DYNAMICS WITH HYBRID METHOD") self.ham = hamiltonian self.dynamics_slow = dynamics_slow self.dynamics_fast = dynamics_fast self.omega_split = omega_split self.use_PD = use_PD self.setup()
def absorption(self, e_min, e_max, de, rho_0, t_final, dt, dipole_file='dipole_dipole.dat', is_damped=True, lineshape_func=False): utils.print_banner("CALCULATING LINEAR ABSORPTION SPECTRUM") energies = np.arange(e_min, e_max, de) omegas = energies / const.hbar mu = self.dipole_site t_damp = 0. if lineshape_func == True: if self.dynamics.ham.nsite == 2: omega_eg = self.dynamics.ham.omega_diff[1, 0] times = np.zeros(int(t_final / dt)) for n in range(len(times)): times[n] = n * dt Cw = np.zeros(len(omegas)) expi = np.exp(1j * (np.outer(omegas, times))) for t, time in enumerate(times): weight = dt - 0.5 * dt * (t == 0 or t == len(times) - 1) gt = self.dynamics.ham.sd[0].line_func(t * dt) Ct = np.exp(-1j * omega_eg * t * dt - gt) if is_damped and t > t_damp: Ct *= switch_to_zero(time, t_damp, t_final) Cw += weight * (expi[:, t] * Ct).real return energies, (mu[1, 0]**2) * Cw else: omega_diff = self.dynamics.ham.omega_diff nbath = self.dynamics.ham.nbath nsite = self.dynamics.ham.nsite sys_eig = self.dynamics.ham.site2eig(self.dynamics.ham.sys) sysbath_eig = [] for n in range(nbath): sysbath_eig.append( self.dynamics.ham.site2eig( self.dynamics.ham.sysbath[n])) mu_eig = self.dynamics.ham.site2eig(mu) gs_index = np.where(np.diag(sys_eig) == 0.)[0][0] markov_rate = [] for l in range(nbath): markovrate_l = np.zeros((nsite, nsite)) for m in range(nsite): for n in range(nsite): markovrate_l[ m, n] = self.dynamics.ham.sd[l].markov_poprate( omega_diff[n, m]) markovrate_l[n, n] = 0.0 markov_rate.append(markovrate_l) times = np.zeros(int(t_final / dt)) for n in range(len(times)): times[n] = n * dt full_rate = np.zeros((nsite, nsite)) for n in range(nbath): full_rate += (sysbath_eig[n]**2) * markov_rate[n] full_rate_sum = np.zeros(nsite) for n in range(nsite): full_rate_sum[n] = (np.sum(full_rate[n, :])) gammas = np.zeros((nsite)) for m in range(nbath): for n in range(nsite): gammas[n] += sysbath_eig[m][n, n]**2 t_damp = 0. times = np.zeros(int(t_final / dt)) for n in range(len(times)): times[n] = n * dt expi = np.exp(1j * (np.outer(omegas, times))) absw = np.zeros(len(omegas)) # Currently assumes all sites have identical J(w); not sure about individual J(w) after site to eig conversion for n in range(nsite): Cw = np.zeros(len(omegas)) for t, time in enumerate(times): weight = dt - 0.5 * dt * (t == 0 or t == len(times) - 1) gt = self.dynamics.ham.sd[0].line_func(t * dt) gt0 = self.dynamics.ham.sd[0].line_func(0.) Ct = np.exp(-1j * omega_diff[n, gs_index] * t * dt - gammas[n] * (gt - gt0) - 0.5 * full_rate_sum[n]) if is_damped and t > t_damp: Ct *= switch_to_zero(time, t_damp, t_final) Cw += weight * (expi[:, t] * Ct).real absw += (mu_eig[n, gs_index]**2) * Cw return energies, absw else: nbath = self.dynamics.ham.nbath nsite = self.dynamics.ham.nsite sysbath_eig = [] for n in range(nbath): sysbath_eig.append( self.dynamics.ham.site2eig(self.dynamics.ham.sysbath[n])) mu_rho_0 = np.dot(mu, rho_0) times, mu_rho = self.dynamics.propagate(mu_rho_0, 0.0, t_final, dt) Cw = np.zeros(len(omegas)) fdipole = open(dipole_file, 'w') t_damp = 0. expi = np.exp(1j * np.outer(omegas, times)) for t, time in enumerate(times): weight = dt - 0.5 * dt * (t == 0 or t == len(times) - 1) Ct = np.trace(np.dot(mu, mu_rho[t])) if is_damped and t > t_damp: Ct *= switch_to_zero(time, t_damp, t_final) fdipole.write('%0.6f %0.6f %0.6f\n' % (time, Ct.real, Ct.imag)) Cw += weight * (expi[:, t] * Ct).real fdipole.close() return energies, Cw
def two_dimensional(self, e1_min, e1_max, de1, e3_min, e3_max, de3, t2_min, t2_max, dt2, rho_g, t_final, dt): utils.print_banner("CALCULATING TWO-DIMENSIONAL SPECTRUM") energy1s = np.arange(e1_min, e1_max, de1) energy3s = np.arange(e3_min, e3_max, de3) omega1s = energy1s/const.hbar omega3s = energy3s/const.hbar time2s = np.arange(t2_min, t2_max+1e-8, dt2) times = np.arange(0.0, t_final, dt) dt2_over_dt = int(dt2/dt) spectrum = np.zeros( (len(omega3s),len(time2s),len(omega1s)) ) print "--- Spectrum will require O(%d) propagations."%(len(times)*len(times)) mu_p = np.tril(self.dipole_site) mu_m = np.triu(self.dipole_site) mu_rp_ese = [ [mu_m,'R'], [mu_p,'L'], [mu_p,'R'], 1 ] # R2 mu_rp_gsb = [ [mu_m,'R'], [mu_p,'R'], [mu_p,'L'], 1 ] # R3 mu_rp_esa = [ [mu_m,'R'], [mu_p,'L'], [mu_p,'L'], -1 ] # R5 mu_nr_ese = [ [mu_p,'L'], [mu_m,'R'], [mu_p,'R'], 1 ] # R1 mu_nr_gsb = [ [mu_p,'L'], [mu_m,'L'], [mu_p,'L'], 1 ] # R4 mu_nr_esa = [ [mu_p,'L'], [mu_m,'R'], [mu_p,'L'], -1 ] # R6 # This part changes based on the desired spectrum # e.g. just the ESA of the non-rephasing spectrum: # mu_rp = [] # mu_nr = [mu_nr_esa] # Total 2D spectrum: mu_rp = [mu_rp_ese, mu_rp_gsb, mu_rp_esa] mu_nr = [mu_nr_ese, mu_nr_gsb, mu_nr_esa] # This part never changes mu_ops = [mu_rp, mu_nr] Rsignal = [] Rsignal.append(np.zeros( (len(times),len(time2s),len(times)), dtype=np.complex_)) Rsignal.append(np.zeros( (len(times),len(time2s),len(times)), dtype=np.complex_)) x, rho_g_baths, x = self.dynamics.propagate( rho_g, 0.0, 0.0, dt, input_has_bath=False, output_has_bath=True, is_verbose=False) rho_g_bath = rho_g_baths[0] print "--- Calculating third-order response function ...", for ph in [0,1]: for mu_op in mu_ops[ph]: rho_0 = self.act(mu_op[0],rho_g_bath) t1s, rhos_t1, x = self.dynamics.propagate( rho_0, 0.0, t_final, dt, input_has_bath=True, output_has_bath=True, is_verbose=False) for t1 in range(len(times)): rho_t1 = rhos_t1[t1] rho_t1_0 = self.act(mu_op[1],rho_t1) t2s, rhos_t2, x = self.dynamics.propagate( rho_t1_0, t2_min, t2_max, dt, input_has_bath=True, output_has_bath=True, is_verbose=False) for t2 in range(len(time2s)): rho_t2 = rhos_t2[t2*dt2_over_dt] rho_t2_0 = self.act(mu_op[2],rho_t2) t3s, rhos_t3, x = self.dynamics.propagate( rho_t2_0, 0.0, t_final, dt, input_has_bath=True, output_has_bath=False, is_verbose=False) for t3 in range(len(times)): rho_t3 = rhos_t3[t3] sign = mu_op[3] Rsignal[ph][t3,t2,t1] += sign*np.trace(np.dot(mu_m,rho_t3)) print "done." print "--- Performing 2D Fourier transform ...", for w3, omega3 in enumerate(omega3s): for w1, omega1 in enumerate(omega1s): for t1, time1 in enumerate(times): weight1 = dt - 0.5*dt*(t1==0 or t1==len(times)-1) exp_iw1t1 = np.exp(1j*omega1*time1) exp_miw1t1 = exp_iw1t1.conj() for t3, time3 in enumerate(times): weight3 = dt - 0.5*dt*(t3==0 or t3==len(times)-1) exp_iw3t3 = np.exp(1j*omega3*time3) for t2 in range(len(time2s)): spectrum[w3,t2,w1] += weight1*weight3*( exp_iw1t1*exp_iw3t3*Rsignal[1][t3,t2,t1] + exp_miw1t1*exp_iw3t3*Rsignal[0][t3,t2,t1] ).real #np.exp(1j*(omega1*time1+omega3*time3))*Rsignal[1][t3,t2,t1] #+np.exp(1j*(-omega1*time1+omega3*time3))*Rsignal[0][t3,t2,t1] ).real print "done." spectra = [] for t2 in range(len(time2s)): spectra.append( spectrum[:,t2,:] ) return energy1s, energy3s, time2s, spectra
def two_dimensional(self, e1_min, e1_max, de1, e3_min, e3_max, de3, time2_min, time2_max, dt2, rho_g, time_final, dt, lioupath = 'total', is_damped=True, lineshape_func = False): utils.print_banner("CALCULATING TWO-DIMENSIONAL SPECTRUM") if lioupath == 'total': print '--- Including all Liouville pathways.' else: print '--- Including only selected Liouville pathways.' energy1s = np.arange(e1_min, e1_max, de1) energy3s = np.arange(e3_min, e3_max, de3) omega1s = energy1s/const.hbar omega3s = energy3s/const.hbar time2_max += 1e-8 # try to include time2_max time2s = np.arange(time2_min, time2_max, dt2) times = np.arange(0.0, time_final, dt) spectrum = np.zeros( (len(omega3s),len(time2s),len(omega1s)) ) print "--- Spectrum will require O(%d) propagations."%(len(times)*len(time2s)) print "--- Calculating third-order response function ...", try: Rsignal = [] Rsignal.append(np.zeros( (len(times),len(time2s),len(times)), dtype=np.complex)) Rsignal.append(np.zeros( (len(times),len(time2s),len(times)), dtype=np.complex)) for traj in range(self.dynamics.ntraj): R_rp, R_nr = self.calculate_R3(rho_g, time2_min, time2_max, dt2, time_final, dt, is_damped=is_damped, lioupath=lioupath, lineshape_func=lineshape_func) Rsignal[0] += R_rp/self.dynamics.ntraj Rsignal[1] += R_nr/self.dynamics.ntraj except AttributeError: Rsignal = self.calculate_R3(rho_g, time2_min, time2_max, dt2, time_final, dt, is_damped=is_damped, lioupath=lioupath, lineshape_func=lineshape_func) # print time correlation R3 # for n in range(1,len(times)-1): # print Rsignal[0][0,0,n].real print "done." print "--- Performing 2D Fourier transform ...", expi1 = np.exp(1j*np.outer(omega1s,times)) expi1[:,0] *= 0.5*dt expi1[:,1:] *= dt expi3 = np.exp(1j*np.outer(omega3s,times)) expi3[:,0] *= 0.5*dt expi3[:,1:] *= dt spectrum = np.einsum('ws,xu,uts->xtw',expi1,expi3,Rsignal[1]).real spectrum += np.einsum('ws,xu,uts->xtw',expi1.conj(),expi3,Rsignal[0]).real # for w3, omega3 in enumerate(omega3s): # for w1, omega1 in enumerate(omega1s): # for t1, time1 in enumerate(times): # weight1 = dt - 0.5*dt*(t1==0 or t1==len(times)-1) # exp_iw1t1 = np.exp(1j*omega1*time1) # exp_miw1t1 = exp_iw1t1.conj() # for t3, time3 in enumerate(times): # weight3 = dt - 0.5*dt*(t3==0 or t3==len(times)-1) # exp_iw3t3 = np.exp(1j*omega3*time3) # for t2 in range(len(time2s)): # spectrum[w3,t2,w1] += weight1*weight3*( # exp_iw1t1*exp_iw3t3*Rsignal[1][t3,t2,t1] # + exp_miw1t1*exp_iw3t3*Rsignal[0][t3,t2,t1] ).real # #np.exp(1j*(omega1*time1+omega3*time3))*Rsignal[1][t3,t2,t1] # #+np.exp(1j*(-omega1*time1+omega3*time3))*Rsignal[0][t3,t2,t1] ).real print "done." spectra = [] for t2 in range(len(time2s)): spectra.append( spectrum[:,t2,:] ) return energy1s, energy3s, time2s, spectra, times, Rsignal
def absorption(self, e_min, e_max, de, rho_0, t_final, dt, dipole_file='dipole_dipole.dat', is_damped=True, lineshape_func = False): utils.print_banner("CALCULATING LINEAR ABSORPTION SPECTRUM") energies = np.arange(e_min, e_max, de) omegas = energies/const.hbar mu = self.dipole_site t_damp=0. if lineshape_func == True: if self.dynamics.ham.nsite == 2: omega_eg = self.dynamics.ham.omega_diff[1,0] times = np.zeros(int(t_final/dt)) for n in range(len(times)): times[n] = n*dt # for t, time in enumerate(times): # gt = self.dynamics.ham.sd[0].line_func(t*dt) # print t*dt, gt.real Cw = np.zeros(len(omegas)) expi = np.exp(1j*(np.outer(omegas,times))) for t, time in enumerate(times): weight = dt - 0.5*dt*(t==0 or t==len(times)-1) gt = self.dynamics.ham.sd[0].line_func(t*dt) # print 't=',t,'\ngt=',gt Ct = np.exp(-1j*omega_eg*t*dt-gt) if is_damped and t > t_damp: Ct *= switch_to_zero(time,t_damp,t_final) Cw += weight*(expi[:,t]*Ct).real return energies, (mu[1,0]**2)*Cw # if self.dynamics.ham.nsite == 3: # nbath = self.dynamics.ham.nbath # nsite = self.dynamics.ham.nsite # omega_diff = self.dynamics.ham.omega_diff # sys_eig = self.dynamics.ham.site2eig(self.dynamics.ham.sys) # times = np.zeros(int(t_final/dt)) # sysbath_eig = [] # for n in range(nbath): # sysbath_eig.append(self.dynamics.ham.site2eig(self.dynamics.ham.sysbath[n])) # mu_eig = self.dynamics.ham.site2eig(mu) # # for n in range(len(times)): # times[n] = n*dt # # for t, time in enumerate(times): # # gt = self.dynamics.ham.sd[0].line_func(t*dt) # # print t*dt, gt.real # Cw = np.zeros(len(omegas)) # expi = np.exp(1j*(np.outer(omegas,times))) # print omega_diff # for t, time in enumerate(times): # weight = dt - 0.5*dt*(t==0 or t==len(times)-1) # gt = self.dynamics.ham.sd[0].line_func(t*dt) # pops1 = self.dynamics.ham.sd[0].sec_poprate(0.*omega_diff[0,2],t*dt) # pops2 = self.dynamics.ham.sd[0].sec_poprate(0.*omega_diff[2,0],t*dt) # Ct = np.exp(-1j*omega_diff[1,2]*t*dt-(sys_eig[2,2]**2)*gt-(sys_eig[0,2]**2)*pops1) + np.exp(-1j*omega_diff[0,1]*t*dt-(sys_eig[0,0]**2)*gt-50.*(sys_eig[2,0]**2)*pops2) # # if is_damped and t > t_damp: # Ct *= switch_to_zero(time,t_damp,t_final) # Cw += weight*(expi[:,t]*Ct).real # return energies, (mu[1,0]**2)*Cw else: omega_diff = self.dynamics.ham.omega_diff nbath = self.dynamics.ham.nbath nsite = self.dynamics.ham.nsite sys_eig = self.dynamics.ham.site2eig(self.dynamics.ham.sys) sysbath_eig = [] for n in range(nbath): sysbath_eig.append(self.dynamics.ham.site2eig(self.dynamics.ham.sysbath[n])) mu_eig = self.dynamics.ham.site2eig(mu) gs_index = np.where(np.diag(sys_eig) == 0.)[0][0] markov_rate = [] for l in range(nbath): markovrate_l = np.zeros((nsite,nsite)) for m in range(nsite): for n in range(nsite): markovrate_l[m,n] = self.dynamics.ham.sd[l].markov_poprate(omega_diff[n,m]) markovrate_l[n,n] = 0.0 markov_rate.append(markovrate_l) times = np.zeros(int(t_final/dt)) for n in range(len(times)): times[n] = n*dt # for t, time in enumerate(times): # gt = self.dynamics.ham.sd[0].sec_poprate(-1.,t*dt) # print t*dt, gt.real # print sys_eig # print omega_diff full_rate = np.zeros((nsite,nsite)) for n in range(nbath): full_rate += (sysbath_eig[n]**2)*markov_rate[n] # print full_rate full_rate_sum = np.zeros(nsite) for n in range(nsite): full_rate_sum[n] = (np.sum(full_rate[n,:])) # full_rate_sum = np.array([0.007806,0.,0.05768]) # # Coefficient for pure dephasing lineshape function on each site gammas = np.zeros((nsite)) # print sysbath_eig # print mu_eig # print sys_eig # print np.diag(sys_eig) # print np.diag(sys_eig)[1] for m in range(nbath): for n in range(nsite): gammas[n] += sysbath_eig[m][n,n]**2 t_damp = 0. times = np.zeros(int(t_final/dt)) for n in range(len(times)): times[n] = n*dt expi = np.exp(1j*(np.outer(omegas,times))) absw = np.zeros(len(omegas)) # Currently assumes all sites have identical J(w); not sure about individual J(w) after site to eig conversion for n in range(nsite): Cw = np.zeros(len(omegas)) for t, time in enumerate(times): weight = dt - 0.5*dt*(t==0 or t==len(times)-1) gt = self.dynamics.ham.sd[0].line_func(t*dt) gt0 = self.dynamics.ham.sd[0].line_func(0.) Ct = np.exp(-1j*omega_diff[n,gs_index]*t*dt-gammas[n]*(gt-gt0) - 0.5*full_rate_sum[n]) if is_damped and t > t_damp: Ct *= switch_to_zero(time,t_damp,t_final) Cw += weight*(expi[:,t]*Ct).real absw += (mu_eig[n,gs_index]**2)*Cw return energies, absw # for l in range(nbath-1): # for m in range(nsite-1): # for n in range(nsite-1): # self.dynamics.ham.sysbath_eig[0][2,1]**2)*self.dynamics.ham.sd[0].pop_rate(omega_diff[1,2]) + (self.dynamics.ham.sysbath_eig[1][2,1]**2)*self.dynamics.ham.sd[1].pop_rate(omega_diff[1,2]) # print self.dynamics.ham.sd[0].pop_rates(self.dynamics.ham.omega_diff) # print "Analytical lineshape function is only implemented for the monomer case." # expi = np.exp(1j*(np.outer(omegas,times))) # weight = dt - 0.5*dt*(t==0 or t==len(times)-1) # Ct = np.exp(-1j*omega_eg*t-self.dynamics.ham.sd[0].line_func(t*dt)) # Cw += weight*(expi[:,t]*Ct).real else: nbath = self.dynamics.ham.nbath nsite = self.dynamics.ham.nsite sysbath_eig = [] for n in range(nbath): sysbath_eig.append(self.dynamics.ham.site2eig(self.dynamics.ham.sysbath[n])) mu_rho_0 = np.dot(mu, rho_0) times, mu_rho = self.dynamics.propagate(mu_rho_0, 0.0, t_final, dt) Cw = np.zeros(len(omegas)) fdipole = open(dipole_file,'w') t_damp = 0. expi = np.exp(1j*np.outer(omegas,times)) for t, time in enumerate(times): weight = dt - 0.5*dt*(t==0 or t==len(times)-1) Ct = np.trace(np.dot(mu,mu_rho[t])) if is_damped and t > t_damp: Ct *= switch_to_zero(time,t_damp,t_final) fdipole.write('%0.6f %0.6f %0.6f\n'%( time, Ct.real, Ct.imag)) Cw += weight*(expi[:,t]*Ct).real fdipole.close() return energies, Cw
def __init__(self, hamiltonian, nmode=300, ntraj=100, dynamics=None, omega_split=None, use_PD=True): """Initialize the FrozenModes class. Parameters ---------- hamiltonian : Hamiltonian An instance of the pyrho Hamiltonian class dynamics : An instance of any pyrho dynamics class (e.g. Redfield) nmode : int The number of explicit classical modes to sample ntraj : int The number of trajectories over which to average """ utils.print_banner("PERFORMING FROZEN MODES DYNAMICS") # .copy() is important to have an instance that is not updated by FM sampling # FrozenModes.ham.sys must always be the original, dynamics.ham.sys will be # updated in each realization self.ham = hamiltonian.copy() self.nmode = nmode self.ntraj = ntraj if dynamics is None: # Pure frozen modes with unitary dynamics self.dynamics = unitary.Unitary(hamiltonian) else: # "Hybrid" frozen modes with dissipative dynamics self.dynamics = dynamics if omega_split is None: # Determine splitting frequency omega_split = list() if self.ham.nsite == 2: omega_R = 2 * np.sqrt((ham[0, 0] - ham[1, 1])**2 / 4.0 + ham[0, 1]**2) / const.hbar else: print "Automated splitting frequency for Nsys > 2 not implemented!" raise SystemExit for n in range(self.ham.nbath): omega_split.append(omega_R / 4.) else: assert (len(omega_split) == self.ham.nbath) for n in range(self.ham.nbath): print "\n--- Splitting energy for bath %d = %0.2lf" % ( n, const.hbar * omega_split[n]) for n in range(self.ham.nbath): Jslow, Jfast = partition_specdens(self.ham.sd[n].J, omega_split[n], use_PD) self.ham.sd[n].J, self.dynamics.ham.sd[n].J = Jslow, Jfast