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)
def _eval_xc_eff(ni, xc_code, rho, deriv=1, omega=None, xctype=None, verbose=None): r'''Returns the derivative tensor against the density parameters [[density_a, (nabla_x)_a, (nabla_y)_a, (nabla_z)_a, tau_a], [density_b, (nabla_x)_b, (nabla_y)_b, (nabla_z)_b, tau_b]]. It differs from the eval_xc method in the derivatives of non-local part. The eval_xc method returns the XC functional derivatives to sigma (|\nabla \rho|^2) Args: rho: 2-dimensional or 3-dimensional array Total density and spin density (and their derivatives if GGA or MGGA functionals) on grids Kwargs: deriv: int derivative orders omega: float define the exponent in the attenuated Coulomb for RSH functional ''' if omega is None: omega = ni.omega if xctype is None: xctype = ni._xc_type(xc_code) if ni.collinear[0] == 'c': # collinear t = rho[0] s = rho[3] elif ni.collinear[0] == 'n': # ncol t = rho[0] m = rho[1:4] s = lib.norm(m, axis=0) elif ni.collinear[0] == 'm': # mcol # called by mcfun.eval_xc_eff which passes (rho, s) only t, s = rho else: raise RuntimeError(f'Unknown collinear scheme {ni.collinear}') if xctype == 'MGGA': ngrids = rho.shape[2] rhop = np.empty((2, 6, ngrids)) rhop[0,:4] = (t[:4] + s[:4]) * .5 rhop[1,:4] = (t[:4] - s[:4]) * .5 # Padding for laplacian rhop[:,4] = 0 rhop[0,5] = (t[4] + s[4]) * .5 rhop[1,5] = (t[4] - s[4]) * .5 else: rhop = np.stack([(t + s) * .5, (t - s) * .5]) spin = 1 exc, vxc, fxc, kxc = ni.eval_xc(xc_code, rhop, spin, 0, deriv, omega, verbose) if deriv > 2: kxc = xc_deriv.transform_kxc(rhop, fxc, kxc, xctype, spin) if deriv > 1: fxc = xc_deriv.transform_fxc(rhop, vxc, fxc, xctype, spin) if deriv > 0: vxc = xc_deriv.transform_vxc(rhop, vxc, xctype, spin) return exc, vxc, fxc, kxc
def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None): r'''A and B matrices for TDDFT response function. A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj) B[i,a,j,b] = (ia||jb) Spin symmetry is considered in the returned A, B lists. List A has three items: (A_aaaa, A_aabb, A_bbbb). A_bbaa = A_aabb.transpose(2,3,0,1). B has three items: (B_aaaa, B_aabb, B_bbbb). B_bbaa = B_aabb.transpose(2,3,0,1). ''' if mo_energy is None: mo_energy = mf.mo_energy if mo_coeff is None: mo_coeff = mf.mo_coeff if mo_occ is None: mo_occ = mf.mo_occ mol = mf.mol nao = mol.nao_nr() occidx_a = numpy.where(mo_occ[0] == 1)[0] viridx_a = numpy.where(mo_occ[0] == 0)[0] occidx_b = numpy.where(mo_occ[1] == 1)[0] viridx_b = numpy.where(mo_occ[1] == 0)[0] orbo_a = mo_coeff[0][:, occidx_a] orbv_a = mo_coeff[0][:, viridx_a] orbo_b = mo_coeff[1][:, occidx_b] orbv_b = mo_coeff[1][:, viridx_b] nocc_a = orbo_a.shape[1] nvir_a = orbv_a.shape[1] nocc_b = orbo_b.shape[1] nvir_b = orbv_b.shape[1] mo_a = numpy.hstack((orbo_a, orbv_a)) mo_b = numpy.hstack((orbo_b, orbv_b)) nmo_a = nocc_a + nvir_a nmo_b = nocc_b + nvir_b e_ia_a = (mo_energy[0][viridx_a, None] - mo_energy[0][occidx_a]).T e_ia_b = (mo_energy[1][viridx_b, None] - mo_energy[1][occidx_b]).T a_aa = numpy.diag(e_ia_a.ravel()).reshape(nocc_a, nvir_a, nocc_a, nvir_a) a_bb = numpy.diag(e_ia_b.ravel()).reshape(nocc_b, nvir_b, nocc_b, nvir_b) a_ab = numpy.zeros((nocc_a, nvir_a, nocc_b, nvir_b)) b_aa = numpy.zeros_like(a_aa) b_ab = numpy.zeros_like(a_ab) b_bb = numpy.zeros_like(a_bb) a = (a_aa, a_ab, a_bb) b = (b_aa, b_ab, b_bb) def add_hf_(a, b, hyb=1): eri_aa = ao2mo.general(mol, [orbo_a, mo_a, mo_a, mo_a], compact=False) eri_ab = ao2mo.general(mol, [orbo_a, mo_a, mo_b, mo_b], compact=False) eri_bb = ao2mo.general(mol, [orbo_b, mo_b, mo_b, mo_b], compact=False) eri_aa = eri_aa.reshape(nocc_a, nmo_a, nmo_a, nmo_a) eri_ab = eri_ab.reshape(nocc_a, nmo_a, nmo_b, nmo_b) eri_bb = eri_bb.reshape(nocc_b, nmo_b, nmo_b, nmo_b) a_aa, a_ab, a_bb = a b_aa, b_ab, b_bb = b a_aa += numpy.einsum('iabj->iajb', eri_aa[:nocc_a, nocc_a:, nocc_a:, :nocc_a]) a_aa -= numpy.einsum('ijba->iajb', eri_aa[:nocc_a, :nocc_a, nocc_a:, nocc_a:]) * hyb b_aa += numpy.einsum('iajb->iajb', eri_aa[:nocc_a, nocc_a:, :nocc_a, nocc_a:]) b_aa -= numpy.einsum('jaib->iajb', eri_aa[:nocc_a, nocc_a:, :nocc_a, nocc_a:]) * hyb a_bb += numpy.einsum('iabj->iajb', eri_bb[:nocc_b, nocc_b:, nocc_b:, :nocc_b]) a_bb -= numpy.einsum('ijba->iajb', eri_bb[:nocc_b, :nocc_b, nocc_b:, nocc_b:]) * hyb b_bb += numpy.einsum('iajb->iajb', eri_bb[:nocc_b, nocc_b:, :nocc_b, nocc_b:]) b_bb -= numpy.einsum('jaib->iajb', eri_bb[:nocc_b, nocc_b:, :nocc_b, nocc_b:]) * hyb a_ab += numpy.einsum('iabj->iajb', eri_ab[:nocc_a, nocc_a:, nocc_b:, :nocc_b]) b_ab += numpy.einsum('iajb->iajb', eri_ab[:nocc_a, nocc_a:, :nocc_b, nocc_b:]) if isinstance(mf, scf.hf.KohnShamDFT): from pyscf.dft import xc_deriv ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True) if getattr(mf, 'nlc', '') != '': logger.warn( mf, 'NLC functional found in DFT object. Its second ' 'deriviative is not available. Its contribution is ' 'not included in the response function.') omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) add_hf_(a, b, hyb) xctype = ni._xc_type(mf.xc) dm0 = mf.make_rdm1(mo_coeff, mo_occ) make_rho = ni._gen_rho_evaluator(mol, dm0, hermi=1)[0] mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .8 - mem_now) if xctype == 'LDA': ao_deriv = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho0a = make_rho(0, ao, mask, xctype) rho0b = make_rho(1, ao, mask, xctype) fxc = ni.eval_xc(mf.xc, (rho0a, rho0b), 1, deriv=2)[2] u_u, u_d, d_d = fxc[0].T rho_o_a = lib.einsum('rp,pi->ri', ao, orbo_a) rho_v_a = lib.einsum('rp,pi->ri', ao, orbv_a) rho_o_b = lib.einsum('rp,pi->ri', ao, orbo_b) rho_v_b = lib.einsum('rp,pi->ri', ao, orbv_b) rho_ov_a = numpy.einsum('ri,ra->ria', rho_o_a, rho_v_a) rho_ov_b = numpy.einsum('ri,ra->ria', rho_o_b, rho_v_b) w_ov = numpy.einsum('ria,r->ria', rho_ov_a, weight * u_u) iajb = lib.einsum('ria,rjb->iajb', rho_ov_a, w_ov) a_aa += iajb b_aa += iajb w_ov = numpy.einsum('ria,r->ria', rho_ov_b, weight * u_d) iajb = lib.einsum('ria,rjb->iajb', rho_ov_a, w_ov) a_ab += iajb b_ab += iajb w_ov = numpy.einsum('ria,r->ria', rho_ov_b, weight * d_d) iajb = lib.einsum('ria,rjb->iajb', rho_ov_b, w_ov) a_bb += iajb b_bb += iajb elif xctype == 'GGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho0a = make_rho(0, ao, mask, xctype) rho0b = make_rho(1, ao, mask, xctype) rho = (rho0a, rho0b) vxc, fxc = ni.eval_xc(mf.xc, rho, 1, deriv=2)[1:3] fxc = xc_deriv.transform_fxc(rho, vxc, fxc, xctype, spin=1) wfxc = fxc * weight rho_o_a = lib.einsum('xrp,pi->xri', ao, orbo_a) rho_v_a = lib.einsum('xrp,pi->xri', ao, orbv_a) rho_o_b = lib.einsum('xrp,pi->xri', ao, orbo_b) rho_v_b = lib.einsum('xrp,pi->xri', ao, orbv_b) rho_ov_a = numpy.einsum('xri,ra->xria', rho_o_a, rho_v_a[0]) rho_ov_b = numpy.einsum('xri,ra->xria', rho_o_b, rho_v_b[0]) rho_ov_a[1:4] += numpy.einsum('ri,xra->xria', rho_o_a[0], rho_v_a[1:4]) rho_ov_b[1:4] += numpy.einsum('ri,xra->xria', rho_o_b[0], rho_v_b[1:4]) w_ov_aa = numpy.einsum('xyr,xria->yria', wfxc[0, :, 0], rho_ov_a) w_ov_ab = numpy.einsum('xyr,xria->yria', wfxc[0, :, 1], rho_ov_a) w_ov_bb = numpy.einsum('xyr,xria->yria', wfxc[1, :, 1], rho_ov_b) iajb = lib.einsum('xria,xrjb->iajb', w_ov_aa, rho_ov_a) a_aa += iajb b_aa += iajb iajb = lib.einsum('xria,xrjb->iajb', w_ov_bb, rho_ov_b) a_bb += iajb b_bb += iajb iajb = lib.einsum('xria,xrjb->iajb', w_ov_ab, rho_ov_b) a_ab += iajb b_ab += iajb elif xctype == 'HF': pass elif xctype == 'NLC': raise NotImplementedError('NLC') elif xctype == 'MGGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho0a = make_rho(0, ao, mask, xctype) rho0b = make_rho(1, ao, mask, xctype) rho = (rho0a, rho0b) vxc, fxc = ni.eval_xc(mf.xc, rho, 1, deriv=2)[1:3] fxc = xc_deriv.transform_fxc(rho, vxc, fxc, xctype, spin=1) wfxc = fxc * weight rho_oa = lib.einsum('xrp,pi->xri', ao, orbo_a) rho_ob = lib.einsum('xrp,pi->xri', ao, orbo_b) rho_va = lib.einsum('xrp,pi->xri', ao, orbv_a) rho_vb = lib.einsum('xrp,pi->xri', ao, orbv_b) rho_ov_a = numpy.einsum('xri,ra->xria', rho_oa, rho_va[0]) rho_ov_b = numpy.einsum('xri,ra->xria', rho_ob, rho_vb[0]) rho_ov_a[1:4] += numpy.einsum('ri,xra->xria', rho_oa[0], rho_va[1:4]) rho_ov_b[1:4] += numpy.einsum('ri,xra->xria', rho_ob[0], rho_vb[1:4]) tau_ov_a = numpy.einsum('xri,xra->ria', rho_oa[1:4], rho_va[1:4]) * .5 tau_ov_b = numpy.einsum('xri,xra->ria', rho_ob[1:4], rho_vb[1:4]) * .5 rho_ov_a = numpy.vstack([rho_ov_a, tau_ov_a[numpy.newaxis]]) rho_ov_b = numpy.vstack([rho_ov_b, tau_ov_b[numpy.newaxis]]) w_ov_aa = numpy.einsum('xyr,xria->yria', wfxc[0, :, 0], rho_ov_a) w_ov_ab = numpy.einsum('xyr,xria->yria', wfxc[0, :, 1], rho_ov_a) w_ov_bb = numpy.einsum('xyr,xria->yria', wfxc[1, :, 1], rho_ov_b) iajb = lib.einsum('xria,xrjb->iajb', w_ov_aa, rho_ov_a) a_aa += iajb b_aa += iajb iajb = lib.einsum('xria,xrjb->iajb', w_ov_bb, rho_ov_b) a_bb += iajb b_bb += iajb iajb = lib.einsum('xria,xrjb->iajb', w_ov_ab, rho_ov_b) a_ab += iajb b_ab += iajb else: add_hf_(a, b) return a, b
def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None): r'''A and B matrices for TDDFT response function. A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj) B[i,a,j,b] = (ia||jb) ''' if mo_energy is None: mo_energy = mf.mo_energy if mo_coeff is None: mo_coeff = mf.mo_coeff if mo_occ is None: mo_occ = mf.mo_occ assert(mo_coeff.dtype == numpy.double) mol = mf.mol nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] nvir = orbv.shape[1] nocc = orbo.shape[1] mo = numpy.hstack((orbo,orbv)) nmo = nocc + nvir e_ia = lib.direct_sum('a-i->ia', mo_energy[viridx], mo_energy[occidx]) a = numpy.diag(e_ia.ravel()).reshape(nocc,nvir,nocc,nvir) b = numpy.zeros_like(a) def add_hf_(a, b, hyb=1): eri_mo = ao2mo.general(mol, [orbo,mo,mo,mo], compact=False) eri_mo = eri_mo.reshape(nocc,nmo,nmo,nmo) a += numpy.einsum('iabj->iajb', eri_mo[:nocc,nocc:,nocc:,:nocc]) * 2 a -= numpy.einsum('ijba->iajb', eri_mo[:nocc,:nocc,nocc:,nocc:]) * hyb b += numpy.einsum('iajb->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * 2 b -= numpy.einsum('jaib->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * hyb if isinstance(mf, scf.hf.KohnShamDFT): from pyscf.dft import xc_deriv ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True) if getattr(mf, 'nlc', '') != '': logger.warn(mf, 'NLC functional found in DFT object. Its second ' 'deriviative is not available. Its contribution is ' 'not included in the response function.') omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) add_hf_(a, b, hyb) xctype = ni._xc_type(mf.xc) dm0 = mf.make_rdm1(mo_coeff, mo_occ) make_rho = ni._gen_rho_evaluator(mol, dm0, hermi=1)[0] mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory*.8-mem_now) if xctype == 'LDA': ao_deriv = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho = make_rho(0, ao, mask, xctype) fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[2] frr = fxc[0] rho_o = lib.einsum('rp,pi->ri', ao, orbo) rho_v = lib.einsum('rp,pi->ri', ao, orbv) rho_ov = numpy.einsum('ri,ra->ria', rho_o, rho_v) w_ov = numpy.einsum('ria,r->ria', rho_ov, weight*frr) iajb = lib.einsum('ria,rjb->iajb', rho_ov, w_ov) * 2 a += iajb b += iajb elif xctype == 'GGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho = make_rho(0, ao, mask, xctype) vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] fxc = xc_deriv.transform_fxc(rho, vxc, fxc, xctype, spin=0) wfxc = fxc * weight rho_o = lib.einsum('xrp,pi->xri', ao, orbo) rho_v = lib.einsum('xrp,pi->xri', ao, orbv) rho_ov = numpy.einsum('xri,ra->xria', rho_o, rho_v[0]) rho_ov[1:4] += numpy.einsum('ri,xra->xria', rho_o[0], rho_v[1:4]) w_ov = numpy.einsum('xyr,xria->yria', wfxc, rho_ov) iajb = lib.einsum('xria,xrjb->iajb', w_ov, rho_ov) * 2 a += iajb b += iajb elif xctype == 'HF': pass elif xctype == 'NLC': raise NotImplementedError('NLC') elif xctype == 'MGGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho = make_rho(0, ao, mask, xctype) vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] fxc = xc_deriv.transform_fxc(rho, vxc, fxc, xctype, spin=0) wfxc = fxc * weight rho_o = lib.einsum('xrp,pi->xri', ao, orbo) rho_v = lib.einsum('xrp,pi->xri', ao, orbv) rho_ov = numpy.einsum('xri,ra->xria', rho_o, rho_v[0]) rho_ov[1:4] += numpy.einsum('ri,xra->xria', rho_o[0], rho_v[1:4]) tau_ov = numpy.einsum('xri,xra->ria', rho_o[1:4], rho_v[1:4]) * .5 rho_ov = numpy.vstack([rho_ov, tau_ov[numpy.newaxis]]) w_ov = numpy.einsum('xyr,xria->yria', wfxc, rho_ov) iajb = lib.einsum('xria,xrjb->iajb', w_ov, rho_ov) * 2 a += iajb b += iajb else: add_hf_(a, b) return a, b