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 hcore_generator(mf, cell=None, kpts=None): if cell is None: cell = mf.cell if kpts is None: kpts = mf.kpts h1 = get_hcore(cell, kpts) dtype = h1.dtype aoslices = cell.aoslice_by_atom() SI=cell.get_SI() ##[natom ,grid] mesh = cell.mesh Gv = cell.Gv ##[grid, 3] ngrids = len(Gv) coords = cell.get_uniform_grids() vlocG = get_vlocG(cell) ###[natom, grid] ptr = mole.PTR_ENV_START 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 return hcore_deriv