Beispiel #1
0
def get_veff(ks_grad, mol=None, dm=None):
    '''Coulomb + XC functional
    '''
    if mol is None: mol = ks_grad.mol
    if dm is None: dm = ks_grad.base.make_rdm1()
    t0 = (time.clock(), time.time())

    mf = ks_grad.base
    ni = mf._numint
    if ks_grad.grids is not None:
        grids = ks_grad.grids
    else:
        grids = mf.grids
    if grids.coords is None:
        grids.build(with_non0tab=True)

    if mf.nlc != '':
        raise NotImplementedError
    #enabling range-separated hybrids
    omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, spin=mol.spin)

    mem_now = lib.current_memory()[0]
    max_memory = max(2000, ks_grad.max_memory*.9-mem_now)
    if ks_grad.grid_response:
        exc, vxc = rks_grad.get_vxc_full_response(
                ni, mol, grids, mf.xc, dm,
                max_memory=max_memory, verbose=ks_grad.verbose)
        logger.debug1(ks_grad, 'sum(grids response) %s', exc.sum(axis=0))
    else:
        exc, vxc = rks_grad.get_vxc(
                ni, mol, grids, mf.xc, dm,
                max_memory=max_memory, verbose=ks_grad.verbose)
    t0 = logger.timer(ks_grad, 'vxc', *t0)

    if abs(hyb) < 1e-10 and abs(alpha) < 1e-10:
        vj = ks_grad.get_j(mol, dm)
        vxc += vj
        if ks_grad.auxbasis_response:
            e1_aux = vj.aux
    else:
        vj, vk = ks_grad.get_jk(mol, dm)
        if ks_grad.auxbasis_response:
            vk_aux = vk.aux * hyb
        vk *= hyb
        if abs(omega) > 1e-10:  # For range separated Coulomb operator
            raise NotImplementedError
            vk_lr = ks_grad.get_k(mol, dm, omega=omega)
            vk += vk_lr * (alpha - hyb)
            if ks_grad.auxbasis_response:
                vk_aux += vk_lr.aux * (alpha - hyb)
        vxc += vj - vk * .5
        if ks_grad.auxbasis_response:
            e1_aux = vj.aux - vk_aux * .5

    if ks_grad.auxbasis_response:
        logger.debug1(ks_grad, 'sum(auxbasis response) %s', e1_aux.sum(axis=0))
        vxc = lib.tag_array(vxc, exc1_grid=exc, aux=e1_aux)
    else:
        vxc = lib.tag_array(vxc, exc1_grid=exc)
    return vxc
Beispiel #2
0
    def test_get_vxc(self):
        mol = gto.Mole()
        mol.verbose = 0
        mol.atom = [
            ['O' , (0. , 0.     , 0.)],
            [1   , (0. , -0.757 , 0.587)],
            [1   , (0. ,  0.757 , 0.587)] ]
        mol.basis = '631g'
        mol.build()
        mf = dft.RKS(mol)
        mf.conv_tol = 1e-12
        mf.grids.radii_adjust = radi.becke_atomic_radii_adjust
        mf.scf()
        g = rks.Gradients(mf)
        g.grid_response = True
        g0 = g.kernel()
        dm0 = mf.make_rdm1()

        mol0 = gto.Mole()
        mol0.verbose = 0
        mol0.atom = [
            ['O' , (0. , 0.     ,-0.00001)],
            [1   , (0. , -0.757 , 0.587)],
            [1   , (0. ,  0.757 , 0.587)] ]
        mol0.basis = '631g'
        mol0.build()
        mf0 = dft.RKS(mol0)
        mf0.grids.radii_adjust = radi.becke_atomic_radii_adjust
        mf0.conv_tol = 1e-12
        e0 = mf0.scf()

        denom = 1/.00002 * lib.param.BOHR
        mol1 = gto.Mole()
        mol1.verbose = 0
        mol1.atom = [
            ['O' , (0. , 0.     , 0.00001)],
            [1   , (0. , -0.757 , 0.587)],
            [1   , (0. ,  0.757 , 0.587)] ]
        mol1.basis = '631g'
        mol1.build()
        mf1 = dft.RKS(mol1)
        mf1.grids.radii_adjust = radi.becke_atomic_radii_adjust
        mf1.conv_tol = 1e-12
        e1 = mf1.scf()
        self.assertAlmostEqual((e1-e0)*denom, g0[0,2], 6)

        # grids response have non-negligible effects for small grids
        grids = dft.gen_grid.Grids(mol)
        grids.atom_grid = (20,86)
        grids.build(with_non0tab=False)
        grids0 = dft.gen_grid.Grids(mol0)
        grids0.atom_grid = (20,86)
        grids0.build(with_non0tab=False)
        grids1 = dft.gen_grid.Grids(mol1)
        grids1.atom_grid = (20,86)
        grids1.build(with_non0tab=False)
        xc = 'lda,'
        exc0 = dft.numint.nr_rks(mf0._numint, mol0, grids0, xc, dm0)[1]
        exc1 = dft.numint.nr_rks(mf1._numint, mol1, grids1, xc, dm0)[1]

        grids0_w = copy.copy(grids0)
        grids0_w.weights = grids1.weights
        grids0_c = copy.copy(grids0)
        grids0_c.coords = grids1.coords
        exc0_w = dft.numint.nr_rks(mf0._numint, mol0, grids0_w, xc, dm0)[1]
        exc0_c = dft.numint.nr_rks(mf1._numint, mol1, grids0_c, xc, dm0)[1]

        dexc_t = (exc1 - exc0) * denom
        dexc_c = (exc0_c - exc0) * denom
        dexc_w = (exc0_w - exc0) * denom
        self.assertAlmostEqual(dexc_t, dexc_c+dexc_w, 4)

        vxc = rks.get_vxc(mf._numint, mol, grids, xc, dm0)[1]
        ev1, vxc1 = rks.get_vxc_full_response(mf._numint, mol, grids, xc, dm0)
        p0, p1 = mol.aoslice_by_atom()[0][2:]
        exc1_approx = numpy.einsum('xij,ij->x', vxc[:,p0:p1], dm0[p0:p1])*2
        exc1_full = numpy.einsum('xij,ij->x', vxc1[:,p0:p1], dm0[p0:p1])*2 + ev1[0]
        self.assertAlmostEqual(dexc_t, exc1_approx[2], 2)
        self.assertAlmostEqual(dexc_t, exc1_full[2], 5)

        xc = 'pbe,'
        exc0 = dft.numint.nr_rks(mf0._numint, mol0, grids0, xc, dm0)[1]
        exc1 = dft.numint.nr_rks(mf1._numint, mol1, grids1, xc, dm0)[1]

        grids0_w = copy.copy(grids0)
        grids0_w.weights = grids1.weights
        grids0_c = copy.copy(grids0)
        grids0_c.coords = grids1.coords
        exc0_w = dft.numint.nr_rks(mf0._numint, mol0, grids0_w, xc, dm0)[1]
        exc0_c = dft.numint.nr_rks(mf1._numint, mol1, grids0_c, xc, dm0)[1]

        dexc_t = (exc1 - exc0) * denom
        dexc_c = (exc0_c - exc0) * denom
        dexc_w = (exc0_w - exc0) * denom
        self.assertAlmostEqual(dexc_t, dexc_c+dexc_w, 4)

        vxc = rks.get_vxc(mf._numint, mol, grids, xc, dm0)[1]
        ev1, vxc1 = rks.get_vxc_full_response(mf._numint, mol, grids, xc, dm0)
        p0, p1 = mol.aoslice_by_atom()[0][2:]
        exc1_approx = numpy.einsum('xij,ij->x', vxc[:,p0:p1], dm0[p0:p1])*2
        exc1_full = numpy.einsum('xij,ij->x', vxc1[:,p0:p1], dm0[p0:p1])*2 + ev1[0]
        self.assertAlmostEqual(dexc_t, exc1_approx[2], 2)
        self.assertAlmostEqual(dexc_t, exc1_full[2], 5)

        xc = 'pbe0'
        grids.radii_adjust = None
        grids0.radii_adjust = None
        grids1.radii_adjust = None
        exc0 = dft.numint.nr_rks(mf0._numint, mol0, grids0, xc, dm0)[1]
        exc1 = dft.numint.nr_rks(mf1._numint, mol1, grids1, xc, dm0)[1]

        grids0_w = copy.copy(grids0)
        grids0_w.weights = grids1.weights
        grids0_c = copy.copy(grids0)
        grids0_c.coords = grids1.coords
        exc0_w = dft.numint.nr_rks(mf0._numint, mol0, grids0_w, xc, dm0)[1]
        exc0_c = dft.numint.nr_rks(mf1._numint, mol1, grids0_c, xc, dm0)[1]

        dexc_t = (exc1 - exc0) * denom
        dexc_c = (exc0_c - exc0) * denom
        dexc_w = (exc0_w - exc0) * denom
        self.assertAlmostEqual(dexc_t, dexc_c+dexc_w, 4)

        vxc = rks.get_vxc(mf._numint, mol, grids, xc, dm0)[1]
        ev1, vxc1 = rks.get_vxc_full_response(mf._numint, mol, grids, xc, dm0)
        p0, p1 = mol.aoslice_by_atom()[0][2:]
        exc1_approx = numpy.einsum('xij,ij->x', vxc[:,p0:p1], dm0[p0:p1])*2
        exc1_full = numpy.einsum('xij,ij->x', vxc1[:,p0:p1], dm0[p0:p1])*2 + ev1[0]
        self.assertAlmostEqual(dexc_t, exc1_approx[2], 1)
#FIXME: exc1_full is quite different to the finite difference results, why?
        self.assertAlmostEqual(dexc_t, exc1_full[2], 2)
Beispiel #3
0
    def test_get_vxc(self):
        mol = gto.Mole()
        mol.verbose = 0
        mol.atom = [['O', (0., 0., 0.)], [1, (0., -0.757, 0.587)],
                    [1, (0., 0.757, 0.587)]]
        mol.basis = '631g'
        mol.build()
        mf = dft.RKS(mol)
        mf.conv_tol = 1e-12
        mf.grids.radii_adjust = radi.becke_atomic_radii_adjust
        mf.scf()
        g = rks.Gradients(mf)
        g.grid_response = True
        g0 = g.kernel()
        dm0 = mf.make_rdm1()

        mol0 = gto.Mole()
        mol0.verbose = 0
        mol0.atom = [['O', (0., 0., -0.00001)], [1, (0., -0.757, 0.587)],
                     [1, (0., 0.757, 0.587)]]
        mol0.basis = '631g'
        mol0.build()
        mf0 = dft.RKS(mol0)
        mf0.grids.radii_adjust = radi.becke_atomic_radii_adjust
        mf0.conv_tol = 1e-12
        e0 = mf0.scf()

        denom = 1 / .00002 * lib.param.BOHR
        mol1 = gto.Mole()
        mol1.verbose = 0
        mol1.atom = [['O', (0., 0., 0.00001)], [1, (0., -0.757, 0.587)],
                     [1, (0., 0.757, 0.587)]]
        mol1.basis = '631g'
        mol1.build()
        mf1 = dft.RKS(mol1)
        mf1.grids.radii_adjust = radi.becke_atomic_radii_adjust
        mf1.conv_tol = 1e-12
        e1 = mf1.scf()
        self.assertAlmostEqual((e1 - e0) * denom, g0[0, 2], 6)

        # grids response have non-negligible effects for small grids
        grids = dft.gen_grid.Grids(mol)
        grids.atom_grid = (20, 86)
        grids.build(with_non0tab=False)
        grids0 = dft.gen_grid.Grids(mol0)
        grids0.atom_grid = (20, 86)
        grids0.build(with_non0tab=False)
        grids1 = dft.gen_grid.Grids(mol1)
        grids1.atom_grid = (20, 86)
        grids1.build(with_non0tab=False)
        xc = 'lda,'
        exc0 = dft.numint.nr_rks(mf0._numint, mol0, grids0, xc, dm0)[1]
        exc1 = dft.numint.nr_rks(mf1._numint, mol1, grids1, xc, dm0)[1]

        grids0_w = copy.copy(grids0)
        grids0_w.weights = grids1.weights
        grids0_c = copy.copy(grids0)
        grids0_c.coords = grids1.coords
        exc0_w = dft.numint.nr_rks(mf0._numint, mol0, grids0_w, xc, dm0)[1]
        exc0_c = dft.numint.nr_rks(mf1._numint, mol1, grids0_c, xc, dm0)[1]

        dexc_t = (exc1 - exc0) * denom
        dexc_c = (exc0_c - exc0) * denom
        dexc_w = (exc0_w - exc0) * denom
        self.assertAlmostEqual(dexc_t, dexc_c + dexc_w, 4)

        vxc = rks.get_vxc(mf._numint, mol, grids, xc, dm0)[1]
        ev1, vxc1 = rks.get_vxc_full_response(mf._numint, mol, grids, xc, dm0)
        p0, p1 = mol.aoslice_by_atom()[0][2:]
        exc1_approx = numpy.einsum('xij,ij->x', vxc[:, p0:p1], dm0[p0:p1]) * 2
        exc1_full = numpy.einsum('xij,ij->x', vxc1[:, p0:p1],
                                 dm0[p0:p1]) * 2 + ev1[0]
        self.assertAlmostEqual(dexc_t, exc1_approx[2], 2)
        self.assertAlmostEqual(dexc_t, exc1_full[2], 5)

        xc = 'pbe,'
        exc0 = dft.numint.nr_rks(mf0._numint, mol0, grids0, xc, dm0)[1]
        exc1 = dft.numint.nr_rks(mf1._numint, mol1, grids1, xc, dm0)[1]

        grids0_w = copy.copy(grids0)
        grids0_w.weights = grids1.weights
        grids0_c = copy.copy(grids0)
        grids0_c.coords = grids1.coords
        exc0_w = dft.numint.nr_rks(mf0._numint, mol0, grids0_w, xc, dm0)[1]
        exc0_c = dft.numint.nr_rks(mf1._numint, mol1, grids0_c, xc, dm0)[1]

        dexc_t = (exc1 - exc0) * denom
        dexc_c = (exc0_c - exc0) * denom
        dexc_w = (exc0_w - exc0) * denom
        self.assertAlmostEqual(dexc_t, dexc_c + dexc_w, 4)

        vxc = rks.get_vxc(mf._numint, mol, grids, xc, dm0)[1]
        ev1, vxc1 = rks.get_vxc_full_response(mf._numint, mol, grids, xc, dm0)
        p0, p1 = mol.aoslice_by_atom()[0][2:]
        exc1_approx = numpy.einsum('xij,ij->x', vxc[:, p0:p1], dm0[p0:p1]) * 2
        exc1_full = numpy.einsum('xij,ij->x', vxc1[:, p0:p1],
                                 dm0[p0:p1]) * 2 + ev1[0]
        self.assertAlmostEqual(dexc_t, exc1_approx[2], 2)
        self.assertAlmostEqual(dexc_t, exc1_full[2], 5)

        xc = 'pbe0'
        grids.radii_adjust = None
        grids0.radii_adjust = None
        grids1.radii_adjust = None
        exc0 = dft.numint.nr_rks(mf0._numint, mol0, grids0, xc, dm0)[1]
        exc1 = dft.numint.nr_rks(mf1._numint, mol1, grids1, xc, dm0)[1]

        grids0_w = copy.copy(grids0)
        grids0_w.weights = grids1.weights
        grids0_c = copy.copy(grids0)
        grids0_c.coords = grids1.coords
        exc0_w = dft.numint.nr_rks(mf0._numint, mol0, grids0_w, xc, dm0)[1]
        exc0_c = dft.numint.nr_rks(mf1._numint, mol1, grids0_c, xc, dm0)[1]

        dexc_t = (exc1 - exc0) * denom
        dexc_c = (exc0_c - exc0) * denom
        dexc_w = (exc0_w - exc0) * denom
        self.assertAlmostEqual(dexc_t, dexc_c + dexc_w, 4)

        vxc = rks.get_vxc(mf._numint, mol, grids, xc, dm0)[1]
        ev1, vxc1 = rks.get_vxc_full_response(mf._numint, mol, grids, xc, dm0)
        p0, p1 = mol.aoslice_by_atom()[0][2:]
        exc1_approx = numpy.einsum('xij,ij->x', vxc[:, p0:p1], dm0[p0:p1]) * 2
        exc1_full = numpy.einsum('xij,ij->x', vxc1[:, p0:p1],
                                 dm0[p0:p1]) * 2 + ev1[0]
        self.assertAlmostEqual(dexc_t, exc1_approx[2], 1)
        #FIXME: exc1_full is quite different to the finite difference results, why?
        self.assertAlmostEqual(dexc_t, exc1_full[2], 2)