Esempio n. 1
0
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)
Esempio n. 2
0
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))
Esempio n. 3
0
    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)
Esempio n. 4
0
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())
Esempio n. 5
0
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)
Esempio n. 6
0
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])
Esempio n. 7
0
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)
Esempio n. 8
0
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)
Esempio n. 9
0
# 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