Esempio n. 1
0
def test_BasisSHO(op, x0):

    sho = Ba.BasisSHO(None, 0.1, 10, x0=x0, dvr=False)
    sho_general = Ba.BasisSHO(None,
                              0.1,
                              10,
                              x0=x0,
                              general_xp_power=True,
                              dvr=False)

    a = sho.op_mat(op)
    b = sho_general.op_mat(op)
    assert np.allclose(a, b)

    sho_dvr = Ba.BasisSHO(None, 0.1, 10, x0=x0, dvr=True)
    sho_dvr_general = Ba.BasisSHO(None,
                                  0.1,
                                  10,
                                  x0=x0,
                                  general_xp_power=True,
                                  dvr=True)
    a_dvr = sho_dvr.op_mat(op)
    b_dvr = sho_dvr_general.op_mat(op)
    a_dvr = sho_dvr.dvr_v @ a_dvr @ sho_dvr.dvr_v.T
    b_dvr = sho_dvr_general.dvr_v @ b_dvr @ sho_dvr_general.dvr_v.T
    if op == "x^2":
        # the last basis is not accurate in dvr
        assert np.allclose(a[:-1, :-1], a_dvr[:-1, :-1])
        assert np.allclose(a[:-1, :-1], b_dvr[:-1, :-1])
    else:
        assert np.allclose(a, a_dvr)
        assert np.allclose(a, b_dvr)
Esempio n. 2
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. 3
0
def construct_vibronic_model(multi_e, dvr):
    r"""
    Bi-linear vibronic coupling model for Pyrazine, 4 modes
    See: Raab, Worth, Meyer, Cederbaum.  J.Chem.Phys. 110 (1999) 936
    The parameters are from heidelberg mctdh package pyr4+.op
    """
    # frequencies
    w10a = 0.1139 * ev2au
    w6a = 0.0739 * ev2au
    w1 = 0.1258 * ev2au
    w9a = 0.1525 * ev2au

    # energy-gap
    delta = 0.42300 * ev2au

    # linear, on-diagonal coupling coefficients
    # H(1,1)
    _6a_s1_s1 = 0.09806 * ev2au
    _1_s1_s1 = 0.05033 * ev2au
    _9a_s1_s1 = 0.14521 * ev2au
    # H(2,2)
    _6a_s2_s2 = -0.13545 * ev2au
    _1_s2_s2 = 0.17100 * ev2au
    _9a_s2_s2 = 0.03746 * ev2au

    # quadratic, on-diagonal coupling coefficients
    # H(1,1)
    _10a_10a_s1_s1 = -0.01159 * ev2au
    _6a_6a_s1_s1 = 0.00000 * ev2au
    _1_1_s1_s1 = 0.00000 * ev2au
    _9a_9a_s1_s1 = 0.00000 * ev2au
    # H(2,2)
    _10a_10a_s2_s2 = -0.01159 * ev2au
    _6a_6a_s2_s2 = 0.00000 * ev2au
    _1_1_s2_s2 = 0.00000 * ev2au
    _9a_9a_s2_s2 = 0.00000 * ev2au

    # bilinear, on-diagonal coupling coefficients
    # H(1,1)
    _6a_1_s1_s1 = 0.00108 * ev2au
    _1_9a_s1_s1 = -0.00474 * ev2au
    _6a_9a_s1_s1 = 0.00204 * ev2au
    # H(2,2)
    _6a_1_s2_s2 = -0.00298 * ev2au
    _1_9a_s2_s2 = -0.00155 * ev2au
    _6a_9a_s2_s2 = 0.00189 * ev2au

    # linear, off-diagonal coupling coefficients
    _10a_s1_s2 = 0.20804 * ev2au

    # bilinear, off-diagonal coupling coefficients
    # H(1,2) and H(2,1)
    _1_10a_s1_s2 = 0.00553 * ev2au
    _6a_10a_s1_s2 = 0.01000 * ev2au
    _9a_10a_s1_s2 = 0.00126 * ev2au

    ham_terms = []
    e_list = ["s1", "s2"]
    v_list = ["10a", "6a", "9a", "1"]
    for (e_isymbol, e_jsymbol) in product(e_list, repeat=2):
        e_op = Op(r"a^\dagger a", [e_isymbol, e_jsymbol])
        for (v_isymbol, v_jsymbol) in product(v_list, repeat=2):
            # linear
            if v_isymbol == v_jsymbol:
                # if one of the permutation is defined, then the `e_idx_tuple` term should
                # be defined as required by Hermitian Hamiltonian
                for eterm1, eterm2 in permut([e_isymbol, e_jsymbol], 2):
                    factor = locals().get(f"_{v_isymbol}_{eterm1}_{eterm2}")
                    if factor is not None:
                        factor *= np.sqrt(eval(f"w{v_isymbol}"))
                        ham_terms.append(e_op * Op("x", v_isymbol) * factor)
                        logger.debug(
                            f"term: {v_isymbol}_{e_isymbol}_{e_jsymbol}")
                        break
                else:
                    logger.debug(
                        f"no term: {v_isymbol}_{e_isymbol}_{e_jsymbol}")

            # quadratic
            # use product to guarantee `break` breaks the whole loop
            it = product(permut([v_isymbol, v_jsymbol], 2),
                         permut([e_isymbol, e_jsymbol], 2))
            for (vterm1, vterm2), (eterm1, eterm2) in it:
                factor = locals().get(f"_{vterm1}_{vterm2}_{eterm1}_{eterm2}")

                if factor is not None:
                    factor *= np.sqrt(
                        eval(f"w{v_isymbol}") * eval(f"w{v_jsymbol}"))
                    if vterm1 == vterm2:
                        v_op = Op("x^2", vterm1)
                    else:
                        v_op = Op("x", vterm1) * Op("x", vterm2)
                    ham_terms.append(e_op * v_op * factor)
                    logger.debug(
                        f"term: {v_isymbol}_{v_jsymbol}_{e_isymbol}_{e_jsymbol}"
                    )
                    break
            else:
                logger.debug(
                    f"no term: {v_isymbol}_{v_jsymbol}_{e_isymbol}_{e_jsymbol}"
                )

    # electronic coupling
    ham_terms.append(Op(r"a^\dagger a", "s1", -delta, [0, 0]))
    ham_terms.append(Op(r"a^\dagger a", "s2", delta, [0, 0]))

    # vibrational kinetic and potential
    for v_isymbol in v_list:
        ham_terms.extend([
            Op("p^2", v_isymbol, 0.5),
            Op("x^2", v_isymbol, 0.5 * eval("w" + v_isymbol)**2)
        ])

    for term in ham_terms:
        logger.info(term)

    basis = []
    if not multi_e:
        for e_isymbol in e_list:
            basis.append(ba.BasisSimpleElectron(e_isymbol))
    else:
        basis.append(ba.BasisMultiElectron(e_list, [0, 0]))

    for v_isymbol in v_list:
        basis.append(
            ba.BasisSHO(v_isymbol, locals()[f"w{v_isymbol}"], 30, dvr=dvr))

    logger.info(f"basis:{basis}")

    return basis, ham_terms
Esempio n. 4
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. 5
0
def test_high_moment():
    sho = Ba.BasisSHO(None, 0.1, 10, dvr=False)
    assert np.allclose(sho.op_mat("x^2"), sho.op_mat("x x"))
    assert np.allclose(sho.op_mat("x^3"), sho.op_mat("x x x"))
    assert np.allclose(sho.op_mat("p^2"), sho.op_mat("p p"))
    assert np.allclose(sho.op_mat("p^3"), sho.op_mat("p p p"))