def wfnPropagation(iMPS, HMPO, nsteps, dt, ephtable, thresh=0, \ cleanexciton=None, prop_method="C_RK4", compress_method="svd", QNargs=None): ''' simple wavefunction propagation through Runge-Kutta methods ''' tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) ketMPS = mpslib.add(iMPS, None, QNargs=QNargs) Hset = [] # energy Vset = [] # overlap for isteps in xrange(nsteps): if isteps != 0: ketMPS = tMPS(ketMPS, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, \ QNargs=QNargs) Hset.append(mpslib.dot(mpslib.conj(ketMPS,QNargs=QNargs), \ mpslib.mapply(HMPO, ketMPS, QNargs=QNargs), QNargs=QNargs)) Vset.append(mpslib.dot(mpslib.conj(ketMPS,QNargs=QNargs), \ ketMPS, QNargs=QNargs)) return Hset, Vset
def ApproxPropagatorMPO(HMPO, dt, ephtable, propagation_c, thresh=0, \ compress_method="svd", QNargs=None): ''' e^-iHdt : approximate propagator MPO from Runge-Kutta methods ''' # Identity operator if QNargs is not None: nmpo = len(HMPO[0]) else: nmpo = len(HMPO) MPOdim = [1] * (nmpo + 1) MPOQN = [[0]] * (nmpo + 1) MPOQNidx = nmpo - 1 MPOQNtot = 0 IMPO = [] for impo in xrange(nmpo): if QNargs is not None: mpo = np.ones([1, HMPO[0][impo].shape[1], 1], dtype=np.complex128) else: mpo = np.ones([1, HMPO[impo].shape[1], 1], dtype=np.complex128) IMPO.append(mpo) IMPO = hilbert_to_liouville(IMPO) QNargslocal = copy.deepcopy(QNargs) if QNargs is not None: IMPO = [IMPO, MPOQN, MPOQNidx, MPOQNtot] # a real MPO compression QNargslocal[1] = True approxMPO = tMPS(IMPO, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ compress_method=compress_method, QNargs=QNargslocal) print "approx propagator thresh:", thresh if QNargs is not None: print "approx propagator dim:", [mpo.shape[0] for mpo in approxMPO[0]] else: print "approx propagator dim:", [mpo.shape[0] for mpo in approxMPO] chkIden = mpslib.mapply(mpslib.conj(approxMPO, QNargs=QNargs), approxMPO, QNargs=QNargs) print "approx propagator Identity error", np.sqrt(mpslib.distance(chkIden, IMPO, QNargs=QNargs) /\ mpslib.dot(IMPO, IMPO, QNargs=QNargs)) return approxMPO
def FiniteT_emi(mol, pbond, iMPO, HMPO, dipoleMPO, nsteps, dt, \ ephtable, insteps, thresh=0, temperature=298, prop_method="C_RK4", compress_method="svd", QNargs=None): ''' Finite temperature emission, already included in FiniteT_spectra ''' tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) beta = constant.T2beta(temperature) ketMPO = thermal_prop(iMPO, HMPO, insteps, ephtable, prop_method=prop_method, thresh=thresh, temperature=temperature, compress_method=compress_method, QNargs=QNargs) braMPO = mpslib.add(ketMPO, None, QNargs=QNargs) #\Psi e^{\-beta H} \Psi Z = mpslib.dot(mpslib.conj(braMPO, QNargs=QNargs), ketMPO, QNargs=QNargs) print "partition function Z(beta)/Z(0)", Z AketMPO = mpslib.mapply(dipoleMPO, ketMPO, QNargs=QNargs) autocorr = [] t = 0.0 ketpropMPO, ketpropMPOdim = ExactPropagatorMPO(mol, pbond, -1.0j * dt, QNargs=QNargs) dipoleMPOdagger = mpslib.conjtrans(dipoleMPO, QNargs=QNargs) if compress_method == "variational": braMPO = mpslib.canonicalise(braMPO, 'l', QNargs=QNargs) for istep in xrange(nsteps): if istep != 0: t += dt AketMPO = mpslib.mapply(ketpropMPO, AketMPO, QNargs=QNargs) braMPO = tMPS(braMPO, HMPO, dt, ephtable, propagation_c, thresh=thresh, cleanexciton=1, compress_method=compress_method, QNargs=QNargs) AAketMPO = mpslib.mapply(dipoleMPOdagger, AketMPO, QNargs=QNargs) ft = mpslib.dot(mpslib.conj(braMPO, QNargs=QNargs), AAketMPO, QNargs=QNargs) autocorr.append(ft / Z) autocorr_store(autocorr, istep) return autocorr
def FiniteT_spectra(spectratype, mol, pbond, iMPO, HMPO, dipoleMPO, nsteps, dt,\ ephtable, insteps=0, thresh=0, temperature=298,\ algorithm=2, prop_method="C_RK4", compress_method="svd", QNargs=None, \ approxeiHt=None, GSshift=0.0, cleanexciton=None, scheme="P&C"): ''' finite temperature propagation only has algorithm 2, two way propagator ''' assert algorithm == 2 assert spectratype in ["abs", "emi"] tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) beta = constant.T2beta(temperature) print "beta=", beta # e^{\-beta H/2} \Psi if spectratype == "emi": ketMPO = thermal_prop(iMPO, HMPO, insteps, ephtable,\ prop_method=prop_method, thresh=thresh,\ temperature=temperature, compress_method=compress_method,\ QNargs=QNargs, approxeiHt=approxeiHt) elif spectratype == "abs": thermalMPO, thermalMPOdim = ExactPropagatorMPO(mol, pbond, -beta/2.0,\ QNargs=QNargs, shift=GSshift) ketMPO = mpslib.mapply(thermalMPO, iMPO, QNargs=QNargs) #\Psi e^{\-beta H} \Psi Z = mpslib.dot(mpslib.conj(ketMPO, QNargs=QNargs), ketMPO, QNargs=QNargs) print "partition function Z(beta)/Z(0)", Z autocorr = [] t = 0.0 exacteiHpt, exacteiHptdim = ExactPropagatorMPO(mol, pbond, -1.0j*dt,\ QNargs=QNargs, shift=GSshift) exacteiHmt, exacteiHmtdim = ExactPropagatorMPO(mol, pbond, 1.0j*dt,\ QNargs=QNargs, shift=GSshift) if spectratype == "abs": ketMPO = mpslib.mapply(dipoleMPO, ketMPO, QNargs=QNargs) else: dipoleMPOdagger = mpslib.conjtrans(dipoleMPO, QNargs=QNargs) if QNargs is not None: dipoleMPOdagger[1] = [[0] * len(impsdim) for impsdim in dipoleMPO[1]] dipoleMPOdagger[3] = 0 ketMPO = mpslib.mapply(ketMPO, dipoleMPOdagger, QNargs=QNargs) braMPO = mpslib.add(ketMPO, None, QNargs=QNargs) if compress_method == "variational": ketMPO = mpslib.canonicalise(ketMPO, 'l', QNargs=QNargs) braMPO = mpslib.canonicalise(braMPO, 'l', QNargs=QNargs) if approxeiHt is not None: approxeiHpt = ApproxPropagatorMPO(HMPO, dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) approxeiHmt = ApproxPropagatorMPO(HMPO, -dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) else: approxeiHpt = None approxeiHmt = None for istep in xrange(nsteps): if istep != 0: t += dt # for emi bra and ket is conjugated if istep % 2 == 0: braMPO = mpslib.mapply(braMPO, exacteiHpt, QNargs=QNargs) braMPO = tMPS(braMPO, HMPO, -dt, ephtable, propagation_c,\ thresh=thresh, cleanexciton=1, compress_method=compress_method, \ QNargs=QNargs, approxeiHt=approxeiHmt, scheme=scheme,\ prefix=scheme+"2") else: ketMPO = mpslib.mapply(ketMPO, exacteiHmt, QNargs=QNargs) ketMPO = tMPS(ketMPO, HMPO, dt, ephtable, propagation_c, \ thresh=thresh, cleanexciton=1, compress_method=compress_method, \ QNargs=QNargs, approxeiHt=approxeiHpt, scheme=scheme,\ prefix=scheme+"1") ft = mpslib.dot(mpslib.conj(braMPO, QNargs=QNargs), ketMPO, QNargs=QNargs) if spectratype == "emi": ft = np.conj(ft) wfn_store(braMPO, istep, "braMPO.pkl") wfn_store(ketMPO, istep, "ketMPO.pkl") autocorr.append(ft / Z) autocorr_store(autocorr, istep) return autocorr
def ZeroTCorr(iMPS, HMPO, dipoleMPO, nsteps, dt, ephtable, thresh=0, \ cleanexciton=None, algorithm=1, prop_method="C_RK4",\ compress_method="svd", QNargs=None, approxeiHt=None, scheme="P&C"): ''' the bra part e^iEt is negected to reduce the oscillation algorithm: algorithm 1 is the only propagte ket in 0, dt, 2dt algorithm 2 is propagte bra and ket in 0, dt, 2dt (in principle, with same calculation cost, more accurate, because the bra is also entangled, the entanglement is not only in ket) compress_method: svd or variational cleanexciton: every time step propagation clean the good quantum number to discard the numerical error thresh: the svd threshold in svd or variational compress ''' AketMPS = mpslib.mapply(dipoleMPO, iMPS, QNargs=QNargs) # store the factor and normalize the AketMPS, factor is the length of AketMPS factor = mpslib.dot(mpslib.conj(AketMPS, QNargs=QNargs), AketMPS, QNargs=QNargs) factor = np.sqrt(np.absolute(factor)) print "factor", factor AketMPS = mpslib.scale(AketMPS, 1. / factor, QNargs=QNargs) if compress_method == "variational": AketMPS = mpslib.canonicalise(AketMPS, 'l', QNargs=QNargs) AbraMPS = mpslib.add(AketMPS, None, QNargs=QNargs) autocorr = [] t = 0.0 tableau = RK.runge_kutta_explicit_tableau(prop_method) propagation_c = RK.runge_kutta_explicit_coefficient(tableau) if approxeiHt is not None: approxeiHpt = ApproxPropagatorMPO(HMPO, dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) approxeiHmt = ApproxPropagatorMPO(HMPO, -dt, ephtable, propagation_c,\ thresh=approxeiHt, compress_method=compress_method, QNargs=QNargs) else: approxeiHpt = None approxeiHmt = None for istep in xrange(nsteps): if istep != 0: t += dt if algorithm == 1: AketMPS = tMPS(AketMPS, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, \ QNargs=QNargs, approxeiHt=approxeiHpt, normalize=1., \ scheme=scheme, prefix=scheme) if algorithm == 2: if istep % 2 == 1: AketMPS = tMPS(AketMPS, HMPO, dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, QNargs=QNargs,\ approxeiHt=approxeiHpt, normalize=1., scheme=scheme, \ prefix=scheme+"1") else: AbraMPS = tMPS(AbraMPS, HMPO, -dt, ephtable, propagation_c, thresh=thresh, \ cleanexciton=cleanexciton, compress_method=compress_method, QNargs=QNargs,\ approxeiHt=approxeiHmt, normalize=1., scheme=scheme,\ prefix=scheme+"2") ft = mpslib.dot(mpslib.conj(AbraMPS, QNargs=QNargs), AketMPS, QNargs=QNargs) * factor**2 wfn_store(AbraMPS, istep, str(dt) + str(thresh) + "AbraMPS.pkl") wfn_store(AketMPS, istep, str(dt) + str(thresh) + "AketMPS.pkl") autocorr.append(ft) autocorr_store(autocorr, istep) return autocorr
def Exact_Spectra(spectratype, mol, pbond, iMPS, dipoleMPO, nsteps, dt,\ temperature, GSshift=0.0, EXshift=0.0): ''' 0T emission spectra exact propagator the bra part e^iEt is negected to reduce the osillation and for single molecule, the EX space propagator e^iHt is local, and so exact GS/EXshift is the ground/excited state space energy shift the aim is to reduce the oscillation of the correlation fucntion support: all cases: 0Temi 1mol case: 0Temi, TTemi, 0Tabs, TTabs ''' assert spectratype in ["emi", "abs"] if spectratype == "emi": space1 = "EX" space2 = "GS" shift1 = EXshift shift2 = GSshift if temperature != 0: assert len(mol) == 1 else: assert len(mol) == 1 space1 = "GS" space2 = "EX" shift1 = GSshift shift2 = EXshift if temperature != 0: beta = constant.T2beta(temperature) print "beta=", beta thermalMPO, thermalMPOdim = ExactPropagatorMPO(mol, pbond, -beta / 2.0, space=space1, shift=shift1) ketMPS = mpslib.mapply(thermalMPO, iMPS) Z = mpslib.dot(mpslib.conj(ketMPS), ketMPS) print "partition function Z(beta)/Z(0)", Z else: ketMPS = iMPS Z = 1.0 AketMPS = mpslib.mapply(dipoleMPO, ketMPS) if temperature != 0: braMPS = mpslib.add(ketMPS, None) else: AbraMPS = mpslib.add(AketMPS, None) t = 0.0 autocorr = [] propMPO1, propMPOdim1 = ExactPropagatorMPO(mol, pbond, -1.0j * dt, space=space1, shift=shift1) propMPO2, propMPOdim2 = ExactPropagatorMPO(mol, pbond, -1.0j * dt, space=space2, shift=shift2) # we can reconstruct the propagator each time if there is accumulated error for istep in xrange(nsteps): if istep != 0: AketMPS = mpslib.mapply(propMPO2, AketMPS) if temperature != 0: braMPS = mpslib.mapply(propMPO1, braMPS) if temperature != 0: AbraMPS = mpslib.mapply(dipoleMPO, braMPS) ft = mpslib.dot(mpslib.conj(AbraMPS), AketMPS) autocorr.append(ft / Z) autocorr_store(autocorr, istep) return autocorr
def Quasi_Boson_MPO(opera, nqb, trunc, base=2, C1=1.0, C2=1.0): ''' nqb : # of quasi boson sites opera : operator to be decomposed "b + b^\dagger" ''' assert opera in ["b + b^\dagger","b^\dagger b", "b", "b^\dagger", \ "C1(b + b^\dagger) + C2(b + b^\dagger)^2"] # the structure is [bra_highest_bit, ket_highest_bit,..., bra_lowest_bit, # ket_lowest_bit] mat = np.zeros([ base, ] * nqb * 2) if opera == "b + b^\dagger" or opera == "b^\dagger" or opera == "b": if opera == "b + b^\dagger" or opera == "b^\dagger": for i in xrange(1, base**nqb): # b^+ lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array( map(int, baseConvert(i - 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = np.sqrt(i) if opera == "b + b^\dagger" or opera == "b": for i in xrange(0, base**nqb - 1): # b lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array( map(int, baseConvert(i + 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = np.sqrt(i + 1) elif opera == "C1(b + b^\dagger) + C2(b + b^\dagger)^2": # b^+ for i in xrange(1, base**nqb): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i - 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C1 * np.sqrt(i) # b for i in xrange(0, base**nqb - 1): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i + 1, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C1 * np.sqrt(i + 1) # bb for i in xrange(0, base**nqb - 2): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i + 2, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C2 * np.sqrt(i + 2) * np.sqrt(i + 1) # b^\dagger b^\dagger for i in xrange(2, base**nqb): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i - 2, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C2 * np.sqrt(i) * np.sqrt(i - 1) # b^\dagger b + b b^\dagger for i in xrange(0, base**nqb): lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = C2 * float(i * 2 + 1) elif opera == "b^\dagger b": # actually Identity operator can be constructed directly for i in xrange(0, base**nqb): # I lstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) rstring = np.array(map(int, baseConvert(i, base).zfill(nqb))) pos = tuple(roundrobin(lstring, rstring)) mat[pos] = float(i) # check the original mat # mat = np.moveaxis(mat,range(1,nqb*2,2),range(nqb,nqb*2)) # print mat.reshape(base**nqb,base**nqb) # decompose canonicalise MPO = [] mat = mat.reshape(1, -1) for idx in xrange(nqb - 1): U, S, Vt = scipy.linalg.svd(mat.reshape(mat.shape[0]*base**2,-1), \ full_matrices=False) U = U.reshape(mat.shape[0], base, base, -1) MPO.append(U) mat = np.einsum("i, ij -> ij", S, Vt) MPO.append(mat.reshape(-1, base, base, 1)) print "original MPO shape:", [i.shape[0] for i in MPO] + [1] # compress MPOnew = mpslib.compress(MPO, 'l', trunc=trunc) print "trunc", trunc, "distance", mpslib.distance(MPO, MPOnew) fidelity = mpslib.dot(mpslib.conj(MPOnew), MPO) / mpslib.dot( mpslib.conj(MPO), MPO) print "compression fidelity:: ", fidelity print "compressed MPO shape", [i.shape[0] for i in MPOnew] + [1] return MPOnew