Exemple #1
0
    def test_mgga_deriv2(self):
        ng = 7
        xctype = 'MGGA'
        np.random.seed(8)
        rho = np.random.rand(2, 5, ng)
        rho1 = np.random.rand(2, 5, ng)
        weight = 1

        exc, vxc, fxc, kxc = eval_xc(f'R-{xctype}', ng)
        ref = v6to5(
            numint._rks_mgga_wv1(v5to6(rho[0]), v5to6(rho1[0]), vxc, fxc,
                                 weight))
        ref[0] *= 2
        ref[4] *= 4
        v1 = xc_deriv.transform_fxc(rho[0], vxc, fxc, xctype, spin=0)
        v1 = np.einsum('xg,xyg->yg', rho1[0], v1)
        self.assertAlmostEqual(abs(v1 - ref).max(), 0, 12)

        exc, vxc, fxc, kxc = eval_xc(f'U-{xctype}', ng)
        ref = v6to5(
            np.array(
                numint._uks_mgga_wv1(v5to6(rho), v5to6(rho1), vxc, fxc,
                                     weight)))
        ref[:, 0] *= 2
        ref[:, 4] *= 4
        v1 = xc_deriv.transform_fxc(rho, vxc, fxc, xctype, spin=1)
        v1 = np.einsum('axg,axbyg->byg', rho1, v1)
        self.assertAlmostEqual(abs(v1 - ref).max(), 0, 12)
Exemple #2
0
def _contract_xc_kernel(td_grad,
                        xc_code,
                        dmvo,
                        dmoo=None,
                        with_vxc=True,
                        with_kxc=True,
                        singlet=True,
                        max_memory=2000):
    mol = td_grad.mol
    mf = td_grad.base._scf
    grids = mf.grids

    ni = mf._numint
    xctype = ni._xc_type(xc_code)

    mo_coeff = mf.mo_coeff
    mo_occ = mf.mo_occ
    nao, nmo = mo_coeff.shape
    shls_slice = (0, mol.nbas)
    ao_loc = mol.ao_loc_nr()

    # dmvo ~ reduce(numpy.dot, (orbv, Xai, orbo.T))
    dmvo = (dmvo + dmvo.T) * .5  # because K_{ia,jb} == K_{ia,jb}

    f1vo = numpy.zeros((4, nao, nao))  # 0th-order, d/dx, d/dy, d/dz
    deriv = 2
    if dmoo is not None:
        f1oo = numpy.zeros((4, nao, nao))
    else:
        f1oo = None
    if with_vxc:
        v1ao = numpy.zeros((4, nao, nao))
    else:
        v1ao = None
    if with_kxc:
        k1ao = numpy.zeros((4, nao, nao))
        deriv = 3
    else:
        k1ao = None

    if xctype == 'LDA':
        ao_deriv = 1
        if singlet:

            def lda_sum_(vmat, ao, wv, mask):
                aow = numint._scale_ao(ao[0], wv)
                for k in range(4):
                    vmat[k] += numint._dot_ao_ao(mol, ao[k], aow, mask,
                                                 shls_slice, ao_loc)

            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
                rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, xctype)
                vxc, fxc, kxc = ni.eval_xc(xc_code, rho, 0, deriv=deriv)[1:]

                wfxc = fxc[0] * weight * 2  # *2 for alpha+beta
                rho1 = ni.eval_rho(mol, ao[0], dmvo, mask, xctype)
                lda_sum_(f1vo, ao, wfxc * rho1, mask)
                if dmoo is not None:
                    rho2 = ni.eval_rho(mol, ao[0], dmoo, mask, xctype)
                    lda_sum_(f1oo, ao, wfxc * rho2, mask)
                if with_vxc:
                    lda_sum_(v1ao, ao, vxc[0] * weight, mask)
                if with_kxc:
                    lda_sum_(k1ao, ao, kxc[0] * weight * rho1**2, mask)
            if with_kxc:  # for (rho1*2)^2, *2 for alpha+beta in singlet
                k1ao *= 4

        else:
            raise NotImplementedError('LDA triplet')

    elif xctype == 'GGA':
        if singlet:

            def gga_sum_(vmat, ao, wv, mask):
                aow = numint._scale_ao(ao[:4], wv[:4])
                tmp = numint._dot_ao_ao(mol, ao[0], aow, mask, shls_slice,
                                        ao_loc)
                vmat[0] += tmp + tmp.T
                rks_grad._gga_grad_sum_(vmat[1:], mol, ao, wv, mask, ao_loc)

            ao_deriv = 2
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
                rho = ni.eval_rho2(mol, ao, mo_coeff, mo_occ, mask, xctype)
                vxc, fxc, kxc = ni.eval_xc(xc_code, rho, 0, deriv=deriv)[1:]

                rho1 = ni.eval_rho(mol, ao, dmvo, mask,
                                   xctype) * 2  # *2 for alpha + beta
                wv = numint._rks_gga_wv1(rho, rho1, vxc, fxc, weight)
                gga_sum_(f1vo, ao, wv, mask)

                if dmoo is not None:
                    rho2 = ni.eval_rho(mol, ao, dmoo, mask, xctype) * 2
                    wv = numint._rks_gga_wv1(rho, rho2, vxc, fxc, weight)
                    gga_sum_(f1oo, ao, wv, mask)
                if with_vxc:
                    wv = numint._rks_gga_wv0(rho, vxc, weight)
                    gga_sum_(v1ao, ao, wv, mask)
                if with_kxc:
                    wv = numint._rks_gga_wv2(rho, rho1, fxc, kxc, weight)
                    gga_sum_(k1ao, ao, wv, mask)
                vxc = fxc = kxc = rho = rho1 = None

        else:
            raise NotImplementedError('GGA triplet')

    elif xctype == 'MGGA':
        if singlet:

            def mgga_sum_(vmat, ao, wv, mask):
                aow = numint._scale_ao(ao[:4], wv[:4])
                tmp = numint._dot_ao_ao(mol, ao[0], aow, mask, shls_slice,
                                        ao_loc)
                aow = numint._scale_ao(ao[1], wv[5], aow)
                tmp += numint._dot_ao_ao(mol, ao[1], aow, mask, shls_slice,
                                         ao_loc)
                aow = numint._scale_ao(ao[2], wv[5], aow)
                tmp += numint._dot_ao_ao(mol, ao[2], aow, mask, shls_slice,
                                         ao_loc)
                aow = numint._scale_ao(ao[3], wv[5], aow)
                tmp += numint._dot_ao_ao(mol, ao[3], aow, mask, shls_slice,
                                         ao_loc)
                vmat[0] += tmp + tmp.T

                rks_grad._gga_grad_sum_(vmat[1:], mol, ao, wv[:4], mask,
                                        ao_loc)
                rks_grad._tau_grad_dot_(vmat[1:], mol, ao, wv[5] * 2, mask,
                                        ao_loc, True)

            ao_deriv = 2
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
                rho = ni.eval_rho2(mol, ao, mo_coeff, mo_occ, mask, xctype)
                vxc, fxc, kxc = ni.eval_xc(xc_code, rho, 0, deriv=deriv)[1:]

                rho1 = ni.eval_rho(mol, ao, dmvo, mask,
                                   xctype) * 2  # *2 for alpha + beta
                wv = numint._rks_mgga_wv1(rho, rho1, vxc, fxc, weight)
                mgga_sum_(f1vo, ao, wv, mask)

                if dmoo is not None:
                    rho2 = ni.eval_rho(mol, ao, dmoo, mask, xctype) * 2
                    wv = numint._rks_mgga_wv1(rho, rho2, vxc, fxc, weight)
                    mgga_sum_(f1oo, ao, wv, mask)
                if with_vxc:
                    wv = numint._rks_mgga_wv0(rho, vxc, weight)
                    mgga_sum_(v1ao, ao, wv, mask)
                if with_kxc:
                    wv = numint._rks_mgga_wv2(rho, rho1, fxc, kxc, weight)
                    mgga_sum_(k1ao, ao, wv, mask)
                vxc = fxc = kxc = rho = rho1 = None
        else:
            raise NotImplementedError('MGGA triplet')

    elif xctype == 'HF':
        pass
    else:
        raise NotImplementedError(f'td-rks for functional {xc_code}')

    f1vo[1:] *= -1
    if f1oo is not None: f1oo[1:] *= -1
    if v1ao is not None: v1ao[1:] *= -1
    if k1ao is not None: k1ao[1:] *= -1
    return f1vo, f1oo, v1ao, k1ao
Exemple #3
0
def _get_vxc_deriv1(hessobj, mo_coeff, mo_occ, max_memory):
    mol = hessobj.mol
    mf = hessobj.base
    if hessobj.grids is not None:
        grids = hessobj.grids
    else:
        grids = mf.grids
    if grids.coords is None:
        grids.build(with_non0tab=True)

    nao, nmo = mo_coeff.shape
    ni = mf._numint
    xctype = ni._xc_type(mf.xc)
    aoslices = mol.aoslice_by_atom()
    shls_slice = (0, mol.nbas)
    ao_loc = mol.ao_loc_nr()
    dm0 = mf.make_rdm1(mo_coeff, mo_occ)

    v_ip = numpy.zeros((3, nao, nao))
    vmat = numpy.zeros((mol.natm, 3, nao, nao))
    max_memory = max(2000, max_memory - vmat.size * 8 / 1e6)
    if xctype == 'LDA':
        ao_deriv = 1
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
            rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, xctype)
            vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
            vrho = vxc[0]
            frr = fxc[0]
            aow = numint._scale_ao(ao[0], weight * vrho)
            rks_grad._d1_dot_(v_ip, mol, ao[1:4], aow, mask, ao_loc, True)

            ao_dm0 = numint._dot_ao_dm(mol, ao[0], dm0, mask, shls_slice,
                                       ao_loc)
            for ia in range(mol.natm):
                p0, p1 = aoslices[ia][2:]
                # First order density = rho1 * 2.  *2 is not applied because + c.c. in the end
                rho1 = numpy.einsum('xpi,pi->xp', ao[1:, :, p0:p1],
                                    ao_dm0[:, p0:p1])
                wv = weight * frr * rho1
                aow = [numint._scale_ao(ao[0], wv[i]) for i in range(3)]
                rks_grad._d1_dot_(vmat[ia], mol, aow, ao[0], mask, ao_loc,
                                  True)
            ao_dm0 = aow = None

    elif xctype == 'GGA':
        ao_deriv = 2
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
            rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, xctype)
            vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]

            wv = numint._rks_gga_wv0(rho, vxc, weight)
            rks_grad._gga_grad_sum_(v_ip, mol, ao, wv, mask, ao_loc)

            ao_dm0 = [
                numint._dot_ao_dm(mol, ao[i], dm0, mask, shls_slice, ao_loc)
                for i in range(4)
            ]
            for ia in range(mol.natm):
                wv = dR_rho1 = _make_dR_rho1(ao, ao_dm0, ia, aoslices)
                wv[0] = numint._rks_gga_wv1(rho, dR_rho1[0], vxc, fxc, weight)
                wv[1] = numint._rks_gga_wv1(rho, dR_rho1[1], vxc, fxc, weight)
                wv[2] = numint._rks_gga_wv1(rho, dR_rho1[2], vxc, fxc, weight)
                aow = [numint._scale_ao(ao[:4], wv[i, :4]) for i in range(3)]
                rks_grad._d1_dot_(vmat[ia], mol, aow, ao[0], mask, ao_loc,
                                  True)
            ao_dm0 = aow = None

    elif xctype == 'MGGA':
        if grids.level < 5:
            logger.warn(mol, 'MGGA Hessian is sensitive to dft grids.')
        ao_deriv = 2
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
            rho = ni.eval_rho2(mol, ao[:10], mo_coeff, mo_occ, mask, xctype)
            vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]

            wv = numint._rks_mgga_wv0(rho, vxc, weight)
            rks_grad._gga_grad_sum_(v_ip, mol, ao, wv, mask, ao_loc)

            # *2 because wv[5] is scaled by 0.5 in _rks_mgga_wv0
            rks_grad._tau_grad_dot_(v_ip, mol, ao, wv[5] * 2, mask, ao_loc,
                                    True)

            ao_dm0 = [
                numint._dot_ao_dm(mol, ao[i], dm0, mask, shls_slice, ao_loc)
                for i in range(4)
            ]
            for ia in range(mol.natm):
                wv = dR_rho1 = _make_dR_rho1(ao, ao_dm0, ia, aoslices, xctype)
                wv[0] = numint._rks_mgga_wv1(rho, dR_rho1[0], vxc, fxc, weight)
                wv[1] = numint._rks_mgga_wv1(rho, dR_rho1[1], vxc, fxc, weight)
                wv[2] = numint._rks_mgga_wv1(rho, dR_rho1[2], vxc, fxc, weight)
                aow = [numint._scale_ao(ao[:4], wv[i, :4]) for i in range(3)]
                rks_grad._d1_dot_(vmat[ia], mol, aow, ao[0], mask, ao_loc,
                                  True)

                for j in range(1, 4):
                    aow = [numint._scale_ao(ao[j], wv[i, 5]) for i in range(3)]
                    rks_grad._d1_dot_(vmat[ia], mol, aow, ao[j], mask, ao_loc,
                                      True)
            ao_dm0 = aow = None

    for ia in range(mol.natm):
        p0, p1 = aoslices[ia][2:]
        vmat[ia, :, p0:p1] += v_ip[:, p0:p1]
        vmat[ia] = -vmat[ia] - vmat[ia].transpose(0, 2, 1)

    return vmat
Exemple #4
0
def _get_vxc_deriv2(hessobj, mo_coeff, mo_occ, max_memory):
    mol = hessobj.mol
    mf = hessobj.base
    if hessobj.grids is not None:
        grids = hessobj.grids
    else:
        grids = mf.grids
    if grids.coords is None:
        grids.build(with_non0tab=True)

    nao, nmo = mo_coeff.shape
    ni = mf._numint
    xctype = ni._xc_type(mf.xc)
    aoslices = mol.aoslice_by_atom()
    shls_slice = (0, mol.nbas)
    ao_loc = mol.ao_loc_nr()
    dm0 = mf.make_rdm1(mo_coeff, mo_occ)

    vmat = numpy.zeros((mol.natm, 3, 3, nao, nao))
    ipip = numpy.zeros((3, 3, nao, nao))
    if xctype == 'LDA':
        ao_deriv = 1
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
            rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, xctype)
            vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
            vrho = vxc[0]
            frr = fxc[0]
            wv = weight * vrho
            aow = [numint._scale_ao(ao[i], wv) for i in range(1, 4)]
            _d1d2_dot_(ipip, mol, aow, ao[1:4], mask, ao_loc, False)

            ao_dm0 = numint._dot_ao_dm(mol, ao[0], dm0, mask, shls_slice,
                                       ao_loc)
            for ia in range(mol.natm):
                p0, p1 = aoslices[ia][2:]
                # *2 for \nabla|ket> in rho1
                rho1 = numpy.einsum('xpi,pi->xp', ao[1:, :, p0:p1],
                                    ao_dm0[:, p0:p1]) * 2
                # aow ~ rho1 ~ d/dR1
                wv = weight * frr * rho1
                aow = [numint._scale_ao(ao[0], wv[i]) for i in range(3)]
                _d1d2_dot_(vmat[ia], mol, ao[1:4], aow, mask, ao_loc, False)
            ao_dm0 = aow = None

        for ia in range(mol.natm):
            p0, p1 = aoslices[ia][2:]
            vmat[ia, :, :, :, p0:p1] += ipip[:, :, :, p0:p1]

    elif xctype == 'GGA':
        ao_deriv = 2
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
            rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, xctype)
            vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]

            wv = numint._rks_gga_wv0(rho, vxc, weight)
            aow = rks_grad._make_dR_dao_w(ao, wv)
            _d1d2_dot_(ipip, mol, aow, ao[1:4], mask, ao_loc, False)

            ao_dm0 = [
                numint._dot_ao_dm(mol, ao[i], dm0, mask, shls_slice, ao_loc)
                for i in range(4)
            ]
            for ia in range(mol.natm):
                wv = dR_rho1 = _make_dR_rho1(ao, ao_dm0, ia, aoslices)
                for i in range(3):
                    wv[i] = numint._rks_gga_wv1(rho, dR_rho1[i], vxc, fxc,
                                                weight)
                    aow = rks_grad._make_dR_dao_w(ao, wv[i])
                    rks_grad._d1_dot_(vmat[ia, i], mol, aow, ao[0], mask,
                                      ao_loc, True)

                aow = [numint._scale_ao(ao[:4], wv[i, :4]) for i in range(3)]
                _d1d2_dot_(vmat[ia], mol, ao[1:4], aow, mask, ao_loc, False)
            ao_dm0 = aow = None

        for ia in range(mol.natm):
            p0, p1 = aoslices[ia][2:]
            vmat[ia, :, :, :, p0:p1] += ipip[:, :, :, p0:p1]
            vmat[ia, :, :, :, p0:p1] += ipip[:, :, p0:p1].transpose(1, 0, 3, 2)

    elif xctype == 'MGGA':
        XX, XY, XZ = 4, 5, 6
        YX, YY, YZ = 5, 7, 8
        ZX, ZY, ZZ = 6, 8, 9
        ao_deriv = 2
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory):
            rho = ni.eval_rho2(mol, ao[:10], mo_coeff, mo_occ, mask, xctype)
            vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]

            wv = numint._rks_mgga_wv0(rho, vxc, weight)
            aow = rks_grad._make_dR_dao_w(ao, wv)
            _d1d2_dot_(ipip, mol, aow, ao[1:4], mask, ao_loc, False)

            aow = [numint._scale_ao(ao[i], wv[5]) for i in range(4, 10)]
            _d1d2_dot_(ipip, mol, [aow[0], aow[1], aow[2]],
                       [ao[XX], ao[XY], ao[XZ]], mask, ao_loc, False)
            _d1d2_dot_(ipip, mol, [aow[1], aow[3], aow[4]],
                       [ao[YX], ao[YY], ao[YZ]], mask, ao_loc, False)
            _d1d2_dot_(ipip, mol, [aow[2], aow[4], aow[5]],
                       [ao[ZX], ao[ZY], ao[ZZ]], mask, ao_loc, False)

            ao_dm0 = [
                numint._dot_ao_dm(mol, ao[i], dm0, mask, shls_slice, ao_loc)
                for i in range(4)
            ]
            for ia in range(mol.natm):
                wv = dR_rho1 = _make_dR_rho1(ao, ao_dm0, ia, aoslices, xctype)
                for i in range(3):
                    wv[i] = numint._rks_mgga_wv1(rho, dR_rho1[i], vxc, fxc,
                                                 weight)
                    aow = rks_grad._make_dR_dao_w(ao, wv[i])
                    rks_grad._d1_dot_(vmat[ia, i], mol, aow, ao[0], mask,
                                      ao_loc, True)

                aow = [numint._scale_ao(ao[:4], wv[i, :4]) for i in range(3)]
                _d1d2_dot_(vmat[ia], mol, ao[1:4], aow, mask, ao_loc, False)

                # *2 because wv[5] is scaled by 0.5 in _rks_mgga_wv1
                wv[:, 5] *= 2
                aow = [numint._scale_ao(ao[1], wv[i, 5]) for i in range(3)]
                _d1d2_dot_(vmat[ia], mol, [ao[XX], ao[XY], ao[XZ]], aow, mask,
                           ao_loc, False)
                aow = [numint._scale_ao(ao[2], wv[i, 5]) for i in range(3)]
                _d1d2_dot_(vmat[ia], mol, [ao[YX], ao[YY], ao[YZ]], aow, mask,
                           ao_loc, False)
                aow = [numint._scale_ao(ao[3], wv[i, 5]) for i in range(3)]
                _d1d2_dot_(vmat[ia], mol, [ao[ZX], ao[ZY], ao[ZZ]], aow, mask,
                           ao_loc, False)

        for ia in range(mol.natm):
            p0, p1 = aoslices[ia][2:]
            vmat[ia, :, :, :, p0:p1] += ipip[:, :, :, p0:p1]
            vmat[ia, :, :, :, p0:p1] += ipip[:, :, p0:p1].transpose(1, 0, 3, 2)

    return vmat