def rcsolve(Hsys, psi0, tlist, e_ops, Q, wc, alpha, N, w_th, sparse=False, options=None): """ Function to solve for an open quantum system using the reaction coordinate (RC) model. Parameters ---------- Hsys: Qobj The system hamiltonian. psi0: Qobj Initial state of the system. tlist: List. Time over which system evolves. e_ops: list of :class:`qutip.Qobj` / callback function single Single operator or list of operators for which to evaluate expectation values. Q: Qobj The coupling between system and bath. wc: Float Cutoff frequency. alpha: Float Coupling strength. N: Integer Number of cavity fock states. w_th: Float Temperature. sparse: Boolean Optional argument to call the sparse eigenstates solver if needed. options : :class:`qutip.Options` With options for the solver. Returns ------- output: Result System evolution. """ if options is None: options = Options() dot_energy, dot_state = Hsys.eigenstates(sparse=sparse) deltaE = dot_energy[1] - dot_energy[0] if (w_th < deltaE/2): warnings.warn("Given w_th might not provide accurate results") gamma = deltaE / (2 * np.pi * wc) wa = 2 * np.pi * gamma * wc # reaction coordinate frequency g = np.sqrt(np.pi * wa * alpha / 2.0) # reaction coordinate coupling nb = (1 / (np.exp(wa/w_th) - 1)) # Reaction coordinate hamiltonian/operators dimensions = dims(Q) a = tensor(destroy(N), qeye(dimensions[1])) unit = tensor(qeye(N), qeye(dimensions[1])) Nmax = N * dimensions[1][0] Q_exp = tensor(qeye(N), Q) Hsys_exp = tensor(qeye(N), Hsys) e_ops_exp = [tensor(qeye(N), kk) for kk in e_ops] na = a.dag() * a xa = a.dag() + a # decoupled Hamiltonian H0 = wa * a.dag() * a + Hsys_exp # interaction H1 = (g * (a.dag() + a) * Q_exp) H = H0 + H1 L = 0 PsipreEta = 0 PsipreX = 0 all_energy, all_state = H.eigenstates(sparse=sparse) Apre = spre((a + a.dag())) Apost = spost(a + a.dag()) for j in range(Nmax): for k in range(Nmax): A = xa.matrix_element(all_state[j].dag(), all_state[k]) delE = (all_energy[j] - all_energy[k]) if abs(A) > 0.0: if abs(delE) > 0.0: X = (0.5 * np.pi * gamma*(all_energy[j] - all_energy[k]) * (np.cosh((all_energy[j] - all_energy[k]) / (2 * w_th)) / (np.sinh((all_energy[j] - all_energy[k]) / (2 * w_th)))) * A) eta = (0.5 * np.pi * gamma * (all_energy[j] - all_energy[k]) * A) PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() PsipreEta = PsipreEta + (eta * all_state[j] * all_state[k].dag()) else: X = 0.5 * np.pi * gamma * A * 2 * w_th PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() A = a + a.dag() L = ((-spre(A * PsipreX)) + (sprepost(A, PsipreX)) + (sprepost(PsipreX, A)) + (-spost(PsipreX * A)) + (spre(A * PsipreEta)) + (sprepost(A, PsipreEta)) + (-sprepost(PsipreEta, A)) + (-spost(PsipreEta * A))) # Setup the operators and the Hamiltonian and the master equation # and solve for time steps in tlist rho0 = (tensor(thermal_dm(N, nb), psi0)) output = mesolve(H, rho0, tlist, [L], e_ops_exp, options=options) return output
def rcsolve(Hsys, psi0, tlist, e_ops, Q, wc, alpha, N, w_th, sparse=False, options=None): """ Function to solve for an open quantum system using the reaction coordinate (RC) model. Parameters ---------- Hsys: Qobj The system hamiltonian. psi0: Qobj Initial state of the system. tlist: List. Time over which system evolves. e_ops: list of :class:`qutip.Qobj` / callback function single Single operator or list of operators for which to evaluate expectation values. Q: Qobj The coupling between system and bath. wc: Float Cutoff frequency. alpha: Float Coupling strength. N: Integer Number of cavity fock states. w_th: Float Temperature. sparse: Boolean Optional argument to call the sparse eigenstates solver if needed. options : :class:`qutip.Options` With options for the solver. Returns ------- output: Result System evolution. """ if options is None: options = Options() dot_energy, dot_state = Hsys.eigenstates(sparse=sparse) deltaE = dot_energy[1] - dot_energy[0] if (w_th < deltaE / 2): warnings.warn("Given w_th might not provide accurate results") gamma = deltaE / (2 * np.pi * wc) wa = 2 * np.pi * gamma * wc # reaction coordinate frequency g = np.sqrt(np.pi * wa * alpha / 2.0) # reaction coordinate coupling nb = (1 / (np.exp(wa / w_th) - 1)) # Reaction coordinate hamiltonian/operators dimensions = dims(Q) a = tensor(destroy(N), qeye(dimensions[1])) unit = tensor(qeye(N), qeye(dimensions[1])) Nmax = N * dimensions[1][0] Q_exp = tensor(qeye(N), Q) Hsys_exp = tensor(qeye(N), Hsys) e_ops_exp = [tensor(qeye(N), kk) for kk in e_ops] na = a.dag() * a xa = a.dag() + a # decoupled Hamiltonian H0 = wa * a.dag() * a + Hsys_exp # interaction H1 = (g * (a.dag() + a) * Q_exp) H = H0 + H1 L = 0 PsipreEta = 0 PsipreX = 0 all_energy, all_state = H.eigenstates(sparse=sparse) Apre = spre((a + a.dag())) Apost = spost(a + a.dag()) for j in range(Nmax): for k in range(Nmax): A = xa.matrix_element(all_state[j].dag(), all_state[k]) delE = (all_energy[j] - all_energy[k]) if abs(A) > 0.0: if abs(delE) > 0.0: X = (0.5 * np.pi * gamma * (all_energy[j] - all_energy[k]) * (np.cosh( (all_energy[j] - all_energy[k]) / (2 * w_th)) / (np.sinh( (all_energy[j] - all_energy[k]) / (2 * w_th)))) * A) eta = (0.5 * np.pi * gamma * (all_energy[j] - all_energy[k]) * A) PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() PsipreEta = PsipreEta + (eta * all_state[j] * all_state[k].dag()) else: X = 0.5 * np.pi * gamma * A * 2 * w_th PsipreX = PsipreX + X * all_state[j] * all_state[k].dag() A = a + a.dag() L = ((-spre(A * PsipreX)) + (sprepost(A, PsipreX)) + (sprepost(PsipreX, A)) + (-spost(PsipreX * A)) + (spre(A * PsipreEta)) + (sprepost(A, PsipreEta)) + (-sprepost(PsipreEta, A)) + (-spost(PsipreEta * A))) # Setup the operators and the Hamiltonian and the master equation # and solve for time steps in tlist rho0 = (tensor(thermal_dm(N, nb), psi0)) output = mesolve(H, rho0, tlist, [L], e_ops_exp, options=options) return output
def hsolve(H, psi0, tlist, Q, gam, lam0, Nc, N, w_th, options=None): """ Function to solve for an open quantum system using the hierarchy model. Parameters ---------- H: Qobj The system hamiltonian. psi0: Qobj Initial state of the system. tlist: List. Time over which system evolves. Q: Qobj The coupling between system and bath. gam: Float Bath cutoff frequency. lam0: Float Coupling strength. Nc: Integer Cutoff parameter. N: Integer Number of matsubara terms. w_th: Float Temperature. options : :class:`qutip.Options` With options for the solver. Returns ------- output: Result System evolution. """ if options is None: options = Options() # Set up terms of the matsubara and tanimura boundaries # Parameters and hamiltonian hbar = 1. kb = 1. # Set by system dimensions = dims(H) Nsup = dimensions[0][0] * dimensions[0][0] unit = qeye(dimensions[0]) # Ntot is the total number of ancillary elements in the hierarchy Ntot = int(round(factorial(Nc+N) / (factorial(Nc) * factorial(N)))) c0 = (lam0 * gam * (_cot(gam * hbar / (2. * kb * w_th)) - (1j))) / hbar LD1 = (-2. * spre(Q) * spost(Q.dag()) + spre(Q.dag()*Q) + spost(Q.dag()*Q)) pref = ((2. * lam0 * kb * w_th / (gam * hbar)) - 1j * lam0) / hbar gj = 2 * np.pi * kb * w_th / hbar L12 = -pref * LD1 + (c0 / gam) * LD1 for i1 in range(1, N): num = (4 * lam0 * gam * kb * w_th * i1 * gj/((i1 * gj)**2 - gam**2)) ci = num / (hbar**2) L12 = L12 + (ci / gj) * LD1 # Setup liouvillian L = liouvillian(H, [L12]) Ltot = L.data unit = sp.eye(Ntot,format='csr') Lbig = sp.kron(unit, Ltot) rho0big1 = np.zeros((Nsup * Ntot), dtype=complex) # Prepare initial state: rhotemp = mat2vec(np.array(psi0.full(), dtype=complex)) for idx, element in enumerate(rhotemp): rho0big1[idx] = element[0] nstates, state2idx, idx2state = enr_state_dictionaries([Nc+1]*(N), Nc) for nlabelt in state_number_enumerate([Nc+1]*(N), Nc): nlabel = list(nlabelt) ntotalcheck = 0 for ncheck in range(N): ntotalcheck = ntotalcheck + nlabel[ncheck] current_pos = int(round(state2idx[tuple(nlabel)])) Ltemp = sp.lil_matrix((Ntot, Ntot)) Ltemp[current_pos, current_pos] = 1 Ltemp.tocsr() Lbig = Lbig + sp.kron(Ltemp, (-nlabel[0] * gam * spre(unit).data)) for kcount in range(1, N): counts = -nlabel[kcount] * kcount * gj * spre(unit).data Lbig = Lbig + sp.kron(Ltemp, counts) for kcount in range(N): if nlabel[kcount] >= 1: # find the position of the neighbour nlabeltemp = copy(nlabel) nlabel[kcount] = nlabel[kcount] - 1 current_pos2 = int(round(state2idx[tuple(nlabel)])) Ltemp = sp.lil_matrix((Ntot, Ntot)) Ltemp[current_pos, current_pos2] = 1 Ltemp.tocsr() # renormalized version: ci = (4 * lam0 * gam * kb * w_th * kcount * gj/((kcount * gj)**2 - gam**2)) / (hbar**2) if kcount == 0: Lbig = Lbig + sp.kron(Ltemp, (-1j * (np.sqrt(nlabeltemp[kcount] / abs(c0))) * ((c0) * spre(Q).data - (np.conj(c0)) * spost(Q).data))) if kcount > 0: ci = (4 * lam0 * gam * kb * w_th * kcount * gj/((kcount * gj)**2 - gam**2)) / (hbar**2) Lbig = Lbig + sp.kron(Ltemp, (-1j * (np.sqrt(nlabeltemp[kcount] / abs(ci))) * ((ci) * spre(Q).data - (np.conj(ci)) * spost(Q).data))) nlabel = copy(nlabeltemp) for kcount in range(N): if ntotalcheck <= (Nc-1): nlabeltemp = copy(nlabel) nlabel[kcount] = nlabel[kcount] + 1 current_pos3 = int(round(state2idx[tuple(nlabel)])) if current_pos3 <= (Ntot): Ltemp = sp.lil_matrix((Ntot, Ntot)) Ltemp[current_pos, current_pos3] = 1 Ltemp.tocsr() # renormalized if kcount == 0: Lbig = Lbig + sp.kron(Ltemp, -1j * (np.sqrt((nlabeltemp[kcount]+1) * abs(c0))) * (spre(Q) - spost(Q)).data) if kcount > 0: ci = (4 * lam0 * gam * kb * w_th * kcount * gj/((kcount * gj)**2 - gam**2)) / (hbar**2) Lbig = Lbig + sp.kron(Ltemp, -1j * (np.sqrt((nlabeltemp[kcount]+1) * abs(ci))) * (spre(Q) - spost(Q)).data) nlabel = copy(nlabeltemp) output = [] for element in rhotemp: output.append([]) r = scipy.integrate.ode(cy_ode_rhs) Lbig2 = Lbig.tocsr() r.set_f_params(Lbig2.data, Lbig2.indices, Lbig2.indptr) r.set_integrator('zvode', method=options.method, order=options.order, atol=options.atol, rtol=options.rtol, nsteps=options.nsteps, first_step=options.first_step, min_step=options.min_step, max_step=options.max_step) r.set_initial_value(rho0big1, tlist[0]) dt = tlist[1] - tlist[0] for t_idx, t in enumerate(tlist): r.integrate(r.t + dt) for idx, element in enumerate(rhotemp): output[idx].append(r.y[idx]) return output