Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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()
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    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()
Exemplo n.º 6
0
    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
Exemplo n.º 7
0
    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()
Exemplo n.º 8
0
    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()
Exemplo n.º 9
0
    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
Exemplo n.º 10
0
    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
Exemplo n.º 11
0
    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()
Exemplo n.º 12
0
    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
Exemplo n.º 13
0
    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()
Exemplo n.º 14
0
    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()
Exemplo n.º 15
0
    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
Exemplo n.º 16
0
    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
Exemplo n.º 17
0
    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
Exemplo n.º 18
0
    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
Exemplo n.º 19
0
    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