示例#1
0
def make_rdms_mcpdft (mc, ot=None, mo_coeff=None, ci=None):
    ''' Build the necessary density matrices for an MC-PDFT calculation 

        Args:
            mc : an instance of CASSCF or CASCI class
                Note: this function does not currently run the CASSCF or CASCI calculation itself

        Kwargs:
            ot : an instance of on-top density functional class - see otfnal.py
            mo_coeff : ndarray of shape (nao, nmo)
                Molecular orbital coefficients
            ci : ndarray or list
                CI vector or vectors. If a list of many CI vectors, mc must be a 
                state-average object with the correct nroots

        Returns:
            dm1s : ndarray of shape (2,nao,nao)
                Spin-separated 1-RDM
            adm : (adm1s, adm2s)
                adm1s : ndarray of shape (2,ncas,ncas)
                    Spin-separated 1-RDM for the active orbitals
                adm2s : 3 ndarrays of shape (ncas,ncas,ncas,ncas)
                    First ndarray is spin-summed casdm2
                    Second ndarray is casdm2_aa + casdm2_bb
                    Third ndarray is casdm2_ab
    '''
    if ci is None: ci = mc.ci
    if ot is None: ot = mc.otfnal
    if mo_coeff is None: mo_coeff = mc.mo_coeff
    ncore, ncas, nelecas = mc.ncore, mc.ncas, mc.nelecas
    nocc = ncore + ncas

    # figure out the correct RDMs to build (state-average or state-specific?)
    nelecas = _unpack_nelec (nelecas)
    ndet = [cistring.num_strings (ncas, n) for n in nelecas]
    ci = np.asarray (ci).reshape (-1, ndet[0], ndet[1])
    nroots = ci.shape[0]
    if nroots > 1:
        _casdms = mc.fcisolver
    else:
        ci = ci[0]
        _casdms = fci.solver (mc._scf.mol, singlet=False, symm=False)

    # Make the rdms
    # make_rdm12s returns (a, b), (aa, ab, bb)
    mo_cas = mo_coeff[:,ncore:nocc]
    moH_cas = mo_cas.conj ().T
    mo_core = mo_coeff[:,:ncore]
    moH_core = mo_core.conj ().T
    adm1s = np.stack (_casdms.make_rdm1s (ci, ncas, nelecas), axis=0)
    adm2s = _casdms.make_rdm12s (ci, ncas, nelecas)[1]
    adm2s = get_2CDMs_from_2RDMs (adm2s, adm1s)
    adm2_ss = adm2s[0] + adm2s[2]
    adm2_os = adm2s[1]
    adm2 = adm2_ss + adm2_os + adm2_os.transpose (2,3,0,1)
    dm1s = np.dot (adm1s, moH_cas)
    dm1s = np.dot (mo_cas, dm1s).transpose (1,0,2)
    dm1s += np.dot (mo_core, moH_core)[None,:,:]
    return dm1s, (adm1s, (adm2, adm2_ss, adm2_os))
示例#2
0
def _get_e_decomp(mc, ot, mo_coeff, ci, e_mcscf):
    if ot is not None:
        xfnal, cfnal = ot.split_x_c()
    ncore, ncas, nelecas = mc.ncore, mc.ncas, mc.nelecas
    if isinstance(mc, mcscf.casci.CASCI):
        _rdms = mc
        _casdms = mc.fcisolver
    else:
        _rdms = mcscf.CASCI(mc._scf, ncas, nelecas)
        _rdms.fcisolver = fci.solver(mc._scf.mol, singlet=False, symm=False)
        _rdms.mo_coeff = mo_coeff
        _rdms.ci = ci
        _casdms = _rdms.fcisolver
    _scf = _rdms._scf.to_uhf()
    dm1s = np.stack(_rdms.make_rdm1s(), axis=0)
    dm1 = dm1s[0] + dm1s[1]
    h = _scf.get_hcore()
    j, k = _scf.get_jk(dm=dm1s)
    e_nn = _scf.energy_nuc()
    e_core = np.tensordot(h, dm1, axes=2)
    #print(j.shape, k.shape, dm1.shape)
    e_coul = np.tensordot(j[0] + j[1], dm1, axes=2) / 2
    e_x = -(np.tensordot(k[0], dm1s[0]) + np.tensordot(k[1], dm1s[1])) / 2
    e_otx = 0.0
    e_otc = 0.0
    if ot is not None:
        adm1s = np.stack(_casdms.make_rdm1s(ci, ncas, nelecas), axis=0)
        adm2s = _casdms.make_rdm12s(_rdms.ci, ncas, nelecas)[1]
        #print(adm2s)
        adm2s = get_2CDMs_from_2RDMs(adm2s, adm1s)
        adm2_ss = adm2s[0] + adm2s[2]
        adm2_os = adm2s[1]
        adm2 = adm2_ss + adm2_os + adm2_os.transpose(2, 3, 0, 1)
        mo_cas = mo_coeff[:, ncore:][:, :ncas]
        e_otx = get_E_ot(xfnal, dm1s, adm2, mo_cas, max_memory=mc.max_memory)
        e_otc = get_E_ot(cfnal, dm1s, adm2, mo_cas, max_memory=mc.max_memory)
    e_c = e_mcscf - e_nn - e_core - e_coul - e_x
    return e_nn, e_core, e_coul, e_x, e_otx, e_otc, e_c
示例#3
0
def kernel(mc, ot, root=-1):
    ''' Calculate MC-PDFT total energy

        Args:
            mc : an instance of CASSCF or CASCI class
                Note: this function does not currently run the CASSCF or CASCI calculation itself
                prior to calculating the MC-PDFT energy. Call mc.kernel () before passing to this function!
            ot : an instance of on-top density functional class - see otfnal.py

        Kwargs:
            root : int
                If mc describes a state-averaged calculation, select the root (0-indexed)
                Negative number requests state-averaged MC-PDFT results (i.e., using state-averaged density matrices)

        Returns:
            Total MC-PDFT energy including nuclear repulsion energy.
    '''
    t0 = (time.clock(), time.time())
    amo = mc.mo_coeff[:, mc.ncore:mc.ncore + mc.ncas]
    # make_rdm12s returns (a, b), (aa, ab, bb)

    mc_1root = mc
    if isinstance(mc.ci, list) and root >= 0:
        mc_1root = mcscf.CASCI(mc._scf, mc.ncas, mc.nelecas)
        mc_1root.fcisolver = fci.solver(mc._scf.mol, singlet=False, symm=False)
        mc_1root.mo_coeff = mc.mo_coeff
        mc_1root.ci = mc.ci[root]
        mc_1root.e_tot = mc.e_tot
    dm1s = np.asarray(mc_1root.make_rdm1s())
    adm1s = np.stack(mc_1root.fcisolver.make_rdm1s(mc_1root.ci, mc.ncas,
                                                   mc.nelecas),
                     axis=0)
    adm2 = get_2CDM_from_2RDM(
        mc_1root.fcisolver.make_rdm12(mc_1root.ci, mc.ncas, mc.nelecas)[1],
        adm1s)
    if ot.verbose >= logger.DEBUG:
        adm2s = get_2CDMs_from_2RDMs(
            mc_1root.fcisolver.make_rdm12s(mc_1root.ci, mc.ncas,
                                           mc.nelecas)[1], adm1s)
        adm2s_ss = adm2s[0] + adm2s[2]
        adm2s_os = adm2s[1]
    spin = abs(mc.nelecas[0] - mc.nelecas[1])
    t0 = logger.timer(ot, 'rdms', *t0)

    omega, alpha, hyb = ot._numint.rsh_and_hybrid_coeff(ot.otxc, spin=spin)
    Vnn = mc._scf.energy_nuc()
    h = mc._scf.get_hcore()
    dm1 = dm1s[0] + dm1s[1]
    if ot.verbose >= logger.DEBUG or abs(hyb) > 1e-10:
        vj, vk = mc._scf.get_jk(dm=dm1s)
        vj = vj[0] + vj[1]
    else:
        vj = mc._scf.get_j(dm=dm1)
    Te_Vne = np.tensordot(h, dm1)
    # (vj_a + vj_b) * (dm_a + dm_b)
    E_j = np.tensordot(vj, dm1) / 2
    # (vk_a * dm_a) + (vk_b * dm_b) Mind the difference!
    if ot.verbose >= logger.DEBUG or abs(hyb) > 1e-10:
        E_x = -(np.tensordot(vk[0], dm1s[0]) +
                np.tensordot(vk[1], dm1s[1])) / 2
    else:
        E_x = 0
    logger.debug(ot, 'CAS energy decomposition:')
    logger.debug(ot, 'Vnn = %s', Vnn)
    logger.debug(ot, 'Te + Vne = %s', Te_Vne)
    logger.debug(ot, 'E_j = %s', E_j)
    logger.debug(ot, 'E_x = %s', E_x)
    if ot.verbose >= logger.DEBUG:
        # g_pqrs * l_pqrs / 2
        #if ot.verbose >= logger.DEBUG:
        aeri = ao2mo.restore(1, mc.get_h2eff(mc.mo_coeff), mc.ncas)
        E_c = np.tensordot(aeri, adm2, axes=4) / 2
        E_c_ss = np.tensordot(aeri, adm2s_ss, axes=4) / 2
        E_c_os = np.tensordot(aeri, adm2s_os, axes=4)  # ab + ba -> factor of 2
        logger.info(ot, 'E_c = %s', E_c)
        logger.info(ot, 'E_c (SS) = %s', E_c_ss)
        logger.info(ot, 'E_c (OS) = %s', E_c_os)
        e_err = E_c_ss + E_c_os - E_c
        assert (abs(e_err) < 1e-8), e_err
        if isinstance(mc_1root.e_tot, float):
            e_err = mc_1root.e_tot - (Vnn + Te_Vne + E_j + E_x + E_c)
            assert (abs(e_err) < 1e-8), e_err
    if abs(hyb) > 1e-10:
        logger.debug(ot, 'Adding %s * %s CAS exchange to E_ot', hyb, E_x)
    t0 = logger.timer(ot, 'Vnn, Te, Vne, E_j, E_x', *t0)

    E_ot = get_E_ot(ot, dm1s, adm2, amo)
    t0 = logger.timer(ot, 'E_ot', *t0)
    e_tot = Vnn + Te_Vne + E_j + (hyb * E_x) + E_ot
    logger.info(ot, 'MC-PDFT E = %s, Eot(%s) = %s', e_tot, ot.otxc, E_ot)

    return e_tot, E_ot