def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None): mol = mf.mol occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) if fock_ao is None: dm1 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_hcore() + mf.get_veff(mol, dm1) fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) g = fock[viridx[:,None],occidx] * 2 foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] h_diag = (fvv.diagonal().reshape(-1,1)-foo.diagonal()) * 2 if hasattr(mf, 'xc'): if APPROX_XC_HESSIAN: from pyscf.dft import vxc x_code = vxc.parse_xc_name(mf.xc)[0] hyb = vxc.hybrid_coeff(x_code, spin=(mol.spin>0)+1) else: save_for_dft = [None, None] # (dm, veff) def h_op(x): x = x.reshape(nvir,nocc) x2 =-numpy.einsum('sq,ps->pq', foo, x) * 2 x2+= numpy.einsum('pr,rq->pq', fvv, x) * 2 d1 = reduce(numpy.dot, (mo_coeff[:,viridx], x, mo_coeff[:,occidx].T)) if hasattr(mf, 'xc'): if APPROX_XC_HESSIAN: vj, vk = mf.get_jk(mol, d1+d1.T) if abs(hyb) < 1e-10: dvhf = vj else: dvhf = vj - vk * hyb * .5 else: if save_for_dft[0] is None: save_for_dft[0] = mf.make_rdm1(mo_coeff, mo_occ) save_for_dft[1] = mf.get_veff(mol, save_for_dft[0]) dm1 = save_for_dft[0] + d1 + d1.T vhf1 = mf.get_veff(mol, dm1, dm_last=save_for_dft[0], vhf_last=save_for_dft[1]) dvhf = vhf1 - save_for_dft[1] save_for_dft[0] = dm1 save_for_dft[1] = vhf1 else: dvhf = mf.get_veff(mol, d1+d1.T) x2 += reduce(numpy.dot, (mo_coeff[:,viridx].T, dvhf, mo_coeff[:,occidx])) * 4 return x2.reshape(-1) return g.reshape(-1), h_op, h_diag.reshape(-1)
def get_veff_(ks, mol, dm, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional for UKS. See pyscf/dft/rks.py :func:`get_veff_` fore more details''' if isinstance(dm, numpy.ndarray) and dm.ndim == 2: dm = numpy.array((dm*.5,dm*.5)) nset = len(dm) // 2 t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.setup_grids_() t0 = logger.timer(ks, 'seting up grids', *t0) x_code, c_code = vxc.parse_xc_name(ks.xc) n, ks._exc, vx = \ ks._numint.nr_uks(mol, ks.grids, x_code, c_code, dm, verbose=ks.verbose) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) hyb = vxc.hybrid_coeff(x_code, spin=(mol.spin>0)+1) if abs(hyb) < 1e-10: vj = ks.get_j(mol, dm, hermi) elif (ks._eri is not None or ks._is_mem_enough() or not ks.direct_scf): vj, vk = ks.get_jk(mol, dm, hermi) else: if (ks.direct_scf and isinstance(vhf_last, numpy.ndarray) and hasattr(ks, '_dm_last')): ddm = numpy.asarray(dm) - numpy.asarray(ks._dm_last) vj, vk = ks.get_jk(mol, ddm, hermi=hermi) vj += ks._vj_last vk += ks._vk_last else: vj, vk = ks.get_jk(mol, dm, hermi) ks._dm_last = dm ks._vj_last, ks._vk_last = vj, vk if abs(hyb) > 1e-10: if nset == 1: ks._exc -=(numpy.einsum('ij,ji', dm[0], vk[0]) +numpy.einsum('ij,ji', dm[1], vk[1])) * .5 * hyb vhf = pyscf.scf.uhf._makevhf(vj, vk*hyb, nset) else: if nset == 1: vhf = vj[0] + vj[1] else: vhf = vj[:nset] + vj[nset:] vhf = numpy.array((vhf,vhf)) if nset == 1: ks._ecoul = numpy.einsum('ij,ji', dm[0]+dm[1], vj[0]+vj[1]) * .5 return vhf + vx
def get_veff_(ks, mol, dm, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional''' t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.setup_grids_() t0 = logger.timer(ks, 'seting up grids', *t0) x_code, c_code = vxc.parse_xc_name(ks.xc) #n, ks._exc, vx = vxc.nr_vxc(mol, ks.grids, x_code, c_code, # dm, spin=1, relativity=0) if ks._numint is None: n, ks._exc, vx = numint.nr_vxc(mol, ks.grids, x_code, c_code, dm, spin=mol.spin, relativity=0) else: n, ks._exc, vx = \ ks._numint.nr_vxc(mol, ks.grids, x_code, c_code, dm, spin=mol.spin, relativity=0) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) hyb = vxc.hybrid_coeff(x_code, spin=1) if abs(hyb) < 1e-10: vj = ks.get_j(mol, dm, hermi) elif (ks._eri is not None or ks._is_mem_enough() or not ks.direct_scf): vj, vk = ks.get_jk(mol, dm, hermi) else: if isinstance(vhf_last, numpy.ndarray): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj, vk = ks.get_jk(mol, ddm, hermi=hermi) vj += ks._vj_last vk += ks._vk_last else: vj, vk = ks.get_jk(mol, dm, hermi) ks._vj_last, ks._vk_last = vj, vk if abs(hyb) > 1e-10: if isinstance(dm, numpy.ndarray) and dm.ndim == 2: ks._exc -= numpy.einsum('ij,ji', dm, vk) * .5 * hyb*.5 vhf = vj - vk * (hyb * .5) else: vhf = vj if isinstance(dm, numpy.ndarray) and dm.ndim == 2: ks._ecoul = numpy.einsum('ij,ji', dm, vj) * .5 return vhf + vx
def gen_g_hop_rohf(mf, mo_coeff, mo_occ, fock_ao=None): mol = mf.mol occidxa = numpy.where(mo_occ>0)[0] occidxb = numpy.where(mo_occ==2)[0] viridxa = numpy.where(mo_occ==0)[0] viridxb = numpy.where(mo_occ<2)[0] mask = pyscf.scf.hf.uniq_var_indices(mo_occ) if fock_ao is None: dm1 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_hcore() + mf.get_veff(mol, dm1) focka = reduce(numpy.dot, (mo_coeff.T, fock_ao[0], mo_coeff)) fockb = reduce(numpy.dot, (mo_coeff.T, fock_ao[1], mo_coeff)) g = numpy.zeros_like(focka) g[viridxa[:,None],occidxa] = focka[viridxa[:,None],occidxa] g[viridxb[:,None],occidxb] += fockb[viridxb[:,None],occidxb] g = g[mask] h_diag = numpy.zeros_like(focka) h_diag[viridxa[:,None],occidxa] -= focka[occidxa,occidxa] h_diag[viridxa[:,None],occidxa] += focka[viridxa,viridxa].reshape(-1,1) h_diag[viridxb[:,None],occidxb] -= fockb[occidxb,occidxb] h_diag[viridxb[:,None],occidxb] += fockb[viridxb,viridxb].reshape(-1,1) h_diag = h_diag[mask] if hasattr(mf, 'xc'): if APPROX_XC_HESSIAN: from pyscf.dft import vxc x_code = vxc.parse_xc_name(mf.xc)[0] hyb = vxc.hybrid_coeff(x_code, spin=(mol.spin>0)+1) else: save_for_dft = [None, None] # (dm, veff) def h_op(x): x1 = numpy.zeros_like(focka) x1[mask] = x x1 = x1 - x1.T x2 = numpy.zeros_like(focka) #: x2[nb:,:na] = numpy.einsum('sp,qs->pq', focka[:na,nb:], x1[:na,:na]) #: x2[nb:,:na] += numpy.einsum('rq,rp->pq', focka[:na,:na], x1[:na,nb:]) #: x2[na:,:na] -= numpy.einsum('sp,rp->rs', focka[:na,:na], x1[na:,:na]) #: x2[na:,:na] -= numpy.einsum('ps,qs->pq', focka[na:], x1[:na]) * 2 #: x2[nb:na,:nb] += numpy.einsum('qr,pr->pq', focka[:nb], x1[nb:na]) #: x2[nb:na,:nb] -= numpy.einsum('rq,sq->rs', focka[nb:na], x1[:nb]) #: x2[nb:,:na] += numpy.einsum('sp,qs->pq', fockb[:nb,nb:], x1[:na,:nb]) #: x2[nb:,:na] += numpy.einsum('rq,rp->pq', fockb[:nb,:na], x1[:nb,nb:]) #: x2[nb:,:nb] -= numpy.einsum('sp,rp->rs', fockb[:nb], x1[nb:]) #: x2[nb:,:nb] -= numpy.einsum('rq,sq->rs', fockb[nb:], x1[:nb]) * 2 x2[viridxb[:,None],occidxa] = \ (numpy.einsum('sp,qs->pq', focka[occidxa[:,None],viridxb], x1[occidxa[:,None],occidxa]) +numpy.einsum('rq,rp->pq', focka[occidxa[:,None],occidxa], x1[occidxa[:,None],viridxb])) x2[viridxa[:,None],occidxa] -= \ (numpy.einsum('sp,rp->rs', focka[occidxa[:,None],occidxa], x1[viridxa[:,None],occidxa]) +numpy.einsum('ps,qs->pq', focka[viridxa], x1[occidxa]) * 2) x2[occidxa[:,None],occidxb] += \ (numpy.einsum('qr,pr->pq', focka[occidxb], x1[occidxa]) -numpy.einsum('rq,sq->rs', focka[occidxa], x1[occidxb])) x2[viridxb[:,None],occidxa] += \ (numpy.einsum('sp,qs->pq', fockb[occidxb[:,None],viridxb], x1[occidxa[:,None],occidxb]) +numpy.einsum('rq,rp->pq', fockb[occidxb[:,None],occidxa], x1[occidxb[:,None],viridxb])) x2[viridxb[:,None],occidxb] -= \ (numpy.einsum('sp,rp->rs', fockb[occidxb], x1[viridxb]) +numpy.einsum('rq,sq->rs', fockb[viridxb], x1[occidxb]) * 2) x2 *= .5 d1a = reduce(numpy.dot, (mo_coeff[:,viridxa], x1[viridxa[:,None],occidxa], mo_coeff[:,occidxa].T)) d1b = reduce(numpy.dot, (mo_coeff[:,viridxb], x1[viridxb[:,None],occidxb], mo_coeff[:,occidxb].T)) if hasattr(mf, 'xc'): if APPROX_XC_HESSIAN: vj, vk = mf.get_jk(mol, numpy.array((d1a+d1a.T,d1b+d1b.T))) if abs(hyb) < 1e-10: dvhf = vj[0] + vj[1] else: dvhf = (vj[0] + vj[1]) - vk * hyb else: from pyscf.dft import uks if save_for_dft[0] is None: save_for_dft[0] = mf.make_rdm1(mo_coeff, mo_occ) save_for_dft[1] = mf.get_veff(mol, save_for_dft[0]) dm1 = numpy.array((save_for_dft[0][0]+d1a+d1a.T, save_for_dft[0][1]+d1b+d1b.T)) vhf1 = uks.get_veff_(mf, mol, dm1, dm_last=save_for_dft[0], vhf_last=save_for_dft[1]) dvhf = (vhf1[0]-save_for_dft[1][0], vhf1[1]-save_for_dft[1][1]) save_for_dft[0] = dm1 save_for_dft[1] = vhf1 else: dvhf = mf.get_veff(mol, numpy.array((d1a+d1a.T,d1b+d1b.T))) x2[viridxa[:,None],occidxa] += reduce(numpy.dot, (mo_coeff[:,viridxa].T, dvhf[0], mo_coeff[:,occidxa])) x2[viridxb[:,None],occidxb] += reduce(numpy.dot, (mo_coeff[:,viridxb].T, dvhf[1], mo_coeff[:,occidxb])) return x2[mask] return g, h_op, h_diag
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None): mol = mf.mol occidxa = numpy.where(mo_occ[0]>0)[0] occidxb = numpy.where(mo_occ[1]>0)[0] viridxa = numpy.where(mo_occ[0]==0)[0] viridxb = numpy.where(mo_occ[1]==0)[0] nocca = len(occidxa) noccb = len(occidxb) nvira = len(viridxa) nvirb = len(viridxb) if fock_ao is None: dm1 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = mf.get_hcore() + mf.get_veff(mol, dm1) focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0])) fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1])) g = numpy.hstack((focka[viridxa[:,None],occidxa].reshape(-1), fockb[viridxb[:,None],occidxb].reshape(-1))) h_diaga =(focka[viridxa,viridxa].reshape(-1,1) - focka[occidxa,occidxa]) h_diagb =(fockb[viridxb,viridxb].reshape(-1,1) - fockb[occidxb,occidxb]) h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1))) if hasattr(mf, 'xc'): if APPROX_XC_HESSIAN: from pyscf.dft import vxc x_code = vxc.parse_xc_name(mf.xc)[0] hyb = vxc.hybrid_coeff(x_code, spin=(mol.spin>0)+1) else: save_for_dft = [None, None] # (dm, veff) def h_op(x): x1a = x[:nvira*nocca].reshape(nvira,nocca) x1b = x[nvira*nocca:].reshape(nvirb,noccb) x2a = numpy.zeros((nvira,nocca)) x2b = numpy.zeros((nvirb,noccb)) x2a -= numpy.einsum('sq,ps->pq', focka[occidxa[:,None],occidxa], x1a) x2a += numpy.einsum('rp,rq->pq', focka[viridxa[:,None],viridxa], x1a) x2b -= numpy.einsum('sq,ps->pq', fockb[occidxb[:,None],occidxb], x1b) x2b += numpy.einsum('rp,rq->pq', fockb[viridxb[:,None],viridxb], x1b) d1a = reduce(numpy.dot, (mo_coeff[0][:,viridxa], x1a, mo_coeff[0][:,occidxa].T)) d1b = reduce(numpy.dot, (mo_coeff[1][:,viridxb], x1b, mo_coeff[1][:,occidxb].T)) if hasattr(mf, 'xc'): if APPROX_XC_HESSIAN: vj, vk = mf.get_jk(mol, numpy.array((d1a+d1a.T,d1b+d1b.T))) if abs(hyb) < 1e-10: dvhf = vj[0] + vj[1] dvhf = (dvhf, dvhf) else: dvhf = (vj[0] + vj[1]) - vk * hyb else: if save_for_dft[0] is None: save_for_dft[0] = mf.make_rdm1(mo_coeff, mo_occ) save_for_dft[1] = mf.get_veff(mol, save_for_dft[0]) dm1 = numpy.array((save_for_dft[0][0]+d1a+d1a.T, save_for_dft[0][1]+d1b+d1b.T)) vhf1 = mf.get_veff(mol, dm1, dm_last=save_for_dft[0], vhf_last=save_for_dft[1]) dvhf = (vhf1[0]-save_for_dft[1][0], vhf1[1]-save_for_dft[1][1]) save_for_dft[0] = dm1 save_for_dft[1] = vhf1 else: dvhf = mf.get_veff(mol, numpy.array((d1a+d1a.T,d1b+d1b.T))) x2a += reduce(numpy.dot, (mo_coeff[0][:,viridxa].T, dvhf[0], mo_coeff[0][:,occidxa])) x2b += reduce(numpy.dot, (mo_coeff[1][:,viridxb].T, dvhf[1], mo_coeff[1][:,occidxb])) return numpy.hstack((x2a.ravel(), x2b.ravel())) return g, h_op, h_diag
def get_veff_(ks, mol, dm, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional .. note:: This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. The ._exc and ._ecoul attributes will be updated after return. Attributes ._dm_last, ._vj_last and ._vk_last might be changed if direct SCF method is applied. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Kwargs: dm_last : ndarray or a list of ndarrays or 0 The density matrix baseline. If not 0, this function computes the increment of HF potential w.r.t. the reference HF potential matrix. vhf_last : ndarray or a list of ndarrays or 0 The reference HF potential matrix. If vhf_last is not given, the function will not call direct_scf and attacalites ._dm_last, ._vj_last and ._vk_last will not be updated. hermi : int Whether J, K matrix is hermitian | 0 : no hermitian or symmetric | 1 : hermitian | 2 : anti-hermitian Returns: matrix Veff = J + Vxc. Veff can be a list matrices, if the input dm is a list of density matrices. ''' t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.setup_grids_() t0 = logger.timer(ks, 'seting up grids', *t0) x_code, c_code = vxc.parse_xc_name(ks.xc) hyb = vxc.hybrid_coeff(x_code, spin=(mol.spin>0)+1) if hermi == 2: # because rho = 0 n, ks._exc, vx = 0, 0, 0 else: if ks._numint is None: n, ks._exc, vx = numint.nr_rks_vxc(mol, ks.grids, x_code, c_code, dm, hermi=hermi) else: n, ks._exc, vx = ks._numint.nr_rks(mol, ks.grids, x_code, c_code, dm, hermi=hermi) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) if abs(hyb) < 1e-10: vj = ks.get_j(mol, dm, hermi) elif (ks._eri is not None or ks._is_mem_enough() or not ks.direct_scf): vj, vk = ks.get_jk(mol, dm, hermi) else: if (ks.direct_scf and isinstance(vhf_last, numpy.ndarray) and hasattr(ks, '_dm_last')): ddm = numpy.asarray(dm) - numpy.asarray(ks._dm_last) vj, vk = ks.get_jk(mol, ddm, hermi=hermi) vj += ks._vj_last vk += ks._vk_last else: vj, vk = ks.get_jk(mol, dm, hermi) ks._dm_last = dm ks._vj_last, ks._vk_last = vj, vk if abs(hyb) > 1e-10: if isinstance(dm, numpy.ndarray) and dm.ndim == 2: ks._exc -= numpy.einsum('ij,ji', dm, vk) * .5 * hyb*.5 vhf = vj - vk * (hyb * .5) else: vhf = vj if isinstance(dm, numpy.ndarray) and dm.ndim == 2: ks._ecoul = numpy.einsum('ij,ji', dm, vj) * .5 return vhf + vx