def test_pyr_4mode(multi_e, dvr): basis, ham_terms = construct_vibronic_model(multi_e, dvr) model = Model(basis, ham_terms) mpo = Mpo(model) logger.info(f"mpo_bond_dims:{mpo.bond_dims}") # same form whether multi_e is True or False init_condition = {"s2": 1} if dvr: for dof in model.v_dofs: idx = model.order[dof] init_condition[dof] = basis[idx].dvr_v[0] mps = Mps.hartree_product_state(model, condition=init_condition) compress_config = CompressConfig(CompressCriteria.fixed, max_bonddim=10) evolve_config = EvolveConfig(EvolveMethod.tdvp_ps) job = VibronicModelDynamics(model, mps0=mps, h_mpo=mpo, compress_config=compress_config, evolve_config=evolve_config, expand=True) time_step_fs = 2 job.evolve(evolve_dt=time_step_fs * fs2au, nsteps=60) from renormalizer.vibronic.tests.mctdh_data import mctdh_data assert np.allclose(mctdh_data[::round(time_step_fs / 0.5)][:61, 1:], job.e_occupations_array, atol=2e-2)
def check_reduced_density_matrix(basis): model = Model(basis, []) mps = Mps.random(model, 1, 20) rdm = mps.calc_edof_rdm().real assert np.allclose(np.diag(rdm), mps.e_occupations) # only test a sample. Should be enough. mpo = Mpo(model, Op(r"a^\dagger a", [0, 3])) assert rdm[-1][0] == pytest.approx(mps.expectation(mpo))
def __init__(self, model: Model = None, terms: Union[Op, List[Op]] = None, offset: Quantity = Quantity(0), ): """ todo: document """ super(Mpo, self).__init__() # leave the possibility to construct MPO by hand if model is None: return if not isinstance(offset, Quantity): raise ValueError(f"offset must be Quantity object. Got {offset} of {type(offset)}.") self.offset = offset.as_au() if terms is None: terms = model.ham_terms elif isinstance(terms, Op): terms = [terms] if len(terms) == 0: raise ValueError("Terms contain nothing.") terms = model.check_operator_terms(terms) if len(terms) == 0: raise ValueError("Terms all have factor 0.") table, factor = _terms_to_table(model, terms, -self.offset) self.dtype = factor.dtype mpo_symbol, mpo_qn, qntot, qnidx = symbolic_mpo(table, factor) # print(_format_symbolic_mpo(mpo_symbol)) self.model = model self.qnidx = qnidx self.qntot = qntot self.qn = mpo_qn self.to_right = False # evaluate the symbolic mpo assert model.basis is not None basis = model.basis for impo, mo in enumerate(mpo_symbol): pdim = basis[impo].nbas nrow, ncol = len(mo), len(mo[0]) mo_mat = np.zeros((nrow, pdim, pdim, ncol), dtype=self.dtype) for irow, icol in itertools.product(range(nrow), range(ncol)): for term in mo[irow][icol]: mo_mat[irow,:,:,icol] += basis[impo].op_mat(term) self.append(mo_mat)
def test_symbolic_mpo(nsites, nterms): possible_operators = ["sigma_+", "sigma_-", "sigma_z"] ham_terms = [] for i in range(nterms): op_list = [ Op(random.choice(possible_operators), j) for j in range(nsites) ] ham_terms.append(Op.product(op_list) * random.random()) basis = [BasisHalfSpin(i) for i in range(nsites)] model = Model(basis, ham_terms) mpo = Mpo(model) dense_mpo = mpo.full_operator() qutip_ham = get_spin_hamiltonian(ham_terms) assert np.allclose(dense_mpo, qutip_ham.data.todense())
def test_VibBasis(basistype): nv = 2 pdim = 6 hessian = np.array([[2, 1], [1, 3]]) e, c = scipy.linalg.eigh(hessian) ham_terms = [] basis = [] for iv in range(nv): op = Op("p^2", f"v_{iv}", factor=0.5, qn=0) ham_terms.append(op) if basistype == "SineDVR": # sqrt(<x^2>) of the highest vibrational basis x_mean = np.sqrt((pdim + 0.5) / np.sqrt(hessian[iv, iv])) bas = Ba.BasisSineDVR(f"v_{iv}", 2 * pdim, -x_mean * 1.5, x_mean * 1.5, endpoint=True) print("x_mean", x_mean, bas.dvr_x) else: if basistype == "SHO": dvr = False else: dvr = True bas = Ba.BasisSHO(f"v_{iv}", np.sqrt(hessian[iv, iv]), pdim, dvr=dvr) basis.append(bas) for iv in range(nv): for jv in range(nv): op = Op("x x", [f"v_{iv}", f"v_{jv}"], factor=0.5 * hessian[iv, jv], qn=[0, 0]) ham_terms.append(op) model = Model(basis, ham_terms) mpo = Mpo(model) mps = Mps.random(model, 0, 10) mps.optimize_config.nroots = 2 energy, mps = gs.optimize_mps(mps, mpo) w1, w2 = np.sqrt(e) std = [(w1 + w2) * 0.5, w1 * 1.5 + w2 * 0.5] print(basistype, "calc:", energy[-1], "exact:", std) assert np.allclose(energy[-1], std)
def test_H_chain_LDOS(): # local density of states of four H_Chain # Ronca,J. Chem. Theory Comput. 2017, 13, 5560-5571 # example to use Mollist2 to do CV calculation spatial_norbs = 4 spin_norbs = spatial_norbs * 2 h1e, h2e, nuc = h_qc.read_fcidump( os.path.join(cur_dir, "fcidump_lowdin_h4.txt"), spatial_norbs) basis, ham_terms = h_qc.qc_model(h1e, h2e) model = Model(basis, ham_terms) mpo = Mpo(model) nelec = spatial_norbs M = 50 procedure = [[M, 0.4], [M, 0.2]] + [ [M, 0], ] * 6 mps = Mps.random(model, nelec, M, percent=1.0) mps.optimize_config.procedure = procedure mps.optimize_config.method = "2site" energies, mps = gs.optimize_mps(mps, mpo) gs_e = min(energies) + nuc assert np.allclose(gs_e, -2.190384218792706) mps_e = mps.expectation(mpo) def photoelectron_operator(idx): # norbs is the spin orbitals # green function op_list = [Op("sigma_z", iorb, qn=0) for iorb in range(idx)] return Op.product(op_list + [Op("sigma_+", idx, qn=-1)]) dipole_model = photoelectron_operator(nelec - 1) dipole_op = Mpo(model, dipole_model) b_mps = dipole_op.apply(mps) #std #test_freq = np.linspace(0.25, 1.25, 100, endpoint=False).tolist() test_freq = np.linspace(0.25, 1.25, 20, endpoint=False).tolist() eta = 0.05 M = 10 procedure_cv = [0.4, 0.2] + [0] * 6 spectra = SpectraZtCV(model, None, M, eta, h_mpo=mpo, method="2site", procedure_cv=procedure_cv, b_mps=b_mps.scale(-eta), e0=mps_e) result = batch_run(test_freq, 1, spectra) std = np.load(os.path.join(cur_dir, "H_chain_std.npy")) #np.save("res", result) #np.save("freq", test_freq) assert np.allclose(result, std[::5])
def test_tda(): from renormalizer.tests.c2h4_para import ff, omega_std, B, zeta # See J. Chem. Phys. 153, 084118 (2020) for the details of the Hamiltonian # the order is according to the harmonic frequency from small to large. ham_terms = [] nmode = 12 omega = {} nterms = 0 # potential terms for term in ff: mode, factor = term[:-1], term[-1] # ignore the factor smaller than 1e-15 if abs(factor) < 1e-15: continue # ignore the expansion larger than 4-th order #if len(mode) > 4: # continue mode = Counter(mode) # the permutation symmetry prefactor prefactor = 1. for p in mode.values(): prefactor *= scipy.special.factorial(p, exact=True) # check harmonic term if len(mode) == 1 and list(mode.values())[0] == 2: omega[list(mode.keys())[0]] = np.sqrt(factor) dof = [f"v_{i}" for i in mode.keys()] symbol = " ".join([f"x^{i}" for i in mode.values()]) qn = [0 for i in mode.keys()] factor /= prefactor ham_terms.append(Op(symbol, dof, factor=factor, qn=qn)) nterms += 1 # Coriolis terms B = np.array(B) zeta = np.array(zeta) terms = [("x", "partialx", "x", "partialx", 1.), ("x", "partialx", "partialx", "x", -1.), ("partialx", "x", "x", "partialx", -1.), ("partialx", "x", "partialx", "x", 1.)] for j, l in itertools.product(range(nmode), repeat=2): for i, k in itertools.product(range(j), range(l)): dof = [f"v_{i}", f"v_{j}", f"v_{k}", f"v_{l}"] tmp = -np.einsum("i,i,i ->", B, zeta[:, i, j], zeta[:, k, l]) qn = [0, 0, 0, 0] if abs(tmp) < 1e-15: continue for term in terms: symbol, factor = " ".join(term[:-1]), term[-1] * tmp ham_terms.append(Op(symbol, dof, factor=factor, qn=qn)) nterms += 4 # Kinetic terms for imode in range(nmode): ham_terms.append(Op("p^2", f"v_{imode}", 0.5, 0)) nterms += 1 logger.info(f"nterms: {nterms}") logger.info( f"omega: {np.sort(np.array(list(omega.values())),axis=None)*au2cm}") logger.info(f"omega_std: {np.array(omega_std)}") basis = [] for imode in range(nmode): basis.append(ba.BasisSHO(f"v_{imode}", omega[imode], 4, dvr=False)) model = Model(basis, ham_terms) mpo = Mpo(model) logger.info(f"mpo_bond_dims:{mpo.bond_dims}") #assert mpo.is_hermitian() alias = [ "v10", "v8", "v7", "v4", "v6", "v3", "v12", "v2", "v11", "v1", "v5", "v9" ] energy_list = {} M = 10 procedure = [[M, 0.4], [M, 0.2], [M, 0.2], [M, 0.1]] + [[M, 0]] * 100 mps = Mps.random(model, 0, M, percent=1.0) mps.optimize_config.procedure = procedure mps.optimize_config.method = "2site" mps.optimize_config.e_rtol = 1e-6 mps.optimize_config.e_atol = 1e-8 mps.optimize_config.nroots = 1 energies, mps = gs.optimize_mps(mps, mpo) logger.info(f"M: {M}, energy : {np.array(energies[-1])*au2cm}") tda = TDA(model, mpo, mps, nroots=3, algo="primme") e = tda.kernel(include_psi0=False) logger.info(f"tda energy : {(e-energies[-1])*au2cm}") assert np.allclose((e - energies[-1]) * au2cm, [824.74925026, 936.42650242, 951.96826289], atol=1) config, compressed_mps = tda.analysis_dominant_config(alias=alias) # std is calculated with M=200, include_psi0=True; the initial gs is # calculated with 9 state SA-DMRG; physical_bond=6 std = np.load(os.path.join(cur_dir, "c2h4_std.npz"))["200"] assert np.allclose(energies[-1] * au2cm, std[0], atol=2) assert np.allclose(e * au2cm, std[1:4], atol=3)
def test_peierls_kubo(): # number of mol n = 4 # electronic coupling V = -Quantity(120, "meV").as_au() # intermolecular vibration freq omega = Quantity(50, "cm-1").as_au() # intermolecular coupling constant g = 4 # number of quanta nlevels = 2 # temperature temperature = Quantity(300, "K") # the Peierls model ham_terms = [] for i in range(n): i1, i2 = i, (i + 1) % n # H_e hop1 = Op(r"a^\dagger a", [i1, i2], V) hop2 = Op(r"a a^\dagger", [i1, i2], V) ham_terms.extend([hop1, hop2]) # H_ph ham_terms.append(Op(r"b^\dagger b", (i, 0), omega)) # H_(e-ph) coup1 = Op(r"b^\dagger + b", (i, 0)) * Op(r"a^\dagger a", [i1, i2]) * g * omega coup2 = Op(r"b^\dagger + b", (i, 0)) * Op(r"a a^\dagger", [i1, i2]) * g * omega ham_terms.extend([coup1, coup2]) basis = [] for ni in range(n): basis.append(BasisSimpleElectron(ni)) basis.append(BasisSHO((ni, 0), omega, nlevels)) model = Model(basis, ham_terms) compress_config = CompressConfig(CompressCriteria.fixed, max_bonddim=24) ievolve_config = EvolveConfig(EvolveMethod.tdvp_vmf, ivp_atol=1e-3, ivp_rtol=1e-5) evolve_config = EvolveConfig(EvolveMethod.tdvp_vmf, ivp_atol=1e-3, ivp_rtol=1e-5) kubo = TransportKubo(model, temperature, compress_config=compress_config, ievolve_config=ievolve_config, evolve_config=evolve_config) kubo.evolve(nsteps=5, evolve_time=1000) qutip_corr, qutip_corr_decomp = get_qutip_peierls_kubo( V, n, nlevels, omega, g, temperature, kubo.evolve_times_array) atol = 1e-7 rtol = 5e-2 # direct comparison may fail because of different sign assert np.allclose(kubo.auto_corr, qutip_corr, atol=atol, rtol=rtol) assert np.allclose(kubo.auto_corr_decomposition, qutip_corr_decomp, atol=atol, rtol=rtol)
# Potential for H2O has high symmetry and constructed MPO is smaller # than MPO in normal case. Use random potential to compare with normal MPO. RANDOM_INTEGRAL = False if RANDOM_INTEGRAL: h1e = np.random.uniform(-1, 1, size=(spin_norbs, spin_norbs)) h2e = np.random.uniform(-1, 1, size=(spin_norbs, spin_norbs, spin_norbs, spin_norbs)) h1e = 0.5 * (h1e + h1e.T) h2e = 0.5 * (h2e + h2e.transpose((2, 3, 0, 1))) basis, ham_terms = h_qc.qc_model(h1e, h2e) model = Model(basis, ham_terms) mpo = Mpo(model) logger.info(f"mpo_bond_dims:{mpo.bond_dims}") nelec = 10 energy_list = {} M = 50 procedure = [[M, 0.4], [M, 0.2], [M, 0.1], [M, 0], [M, 0], [M, 0], [M, 0]] mps = Mps.random(model, nelec, M, percent=1.0) mps.optimize_config.procedure = procedure mps.optimize_config.method = "2site" energies, mps = gs.optimize_mps(mps.copy(), mpo) gs_e = min(energies) + nuc logger.info(f"lowest energy: {gs_e}") # fci result