def vind(dm1): if hermi == 2: v1 = numpy.zeros_like(dm1) else: v1 = ni.nr_uks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, hermi, rho0, vxc, fxc, max_memory=max_memory) if not hybrid: if with_j: vj = mf.get_j(mol, dm1, hermi=hermi) v1 += vj[0] + vj[1] else: if with_j: vj, vk = mf.get_jk(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha - hyb) v1 += vj[0] + vj[1] - vk else: vk = mf.get_k(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha - hyb) v1 -= vk return v1
def _get_k_lr(mol, dm, omega=0, hermi=0): nso = dm.shape[-1] nao = nso // 2 dms = dm.reshape(-1, nso, nso) n_dm = dms.shape[0] dmaa = dms[:, :nao, :nao] dmab = dms[:, nao:, :nao] dmbb = dms[:, nao:, nao:] dms = numpy.vstack((dmaa, dmbb, dmab)) if dm.dtype == numpy.complex128: dms = numpy.vstack((dms.real, dms.imag)) hermi = 0 k1 = rks._get_k_lr(mol, dms, omega, hermi) k1 = k1.reshape(-1, n_dm, nao, nao) if dm.dtype == numpy.complex128: k1 = k1[:3] + k1[3:] * 1j vk = numpy.zeros((n_dm, nso, nso), dm.dtype) vk[:, :nao, :nao] = k1[0] vk[:, nao:, nao:] = k1[1] vk[:, :nao, nao:] = k1[2] vk[:, nao:, :nao] = k1[2].transpose(0, 2, 1).conj() vk = vk.reshape(dm.shape) return vk
def _get_k_lr(mol, dm, omega=0, hermi=0): nso = dm.shape[-1] nao = nso // 2 dms = dm.reshape(-1,nso,nso) n_dm = dms.shape[0] dmaa = dms[:,:nao,:nao] dmab = dms[:,nao:,:nao] dmbb = dms[:,nao:,nao:] dms = numpy.vstack((dmaa, dmbb, dmab)) if dm.dtype == numpy.complex128: dms = numpy.vstack((dms.real, dms.imag)) hermi = 0 k1 = rks._get_k_lr(mol, dms, omega, hermi) k1 = k1.reshape(-1,n_dm,nao,nao) if dm.dtype == numpy.complex128: k1 = k1[:3] + k1[3:] * 1j vk = numpy.zeros((n_dm,nso,nso), dm.dtype) vk[:,:nao,:nao] = k1[0] vk[:,nao:,nao:] = k1[1] vk[:,:nao,nao:] = k1[2] vk[:,nao:,:nao] = k1[2].transpose(0,2,1).conj() vk = vk.reshape(dm.shape) return vk
def vind(dm1): # The singlet hessian if hermi == 2: v1 = numpy.zeros_like(dm1) else: v1 = ni.nr_rks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, hermi, rho0, vxc, fxc, max_memory=max_memory) if hybrid: if hermi != 2: vj, vk = mf.get_jk(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha - hyb) v1 += vj - .5 * vk else: v1 -= .5 * hyb * mf.get_k(mol, dm1, hermi=hermi) elif hermi != 2: v1 += mf.get_j(mol, dm1, hermi=hermi) return v1
def vind(dm1): if hermi == 2: v1 = numpy.zeros_like(dm1) else: # nr_rks_fxc_st requires alpha of dm1, dm1*.5 should be scaled v1 = numint.nr_rks_fxc_st(ni, mol, mf.grids, mf.xc, dm0, dm1, 0, False, rho0, vxc, fxc, max_memory=max_memory) v1 *= .5 if hybrid: vk = mf.get_k(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha - hyb) v1 += -.5 * vk return v1
def vind(dm1): if hermi == 2: v1 = numpy.zeros_like(dm1) else: v1 = ni.nr_uks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, hermi, rho0, vxc, fxc, max_memory=max_memory) if not hybrid: if with_j: vj = mf.get_j(mol, dm1, hermi=hermi) v1 += vj[0] + vj[1] else: if with_j: vj, vk = mf.get_jk(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha-hyb) v1 += vj[0] + vj[1] - vk else: vk = mf.get_k(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha-hyb) v1 -= vk return v1
def vind(dm1): if hermi == 2: v1 = numpy.zeros_like(dm1) else: # nr_rks_fxc_st requires alpha of dm1, dm1*.5 should be scaled v1 = numint.nr_rks_fxc_st(ni, mol, mf.grids, mf.xc, dm0, dm1, 0, False, rho0, vxc, fxc, max_memory=max_memory) v1 *= .5 if hybrid: vk = mf.get_k(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha-hyb) v1 += -.5 * vk return v1
def fvind(x): # Cannot make call to .base.get_vind because first order orbitals are solved # through closed shell ground state CPHF. dm = reduce(numpy.dot, (orbv, x.reshape(nvir,nocc), orbo.T)) dm = dm + dm.T # Call singlet XC kernel contraction, for closed shell ground state vindxc = numint.nr_rks_fxc_st(ni, mol, mf.grids, mf.xc, dm0, dm, 0, singlet, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm) veff = vj * 2 - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm, omega, hermi=1) * (alpha-hyb) else: vj = mf.get_j(mol, dm) veff = vj * 2 + vindxc return reduce(numpy.dot, (orbv.T, veff, orbo)).ravel()
def fvind(x): # Cannot make call to .base.get_vind because first order orbitals are solved # through closed shell ground state CPHF. dm = reduce(numpy.dot, (orbv, x.reshape(nvir, nocc), orbo.T)) dm = dm + dm.T # Call singlet XC kernel contraction, for closed shell ground state vindxc = numint.nr_rks_fxc_st(ni, mol, mf.grids, mf.xc, dm0, dm, 0, singlet, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm) veff = vj * 2 - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm, omega, hermi=1) * (alpha - hyb) else: vj = mf.get_j(mol, dm) veff = vj * 2 + vindxc return reduce(numpy.dot, (orbv.T, veff, orbo)).ravel()
def vind(dm1): # The singlet hessian if hermi == 2: v1 = numpy.zeros_like(dm1) else: v1 = ni.nr_rks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, hermi, rho0, vxc, fxc, max_memory=max_memory) if hybrid: if hermi != 2: vj, vk = mf.get_jk(mol, dm1, hermi=hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb vk += rks._get_k_lr(mol, dm1, omega, hermi) * (alpha-hyb) v1 += vj - .5 * vk else: v1 -= .5 * hyb * mf.get_k(mol, dm1, hermi=hermi) elif hermi != 2: v1 += mf.get_j(mol, dm1, hermi=hermi) return v1
def fvind(x): dm1 = numpy.empty((2,nao,nao)) xa = x[0,:nvira*nocca].reshape(nvira,nocca) xb = x[0,nvira*nocca:].reshape(nvirb,noccb) dma = reduce(numpy.dot, (orbva, xa, orboa.T)) dmb = reduce(numpy.dot, (orbvb, xb, orbob.T)) dm1[0] = dma + dma.T dm1[1] = dmb + dmb.T relativity = 0 hermi = 1 vindxc = numint.nr_uks_fxc(ni, mol, mf.grids, mf.xc, dm0, dm1, relativity, hermi, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm1) veff = vj[0] + vj[1] - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm1, omega, hermi=1) * (alpha-hyb) else: vj = mf.get_j(mol, dm1) veff = vj[0] + vj[1] + vindxc v1a = reduce(numpy.dot, (orbva.T, veff[0], orboa)) v1b = reduce(numpy.dot, (orbvb.T, veff[1], orbob)) return numpy.hstack((v1a.ravel(), v1b.ravel()))
def kernel(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO): log = logger.new_logger(td_grad, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad.base._scf mo_coeff = mf.mo_coeff mo_energy = mf.mo_energy mo_occ = mf.mo_occ 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) orboa = mo_coeff[0][:,occidxa] orbob = mo_coeff[1][:,occidxb] orbva = mo_coeff[0][:,viridxa] orbvb = mo_coeff[1][:,viridxb] nao = mo_coeff[0].shape[0] nmoa = nocca + nvira nmob = noccb + nvirb (xa, xb), (ya, yb) = x_y xpya = (xa+ya).reshape(nocca,nvira).T xpyb = (xb+yb).reshape(noccb,nvirb).T xmya = (xa-ya).reshape(nocca,nvira).T xmyb = (xb-yb).reshape(noccb,nvirb).T dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum('ai,bi->ab', xmya, xmya) dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum('ai,bi->ab', xmyb, xmyb) dooa =-numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum('ai,aj->ij', xmya, xmya) doob =-numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum('ai,aj->ij', xmyb, xmyb) dmzvopa = reduce(numpy.dot, (orbva, xpya, orboa.T)) dmzvopb = reduce(numpy.dot, (orbvb, xpyb, orbob.T)) dmzvoma = reduce(numpy.dot, (orbva, xmya, orboa.T)) dmzvomb = reduce(numpy.dot, (orbvb, xmyb, orbob.T)) dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T)) dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T)) dmzooa+= reduce(numpy.dot, (orbva, dvva, orbva.T)) dmzoob+= reduce(numpy.dot, (orbvb, dvvb, orbvb.T)) ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 3, raise_error=True) omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) # dm0 = mf.make_rdm1(mo_coeff, mo_occ), but it is not used when computing # fxc since rho0 is passed to fxc function. dm0 = None rho0, vxc, fxc = ni.cache_xc_kernel(mf.mol, mf.grids, mf.xc, mo_coeff, mo_occ, spin=1) f1vo, f1oo, vxc1, k1ao = \ _contract_xc_kernel(td_grad, mf.xc, (dmzvopa,dmzvopb), (dmzooa,dmzoob), True, True, max_memory) if abs(hyb) > 1e-10: dm = (dmzooa, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T, dmzoob, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T) vj, vk = mf.get_jk(mol, dm, hermi=0) vj = vj.reshape(2,3,nao,nao) vk = vk.reshape(2,3,nao,nao) * hyb if abs(omega) > 1e-10: vk += rks._get_k_lr(mol, dm, omega).reshape(2,3,nao,nao) * (alpha-hyb) veff0doo = vj[0,0]+vj[1,0] - vk[:,0] + f1oo[:,0] + k1ao[:,0] * 2 wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2 wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2 veff = vj[0,1]+vj[1,1] - vk[:,1] + f1vo[:,0] * 2 veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0])) veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1])) wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) * 2 wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) * 2 wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:,nocca:], xpya) * 2 wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:,noccb:], xpyb) * 2 veff = -vk[:,2] veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0])) veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1])) wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya) * 2 wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb) * 2 wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:,nocca:], xmya) * 2 wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:,noccb:], xmyb) * 2 else: dm = (dmzooa, dmzvopa+dmzvopa.T, dmzoob, dmzvopb+dmzvopb.T) vj = mf.get_j(mol, dm, hermi=1).reshape(2,2,nao,nao) veff0doo = vj[0,0]+vj[1,0] + f1oo[:,0] + k1ao[:,0] * 2 wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2 wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2 veff = vj[0,1]+vj[1,1] + f1vo[:,0] * 2 veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0])) veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1])) wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) * 2 wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) * 2 wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:,nocca:], xpya) * 2 wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:,noccb:], xpyb) * 2 veff0moma = numpy.zeros((nmoa,nmoa)) veff0momb = numpy.zeros((nmob,nmob)) def fvind(x): dm1 = numpy.empty((2,nao,nao)) xa = x[0,:nvira*nocca].reshape(nvira,nocca) xb = x[0,nvira*nocca:].reshape(nvirb,noccb) dma = reduce(numpy.dot, (orbva, xa, orboa.T)) dmb = reduce(numpy.dot, (orbvb, xb, orbob.T)) dm1[0] = dma + dma.T dm1[1] = dmb + dmb.T relativity = 0 hermi = 1 vindxc = numint.nr_uks_fxc(ni, mol, mf.grids, mf.xc, dm0, dm1, relativity, hermi, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm1) veff = vj[0] + vj[1] - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm1, omega, hermi=1) * (alpha-hyb) else: vj = mf.get_j(mol, dm1) veff = vj[0] + vj[1] + vindxc v1a = reduce(numpy.dot, (orbva.T, veff[0], orboa)) v1b = reduce(numpy.dot, (orbvb.T, veff[1], orbob)) return numpy.hstack((v1a.ravel(), v1b.ravel())) z1a, z1b = ucphf.solve(fvind, mo_energy, mo_occ, (wvoa,wvob), max_cycle=td_grad.cphf_max_cycle, tol=td_grad.cphf_conv_tol)[0] time1 = log.timer('Z-vector using UCPHF solver', *time0) z1ao = numpy.empty((2,nao,nao)) z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T)) z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T)) fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None, False, False, max_memory)[0] if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj[0]+vj[1] - hyb * vk + fxcz1[:,0] if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, z1ao, omega) * (alpha-hyb) else: vj = mf.get_j(mol, z1ao, hermi=1) veff = vj[0]+vj[1] + fxcz1[:,0] im0a = numpy.zeros((nmoa,nmoa)) im0b = numpy.zeros((nmob,nmob)) im0a[:nocca,:nocca] = reduce(numpy.dot, (orboa.T, veff0doo[0]+veff[0], orboa)) * .5 im0b[:noccb,:noccb] = reduce(numpy.dot, (orbob.T, veff0doo[1]+veff[1], orbob)) * .5 im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0mopa[nocca:,:nocca], xpya) * .5 im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0mopb[noccb:,:noccb], xpyb) * .5 im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0moma[nocca:,:nocca], xmya) * .5 im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0momb[noccb:,:noccb], xmyb) * .5 im0a[nocca:,nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:,:nocca], xpya) * .5 im0b[noccb:,noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:,:noccb], xpyb) * .5 im0a[nocca:,nocca:]+= numpy.einsum('ci,ai->ac', veff0moma[nocca:,:nocca], xmya) * .5 im0b[noccb:,noccb:]+= numpy.einsum('ci,ai->ac', veff0momb[noccb:,:noccb], xmyb) * .5 im0a[nocca:,:nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) im0b[noccb:,:noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) im0a[nocca:,:nocca]+= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya) im0b[noccb:,:noccb]+= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb) zeta_a = (mo_energy[0][:,None] + mo_energy[0]) * .5 zeta_b = (mo_energy[1][:,None] + mo_energy[1]) * .5 zeta_a[nocca:,:nocca] = mo_energy[0][:nocca] zeta_b[noccb:,:noccb] = mo_energy[1][:noccb] zeta_a[:nocca,nocca:] = mo_energy[0][nocca:] zeta_b[:noccb,noccb:] = mo_energy[1][noccb:] dm1a = numpy.zeros((nmoa,nmoa)) dm1b = numpy.zeros((nmob,nmob)) dm1a[:nocca,:nocca] = dooa * .5 dm1b[:noccb,:noccb] = doob * .5 dm1a[nocca:,nocca:] = dvva * .5 dm1b[noccb:,noccb:] = dvvb * .5 dm1a[nocca:,:nocca] = z1a * .5 dm1b[noccb:,:noccb] = z1b * .5 dm1a[:nocca,:nocca] += numpy.eye(nocca) # for ground state dm1b[:noccb,:noccb] += numpy.eye(noccb) im0a = reduce(numpy.dot, (mo_coeff[0], im0a+zeta_a*dm1a, mo_coeff[0].T)) im0b = reduce(numpy.dot, (mo_coeff[1], im0b+zeta_b*dm1b, mo_coeff[1].T)) im0 = im0a + im0b hcore_deriv = td_grad.hcore_generator(mol) s1 = td_grad.get_ovlp(mol) dmz1dooa = z1ao[0] + dmzooa dmz1doob = z1ao[1] + dmzoob oo0a = reduce(numpy.dot, (orboa, orboa.T)) oo0b = reduce(numpy.dot, (orbob, orbob.T)) as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5 if abs(hyb) > 1e-10: dm = (oo0a, dmz1dooa+dmz1dooa.T, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T, oo0b, dmz1doob+dmz1doob.T, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T) vj, vk = td_grad.get_jk(mol, dm) vj = vj.reshape(2,4,3,nao,nao) vk = vk.reshape(2,4,3,nao,nao) * hyb if abs(omega) > 1e-10: with mol.with_range_coulomb(omega): vk += td_grad.get_k(mol, dm).reshape(2,4,3,nao,nao) * (alpha-hyb) veff1 = vj[0] + vj[1] - vk else: dm = (oo0a, dmz1dooa+dmz1dooa.T, dmzvopa+dmzvopa.T, oo0b, dmz1doob+dmz1doob.T, dmzvopb+dmzvopb.T) vj = td_grad.get_j(mol, dm).reshape(2,3,3,nao,nao) veff1 = numpy.zeros((2,4,3,nao,nao)) veff1[:,:3] = vj[0] + vj[1] veff1[:,0] += vxc1[:,1:] veff1[:,1] +=(f1oo[:,1:] + fxcz1[:,1:] + k1ao[:,1:]*2)*2 # *2 for dmz1doo+dmz1oo.T veff1[:,2] += f1vo[:,1:] * 2 veff1a, veff1b = veff1 time1 = log.timer('2e AO integral derivatives', *time1) if atmlst is None: atmlst = range(mol.natm) offsetdic = mol.offset_nr_by_atom() de = numpy.zeros((len(atmlst),3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] # Ground state gradients h1ao = hcore_deriv(ia) de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1) de[k] += numpy.einsum('xpq,pq->x', veff1a[0,:,p0:p1], oo0a[p0:p1]) de[k] += numpy.einsum('xpq,pq->x', veff1b[0,:,p0:p1], oo0b[p0:p1]) de[k] += numpy.einsum('xpq,qp->x', veff1a[0,:,p0:p1], oo0a[:,p0:p1]) de[k] += numpy.einsum('xpq,qp->x', veff1b[0,:,p0:p1], oo0b[:,p0:p1]) de[k] += numpy.einsum('xpq,pq->x', veff1a[0,:,p0:p1], dmz1dooa[p0:p1]) * .5 de[k] += numpy.einsum('xpq,pq->x', veff1b[0,:,p0:p1], dmz1doob[p0:p1]) * .5 de[k] += numpy.einsum('xpq,qp->x', veff1a[0,:,p0:p1], dmz1dooa[:,p0:p1]) * .5 de[k] += numpy.einsum('xpq,qp->x', veff1b[0,:,p0:p1], dmz1doob[:,p0:p1]) * .5 de[k] -= numpy.einsum('xpq,pq->x', s1[:,p0:p1], im0[p0:p1]) de[k] -= numpy.einsum('xqp,pq->x', s1[:,p0:p1], im0[:,p0:p1]) de[k] += numpy.einsum('xij,ij->x', veff1a[1,:,p0:p1], oo0a[p0:p1]) * .5 de[k] += numpy.einsum('xij,ij->x', veff1b[1,:,p0:p1], oo0b[p0:p1]) * .5 de[k] += numpy.einsum('xij,ij->x', veff1a[2,:,p0:p1], dmzvopa[p0:p1,:]) de[k] += numpy.einsum('xij,ij->x', veff1b[2,:,p0:p1], dmzvopb[p0:p1,:]) de[k] += numpy.einsum('xij,ij->x', veff1a[3,:,p0:p1], dmzvoma[p0:p1,:]) de[k] += numpy.einsum('xij,ij->x', veff1b[3,:,p0:p1], dmzvomb[p0:p1,:]) de[k] += numpy.einsum('xji,ij->x', veff1a[2,:,p0:p1], dmzvopa[:,p0:p1]) de[k] += numpy.einsum('xji,ij->x', veff1b[2,:,p0:p1], dmzvopb[:,p0:p1]) de[k] -= numpy.einsum('xji,ij->x', veff1a[3,:,p0:p1], dmzvoma[:,p0:p1]) de[k] -= numpy.einsum('xji,ij->x', veff1b[3,:,p0:p1], dmzvomb[:,p0:p1]) log.timer('TDUHF nuclear gradients', *time0) return de
def kernel(td_grad, x_y, singlet=True, atmlst=None, max_memory=2000, verbose=logger.INFO): log = logger.new_logger(td_grad, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad.base._scf mo_coeff = mf.mo_coeff mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape nocc = (mo_occ>0).sum() nvir = nmo - nocc x, y = x_y xpy = (x+y).reshape(nocc,nvir).T xmy = (x-y).reshape(nocc,nvir).T orbv = mo_coeff[:,nocc:] orbo = mo_coeff[:,:nocc] dvv = numpy.einsum('ai,bi->ab', xpy, xpy) + numpy.einsum('ai,bi->ab', xmy, xmy) doo =-numpy.einsum('ai,aj->ij', xpy, xpy) - numpy.einsum('ai,aj->ij', xmy, xmy) dmzvop = reduce(numpy.dot, (orbv, xpy, orbo.T)) dmzvom = reduce(numpy.dot, (orbv, xmy, orbo.T)) dmzoo = reduce(numpy.dot, (orbo, doo, orbo.T)) dmzoo+= reduce(numpy.dot, (orbv, dvv, orbv.T)) mem_now = lib.current_memory()[0] max_memory = max(2000, td_grad.max_memory*.9-mem_now) ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 3, raise_error=True) omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) # dm0 = mf.make_rdm1(mo_coeff, mo_occ), but it is not used when computing # fxc since rho0 is passed to fxc function. dm0 = None rho0, vxc, fxc = ni.cache_xc_kernel(mf.mol, mf.grids, mf.xc, [mo_coeff]*2, [mo_occ*.5]*2, spin=1) f1vo, f1oo, vxc1, k1ao = \ _contract_xc_kernel(td_grad, mf.xc, dmzvop, dmzoo, True, True, singlet, max_memory) if abs(hyb) > 1e-10: dm = (dmzoo, dmzvop+dmzvop.T, dmzvom-dmzvom.T) vj, vk = mf.get_jk(mol, dm, hermi=0) vk *= hyb if abs(omega) > 1e-10: vk += rks._get_k_lr(mol, dm, omega) * (alpha-hyb) veff0doo = vj[0] * 2 - vk[0] + f1oo[0] + k1ao[0] * 2 wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - vk[1] + f1vo[0] * 2 else: veff = -vk[1] + f1vo[0] * 2 veff0mop = reduce(numpy.dot, (mo_coeff.T, veff, mo_coeff)) wvo -= numpy.einsum('ki,ai->ak', veff0mop[:nocc,:nocc], xpy) * 2 wvo += numpy.einsum('ac,ai->ci', veff0mop[nocc:,nocc:], xpy) * 2 veff = -vk[2] veff0mom = reduce(numpy.dot, (mo_coeff.T, veff, mo_coeff)) wvo -= numpy.einsum('ki,ai->ak', veff0mom[:nocc,:nocc], xmy) * 2 wvo += numpy.einsum('ac,ai->ci', veff0mom[nocc:,nocc:], xmy) * 2 else: vj = mf.get_j(mol, (dmzoo, dmzvop+dmzvop.T), hermi=1) veff0doo = vj[0] * 2 + f1oo[0] + k1ao[0] * 2 wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 + f1vo[0] * 2 else: veff = f1vo[0] * 2 veff0mop = reduce(numpy.dot, (mo_coeff.T, veff, mo_coeff)) wvo -= numpy.einsum('ki,ai->ak', veff0mop[:nocc,:nocc], xpy) * 2 wvo += numpy.einsum('ac,ai->ci', veff0mop[nocc:,nocc:], xpy) * 2 veff0mom = numpy.zeros((nmo,nmo)) def fvind(x): # Cannot make call to .base.get_vind because first order orbitals are solved # through closed shell ground state CPHF. dm = reduce(numpy.dot, (orbv, x.reshape(nvir,nocc), orbo.T)) dm = dm + dm.T # Call singlet XC kernel contraction, for closed shell ground state vindxc = numint.nr_rks_fxc_st(ni, mol, mf.grids, mf.xc, dm0, dm, 0, singlet, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm) veff = vj * 2 - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm, omega, hermi=1) * (alpha-hyb) else: vj = mf.get_j(mol, dm) veff = vj * 2 + vindxc return reduce(numpy.dot, (orbv.T, veff, orbo)).ravel() z1 = cphf.solve(fvind, mo_energy, mo_occ, wvo, max_cycle=td_grad.cphf_max_cycle, tol=td_grad.cphf_conv_tol)[0] z1 = z1.reshape(nvir,nocc) time1 = log.timer('Z-vector using CPHF solver', *time0) z1ao = reduce(numpy.dot, (orbv, z1, orbo.T)) # Note Z-vector is always associated to singlet integrals. fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None, False, False, True, max_memory)[0] if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj * 2 - hyb * vk + fxcz1[0] if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, z1ao, omega) * (alpha-hyb) else: vj = mf.get_j(mol, z1ao, hermi=1) veff = vj * 2 + fxcz1[0] im0 = numpy.zeros((nmo,nmo)) im0[:nocc,:nocc] = reduce(numpy.dot, (orbo.T, veff0doo+veff, orbo)) im0[:nocc,:nocc]+= numpy.einsum('ak,ai->ki', veff0mop[nocc:,:nocc], xpy) im0[:nocc,:nocc]+= numpy.einsum('ak,ai->ki', veff0mom[nocc:,:nocc], xmy) im0[nocc:,nocc:] = numpy.einsum('ci,ai->ac', veff0mop[nocc:,:nocc], xpy) im0[nocc:,nocc:]+= numpy.einsum('ci,ai->ac', veff0mom[nocc:,:nocc], xmy) im0[nocc:,:nocc] = numpy.einsum('ki,ai->ak', veff0mop[:nocc,:nocc], xpy)*2 im0[nocc:,:nocc]+= numpy.einsum('ki,ai->ak', veff0mom[:nocc,:nocc], xmy)*2 zeta = lib.direct_sum('i+j->ij', mo_energy, mo_energy) * .5 zeta[nocc:,:nocc] = mo_energy[:nocc] zeta[:nocc,nocc:] = mo_energy[nocc:] dm1 = numpy.zeros((nmo,nmo)) dm1[:nocc,:nocc] = doo dm1[nocc:,nocc:] = dvv dm1[nocc:,:nocc] = z1 dm1[:nocc,:nocc] += numpy.eye(nocc)*2 # for ground state im0 = reduce(numpy.dot, (mo_coeff, im0+zeta*dm1, mo_coeff.T)) hcore_deriv = td_grad.hcore_generator(mol) s1 = td_grad.get_ovlp(mol) dmz1doo = z1ao + dmzoo oo0 = reduce(numpy.dot, (orbo, orbo.T)) if abs(hyb) > 1e-10: dm = (oo0, dmz1doo+dmz1doo.T, dmzvop+dmzvop.T, dmzvom-dmzvom.T) vj, vk = td_grad.get_jk(mol, dm) vk *= hyb if abs(omega) > 1e-10: with mol.with_range_coulomb(omega): vk += td_grad.get_k(mol, dm) * (alpha-hyb) vj = vj.reshape(-1,3,nao,nao) vk = vk.reshape(-1,3,nao,nao) if singlet: veff1 = vj * 2 - vk else: veff1 = numpy.vstack((vj[:2]*2-vk[:2], -vk[2:])) else: vj = td_grad.get_j(mol, (oo0, dmz1doo+dmz1doo.T, dmzvop+dmzvop.T)) vj = vj.reshape(-1,3,nao,nao) veff1 = numpy.zeros((4,3,nao,nao)) if singlet: veff1[:3] = vj * 2 else: veff1[:2] = vj[:2] * 2 veff1[0] += vxc1[1:] veff1[1] +=(f1oo[1:] + fxcz1[1:] + k1ao[1:]*2)*2 # *2 for dmz1doo+dmz1oo.T veff1[2] += f1vo[1:] * 2 time1 = log.timer('2e AO integral derivatives', *time1) if atmlst is None: atmlst = range(mol.natm) offsetdic = mol.offset_nr_by_atom() de = numpy.zeros((len(atmlst),3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] # Ground state gradients h1ao = hcore_deriv(ia) h1ao[:,p0:p1] += veff1[0,:,p0:p1] h1ao[:,:,p0:p1] += veff1[0,:,p0:p1].transpose(0,2,1) # oo0*2 for doubly occupied orbitals e1 = numpy.einsum('xpq,pq->x', h1ao, oo0) * 2 e1 += numpy.einsum('xpq,pq->x', h1ao, dmz1doo) e1 -= numpy.einsum('xpq,pq->x', s1[:,p0:p1], im0[p0:p1]) e1 -= numpy.einsum('xqp,pq->x', s1[:,p0:p1], im0[:,p0:p1]) e1 += numpy.einsum('xij,ij->x', veff1[1,:,p0:p1], oo0[p0:p1]) e1 += numpy.einsum('xij,ij->x', veff1[2,:,p0:p1], dmzvop[p0:p1,:]) * 2 e1 += numpy.einsum('xij,ij->x', veff1[3,:,p0:p1], dmzvom[p0:p1,:]) * 2 e1 += numpy.einsum('xji,ij->x', veff1[2,:,p0:p1], dmzvop[:,p0:p1]) * 2 e1 -= numpy.einsum('xji,ij->x', veff1[3,:,p0:p1], dmzvom[:,p0:p1]) * 2 de[k] = e1 log.timer('TDDFT nuclear gradients', *time0) return de
def kernel(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO): log = logger.new_logger(td_grad, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad.base._scf mo_coeff = mf.mo_coeff mo_energy = mf.mo_energy mo_occ = mf.mo_occ 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) orboa = mo_coeff[0][:, occidxa] orbob = mo_coeff[1][:, occidxb] orbva = mo_coeff[0][:, viridxa] orbvb = mo_coeff[1][:, viridxb] nao = mo_coeff[0].shape[0] nmoa = nocca + nvira nmob = noccb + nvirb (xa, xb), (ya, yb) = x_y xpya = (xa + ya).reshape(nocca, nvira).T xpyb = (xb + yb).reshape(noccb, nvirb).T xmya = (xa - ya).reshape(nocca, nvira).T xmyb = (xb - yb).reshape(noccb, nvirb).T dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum( 'ai,bi->ab', xmya, xmya) dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum( 'ai,bi->ab', xmyb, xmyb) dooa = -numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum( 'ai,aj->ij', xmya, xmya) doob = -numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum( 'ai,aj->ij', xmyb, xmyb) dmzvopa = reduce(numpy.dot, (orbva, xpya, orboa.T)) dmzvopb = reduce(numpy.dot, (orbvb, xpyb, orbob.T)) dmzvoma = reduce(numpy.dot, (orbva, xmya, orboa.T)) dmzvomb = reduce(numpy.dot, (orbvb, xmyb, orbob.T)) dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T)) dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T)) dmzooa += reduce(numpy.dot, (orbva, dvva, orbva.T)) dmzoob += reduce(numpy.dot, (orbvb, dvvb, orbvb.T)) ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 3, raise_error=True) omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) # dm0 = mf.make_rdm1(mo_coeff, mo_occ), but it is not used when computing # fxc since rho0 is passed to fxc function. dm0 = None rho0, vxc, fxc = ni.cache_xc_kernel(mf.mol, mf.grids, mf.xc, mo_coeff, mo_occ, spin=1) f1vo, f1oo, vxc1, k1ao = \ _contract_xc_kernel(td_grad, mf.xc, (dmzvopa,dmzvopb), (dmzooa,dmzoob), True, True, max_memory) if abs(hyb) > 1e-10: dm = (dmzooa, dmzvopa + dmzvopa.T, dmzvoma - dmzvoma.T, dmzoob, dmzvopb + dmzvopb.T, dmzvomb - dmzvomb.T) vj, vk = mf.get_jk(mol, dm, hermi=0) vj = vj.reshape(2, 3, nao, nao) vk = vk.reshape(2, 3, nao, nao) * hyb if abs(omega) > 1e-10: vk += rks._get_k_lr(mol, dm, omega).reshape(2, 3, nao, nao) * (alpha - hyb) veff0doo = vj[0, 0] + vj[1, 0] - vk[:, 0] + f1oo[:, 0] + k1ao[:, 0] * 2 wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2 wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2 veff = vj[0, 1] + vj[1, 1] - vk[:, 1] + f1vo[:, 0] * 2 veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0])) veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1])) wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca], xpya) * 2 wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb], xpyb) * 2 wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:, nocca:], xpya) * 2 wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:, noccb:], xpyb) * 2 veff = -vk[:, 2] veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0])) veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1])) wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca, :nocca], xmya) * 2 wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb, :noccb], xmyb) * 2 wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:, nocca:], xmya) * 2 wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:, noccb:], xmyb) * 2 else: dm = (dmzooa, dmzvopa + dmzvopa.T, dmzoob, dmzvopb + dmzvopb.T) vj = mf.get_j(mol, dm, hermi=1).reshape(2, 2, nao, nao) veff0doo = vj[0, 0] + vj[1, 0] + f1oo[:, 0] + k1ao[:, 0] * 2 wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2 wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2 veff = vj[0, 1] + vj[1, 1] + f1vo[:, 0] * 2 veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0])) veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1])) wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca], xpya) * 2 wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb], xpyb) * 2 wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:, nocca:], xpya) * 2 wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:, noccb:], xpyb) * 2 veff0moma = numpy.zeros((nmoa, nmoa)) veff0momb = numpy.zeros((nmob, nmob)) def fvind(x): dm1 = numpy.empty((2, nao, nao)) xa = x[0, :nvira * nocca].reshape(nvira, nocca) xb = x[0, nvira * nocca:].reshape(nvirb, noccb) dma = reduce(numpy.dot, (orbva, xa, orboa.T)) dmb = reduce(numpy.dot, (orbvb, xb, orbob.T)) dm1[0] = dma + dma.T dm1[1] = dmb + dmb.T relativity = 0 hermi = 1 vindxc = numint.nr_uks_fxc(ni, mol, mf.grids, mf.xc, dm0, dm1, relativity, hermi, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm1) veff = vj[0] + vj[1] - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm1, omega, hermi=1) * (alpha - hyb) else: vj = mf.get_j(mol, dm1) veff = vj[0] + vj[1] + vindxc v1a = reduce(numpy.dot, (orbva.T, veff[0], orboa)) v1b = reduce(numpy.dot, (orbvb.T, veff[1], orbob)) return numpy.hstack((v1a.ravel(), v1b.ravel())) z1a, z1b = ucphf.solve(fvind, mo_energy, mo_occ, (wvoa, wvob), max_cycle=td_grad.cphf_max_cycle, tol=td_grad.cphf_conv_tol)[0] time1 = log.timer('Z-vector using UCPHF solver', *time0) z1ao = numpy.empty((2, nao, nao)) z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T)) z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T)) fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None, False, False, max_memory)[0] if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj[0] + vj[1] - hyb * vk + fxcz1[:, 0] if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, z1ao, omega) * (alpha - hyb) else: vj = mf.get_j(mol, z1ao, hermi=1) veff = vj[0] + vj[1] + fxcz1[:, 0] im0a = numpy.zeros((nmoa, nmoa)) im0b = numpy.zeros((nmob, nmob)) im0a[:nocca, :nocca] = reduce(numpy.dot, (orboa.T, veff0doo[0] + veff[0], orboa)) * .5 im0b[:noccb, :noccb] = reduce(numpy.dot, (orbob.T, veff0doo[1] + veff[1], orbob)) * .5 im0a[:nocca, :nocca] += numpy.einsum('ak,ai->ki', veff0mopa[nocca:, :nocca], xpya) * .5 im0b[:noccb, :noccb] += numpy.einsum('ak,ai->ki', veff0mopb[noccb:, :noccb], xpyb) * .5 im0a[:nocca, :nocca] += numpy.einsum('ak,ai->ki', veff0moma[nocca:, :nocca], xmya) * .5 im0b[:noccb, :noccb] += numpy.einsum('ak,ai->ki', veff0momb[noccb:, :noccb], xmyb) * .5 im0a[nocca:, nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:, :nocca], xpya) * .5 im0b[noccb:, noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:, :noccb], xpyb) * .5 im0a[nocca:, nocca:] += numpy.einsum('ci,ai->ac', veff0moma[nocca:, :nocca], xmya) * .5 im0b[noccb:, noccb:] += numpy.einsum('ci,ai->ac', veff0momb[noccb:, :noccb], xmyb) * .5 im0a[nocca:, :nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca], xpya) im0b[noccb:, :noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb], xpyb) im0a[nocca:, :nocca] += numpy.einsum('ki,ai->ak', veff0moma[:nocca, :nocca], xmya) im0b[noccb:, :noccb] += numpy.einsum('ki,ai->ak', veff0momb[:noccb, :noccb], xmyb) zeta_a = (mo_energy[0][:, None] + mo_energy[0]) * .5 zeta_b = (mo_energy[1][:, None] + mo_energy[1]) * .5 zeta_a[nocca:, :nocca] = mo_energy[0][:nocca] zeta_b[noccb:, :noccb] = mo_energy[1][:noccb] zeta_a[:nocca, nocca:] = mo_energy[0][nocca:] zeta_b[:noccb, noccb:] = mo_energy[1][noccb:] dm1a = numpy.zeros((nmoa, nmoa)) dm1b = numpy.zeros((nmob, nmob)) dm1a[:nocca, :nocca] = dooa * .5 dm1b[:noccb, :noccb] = doob * .5 dm1a[nocca:, nocca:] = dvva * .5 dm1b[noccb:, noccb:] = dvvb * .5 dm1a[nocca:, :nocca] = z1a * .5 dm1b[noccb:, :noccb] = z1b * .5 dm1a[:nocca, :nocca] += numpy.eye(nocca) # for ground state dm1b[:noccb, :noccb] += numpy.eye(noccb) im0a = reduce(numpy.dot, (mo_coeff[0], im0a + zeta_a * dm1a, mo_coeff[0].T)) im0b = reduce(numpy.dot, (mo_coeff[1], im0b + zeta_b * dm1b, mo_coeff[1].T)) im0 = im0a + im0b hcore_deriv = td_grad.hcore_generator(mol) s1 = td_grad.get_ovlp(mol) dmz1dooa = z1ao[0] + dmzooa dmz1doob = z1ao[1] + dmzoob oo0a = reduce(numpy.dot, (orboa, orboa.T)) oo0b = reduce(numpy.dot, (orbob, orbob.T)) as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5 if abs(hyb) > 1e-10: dm = (oo0a, dmz1dooa + dmz1dooa.T, dmzvopa + dmzvopa.T, dmzvoma - dmzvoma.T, oo0b, dmz1doob + dmz1doob.T, dmzvopb + dmzvopb.T, dmzvomb - dmzvomb.T) vj, vk = td_grad.get_jk(mol, dm) vj = vj.reshape(2, 4, 3, nao, nao) vk = vk.reshape(2, 4, 3, nao, nao) * hyb if abs(omega) > 1e-10: with mol.with_range_coulomb(omega): vk += td_grad.get_k(mol, dm).reshape(2, 4, 3, nao, nao) * (alpha - hyb) veff1 = vj[0] + vj[1] - vk else: dm = (oo0a, dmz1dooa + dmz1dooa.T, dmzvopa + dmzvopa.T, oo0b, dmz1doob + dmz1doob.T, dmzvopb + dmzvopb.T) vj = td_grad.get_j(mol, dm).reshape(2, 3, 3, nao, nao) veff1 = numpy.zeros((2, 4, 3, nao, nao)) veff1[:, :3] = vj[0] + vj[1] veff1[:, 0] += vxc1[:, 1:] veff1[:, 1] += (f1oo[:, 1:] + fxcz1[:, 1:] + k1ao[:, 1:] * 2) * 2 # *2 for dmz1doo+dmz1oo.T veff1[:, 2] += f1vo[:, 1:] * 2 veff1a, veff1b = veff1 time1 = log.timer('2e AO integral derivatives', *time1) if atmlst is None: atmlst = range(mol.natm) offsetdic = mol.offset_nr_by_atom() de = numpy.zeros((len(atmlst), 3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] # Ground state gradients h1ao = hcore_deriv(ia) de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1) de[k] += numpy.einsum('xpq,pq->x', veff1a[0, :, p0:p1], oo0a[p0:p1]) de[k] += numpy.einsum('xpq,pq->x', veff1b[0, :, p0:p1], oo0b[p0:p1]) de[k] += numpy.einsum('xpq,qp->x', veff1a[0, :, p0:p1], oo0a[:, p0:p1]) de[k] += numpy.einsum('xpq,qp->x', veff1b[0, :, p0:p1], oo0b[:, p0:p1]) de[k] += numpy.einsum('xpq,pq->x', veff1a[0, :, p0:p1], dmz1dooa[p0:p1]) * .5 de[k] += numpy.einsum('xpq,pq->x', veff1b[0, :, p0:p1], dmz1doob[p0:p1]) * .5 de[k] += numpy.einsum('xpq,qp->x', veff1a[0, :, p0:p1], dmz1dooa[:, p0:p1]) * .5 de[k] += numpy.einsum('xpq,qp->x', veff1b[0, :, p0:p1], dmz1doob[:, p0:p1]) * .5 de[k] -= numpy.einsum('xpq,pq->x', s1[:, p0:p1], im0[p0:p1]) de[k] -= numpy.einsum('xqp,pq->x', s1[:, p0:p1], im0[:, p0:p1]) de[k] += numpy.einsum('xij,ij->x', veff1a[1, :, p0:p1], oo0a[p0:p1]) * .5 de[k] += numpy.einsum('xij,ij->x', veff1b[1, :, p0:p1], oo0b[p0:p1]) * .5 de[k] += numpy.einsum('xij,ij->x', veff1a[2, :, p0:p1], dmzvopa[p0:p1, :]) de[k] += numpy.einsum('xij,ij->x', veff1b[2, :, p0:p1], dmzvopb[p0:p1, :]) de[k] += numpy.einsum('xij,ij->x', veff1a[3, :, p0:p1], dmzvoma[p0:p1, :]) de[k] += numpy.einsum('xij,ij->x', veff1b[3, :, p0:p1], dmzvomb[p0:p1, :]) de[k] += numpy.einsum('xji,ij->x', veff1a[2, :, p0:p1], dmzvopa[:, p0:p1]) de[k] += numpy.einsum('xji,ij->x', veff1b[2, :, p0:p1], dmzvopb[:, p0:p1]) de[k] -= numpy.einsum('xji,ij->x', veff1a[3, :, p0:p1], dmzvoma[:, p0:p1]) de[k] -= numpy.einsum('xji,ij->x', veff1b[3, :, p0:p1], dmzvomb[:, p0:p1]) log.timer('TDUHF nuclear gradients', *time0) return de
def get_veff(ks, mol=None, dm=None, 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 mol is None: mol = ks.mol if dm is None: dm = ks.make_rdm1() if not isinstance(dm, numpy.ndarray): dm = numpy.asarray(dm) if dm.ndim == 2: # RHF DM dm = numpy.asarray((dm * .5, dm * .5)) ground_state = (dm.ndim == 3 and dm.shape[0] == 2) t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.grids = rks.prune_small_rho_grids_(ks, mol, dm[0] + dm[1], ks.grids) t0 = logger.timer(ks, 'setting up grids', *t0) if ks.nlc != '': if ks.nlcgrids.coords is None: ks.nlcgrids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.nlcgrids = rks.prune_small_rho_grids_( ks, mol, dm[0] + dm[1], ks.nlcgrids) t0 = logger.timer(ks, 'setting up nlc grids', *t0) ni = ks._numint if hermi == 2: # because rho = 0 n, exc, vxc = (0, 0), 0, 0 else: max_memory = ks.max_memory - lib.current_memory()[0] n, exc, vxc = ni.nr_uks(mol, ks.grids, ks.xc, dm, max_memory=max_memory) if ks.nlc != '': assert ('VV10' in ks.nlc.upper()) _, enlc, vnlc = ni.nr_rks(mol, ks.nlcgrids, ks.xc + '__' + ks.nlc, dm[0] + dm[1], max_memory=max_memory) exc += enlc vxc += vnlc logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) #enabling range-separated hybrids omega, alpha, hyb = ni.rsh_and_hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10 and abs(alpha) < 1e-10: vk = None if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vj', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj = ks.get_j(mol, ddm[0] + ddm[1], hermi) vj += vhf_last.vj else: vj = ks.get_j(mol, dm[0] + dm[1], hermi) vxc += vj else: if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vk', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vk *= hyb if abs(omega) > 1e-10: vklr = rks._get_k_lr(mol, ddm, omega, hermi, ks.opt) vklr *= (alpha - hyb) vk += vklr vj = vj[0] + vj[1] + vhf_last.vj vk += vhf_last.vk else: vj, vk = ks.get_jk(mol, dm, hermi) vj = vj[0] + vj[1] vk *= hyb if abs(omega) > 1e-10: vklr = rks._get_k_lr(mol, dm, omega, hermi, ks.opt) vklr *= (alpha - hyb) vk += vklr vxc += vj - vk if ground_state: exc -= (numpy.einsum('ij,ji', dm[0], vk[0]) + numpy.einsum('ij,ji', dm[1], vk[1])) * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm[0] + dm[1], vj) * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk) return vxc
def kernel(td_grad, x_y, singlet=True, atmlst=None, max_memory=2000, verbose=logger.INFO): log = logger.new_logger(td_grad, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad.base._scf mo_coeff = mf.mo_coeff mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape nocc = (mo_occ > 0).sum() nvir = nmo - nocc x, y = x_y xpy = (x + y).reshape(nocc, nvir).T xmy = (x - y).reshape(nocc, nvir).T orbv = mo_coeff[:, nocc:] orbo = mo_coeff[:, :nocc] dvv = numpy.einsum('ai,bi->ab', xpy, xpy) + numpy.einsum( 'ai,bi->ab', xmy, xmy) doo = -numpy.einsum('ai,aj->ij', xpy, xpy) - numpy.einsum( 'ai,aj->ij', xmy, xmy) dmzvop = reduce(numpy.dot, (orbv, xpy, orbo.T)) dmzvom = reduce(numpy.dot, (orbv, xmy, orbo.T)) dmzoo = reduce(numpy.dot, (orbo, doo, orbo.T)) dmzoo += reduce(numpy.dot, (orbv, dvv, orbv.T)) mem_now = lib.current_memory()[0] max_memory = max(2000, td_grad.max_memory * .9 - mem_now) ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 3, raise_error=True) omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) # dm0 = mf.make_rdm1(mo_coeff, mo_occ), but it is not used when computing # fxc since rho0 is passed to fxc function. dm0 = None rho0, vxc, fxc = ni.cache_xc_kernel(mf.mol, mf.grids, mf.xc, [mo_coeff] * 2, [mo_occ * .5] * 2, spin=1) f1vo, f1oo, vxc1, k1ao = \ _contract_xc_kernel(td_grad, mf.xc, dmzvop, dmzoo, True, True, singlet, max_memory) if abs(hyb) > 1e-10: dm = (dmzoo, dmzvop + dmzvop.T, dmzvom - dmzvom.T) vj, vk = mf.get_jk(mol, dm, hermi=0) vk *= hyb if abs(omega) > 1e-10: vk += rks._get_k_lr(mol, dm, omega) * (alpha - hyb) veff0doo = vj[0] * 2 - vk[0] + f1oo[0] + k1ao[0] * 2 wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - vk[1] + f1vo[0] * 2 else: veff = -vk[1] + f1vo[0] * 2 veff0mop = reduce(numpy.dot, (mo_coeff.T, veff, mo_coeff)) wvo -= numpy.einsum('ki,ai->ak', veff0mop[:nocc, :nocc], xpy) * 2 wvo += numpy.einsum('ac,ai->ci', veff0mop[nocc:, nocc:], xpy) * 2 veff = -vk[2] veff0mom = reduce(numpy.dot, (mo_coeff.T, veff, mo_coeff)) wvo -= numpy.einsum('ki,ai->ak', veff0mom[:nocc, :nocc], xmy) * 2 wvo += numpy.einsum('ac,ai->ci', veff0mom[nocc:, nocc:], xmy) * 2 else: vj = mf.get_j(mol, (dmzoo, dmzvop + dmzvop.T), hermi=1) veff0doo = vj[0] * 2 + f1oo[0] + k1ao[0] * 2 wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 + f1vo[0] * 2 else: veff = f1vo[0] * 2 veff0mop = reduce(numpy.dot, (mo_coeff.T, veff, mo_coeff)) wvo -= numpy.einsum('ki,ai->ak', veff0mop[:nocc, :nocc], xpy) * 2 wvo += numpy.einsum('ac,ai->ci', veff0mop[nocc:, nocc:], xpy) * 2 veff0mom = numpy.zeros((nmo, nmo)) def fvind(x): # Cannot make call to .base.get_vind because first order orbitals are solved # through closed shell ground state CPHF. dm = reduce(numpy.dot, (orbv, x.reshape(nvir, nocc), orbo.T)) dm = dm + dm.T # Call singlet XC kernel contraction, for closed shell ground state vindxc = numint.nr_rks_fxc_st(ni, mol, mf.grids, mf.xc, dm0, dm, 0, singlet, rho0, vxc, fxc, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm) veff = vj * 2 - hyb * vk + vindxc if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, dm, omega, hermi=1) * (alpha - hyb) else: vj = mf.get_j(mol, dm) veff = vj * 2 + vindxc return reduce(numpy.dot, (orbv.T, veff, orbo)).ravel() z1 = cphf.solve(fvind, mo_energy, mo_occ, wvo, max_cycle=td_grad.cphf_max_cycle, tol=td_grad.cphf_conv_tol)[0] z1 = z1.reshape(nvir, nocc) time1 = log.timer('Z-vector using CPHF solver', *time0) z1ao = reduce(numpy.dot, (orbv, z1, orbo.T)) # Note Z-vector is always associated to singlet integrals. fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None, False, False, True, max_memory)[0] if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj * 2 - hyb * vk + fxcz1[0] if abs(omega) > 1e-10: veff -= rks._get_k_lr(mol, z1ao, omega) * (alpha - hyb) else: vj = mf.get_j(mol, z1ao, hermi=1) veff = vj * 2 + fxcz1[0] im0 = numpy.zeros((nmo, nmo)) im0[:nocc, :nocc] = reduce(numpy.dot, (orbo.T, veff0doo + veff, orbo)) im0[:nocc, :nocc] += numpy.einsum('ak,ai->ki', veff0mop[nocc:, :nocc], xpy) im0[:nocc, :nocc] += numpy.einsum('ak,ai->ki', veff0mom[nocc:, :nocc], xmy) im0[nocc:, nocc:] = numpy.einsum('ci,ai->ac', veff0mop[nocc:, :nocc], xpy) im0[nocc:, nocc:] += numpy.einsum('ci,ai->ac', veff0mom[nocc:, :nocc], xmy) im0[nocc:, :nocc] = numpy.einsum('ki,ai->ak', veff0mop[:nocc, :nocc], xpy) * 2 im0[nocc:, :nocc] += numpy.einsum('ki,ai->ak', veff0mom[:nocc, :nocc], xmy) * 2 zeta = lib.direct_sum('i+j->ij', mo_energy, mo_energy) * .5 zeta[nocc:, :nocc] = mo_energy[:nocc] zeta[:nocc, nocc:] = mo_energy[nocc:] dm1 = numpy.zeros((nmo, nmo)) dm1[:nocc, :nocc] = doo dm1[nocc:, nocc:] = dvv dm1[nocc:, :nocc] = z1 dm1[:nocc, :nocc] += numpy.eye(nocc) * 2 # for ground state im0 = reduce(numpy.dot, (mo_coeff, im0 + zeta * dm1, mo_coeff.T)) hcore_deriv = td_grad.hcore_generator(mol) s1 = td_grad.get_ovlp(mol) dmz1doo = z1ao + dmzoo oo0 = reduce(numpy.dot, (orbo, orbo.T)) if abs(hyb) > 1e-10: dm = (oo0, dmz1doo + dmz1doo.T, dmzvop + dmzvop.T, dmzvom - dmzvom.T) vj, vk = td_grad.get_jk(mol, dm) vk *= hyb if abs(omega) > 1e-10: with mol.with_range_coulomb(omega): vk += td_grad.get_k(mol, dm) * (alpha - hyb) vj = vj.reshape(-1, 3, nao, nao) vk = vk.reshape(-1, 3, nao, nao) if singlet: veff1 = vj * 2 - vk else: veff1 = numpy.vstack((vj[:2] * 2 - vk[:2], -vk[2:])) else: vj = td_grad.get_j(mol, (oo0, dmz1doo + dmz1doo.T, dmzvop + dmzvop.T)) vj = vj.reshape(-1, 3, nao, nao) veff1 = numpy.zeros((4, 3, nao, nao)) if singlet: veff1[:3] = vj * 2 else: veff1[:2] = vj[:2] * 2 veff1[0] += vxc1[1:] veff1[1] += (f1oo[1:] + fxcz1[1:] + k1ao[1:] * 2) * 2 # *2 for dmz1doo+dmz1oo.T veff1[2] += f1vo[1:] * 2 time1 = log.timer('2e AO integral derivatives', *time1) if atmlst is None: atmlst = range(mol.natm) offsetdic = mol.offset_nr_by_atom() de = numpy.zeros((len(atmlst), 3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] # Ground state gradients h1ao = hcore_deriv(ia) h1ao[:, p0:p1] += veff1[0, :, p0:p1] h1ao[:, :, p0:p1] += veff1[0, :, p0:p1].transpose(0, 2, 1) # oo0*2 for doubly occupied orbitals e1 = numpy.einsum('xpq,pq->x', h1ao, oo0) * 2 e1 += numpy.einsum('xpq,pq->x', h1ao, dmz1doo) e1 -= numpy.einsum('xpq,pq->x', s1[:, p0:p1], im0[p0:p1]) e1 -= numpy.einsum('xqp,pq->x', s1[:, p0:p1], im0[:, p0:p1]) e1 += numpy.einsum('xij,ij->x', veff1[1, :, p0:p1], oo0[p0:p1]) e1 += numpy.einsum('xij,ij->x', veff1[2, :, p0:p1], dmzvop[p0:p1, :]) * 2 e1 += numpy.einsum('xij,ij->x', veff1[3, :, p0:p1], dmzvom[p0:p1, :]) * 2 e1 += numpy.einsum('xji,ij->x', veff1[2, :, p0:p1], dmzvop[:, p0:p1]) * 2 e1 -= numpy.einsum('xji,ij->x', veff1[3, :, p0:p1], dmzvom[:, p0:p1]) * 2 de[k] = e1 log.timer('TDDFT nuclear gradients', *time0) return de
def get_veff(ks, mol=None, dm=None, 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 mol is None: mol = ks.mol if dm is None: dm = ks.make_rdm1() if not isinstance(dm, numpy.ndarray): dm = numpy.asarray(dm) if dm.ndim == 2: # RHF DM dm = numpy.asarray((dm*.5,dm*.5)) ground_state = (dm.ndim == 3 and dm.shape[0] == 2) t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.grids = rks.prune_small_rho_grids_(ks, mol, dm[0]+dm[1], ks.grids) t0 = logger.timer(ks, 'setting up grids', *t0) if ks.nlc != '': if ks.nlcgrids.coords is None: ks.nlcgrids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.nlcgrids = rks.prune_small_rho_grids_(ks, mol, dm[0]+dm[1], ks.nlcgrids) t0 = logger.timer(ks, 'setting up nlc grids', *t0) ni = ks._numint if hermi == 2: # because rho = 0 n, exc, vxc = (0,0), 0, 0 else: max_memory = ks.max_memory - lib.current_memory()[0] n, exc, vxc = ni.nr_uks(mol, ks.grids, ks.xc, dm, max_memory=max_memory) if ks.nlc != '': assert('VV10' in ks.nlc.upper()) _, enlc, vnlc = ni.nr_rks(mol, ks.nlcgrids, ks.xc+'__'+ks.nlc, dm[0]+dm[1], max_memory=max_memory) exc += enlc vxc += vnlc logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) #enabling range-separated hybrids omega, alpha, hyb = ni.rsh_and_hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10 and abs(alpha) < 1e-10: vk = None if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vj', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj = ks.get_j(mol, ddm[0]+ddm[1], hermi) vj += vhf_last.vj else: vj = ks.get_j(mol, dm[0]+dm[1], hermi) vxc += vj else: if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vk', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vk *= hyb if abs(omega) > 1e-10: vklr = rks._get_k_lr(mol, ddm, omega, hermi) vklr *= (alpha - hyb) vk += vklr vj = vj[0] + vj[1] + vhf_last.vj vk += vhf_last.vk else: vj, vk = ks.get_jk(mol, dm, hermi) vj = vj[0] + vj[1] vk *= hyb if abs(omega) > 1e-10: vklr = rks._get_k_lr(mol, dm, omega, hermi) vklr *= (alpha - hyb) vk += vklr vxc += vj - vk if ground_state: exc -=(numpy.einsum('ij,ji', dm[0], vk[0]) + numpy.einsum('ij,ji', dm[1], vk[1])) * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm[0]+dm[1], vj) * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk) return vxc