def test_ft_ao_with_kpts(self): numpy.random.seed(1) kpt = numpy.random.random(3) coords = pdft.gen_grid.gen_uniform_grids(cell) aoR = pdft.numint.eval_ao(cell, coords, kpt=kpt) ngs, nao = aoR.shape expmikr = numpy.exp(-1j * numpy.dot(coords, kpt)) ref = numpy.asarray( [tools.fftk(aoR[:, i], cell.gs, expmikr) for i in range(nao)]) ref = ref.T * (cell.vol / ngs) dat = ft_ao.ft_ao(cell, cell.Gv, kpt=kpt) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 0] - dat[:, 0]), 1.3359899490499813e-10, 9) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 1] - dat[:, 1]), 0.0042404556036939756, 4) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 2:] - dat[:, 2:]), 4.8856357999633564e-14, 9) coords = pdft.gen_grid.gen_uniform_grids(cell1) aoR = pdft.numint.eval_ao(cell1, coords, kpt=kpt) ngs, nao = aoR.shape expmikr = numpy.exp(-1j * numpy.dot(coords, kpt)) ref = numpy.asarray( [tools.fftk(aoR[:, i], cell1.gs, expmikr) for i in range(nao)]) ref = ref.T * (cell1.vol / ngs) dat = ft_ao.ft_ao(cell1, cell1.Gv, kpt=kpt) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 0] - dat[:, 0]), 0, 5) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 1] - dat[:, 1]), 0, 3) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 2:] - dat[:, 2:]), 0, 3)
def get_mo_pairs_G_old(cell, mo_coeffs, kpts=None, q=None): '''Calculate forward (G|ij) and "inverse" (ij|G) FFT of all MO pairs. TODO: - Implement simplifications for real orbitals. Args: mo_coeff: length-2 list of (nao,nmo) ndarrays The two sets of MO coefficients to use in calculating the product |ij). Returns: mo_pairs_G, mo_pairs_invG : (ngrids, nmoi*nmoj) ndarray The FFTs of the real-space MO pairs. ''' coords = gen_uniform_grids(cell) if kpts is None: q = np.zeros(3) aoR = eval_ao(cell, coords) ngrids = aoR.shape[0] if np.array_equal(mo_coeffs[0], mo_coeffs[1]): nmoi = nmoj = mo_coeffs[0].shape[1] moiR = mojR = einsum('ri,ia->ra', aoR, mo_coeffs[0]) else: nmoi = mo_coeffs[0].shape[1] nmoj = mo_coeffs[1].shape[1] moiR = einsum('ri,ia->ra', aoR, mo_coeffs[0]) mojR = einsum('ri,ia->ra', aoR, mo_coeffs[1]) else: if q is None: q = kpts[1] - kpts[0] aoR_ki = eval_ao(cell, coords, kpt=kpts[0]) aoR_kj = eval_ao(cell, coords, kpt=kpts[1]) ngrids = aoR_ki.shape[0] nmoi = mo_coeffs[0].shape[1] nmoj = mo_coeffs[1].shape[1] moiR = einsum('ri,ia->ra', aoR_ki, mo_coeffs[0]) mojR = einsum('ri,ia->ra', aoR_kj, mo_coeffs[1]) mo_pairs_R = np.einsum('ri,rj->rij', np.conj(moiR), mojR) mo_pairs_G = np.zeros([ngrids, nmoi * nmoj], np.complex128) mo_pairs_invG = np.zeros([ngrids, nmoi * nmoj], np.complex128) fac = np.exp(-1j * np.dot(coords, q)) for i in range(nmoi): for j in range(nmoj): mo_pairs_G[:, i * nmoj + j] = tools.fftk(mo_pairs_R[:, i, j], cell.mesh, fac) mo_pairs_invG[:, i * nmoj + j] = np.conj( tools.fftk(np.conj(mo_pairs_R[:, i, j]), cell.mesh, fac.conj())) return mo_pairs_G, mo_pairs_invG
def get_mo_pairs_G_old(cell, mo_coeffs, kpts=None, q=None): '''Calculate forward (G|ij) and "inverse" (ij|G) FFT of all MO pairs. TODO: - Implement simplifications for real orbitals. Args: mo_coeff: length-2 list of (nao,nmo) ndarrays The two sets of MO coefficients to use in calculating the product |ij). Returns: mo_pairs_G, mo_pairs_invG : (ngs, nmoi*nmoj) ndarray The FFTs of the real-space MO pairs. ''' coords = gen_uniform_grids(cell) if kpts is None: q = np.zeros(3) aoR = eval_ao(cell, coords) ngs = aoR.shape[0] if np.array_equal(mo_coeffs[0], mo_coeffs[1]): nmoi = nmoj = mo_coeffs[0].shape[1] moiR = mojR = einsum('ri,ia->ra', aoR, mo_coeffs[0]) else: nmoi = mo_coeffs[0].shape[1] nmoj = mo_coeffs[1].shape[1] moiR = einsum('ri,ia->ra', aoR, mo_coeffs[0]) mojR = einsum('ri,ia->ra', aoR, mo_coeffs[1]) else: if q is None: q = kpts[1]-kpts[0] aoR_ki = eval_ao(cell, coords, kpt=kpts[0]) aoR_kj = eval_ao(cell, coords, kpt=kpts[1]) ngs = aoR_ki.shape[0] nmoi = mo_coeffs[0].shape[1] nmoj = mo_coeffs[1].shape[1] moiR = einsum('ri,ia->ra', aoR_ki, mo_coeffs[0]) mojR = einsum('ri,ia->ra', aoR_kj, mo_coeffs[1]) mo_pairs_R = np.einsum('ri,rj->rij', np.conj(moiR), mojR) mo_pairs_G = np.zeros([ngs,nmoi*nmoj], np.complex128) mo_pairs_invG = np.zeros([ngs,nmoi*nmoj], np.complex128) fac = np.exp(-1j*np.dot(coords, q)) for i in xrange(nmoi): for j in xrange(nmoj): mo_pairs_G[:,i*nmoj+j] = tools.fftk(mo_pairs_R[:,i,j], cell.gs, fac) mo_pairs_invG[:,i*nmoj+j] = np.conj(tools.fftk(np.conj(mo_pairs_R[:,i,j]), cell.gs, fac.conj())) return mo_pairs_G, mo_pairs_invG
def test_ft_aoao_with_kpts(self): numpy.random.seed(1) kpti, kptj = numpy.random.random((2, 3)) dat = ft_ao.ft_aopair(cell, cell.Gv, kpti_kptj=(kpti, kptj)) self.assertAlmostEqual(finger(dat), -0.80184732435570638 + 2.4078835207597176j, 9) coords = pdft.gen_grid.gen_uniform_grids(cell) aoi = pdft.numint.eval_ao(cell, coords, kpt=kpti) aoj = pdft.numint.eval_ao(cell, coords, kpt=kptj) ngs, nao = aoj.shape q = kptj - kpti expmikr = numpy.exp(-1j * numpy.dot(coords, q)) ref = numpy.asarray([ tools.fftk(aoi[:, i].conj() * aoj[:, j], cell.gs, expmikr) for i in range(nao) for j in range(nao) ]) ref = ref.reshape(nao, nao, -1).transpose(2, 0, 1) * (cell.vol / ngs) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 0, 0] - dat[:, 0, 0]), 0, 5) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 1, 1] - dat[:, 1, 1]), 0.023225471785938184, 4) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 2:, 2:] - dat[:, 2:, 2:]), 0, 9) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 0, 2:] - dat[:, 0, 2:]), 0, 9) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 2:, 0] - dat[:, 2:, 0]), 0, 9) coords = pdft.gen_grid.gen_uniform_grids(cell1) aoi = pdft.numint.eval_ao(cell1, coords, kpt=kpti) aoj = pdft.numint.eval_ao(cell1, coords, kpt=kptj) ngs, nao = aoj.shape q = kptj - kpti dat = ft_ao.ft_aopair(cell1, cell1.Gv, kpti_kptj=(kpti, kptj), q=q) self.assertAlmostEqual(finger(dat), 0.72664436503332241 + 3.2542145296611373j, 9) expmikr = numpy.exp(-1j * numpy.dot(coords, q)) ref = numpy.asarray([ tools.fftk(aoi[:, i].conj() * aoj[:, j], cell1.gs, expmikr) for i in range(nao) for j in range(nao) ]) ref = ref.reshape(nao, nao, -1).transpose(2, 0, 1) * (cell1.vol / ngs) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 0, 0] - dat[:, 0, 0]), 0, 7) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 1, 1] - dat[:, 1, 1]), 0, 7) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 2:, 2:] - dat[:, 2:, 2:]), 0, 7) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 0, 2:] - dat[:, 0, 2:]), 0, 7) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 2:, 0] - dat[:, 2:, 0]), 0, 7)
def prod(ij): i, j = divmod(ij, nao) rhoR = aoR_k1[:,i] * aoR_k2[:,j].conj() rhoG = tools.fftk(rhoR, cell.gs, expmikr) vG = coulG*rhoG vR = tools.ifftk(vG, cell.gs, expmikr.conj()) return vR
def get_vkR_(mf, cell, aoR_k1, aoR_k2, kpt1, kpt2): '''Get the real-space 2-index "exchange" potential V_{i,k1; j,k2}(r). Kwargs: kpts : (nkpts, 3) ndarray The sampled k-points; may be required for G=0 correction. Returns: vR : (ngs, nao, nao) ndarray The real-space "exchange" potential at every grid point, for all AO pairs. Note: This is essentially a density-fitting or resolution-of-the-identity. The returned object is of size ngs*nao**2 and could be precomputed and saved in vhfopt. ''' coords = pyscf.pbc.dft.gen_grid.gen_uniform_grids(cell) ngs, nao = aoR_k1.shape coulG = tools.get_coulG(cell, kpt1-kpt2, exx=True, mf=mf) vR = np.zeros((ngs,nao,nao), dtype=np.complex128) for i in range(nao): for j in range(nao): rhoR = aoR_k1[:,i] * aoR_k2[:,j].conj() rhoG = tools.fftk(rhoR, cell.gs, coords, kpt1-kpt2) vG = coulG*rhoG vR[:,i,j] = tools.ifftk(vG, cell.gs, coords, kpt1-kpt2) return vR
def test_ft_aoao_pair_vs_fft(self): numpy.random.seed(1) kpti, kptj = numpy.random.random((2, 3)) coords = pdft.gen_grid.gen_uniform_grids(cell1) aoi = pdft.numint.eval_ao(cell1, coords, kpt=kpti) aoj = pdft.numint.eval_ao(cell1, coords, kpt=kptj) ngrids, nao = aoj.shape q = kptj - kpti dat = ft_ao.ft_aopair(cell1, cell1.Gv, kpti_kptj=(kpti, kptj), q=q) self.assertAlmostEqual(finger(dat), 0.72664436503332241 + 3.2542145296611373j, 9) expmikr = numpy.exp(-1j * numpy.dot(coords, q)) ref = numpy.asarray([ tools.fftk(aoi[:, i].conj() * aoj[:, j], cell1.mesh, expmikr) for i in range(nao) for j in range(nao) ]) ref = ref.reshape(nao, nao, -1).transpose(2, 0, 1) * (cell1.vol / ngrids) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 0, 0] - dat[:, 0, 0]), 0, 7) self.assertAlmostEqual(numpy.linalg.norm(ref[:, 1, 1] - dat[:, 1, 1]), 0, 7) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 2:, 2:] - dat[:, 2:, 2:]), 0, 7) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 0, 2:] - dat[:, 0, 2:]), 0, 7) self.assertAlmostEqual( numpy.linalg.norm(ref[:, 2:, 0] - dat[:, 2:, 0]), 0, 7)
def prod(ij): i, j = divmod(ij, nao) rhoR = aoR_k1[:, i] * aoR_k2[:, j].conj() rhoG = tools.fftk(rhoR, cell.gs, expmikr) vG = coulG * rhoG vR = tools.ifftk(vG, cell.gs, expmikr.conj()) return vR
def get_hcore(cell, kpts): '''Part of the nuclear gradients of core Hamiltonian''' h1 = np.asarray(cell.pbc_intor('int1e_ipkin', kpts=kpts)) dtype = h1.dtype if cell._pseudo: SI = cell.get_SI() nao = cell.nao_nr() Gv = cell.Gv natom = cell.natm coords = cell.get_uniform_grids() ngrids, nkpts = len(coords), len(kpts) vlocG = get_vlocG(cell) vpplocG = -np.einsum('ij,ij->j', SI, vlocG) vpplocG[0] = np.sum(get_alphas(cell)) vpplocR = tools.ifft(vpplocG, cell.mesh).real fakemol = _make_fakemol() ptr = mole.PTR_ENV_START for kn, kpt in enumerate(kpts): aos = eval_ao_kpts(cell, coords, kpt, deriv=1)[0] vloc = np.einsum('agi,g,gj->aij', aos[1:].conj(), vpplocR, aos[0]) expir = np.exp(-1j * np.dot(coords, kpt)) aokG = np.asarray([ tools.fftk(np.asarray(ao.T, order='C'), cell.mesh, expir).T for ao in aos ]) Gk = Gv + kpt G_rad = lib.norm(Gk, axis=1) vnl = np.zeros(vloc.shape, dtype=np.complex128) for ia in range(natom): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0, mole.ANG_OF] = l fakemol._env[ptr + 3] = .5 * rl**2 fakemol._env[ptr + 4] = rl**(l + 1.5) * np.pi**1.25 pYlm_part = fakemol.eval_gto('GTOval', Gk) pYlm = np.empty((nl, l * 2 + 1, ngrids)) for k in range(nl): qkl = _qli(G_rad * rl, l, k) pYlm[k] = pYlm_part.T * qkl SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,agp->anmp', SPG_lmi, aokG) tmp = np.einsum('ij,ajmp->aimp', hl, SPG_lm_aoG[1:]) vnl += np.einsum('aimp,imq->apq', tmp.conj(), SPG_lm_aoG[0]) vnl *= (1. / ngrids**2) if dtype == np.float64: h1[kn, :] += vloc.real + vnl.real else: h1[kn, :] += vloc + vnl else: raise NotImplementedError return h1
def get_pp_o1(cell, kpt=np.zeros(3)): '''Get the periodic pseudotential nuc-el AO matrix, with G=0 removed. ''' coords = pyscf.pbc.dft.gen_grid.gen_uniform_grids(cell) aoR = pyscf.pbc.dft.numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() vlocG = pseudo.get_vlocG(cell) vpplocG = -np.sum(SI * vlocG, axis=0) # vpploc evaluated in real-space vpplocR = tools.ifft(vpplocG, cell.gs) vpploc = np.dot(aoR.T.conj(), vpplocR.reshape(-1,1)*aoR) # vppnonloc evaluated in reciprocal space aokG = np.empty(aoR.shape, np.complex128) for i in range(nao): aokG[:,i] = tools.fftk(aoR[:,i], cell.gs, coords, kpt) ngs = len(aokG) fakemol = pyscf.gto.Mole() fakemol._atm = np.zeros((1,pyscf.gto.ATM_SLOTS), dtype=np.int32) fakemol._bas = np.zeros((1,pyscf.gto.BAS_SLOTS), dtype=np.int32) fakemol._env = np.zeros(5) fakemol._bas[0,pyscf.gto.NPRIM_OF ] = 1 fakemol._bas[0,pyscf.gto.NCTR_OF ] = 1 fakemol._bas[0,pyscf.gto.PTR_EXP ] = 3 fakemol._bas[0,pyscf.gto.PTR_COEFF] = 4 Gv = np.asarray(cell.Gv+kpt) G_rad = pyscf.lib.norm(Gv, axis=1) vppnl = np.zeros((nao,nao), dtype=np.complex128) for ia in range(cell.natm): pp = cell._pseudo[cell.atom_symbol(ia)] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0,pyscf.gto.ANG_OF] = l fakemol._env[3] = .5*rl**2 fakemol._env[4] = rl**(l+1.5)*np.pi**1.25 pYlm_part = pyscf.dft.numint.eval_ao(fakemol, Gv, deriv=0) pYlm = np.empty((nl,l*2+1,ngs)) for k in range(nl): qkl = pseudo.pp._qli(G_rad*rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) tmp = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += np.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) vppnl *= (1./ngs**2) return vpploc + vppnl
def hcore_deriv(atm_id): shl0, shl1, p0, p1 = aoslices[atm_id] symb = cell.atom_symbol(atm_id) fakemol = _make_fakemol() vloc_g = 1j * np.einsum('ga,g->ag', Gv, SI[atm_id] * vlocG[atm_id]) nkpts, nao = h1.shape[0], h1.shape[2] hcore = np.zeros([3, nkpts, nao, nao], dtype=h1.dtype) for kn, kpt in enumerate(kpts): ao = eval_ao_kpts(cell, coords, kpt)[0] rho = np.einsum('gi,gj->gij', ao.conj(), ao) for ax in range(3): vloc_R = tools.ifft(vloc_g[ax], mesh).real vloc = np.einsum('gij,g->ij', rho, vloc_R) hcore[ax, kn] += vloc rho = None aokG = tools.fftk(np.asarray(ao.T, order='C'), mesh, np.exp(-1j * np.dot(coords, kpt))).T ao = None Gk = Gv + kpt G_rad = lib.norm(Gk, axis=1) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0, mole.ANG_OF] = l fakemol._env[ptr + 3] = .5 * rl**2 fakemol._env[ptr + 4] = rl**(l + 1.5) * np.pi**1.25 pYlm_part = fakemol.eval_gto('GTOval', Gk) pYlm = np.empty((nl, l * 2 + 1, ngrids)) for k in range(nl): qkl = _qli(G_rad * rl, l, k) pYlm[k] = pYlm_part.T * qkl SPG_lmi = np.einsum('g,nmg->nmg', SI[atm_id].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) SPG_lmi_G = 1j * np.einsum('nmg, ga->anmg', SPG_lmi, Gv) SPG_lm_G_aoG = np.einsum('anmg, gp->anmp', SPG_lmi_G, aokG) tmp_1 = np.einsum('ij,ajmp->aimp', hl, SPG_lm_G_aoG) tmp_2 = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl = np.einsum( 'imp,aimq->apq', SPG_lm_aoG.conj(), tmp_1) + np.einsum( 'aimp,imq->apq', SPG_lm_G_aoG.conj(), tmp_2) vppnl *= (1. / ngrids**2) if dtype == np.float64: hcore[:, kn] += vppnl.real else: hcore[:, kn] += vppnl hcore[:, kn, p0:p1] -= h1[kn, :, p0:p1] hcore[:, kn, :, p0:p1] -= h1[kn, :, p0:p1].transpose(0, 2, 1).conj() return hcore
def test_ft_ao_with_kpts(self): numpy.random.seed(1) kpt = numpy.random.random(3) coords = pdft.gen_grid.gen_uniform_grids(cell) aoR = pdft.numint.eval_ao(cell, coords, kpt=kpt) ngs, nao = aoR.shape expmikr = numpy.exp(-1j*numpy.dot(coords,kpt)) ref = numpy.asarray([tools.fftk(aoR[:,i], cell.gs, expmikr) for i in range(nao)]) ref = ref.T * (cell.vol/ngs) dat = ft_ao.ft_ao(cell, cell.Gv, kpt=kpt) self.assertAlmostEqual(numpy.linalg.norm(ref[:,0]-dat[:,0]) , 1.3359899490499813e-10, 9) self.assertAlmostEqual(numpy.linalg.norm(ref[:,1]-dat[:,1]) , 0.0042404556036939756 , 4) self.assertAlmostEqual(numpy.linalg.norm(ref[:,2:]-dat[:,2:]), 4.8856357999633564e-14, 9)
def get_pp_nl(cell, kpt=np.zeros(3)): coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() aokG = tools.fftk(np.asarray(aoR.T, order='C'), cell.gs, np.exp(-1j*np.dot(coords, kpt))).T ngs = len(aokG) fakemol = pyscf.gto.Mole() fakemol._atm = np.zeros((1,pyscf.gto.ATM_SLOTS), dtype=np.int32) fakemol._bas = np.zeros((1,pyscf.gto.BAS_SLOTS), dtype=np.int32) ptr = pyscf.gto.PTR_ENV_START fakemol._env = np.zeros(ptr+10) fakemol._bas[0,pyscf.gto.NPRIM_OF ] = 1 fakemol._bas[0,pyscf.gto.NCTR_OF ] = 1 fakemol._bas[0,pyscf.gto.PTR_EXP ] = ptr+3 fakemol._bas[0,pyscf.gto.PTR_COEFF] = ptr+4 Gv = np.asarray(cell.Gv+kpt) G_rad = lib.norm(Gv, axis=1) vppnl = np.zeros((nao,nao), dtype=np.complex128) for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0,pyscf.gto.ANG_OF] = l fakemol._env[ptr+3] = .5*rl**2 fakemol._env[ptr+4] = rl**(l+1.5)*np.pi**1.25 pYlm_part = pyscf.dft.numint.eval_ao(fakemol, Gv, deriv=0) pYlm = np.empty((nl,l*2+1,ngs)) for k in range(nl): qkl = pseudo.pp._qli(G_rad*rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) tmp = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += np.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) vppnl *= (1./ngs**2) if aoR.dtype == np.double: return vppnl.real else: return vppnl
def get_pp_nl(cell, kpt=np.zeros(3)): coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() aokG = tools.fftk(np.asarray(aoR.T, order='C'), cell.gs, np.exp(-1j * np.dot(coords, kpt))).T ngs = len(aokG) fakemol = pyscf.gto.Mole() fakemol._atm = np.zeros((1, pyscf.gto.ATM_SLOTS), dtype=np.int32) fakemol._bas = np.zeros((1, pyscf.gto.BAS_SLOTS), dtype=np.int32) ptr = pyscf.gto.PTR_ENV_START fakemol._env = np.zeros(ptr + 10) fakemol._bas[0, pyscf.gto.NPRIM_OF] = 1 fakemol._bas[0, pyscf.gto.NCTR_OF] = 1 fakemol._bas[0, pyscf.gto.PTR_EXP] = ptr + 3 fakemol._bas[0, pyscf.gto.PTR_COEFF] = ptr + 4 Gv = np.asarray(cell.Gv + kpt) G_rad = lib.norm(Gv, axis=1) vppnl = np.zeros((nao, nao), dtype=np.complex128) for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0, pyscf.gto.ANG_OF] = l fakemol._env[ptr + 3] = .5 * rl**2 fakemol._env[ptr + 4] = rl**(l + 1.5) * np.pi**1.25 pYlm_part = pyscf.dft.numint.eval_ao(fakemol, Gv, deriv=0) pYlm = np.empty((nl, l * 2 + 1, ngs)) for k in range(nl): qkl = pseudo.pp._qli(G_rad * rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) tmp = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += np.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) vppnl *= (1. / ngs**2) if aoR.dtype == np.double: return vppnl.real else: return vppnl
def test_ft_aoao_with_kpts(self): numpy.random.seed(1) kpti, kptj = numpy.random.random((2,3)) coords = pdft.gen_grid.gen_uniform_grids(cell) aoi = pdft.numint.eval_ao(cell, coords, kpt=kpti) aoj = pdft.numint.eval_ao(cell, coords, kpt=kptj) ngs, nao = aoj.shape q = kptj - kpti ref = numpy.asarray([tools.fftk(aoi[:,i].conj()*aoj[:,j], cell.gs, coords, q) for i in range(nao) for j in range(nao)]) ref = ref.reshape(nao,nao,-1).transpose(2,0,1) * (cell.vol/ngs) dat = ft_ao.ft_aopair(cell, cell.Gv, kpti_kptj=(kpti,kptj)) self.assertAlmostEqual(numpy.linalg.norm(ref[:,0,0]-dat[:,0,0]) , 1.8912693795904546e-06, 7) self.assertAlmostEqual(numpy.linalg.norm(ref[:,1,1]-dat[:,1,1]) , 0.023225471785938184 , 4) self.assertAlmostEqual(numpy.linalg.norm(ref[:,2:,2:]-dat[:,2:,2:]), 3.9231124086361633e-14, 9) self.assertAlmostEqual(numpy.linalg.norm(ref[:,0,2:]-dat[:,0,2:]) , 3.6949758392853562e-11, 9) self.assertAlmostEqual(numpy.linalg.norm(ref[:,2:,0]-dat[:,2:,0]) , 4.1245047267152665e-11, 9)
def get_pp(cell, kpt=np.zeros(3)): '''Get the periodic pseudotential nuc-el AO matrix, with G=0 removed. ''' coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() vlocG = pseudo.get_vlocG(cell) vlocG[:, 0] = 0 vpplocG = -np.sum(SI * vlocG, axis=0) # vpploc evaluated in real-space vpplocR = tools.ifft(vpplocG, cell.mesh) vpploc = np.dot(aoR.T.conj(), vpplocR.reshape(-1, 1) * aoR) # vppnonloc evaluated in reciprocal space aokG = np.empty(aoR.shape, np.complex128) expmikr = np.exp(-1j * np.dot(coords, kpt)) for i in range(nao): aokG[:, i] = tools.fftk(aoR[:, i], cell.mesh, expmikr) ngrids = len(aokG) vppnl = np.zeros((nao, nao), dtype=np.complex128) hs, projGs = pseudo.get_projG(cell, kpt) for ia, [h_ia, projG_ia] in enumerate(zip(hs, projGs)): for l, h in enumerate(h_ia): nl = h.shape[0] for m in range(-l, l + 1): SPG_lm_aoG = np.zeros((nl, nao), dtype=np.complex128) for i in range(nl): SPG_lmi = SI[ia, :] * projG_ia[l][m][i] SPG_lm_aoG[i, :] = np.einsum('g,gp->p', SPG_lmi.conj(), aokG) for i in range(nl): for j in range(nl): # Note: There is no (-1)^l here. vppnl += h[i, j] * np.einsum('p,q->pq', SPG_lm_aoG[i, :].conj(), SPG_lm_aoG[j, :]) vppnl *= (1. / ngrids**2) ovlp = cell.pbc_intor('int1e_ovlp_sph', hermi=1, kpts=kpt) vpploc += 1. / cell.vol * np.sum(pseudo.get_alphas(cell)) * ovlp return vpploc + vppnl
def get_pp(cell, kpt=np.zeros(3)): '''Get the periodic pseudotential nuc-el AO matrix, with G=0 removed. ''' coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() vlocG = pseudo.get_vlocG(cell) vlocG[:,0] = 0 vpplocG = -np.sum(SI * vlocG, axis=0) # vpploc evaluated in real-space vpplocR = tools.ifft(vpplocG, cell.mesh) vpploc = np.dot(aoR.T.conj(), vpplocR.reshape(-1,1)*aoR) # vppnonloc evaluated in reciprocal space aokG = np.empty(aoR.shape, np.complex128) expmikr = np.exp(-1j*np.dot(coords,kpt)) for i in range(nao): aokG[:,i] = tools.fftk(aoR[:,i], cell.mesh, expmikr) ngrids = len(aokG) vppnl = np.zeros((nao,nao), dtype=np.complex128) hs, projGs = pseudo.get_projG(cell, kpt) for ia, [h_ia,projG_ia] in enumerate(zip(hs,projGs)): for l, h in enumerate(h_ia): nl = h.shape[0] for m in range(-l,l+1): SPG_lm_aoG = np.zeros((nl,nao), dtype=np.complex128) for i in range(nl): SPG_lmi = SI[ia,:] * projG_ia[l][m][i] SPG_lm_aoG[i,:] = np.einsum('g,gp->p', SPG_lmi.conj(), aokG) for i in range(nl): for j in range(nl): # Note: There is no (-1)^l here. vppnl += h[i,j]*np.einsum('p,q->pq', SPG_lm_aoG[i,:].conj(), SPG_lm_aoG[j,:]) vppnl *= (1./ngrids**2) ovlp = cell.pbc_intor('int1e_ovlp_sph', hermi=1, kpts=kpt) vpploc += 1./cell.vol * np.sum(pseudo.get_alphas(cell)) * ovlp return vpploc + vppnl
def get_vkR(mydf, cell, aoR_k1, aoR_k2, kpt1, kpt2, coords, gs, exxdiv): """Get the real-space 2-index "exchange" potential V_{i,k1; j,k2}(r) where {i,k1} = exp^{i k1 r) |i> , {j,k2} = exp^{-i k2 r) <j| Kwargs: kpt1, kpt2 : (3,) ndarray The sampled k-points; may be required for G=0 correction. Returns: vR : (ngs, nao, nao) ndarray The real-space "exchange" potential at every grid point, for all AO pairs. Note: This is essentially a density-fitting or resolution-of-the-identity. The returned object is of size ngs*nao**2 """ ngs, nao = aoR_k1.shape expmikr = np.exp(-1j * np.dot(kpt1 - kpt2, coords.T)) mydf.exxdiv = exxdiv coulG = tools.get_coulG(cell, kpt1 - kpt2, True, mydf, gs) aoR_k1 = np.asarray(aoR_k1.T, order="C") aoR_k2 = np.asarray(aoR_k2.T, order="C") vR = np.empty((nao, nao, ngs), dtype=np.complex128) for i in range(nao): rhoR = aoR_k1 * aoR_k2[i].conj() rhoG = tools.fftk(rhoR, gs, expmikr) vG = rhoG * coulG vR[:, i] = tools.ifftk(vG, gs, expmikr.conj()) vR = vR.transpose(2, 0, 1) if aoR_k1.dtype == np.double and aoR_k2.dtype == np.double: return vR.real else: return vR
def get_vkR(mydf, cell, aoR_k1, aoR_k2, kpt1, kpt2, coords, gs, exxdiv): '''Get the real-space 2-index "exchange" potential V_{i,k1; j,k2}(r) where {i,k1} = exp^{i k1 r) |i> , {j,k2} = exp^{-i k2 r) <j| Kwargs: kpt1, kpt2 : (3,) ndarray The sampled k-points; may be required for G=0 correction. Returns: vR : (ngs, nao, nao) ndarray The real-space "exchange" potential at every grid point, for all AO pairs. Note: This is essentially a density-fitting or resolution-of-the-identity. The returned object is of size ngs*nao**2 ''' ngs, nao = aoR_k1.shape expmikr = np.exp(-1j * np.dot(kpt1 - kpt2, coords.T)) mydf.exxdiv = exxdiv coulG = tools.get_coulG(cell, kpt1 - kpt2, True, mydf, gs) aoR_k1 = np.asarray(aoR_k1.T, order='C') aoR_k2 = np.asarray(aoR_k2.T, order='C') vR = np.empty((nao, nao, ngs), dtype=np.complex128) for i in range(nao): rhoR = aoR_k1 * aoR_k2[i].conj() rhoG = tools.fftk(rhoR, gs, expmikr) vG = rhoG * coulG vR[:, i] = tools.ifftk(vG, gs, expmikr.conj()) vR = vR.transpose(2, 0, 1) if aoR_k1.dtype == np.double and aoR_k2.dtype == np.double: return vR.real else: return vR
def get_t_pw(cell, kpt=np.zeros(3)): '''Get the kinetic energy AO matrix using the PW resolution. Note: Incurs error due to finite resolution of the gradient operator. ''' coords = pyscf.pbc.dft.gen_grid.gen_uniform_grids(cell) aoR = pyscf.pbc.dft.numint.eval_ao(cell, coords, kpt, deriv=0) nao = cell.nao_nr() kG = kpt + cell.Gv abskG2 = np.einsum('gi,gi->g', kG, kG) aokG = np.empty(aoR.shape, np.complex128) TaokG = np.empty(aoR.shape, np.complex128) nao = cell.nao_nr() for i in range(nao): aokG[:,i] = tools.fftk(aoR[:,i], cell.gs, coords, kpt) TaokG[:,i] = 0.5*abskG2*aokG[:,i] ngs = len(aokG) t = np.dot(aokG.T.conj(), TaokG) t *= (cell.vol/ngs**2) return t
def get_pp(cell, kpt=np.zeros(3)): '''Get the periodic pseudotential nuc-el AO matrix ''' import pyscf.dft from pyscf.pbc import tools from pyscf.pbc.dft import gen_grid from pyscf.pbc.dft import numint coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() vlocG = get_vlocG(cell) vpplocG = -np.sum(SI * vlocG, axis=0) vpplocG[0] = np.sum(get_alphas(cell)) # from get_jvloc_G0 function # vpploc evaluated in real-space vpplocR = tools.ifft(vpplocG, cell.gs).real vpploc = np.dot(aoR.T.conj(), vpplocR.reshape(-1, 1) * aoR) # vppnonloc evaluated in reciprocal space aokG = tools.fftk(np.asarray(aoR.T, order='C'), cell.gs, np.exp(-1j * np.dot(coords, kpt))).T ngs = len(aokG) fakemol = pyscf.gto.Mole() fakemol._atm = np.zeros((1, pyscf.gto.ATM_SLOTS), dtype=np.int32) fakemol._bas = np.zeros((1, pyscf.gto.BAS_SLOTS), dtype=np.int32) ptr = pyscf.gto.PTR_ENV_START fakemol._env = np.zeros(ptr + 10) fakemol._bas[0, pyscf.gto.NPRIM_OF] = 1 fakemol._bas[0, pyscf.gto.NCTR_OF] = 1 fakemol._bas[0, pyscf.gto.PTR_EXP] = ptr + 3 fakemol._bas[0, pyscf.gto.PTR_COEFF] = ptr + 4 Gv = np.asarray(cell.Gv + kpt) G_rad = lib.norm(Gv, axis=1) vppnl = np.zeros((nao, nao), dtype=np.complex128) for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0, pyscf.gto.ANG_OF] = l fakemol._env[ptr + 3] = .5 * rl**2 fakemol._env[ptr + 4] = rl**(l + 1.5) * np.pi**1.25 pYlm_part = pyscf.dft.numint.eval_ao(fakemol, Gv, deriv=0) pYlm = np.empty((nl, l * 2 + 1, ngs)) for k in range(nl): qkl = _qli(G_rad * rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) tmp = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += np.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) vppnl *= (1. / ngs**2) if aoR.dtype == np.double: return vpploc.real + vppnl.real else: return vpploc + vppnl
def get_pp(cell, kpt=np.zeros(3)): '''Get the periodic pseudotential nuc-el AO matrix ''' from pyscf.pbc import tools coords = cell.get_uniform_grids() aoR = cell.pbc_eval_gto('GTOval', coords, kpt=kpt) nao = cell.nao_nr() SI = cell.get_SI() vlocG = get_vlocG(cell) vpplocG = -np.sum(SI * vlocG, axis=0) vpplocG[0] = np.sum(get_alphas(cell)) # from get_jvloc_G0 function # vpploc evaluated in real-space vpplocR = tools.ifft(vpplocG, cell.mesh).real vpploc = np.dot(aoR.T.conj(), vpplocR.reshape(-1,1)*aoR) # vppnonloc evaluated in reciprocal space aokG = tools.fftk(np.asarray(aoR.T, order='C'), cell.mesh, np.exp(-1j*np.dot(coords, kpt))).T ngrids = len(aokG) fakemol = mole.Mole() fakemol._atm = np.zeros((1,mole.ATM_SLOTS), dtype=np.int32) fakemol._bas = np.zeros((1,mole.BAS_SLOTS), dtype=np.int32) ptr = mole.PTR_ENV_START fakemol._env = np.zeros(ptr+10) fakemol._bas[0,mole.NPRIM_OF ] = 1 fakemol._bas[0,mole.NCTR_OF ] = 1 fakemol._bas[0,mole.PTR_EXP ] = ptr+3 fakemol._bas[0,mole.PTR_COEFF] = ptr+4 Gv = np.asarray(cell.Gv+kpt) G_rad = lib.norm(Gv, axis=1) vppnl = np.zeros((nao,nao), dtype=np.complex128) for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0,mole.ANG_OF] = l fakemol._env[ptr+3] = .5*rl**2 fakemol._env[ptr+4] = rl**(l+1.5)*np.pi**1.25 pYlm_part = fakemol.eval_gto('GTOval', Gv) pYlm = np.empty((nl,l*2+1,ngrids)) for k in range(nl): qkl = _qli(G_rad*rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) tmp = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += np.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) vppnl *= (1./ngrids**2) if aoR.dtype == np.double: return vpploc.real + vppnl.real else: return vpploc + vppnl