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
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)
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)