def solve_mo1(sscobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): cput1 = (time.clock(), time.time()) log = logger.Logger(sscobj.stdout, sscobj.verbose) if mo_energy is None: mo_energy = sscobj._scf.mo_energy if mo_coeff is None: mo_coeff = sscobj._scf.mo_coeff if mo_occ is None: mo_occ = sscobj._scf.mo_occ if with_cphf is None: with_cphf = sscobj.cphf mol = sscobj.mol if h1 is None: atmlst = sorted(set([j for i,j in sscobj.nuc_pair])) h1 = numpy.asarray(make_h1_pso(mol, mo_coeff, mo_occ, atmlst)) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(sscobj._scf, mo_coeff, mo_occ) mo1, mo_e1 = cphf.solve(vind, mo_energy, mo_occ, h1, None, sscobj.max_cycle_cphf, sscobj.conv_tol, verbose=log) else: e_ai = lib.direct_sum('i-a->ai', mo_energy[mo_occ>0], mo_energy[mo_occ==0]) mo1 = h1 * (1 / e_ai) mo_e1 = None logger.timer(sscobj, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def solve_mo1(self, mo_energy=None, mo_occ=None, h1=None, with_cphf=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ if with_cphf is None: with_cphf = self.cphf mol = self.mol mo_coeff = self._scf.mo_coeff if h1 is None: atmlst = sorted(set([j for i, j in self.nuc_pair])) h1 = numpy.asarray(make_h1_pso(mol, mo_coeff, mo_occ, atmlst)) if with_cphf: vind = self.gen_vind(self._scf, mo_coeff, mo_occ) mo1, mo_e1 = cphf.solve(vind, mo_energy, mo_occ, h1, None, self.max_cycle_cphf, self.conv_tol, verbose=log) else: e_ai = lib.direct_sum('i-a->ai', mo_energy[mo_occ > 0], mo_energy[mo_occ == 0]) mo1 = h1 * (1 / e_ai) mo_e1 = None logger.timer(self, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def solve_mo1(self, mo_energy=None, mo_occ=None, h1=None, s1=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ mol = self.mol if h1 is None: mo_coeff = self._scf.mo_coeff dm0 = self._scf.make_rdm1(mo_coeff, mo_occ) h1 = _mat_ao2mo(self.make_h10(mol, dm0), mo_coeff, mo_occ) if s1 is None: s1 = _mat_ao2mo(self.make_s10(mol), mo_coeff, mo_occ) cput1 = log.timer("first order Fock matrix", *cput1) if self.cphf: mo10, mo_e10 = cphf.solve( self.get_vind, mo_energy, mo_occ, h1, s1, self.max_cycle_cphf, self.conv_tol, verbose=log ) else: mo10, mo_e10 = solve_mo1(mo_energy, mo_occ, h1, s1) logger.timer(self, "solving mo1 eqn", *cput1) return mo10, mo_e10
def response_dm1(cc, t1, t2, l1, l2, eris=None, IX=None): from pyscf.scf import cphf if eris is None: # Note eris are in Chemist's notation eris = ccsd._ERIS(cc) if IX is None: Ioo, Ivv, Ivo, Xvo = IX_intermediates(cc, t1, t2, l1, l2, eris) else: Ioo, Ivv, Ivo, Xvo = IX nocc, nvir = t1.shape nmo = nocc + nvir def fvind(x): x = x.reshape(Xvo.shape) if eris is None: mo_coeff = cc.mo_coeff dm = reduce(numpy.dot, (mo_coeff[:,nocc:], x, mo_coeff[:,:nocc].T)) v = reduce(numpy.dot, (mo_coeff[:,nocc:].T, cc._scf.get_veff(mol, dm), mo_coeff[:,:nocc])) else: v = numpy.einsum('iajb,bj->ai', eris.ovov, x) * 4 v -= numpy.einsum('jiab,bj->ai', eris.oovv, x) v -= numpy.einsum('ibja,bj->ai', eris.ovov, x) return v mo_energy = eris.fock.diagonal() mo_occ = numpy.zeros_like(mo_energy) mo_occ[:nocc] = 2 dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo,nmo)) dm1[nocc:,:nocc] = dvo dm1[:nocc,nocc:] = dvo.T return dm1
def _response_dm1(mycc, Xvo, eris=None): nvir, nocc = Xvo.shape nmo = nocc + nvir with_frozen = not (mycc.frozen is None or mycc.frozen is 0) if eris is None or with_frozen: mo_energy = mycc._scf.mo_energy mo_occ = mycc.mo_occ mo_coeff = mycc.mo_coeff def fvind(x): x = x.reshape(Xvo.shape) dm = reduce(numpy.dot, (mo_coeff[:,nocc:], x, mo_coeff[:,:nocc].T)) v = mycc._scf.get_veff(mycc.mol, dm + dm.T) v = reduce(numpy.dot, (mo_coeff[:,nocc:].T, v, mo_coeff[:,:nocc])) return v * 2 else: mo_energy = eris.mo_energy mo_occ = numpy.zeros_like(mo_energy) mo_occ[:nocc] = 2 ovvo = numpy.empty((nocc,nvir,nvir,nocc)) for i in range(nocc): ovvo[i] = eris.ovvo[i] ovvo[i] = ovvo[i] * 4 - ovvo[i].transpose(1,0,2) ovvo[i]-= eris.oovv[i].transpose(2,1,0) def fvind(x): return numpy.einsum('iabj,bj->ai', ovvo, x.reshape(Xvo.shape)) dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo,nmo)) dm1[nocc:,:nocc] = dvo dm1[:nocc,nocc:] = dvo.T return dm1
def h_op(x): x = x.reshape(natm,3) hx = numpy.einsum('abxy,ax->by', de2, x) h1ao = 0 s1ao = 0 for ia in range(natm): shl0, shl1, p0, p1 = aoslices[ia] h1ao_i = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/%d' % ia) h1ao += numpy.einsum('x,xij->ij', x[ia], h1ao_i) s1ao_i = numpy.zeros((3,nao,nao)) s1ao_i[:,p0:p1] += s1a[:,p0:p1] s1ao_i[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1ao += numpy.einsum('x,xij->ij', x[ia], s1ao_i) s1vo = reduce(numpy.dot, (mo_coeff.T, s1ao, mocc)) h1vo = reduce(numpy.dot, (mo_coeff.T, h1ao, mocc)) mo1, mo_e1 = cphf.solve(fvind, mo_energy, mo_occ, h1vo, s1vo) mo1 = numpy.dot(mo_coeff, mo1) mo_e1 = mo_e1.reshape(nocc,nocc) dm1 = numpy.einsum('pi,qi->pq', mo1, mocc) dme1 = numpy.einsum('pi,qi,i->pq', mo1, mocc, mo_energy[mo_occ>0]) dme1 = dme1 + dme1.T + reduce(numpy.dot, (mocc, mo_e1.T, mocc.T)) for ja in range(natm): q0, q1 = aoslices[ja][2:] h1ao = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/%s'%ja) hx[ja] += numpy.einsum('xpq,pq->x', h1ao, dm1) * 4 hx[ja] -= numpy.einsum('xpq,pq->x', s1a[:,q0:q1], dme1[q0:q1]) * 2 hx[ja] -= numpy.einsum('xpq,qp->x', s1a[:,q0:q1], dme1[:,q0:q1]) * 2 return hx.ravel()
def h_op(x): x = x.reshape(natm,3) hx = numpy.einsum('abxy,ax->by', de2, x) h1ao = 0 s1ao = 0 for ia in range(natm): shl0, shl1, p0, p1 = aoslices[ia] h1ao_i = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/%d' % ia) h1ao += numpy.einsum('x,xij->ij', x[ia], h1ao_i) s1ao_i = numpy.zeros((3,nao,nao)) s1ao_i[:,p0:p1] += s1a[:,p0:p1] s1ao_i[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1ao += numpy.einsum('x,xij->ij', x[ia], s1ao_i) s1vo = reduce(numpy.dot, (mo_coeff.T, s1ao, mocc)) h1vo = reduce(numpy.dot, (mo_coeff.T, h1ao, mocc)) mo1, mo_e1 = cphf.solve(fvind, mo_energy, mo_occ, h1vo, s1vo) mo1 = numpy.dot(mo_coeff, mo1) mo_e1 = mo_e1.reshape(nocc,nocc) dm1 = numpy.einsum('pi,qi->pq', mo1, mocc) dme1 = numpy.einsum('pi,qi,i->pq', mo1, mocc, mo_energy[mo_occ>0]) dme1 = dme1 + dme1.T + reduce(numpy.dot, (mocc, mo_e1, mocc.T)) for ja in range(natm): q0, q1 = aoslices[ja][2:] h1ao = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/%s'%ja) hx[ja] += numpy.einsum('xpq,pq->x', h1ao, dm1) * 4 hx[ja] -= numpy.einsum('xpq,pq->x', s1a[:,q0:q1], dme1[q0:q1]) * 2 hx[ja] -= numpy.einsum('xpq,qp->x', s1a[:,q0:q1], dme1[:,q0:q1]) * 2 return hx.ravel()
def solve_cphf_rhf(mf, Lvo, max_cycle, tol, logger): ''' Solve the CPHF equations. (e[i] - e[a]) zvo[a, i] - sum_bj [ 4 (ai|bj) - (ab|ij) - (aj|ib) ] zvo[b, j] = Lvo[a, i] Args: mf : an RHF object Lvo : right-hand side the the response equation max_cycle : number of iterations for the CPHF solver tol : convergence tolerance for the CPHF solver logger : Logger object ''' logger.info('Solving the CPHF response equations') logger.info('Max. iterations: {0:d}'.format(max_cycle)) logger.info('Convergence tolerance: {0:.3g}'.format(tol)) # Currently we need to make the CPHF solver somewhat more talkative to see anything at all. cphf_verbose = logger.verbose if logger.verbose == lib.logger.INFO: cphf_verbose = lib.logger.DEBUG def fvind(z): return fock_response_rhf(mf, z.reshape(Lvo.shape), full=False) zvo = cphf.solve(fvind, mf.mo_energy, mf.mo_occ, Lvo, max_cycle=max_cycle, tol=tol, verbose=cphf_verbose)[0] logger.info('CPHF iterations finished') return zvo
def _get_Z(self): so, sv, sa = self.so, self.sv, self.sa Ax0_Core = self.Ax0_Core e, mo_occ = self.e, self.mo_occ F_0_mo = self.nc_deriv.F_0_mo Z = cphf.solve(Ax0_Core(sv, so, sv, so), e, mo_occ, F_0_mo[sv, so], max_cycle=100, tol=1e-15)[0] return Z
def _response_dm1(mycc, Xvo, eris=None): nvir, nocc = Xvo.shape nmo = nocc + nvir with_frozen = not (mycc.frozen is None or mycc.frozen is 0) if eris is None or with_frozen: mo_energy = mycc._scf.mo_energy mo_occ = mycc.mo_occ mo_coeff = mycc.mo_coeff def fvind(x): x = x.reshape(Xvo.shape) dm = reduce(numpy.dot, (mo_coeff[:, nocc:], x, mo_coeff[:, :nocc].T)) v = mycc._scf.get_veff(mycc.mol, dm + dm.T) v = reduce(numpy.dot, (mo_coeff[:, nocc:].T, v, mo_coeff[:, :nocc])) return v * 2 else: mo_energy = eris.fock.diagonal() mo_occ = numpy.zeros_like(mo_energy) mo_occ[:nocc] = 2 ovvo = numpy.empty((nocc, nvir, nvir, nocc)) for i in range(nocc): ovvo[i] = eris.ovvo[i] ovvo[i] = ovvo[i] * 4 - ovvo[i].transpose(1, 0, 2) ovvo[i] -= eris.oovv[i].transpose(2, 1, 0) def fvind(x): return numpy.einsum('iabj,bj->ai', ovvo, x.reshape(Xvo.shape)) dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo, nmo)) dm1[nocc:, :nocc] = dvo dm1[:nocc, nocc:] = dvo.T return dm1
def solve_mo1(self, mo_energy=None, mo_occ=None, h1=None, s1=None, with_cphf=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ if with_cphf is None: with_cphf = self.cphf mol = self.mol mo_coeff = self._scf.mo_coeff orbo = mo_coeff[:,mo_occ>0] if h1 is None: dm0 = self._scf.make_rdm1(mo_coeff, mo_occ) h1 = numpy.asarray([reduce(numpy.dot, (mo_coeff.T.conj(), x, orbo)) for x in self.make_h10(mol, dm0)]) if s1 is None: s1 = numpy.asarray([reduce(numpy.dot, (mo_coeff.T.conj(), x, orbo)) for x in self.make_s10(mol)]) cput1 = log.timer('first order Fock matrix', *cput1) if with_cphf: vind = self.gen_vind(self._scf) mo10, mo_e10 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, self.max_cycle_cphf, self.conv_tol, verbose=log) else: mo10, mo_e10 = solve_mo1(mo_energy, mo_occ, h1, s1) logger.timer(self, 'solving mo1 eqn', *cput1) return mo10, mo_e10
def solve_mo1(self, mo_energy=None, mo_occ=None, h1=None, s1=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ mol = self.mol if h1 is None: mo_coeff = self._scf.mo_coeff dm0 = self._scf.make_rdm1(mo_coeff, mo_occ) h1 = _mat_ao2mo(self.make_h10(mol, dm0), mo_coeff, mo_occ) if s1 is None: s1 = _mat_ao2mo(self.make_s10(mol), mo_coeff, mo_occ) cput1 = log.timer('first order Fock matrix', *cput1) if self.cphf: mo10, mo_e10 = cphf.solve(self.get_vind, mo_energy, mo_occ, h1, s1, self.max_cycle_cphf, self.conv_tol, verbose=log) else: mo10, mo_e10 = solve_mo1(mo_energy, mo_occ, h1, s1) logger.timer(self, 'solving mo1 eqn', *cput1) return mo10, mo_e10
def solve_mo1(mf, mo_energy, mo_coeff, mo_occ, h1ao_or_chkfile, fx=None, atmlst=None, max_memory=4000, verbose=None): mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] if fx is None: fx = gen_vind(mf, mo_coeff, mo_occ) s1a = -mol.intor('int1e_ipovlp', comp=3) def _ao2mo(mat): return numpy.asarray([reduce(numpy.dot, (mo_coeff.T, x, mocc)) for x in mat]) mem_now = lib.current_memory()[0] max_memory = max(2000, max_memory*.9-mem_now) blksize = max(2, int(max_memory*1e6/8 / (nmo*nocc*3*6))) mo1s = [None] * mol.natm e1s = [None] * mol.natm aoslices = mol.aoslice_by_atom() for ia0, ia1 in lib.prange(0, len(atmlst), blksize): s1vo = [] h1vo = [] for i0 in range(ia0, ia1): ia = atmlst[i0] shl0, shl1, p0, p1 = aoslices[ia] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1vo.append(_ao2mo(s1ao)) if isinstance(h1ao_or_chkfile, str): key = 'scf_f1ao/%d' % ia h1ao = lib.chkfile.load(h1ao_or_chkfile, key) else: h1ao = h1ao_or_chkfile[ia] h1vo.append(_ao2mo(h1ao)) h1vo = numpy.vstack(h1vo) s1vo = numpy.vstack(s1vo) mo1, e1 = cphf.solve(fx, mo_energy, mo_occ, h1vo, s1vo) mo1 = numpy.einsum('pq,xqi->xpi', mo_coeff, mo1).reshape(-1,3,nao,nocc) e1 = e1.reshape(-1,3,nocc,nocc) for k in range(ia1-ia0): ia = atmlst[k+ia0] if isinstance(h1ao_or_chkfile, str): key = 'scf_mo1/%d' % ia lib.chkfile.save(h1ao_or_chkfile, key, mo1[k]) else: mo1s[ia] = mo1[k] e1s[ia] = e1[k].reshape(3,nocc,nocc) mo1 = e1 = None if isinstance(h1ao_or_chkfile, str): return h1ao_or_chkfile, e1s else: return mo1s, e1s
def solve_mo1(self, mo_energy=None, mo_occ=None, h1=None, with_cphf=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ if with_cphf is None: with_cphf = self.cphf mol = self.mol mo_coeff = self._scf.mo_coeff if self.mb.upper().startswith('ST'): # Sternheim approximation nmo = mo_occ.size mo_energy = mo_energy[nmo // 2:] mo_coeff = mo_coeff[:, nmo // 2:] mo_occ = mo_occ[nmo // 2:] if h1 is None: atmlst = sorted(set([j for i, j in self.nuc_pair])) h1 = numpy.asarray(make_h1(mol, mo_coeff, mo_occ, atmlst)) if with_cphf: vind = self.gen_vind(self._scf, mo_coeff, mo_occ) mo1, mo_e1 = cphf.solve(vind, mo_energy, mo_occ, h1, None, self.max_cycle_cphf, self.conv_tol, verbose=log) else: e_ai = lib.direct_sum('i-a->ai', mo_energy[mo_occ > 0], mo_energy[mo_occ == 0]) mo1 = h1 / e_ai mo_e1 = None # Calculate RMB with approximation # |MO1> = Z_RMB |i> + |p> bar{C}_{pi}^1 ~= |p> C_{pi}^1 # bar{C}_{pi}^1 ~= C_{pi}^1 - <p|Z_RMB|i> if self.mb.upper() == 'RMB': orbo = mo_coeff[:, mo_occ > 0] orbv = mo_coeff[:, mo_occ == 0] n4c = mo_coeff.shape[0] n2c = n4c // 2 c = lib.param.LIGHT_SPEED orbvS_T = orbv[n2c:].conj().T for ia in atmlst: mol.set_rinv_origin(mol.atom_coord(ia)) a01int = mol.intor('int1e_sa01sp_spinor', 3) for k in range(3): s1 = orbvS_T.dot(a01int[k].conj().T).dot(orbo[n2c:]) mo1[ia * 3 + k] -= s1 * (.25 / c**2) logger.timer(self, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def solve_mo1(nmrobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): '''Solve the first order equation Kwargs: with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' if mo_energy is None: mo_energy = nmrobj._scf.mo_energy if mo_coeff is None: mo_coeff = nmrobj._scf.mo_coeff if mo_occ is None: mo_occ = nmrobj._scf.mo_occ if with_cphf is None: with_cphf = nmrobj.cphf cput1 = (time.clock(), time.time()) log = logger.Logger(nmrobj.stdout, nmrobj.verbose) mol = nmrobj.mol orbo = mo_coeff[:, mo_occ > 0] if h1 is None: dm0 = nmrobj._scf.make_rdm1(mo_coeff, mo_occ) h1 = lib.einsum('xpq,pi,qj->xij', nmrobj.get_fock(dm0), mo_coeff.conj(), orbo) cput1 = log.timer('first order Fock matrix', *cput1) if s1 is None: s1 = lib.einsum('xpq,pi,qj->xij', nmrobj.get_ovlp(mol), mo_coeff.conj(), orbo) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(nmrobj._scf, mo_coeff, mo_occ) mo10, mo_e10 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, nmrobj.max_cycle_cphf, nmrobj.conv_tol, verbose=log) else: mo10, mo_e10 = _solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1) log.timer('solving mo1 eqn', *cput1) return mo10, mo_e10
def _get_U_1(self): B_1 = self.B_1 S_1_mo = self.S_1_mo if S_1_mo is 0: S_1_mo = np.zeros_like(B_1) Ax0_Core = self.Ax0_Core sv = self.sv so = self.so # Generate v-o block of U U_1_ai = cphf.solve(self.Ax0_Core(sv, so, sv, so), self.e, self.scf_eng.mo_occ, B_1[:, sv, so], max_cycle=100, tol=1e-13, hermi=False)[0] U_1_ai.shape = (B_1.shape[0], self.nvir, self.nocc) # Test whether converged conv = (+U_1_ai * lib.direct_sum("a - i", self.ev, self.eo) + self.Ax0_Core(sv, so, sv, so)(U_1_ai) + self.B_1[:, sv, so]) if abs(conv).max() > 1e-8: msg = "\nget_E_1: CP-HF not converged well!\nMaximum deviation: " + str( abs(conv).max()) warnings.warn(msg) if self.rotation: # Generate rotated U U_1_pq = -0.5 * S_1_mo U_1_pq[:, sv, so] = U_1_ai U_1_pq[:, so, sv] = -S_1_mo[:, so, sv] - U_1_pq[:, sv, so].swapaxes( -1, -2) else: # Generate total U D_pq = -lib.direct_sum("p - q -> pq", self.e, self.e) + 1e-300 U_1_pq = np.zeros((B_1.shape[0], self.nmo, self.nmo)) U_1_pq[:, sv, so] = U_1_ai U_1_pq[:, so, sv] = -S_1_mo[:, so, sv] - U_1_pq[:, sv, so].swapaxes( -1, -2) U_1_pq[:, so, so] = (Ax0_Core(so, so, sv, so)(U_1_ai) + B_1[:, so, so]) / D_pq[so, so] U_1_pq[:, sv, sv] = (Ax0_Core(sv, sv, sv, so)(U_1_ai) + B_1[:, sv, sv]) / D_pq[sv, sv] for p in range(self.nmo): U_1_pq[:, p, p] = -S_1_mo[:, p, p] / 2 U_1_pq -= (U_1_pq + U_1_pq.swapaxes(-1, -2) + S_1_mo) / 2 U_1_pq -= (U_1_pq + U_1_pq.swapaxes(-1, -2) + S_1_mo) / 2 self._U_1 = U_1_pq return self._U_1
def Z(self): so, sv = self.so, self.sv Ax0_Core = self.Ax0_Core e, mo_occ = self.e, self.mo_occ F_0_mo = self.nc_deriv.F_0_mo Z = cphf.solve(Ax0_Core(sv, so, sv, so, in_cphf=True), e, mo_occ, F_0_mo[sv, so], max_cycle=100, tol=self.cphf_tol)[0] return Z
def U_1(self): B_1 = self.B_1 S_1_mo = self.S_1_mo if not isinstance(S_1_mo, np.ndarray): S_1_mo = np.zeros_like(B_1) Ax0_Core = self.Ax0_Core sv = self.sv so = self.so # Generate v-o block of U U_1_ai = cphf.solve(self.Ax0_Core(sv, so, sv, so, in_cphf=True), self.e, self.scf_eng.mo_occ, B_1[:, sv, so], max_cycle=100, tol=self.cphf_tol, hermi=False)[0] U_1_ai.shape = (B_1.shape[0], self.nvir, self.nocc) # Test whether converged conv = (+U_1_ai * (self.ev[:, None] - self.eo[None, :]) + self.Ax0_Core(sv, so, sv, so)(U_1_ai) + self.B_1[:, sv, so]) if abs(conv).max() > 1e-8: msg = "\nget_E_1: CP-HF not converged well!\nMaximum deviation: " + str( abs(conv).max()) warnings.warn(msg) if self.rotation: # Generate rotated U U_1_pq = -0.5 * S_1_mo U_1_pq[:, sv, so] = U_1_ai U_1_pq[:, so, sv] = -S_1_mo[:, so, sv] - U_1_pq[:, sv, so].swapaxes( -1, -2) else: # Generate total U D_pq = -(self.e[:, None] - self.e[None, :]) + 1e-300 U_1_pq = np.zeros((B_1.shape[0], self.nmo, self.nmo)) U_1_pq[:, sv, so] = U_1_ai U_1_pq[:, so, sv] = -S_1_mo[:, so, sv] - U_1_pq[:, sv, so].swapaxes( -1, -2) U_1_pq[:, so, so] = (Ax0_Core(so, so, sv, so)(U_1_ai) + B_1[:, so, so]) / D_pq[so, so] U_1_pq[:, sv, sv] = (Ax0_Core(sv, sv, sv, so)(U_1_ai) + B_1[:, sv, sv]) / D_pq[sv, sv] for p in range(self.nmo): U_1_pq[:, p, p] = -S_1_mo[:, p, p] / 2 U_1_pq -= (U_1_pq + U_1_pq.swapaxes(-1, -2) + S_1_mo) / 2 U_1_pq -= (U_1_pq + U_1_pq.swapaxes(-1, -2) + S_1_mo) / 2 return U_1_pq
def _get_U_2(self): B_2 = self.B_2 Xi_2 = self.Xi_2 Ax0_Core = self.A.Ax0_Core sv, so = self.sv, self.so nvir, nocc = self.nvir, self.nocc # Generate v-o block of U U_2_ai = cphf.solve( Ax0_Core(sv, so, sv, so, in_cphf=True), self.e, self.A.scf_eng.mo_occ, B_2[:, :, sv, so].reshape(-1, nvir, nocc), max_cycle=100, tol=self.A.cphf_tol, hermi=False )[0] U_2_ai.shape = (B_2.shape[0], B_2.shape[1], self.nvir, self.nocc) # Test whether converged conv = ( + U_2_ai * (self.ev[:, None] - self.eo[None, :]) + Ax0_Core(sv, so, sv, so)(U_2_ai) + self.B_2[:, :, sv, so] ) if abs(conv).max() > 1e-8: msg = "\nget_U_2: CP-HF not converged well!\nMaximum deviation: " + str(abs(conv).max()) warnings.warn(msg) if self.rotation: # Generate rotated U U_2_pq = - 0.5 * Xi_2 U_2_pq[:, :, sv, so] = U_2_ai U_2_pq[:, :, so, sv] = - Xi_2[:, :, so, sv] - U_2_pq[:, :, sv, so].swapaxes(-1, -2) else: # Generate total U D_pq = - (self.e[:, None] - self.e[None, :]) + 1e-300 U_2_pq = np.zeros((B_2.shape[0], B_2.shape[1], self.nmo, self.nmo)) U_2_pq[:, :, sv, so] = U_2_ai U_2_pq[:, :, so, sv] = - Xi_2[:, :, so, sv] - U_2_pq[:, :, sv, so].swapaxes(-1, -2) U_2_pq[:, :, so, so] = (Ax0_Core(so, so, sv, so)(U_2_ai) + B_2[:, :, so, so]) / D_pq[so, so] U_2_pq[:, :, sv, sv] = (Ax0_Core(sv, sv, sv, so)(U_2_ai) + B_2[:, :, sv, sv]) / D_pq[sv, sv] for p in range(self.nmo): U_2_pq[:, :, p, p] = - Xi_2[:, :, p, p] / 2 U_2_pq -= (U_2_pq + U_2_pq.swapaxes(-1, -2) + Xi_2) / 2 U_2_pq -= (U_2_pq + U_2_pq.swapaxes(-1, -2) + Xi_2) / 2 self._U_2 = U_2_pq return self._U_2
def response_dm1(mycc, t1, t2, l1, l2, eris=None, IX=None, max_memory=2000): if eris is None: # Note eris are in Chemist's notation eris = ccsd._ERIS(mycc) if IX is None: Ioo, Ivv, Ivo, Xvo = IX_intermediates(mycc, t1, t2, l1, l2, eris, max_memory=2000) else: Ioo, Ivv, Ivo, Xvo = IX nocc, nvir = t1.shape nmo = nocc + nvir max_memory = max_memory - lib.current_memory()[0] blksize = max(ccsd.BLKMIN, int(max_memory * 1e6 / 8 / (nocc * nvir**2))) def fvind(x): x = x.reshape(Xvo.shape) if eris is None: mo_coeff = mycc.mo_coeff dm = reduce(numpy.dot, (mo_coeff[:, nocc:], x, mo_coeff[:, :nocc].T)) dm = (dm + dm.T) * 2 v = reduce(numpy.dot, (mo_coeff[:, nocc:].T, mycc._scf.get_veff( mol, dm), mo_coeff[:, :nocc])) else: v = numpy.zeros((nocc, nvir)) for p0, p1 in prange(0, nocc, blksize): eris_ovov = _cp(eris.ovov[p0:p1]) v[p0:p1] += numpy.einsum('iajb,bj->ia', eris_ovov, x) * 4 v[p0:p1] -= numpy.einsum('ibja,bj->ia', eris_ovov, x) eris_ovov = None v[p0:p1] -= numpy.einsum('ijba,bj->ia', _cp(eris.oovv[p0:p1]), x[:, p0:p1]) return v.T mo_energy = eris.fock.diagonal() mo_occ = numpy.zeros_like(mo_energy) mo_occ[:nocc] = 2 dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo, nmo)) dm1[nocc:, :nocc] = dvo dm1[:nocc, nocc:] = dvo.T return dm1
def hyper_polarizability(polobj, with_cphf=True): from pyscf.prop.nmr import rhf as rhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] orbv = mo_coeff[:, ~occidx] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1 = lib.einsum('xpq,pi,qj->xij', int_r, mo_coeff.conj(), orbo) s1 = numpy.zeros_like(h1) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: mo1, e1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, polobj.max_cycle_cphf, polobj.conv_tol, verbose=log) else: mo1, e1 = rhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1) mo1 = lib.einsum('xqi,pq->xpi', mo1, mo_coeff) dm1 = lib.einsum('xpi,qi->xpq', mo1, orbo) * 2 dm1 = dm1 + dm1.transpose(0, 2, 1) vresp = mf.gen_response(hermi=1) h1ao = int_r + vresp(dm1) # *2 for double occupancy e3 = lib.einsum('xpq,ypi,zqi->xyz', h1ao, mo1, mo1) * 2 e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', mf.get_ovlp(), mo1, mo1, e1) * 2 e3 = (e3 + e3.transpose(1, 2, 0) + e3.transpose(2, 0, 1) + e3.transpose(0, 2, 1) + e3.transpose(1, 0, 2) + e3.transpose(2, 1, 0)) e3 = -e3 log.debug('Static hyper polarizability tensor\n%s', e3) return e3
def _response_dm1(mp, Xvo): nvir, nocc = Xvo.shape nmo = nocc + nvir mo_energy = mp._scf.mo_energy mo_occ = mp.mo_occ mo_coeff = mp.mo_coeff def fvind(x): x = x.reshape(Xvo.shape) dm = reduce(numpy.dot, (mo_coeff[:,nocc:], x, mo_coeff[:,:nocc].T)) v = mp._scf.get_veff(mp.mol, dm + dm.T) v = reduce(numpy.dot, (mo_coeff[:,nocc:].T, v, mo_coeff[:,:nocc])) return v * 2 dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo,nmo)) dm1[nocc:,:nocc] = dvo dm1[:nocc,nocc:] = dvo.T return dm1
def _response_dm1(mp, Xvo): nvir, nocc = Xvo.shape nmo = nocc + nvir with_frozen = not (mp.frozen is None or mp.frozen is 0) mo_energy = mp._scf.mo_energy mo_occ = mp.mo_occ mo_coeff = mp.mo_coeff def fvind(x): x = x.reshape(Xvo.shape) dm = reduce(numpy.dot, (mo_coeff[:,nocc:], x, mo_coeff[:,:nocc].T)) v = mp._scf.get_veff(mp.mol, dm + dm.T) v = reduce(numpy.dot, (mo_coeff[:,nocc:].T, v, mo_coeff[:,:nocc])) return v * 2 dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo,nmo)) dm1[nocc:,:nocc] = dvo dm1[:nocc,nocc:] = dvo.T return dm1
def solve_mo1(nmrobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): '''Solve the first order equation Kwargs: with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' if mo_energy is None: mo_energy = nmrobj._scf.mo_energy if mo_coeff is None: mo_coeff = nmrobj._scf.mo_coeff if mo_occ is None: mo_occ = nmrobj._scf.mo_occ if with_cphf is None: with_cphf = nmrobj.cphf cput1 = (time.clock(), time.time()) log = logger.Logger(nmrobj.stdout, nmrobj.verbose) mol = nmrobj.mol orbo = mo_coeff[:,mo_occ>0] if h1 is None: dm0 = nmrobj._scf.make_rdm1(mo_coeff, mo_occ) h1 = lib.einsum('xpq,pi,qj->xij', nmrobj.get_fock(dm0), mo_coeff.conj(), orbo) cput1 = log.timer('first order Fock matrix', *cput1) if s1 is None: s1 = lib.einsum('xpq,pi,qj->xij', nmrobj.get_ovlp(mol), mo_coeff.conj(), orbo) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(nmrobj._scf, mo_coeff, mo_occ) mo10, mo_e10 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, nmrobj.max_cycle_cphf, nmrobj.conv_tol, verbose=log) else: mo10, mo_e10 = _solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1) log.timer('solving mo1 eqn', *cput1) return mo10, mo_e10
def polarizability(polobj, with_cphf=True): from pyscf.prop.nmr import rhf as rhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] orbv = mo_coeff[:, ~occidx] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1 = lib.einsum('xpq,pi,qj->xij', int_r, mo_coeff.conj(), orbo) s1 = numpy.zeros_like(h1) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: mo1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, polobj.max_cycle_cphf, polobj.conv_tol, verbose=log)[0] else: mo1 = rhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1)[0] e2 = numpy.einsum('xpi,ypi->xy', h1, mo1) # *-1 from the definition of dipole moment. *2 for double occupancy e2 = (e2 + e2.T) * -2 if mf.verbose >= logger.INFO: xx, yy, zz = e2.diagonal() log.note('Isotropic polarizability %.12g', (xx + yy + zz) / 3) log.note('Polarizability anisotropy %.12g', (.5 * ((xx - yy)**2 + (yy - zz)**2 + (zz - xx)**2))**.5) log.debug('Static polarizability tensor\n%s', e2) return e2
def D_r(self): L = self.L D_r = np.copy(self.D_r_oovv) so, sv = self.so, self.sv Ax0_Core = self.Ax0_Core e, mo_occ = self.e, self.mo_occ D_r[sv, so] = cphf.solve(Ax0_Core(sv, so, sv, so, in_cphf=True), e, mo_occ, L, max_cycle=100, tol=self.cphf_tol)[0] conv = (+D_r[sv, so] * (self.ev[:, None] - self.eo[None, :]) + Ax0_Core(sv, so, sv, so)(D_r[sv, so]) + L) if abs(conv).max() > 1e-8: msg = "\nget_E_1: CP-HF not converged well!\nMaximum deviation: " + str( abs(conv).max()) warnings.warn(msg) return D_r
def response_dm1(mycc, t1, t2, l1, l2, eris=None, IX=None): if eris is None: # Note eris are in Chemist's notation eris = ccsd._ERIS(mycc) if IX is None: Ioo, Ivv, Ivo, Xvo = IX_intermediates(mycc, t1, t2, l1, l2, eris) else: Ioo, Ivv, Ivo, Xvo = IX nocc, nvir = t1.shape nmo = nocc + nvir max_memory = mycc.max_memory - lib.current_memory()[0] blksize = max(ccsd.BLKMIN, int(max_memory * 1e6 / 8 / (nocc * nvir**2))) def fvind(x): x = x.reshape(Xvo.shape) if eris is None: mo_coeff = mycc.mo_coeff dm = reduce(numpy.dot, (mo_coeff[:, nocc:], x, mo_coeff[:, :nocc].T)) dm = (dm + dm.T) * 2 v = reduce(numpy.dot, (mo_coeff[:, nocc:].T, mycc._scf.get_veff(mol, dm), mo_coeff[:, :nocc])) else: v = numpy.zeros((nocc, nvir)) for p0, p1 in prange(0, nocc, blksize): eris_ovov = _cp(eris.ovov[p0:p1]) v[p0:p1] += numpy.einsum('iajb,bj->ia', eris_ovov, x) * 4 v[p0:p1] -= numpy.einsum('ibja,bj->ia', eris_ovov, x) eris_ovov = None v[p0:p1] -= numpy.einsum('ijba,bj->ia', _cp(eris.oovv[p0:p1]), x[:, p0:p1]) return v.T mo_energy = eris.fock.diagonal() mo_occ = numpy.zeros_like(mo_energy) mo_occ[:nocc] = 2 dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo, nmo)) dm1[nocc:, :nocc] = dvo dm1[:nocc, nocc:] = dvo.T return dm1
def _get_D_r(self): L = self.L D_r = self._D_r so, sv, sa = self.so, self.sv, self.sa Ax0_Core = self.Ax0_Core e, mo_occ = self.e, self.mo_occ D_r[sv, so] = cphf.solve(Ax0_Core(sv, so, sv, so), e, mo_occ, L, max_cycle=100, tol=1e-15)[0] conv = (+D_r[sv, so] * (self.ev[:, None] - self.eo[None, :]) + Ax0_Core(sv, so, sv, so)(D_r[sv, so]) + L) if abs(conv).max() > 1e-8: msg = "\nget_E_1: CP-HF not converged well!\nMaximum deviation: " + str( abs(conv).max()) warnings.warn(msg) return D_r
def hyper_polarizability(polobj, with_cphf=True): from pyscf.prop.nmr import rhf as rhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] orbv = mo_coeff[:,~occidx] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1 = lib.einsum('xpq,pi,qj->xij', int_r, mo_coeff.conj(), orbo) s1 = numpy.zeros_like(h1) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: mo1, e1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, polobj.max_cycle_cphf, polobj.conv_tol, verbose=log) else: mo1, e1 = rhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1) mo1 = lib.einsum('xqi,pq->xpi', mo1, mo_coeff) dm1 = lib.einsum('xpi,qi->xpq', mo1, orbo) * 2 dm1 = dm1 + dm1.transpose(0,2,1) vresp = _gen_rhf_response(mf, hermi=1) h1ao = int_r + vresp(dm1) # *2 for double occupancy e3 = lib.einsum('xpq,ypi,zqi->xyz', h1ao, mo1, mo1) * 2 e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', mf.get_ovlp(), mo1, mo1, e1) * 2 e3 = (e3 + e3.transpose(1,2,0) + e3.transpose(2,0,1) + e3.transpose(0,2,1) + e3.transpose(1,0,2) + e3.transpose(2,1,0)) e3 = -e3 log.debug('Static hyper polarizability tensor\n%s', e3) return e3
def solve_mo1(sscobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): cput1 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(sscobj.stdout, sscobj.verbose) if mo_energy is None: mo_energy = sscobj._scf.mo_energy if mo_coeff is None: mo_coeff = sscobj._scf.mo_coeff if mo_occ is None: mo_occ = sscobj._scf.mo_occ if with_cphf is None: with_cphf = sscobj.cphf mol = sscobj.mol if h1 is None: atmlst = sorted(set([j for i, j in sscobj.nuc_pair])) h1 = numpy.asarray(make_h1_pso(mol, mo_coeff, mo_occ, atmlst)) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(sscobj._scf, mo_coeff, mo_occ) mo1, mo_e1 = cphf.solve(vind, mo_energy, mo_occ, h1, None, sscobj.max_cycle_cphf, sscobj.conv_tol, verbose=log) else: e_ai = lib.direct_sum('i-a->ai', mo_energy[mo_occ > 0], mo_energy[mo_occ == 0]) mo1 = h1 * (1 / e_ai) mo_e1 = None logger.timer(sscobj, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def polarizability(polobj, with_cphf=True): from pyscf.prop.nmr import rhf as rhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] orbv = mo_coeff[:,~occidx] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1 = lib.einsum('xpq,pi,qj->xij', int_r, mo_coeff.conj(), orbo) s1 = numpy.zeros_like(h1) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: mo1 = cphf.solve(vind, mo_energy, mo_occ, h1, s1, polobj.max_cycle_cphf, polobj.conv_tol, verbose=log)[0] else: mo1 = rhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1)[0] e2 = numpy.einsum('xpi,ypi->xy', h1, mo1) # *-1 from the definition of dipole moment. *2 for double occupancy e2 = (e2 + e2.T) * -2 if mf.verbose >= logger.INFO: xx, yy, zz = e2.diagonal() log.note('Isotropic polarizability %.12g', (xx+yy+zz)/3) log.note('Polarizability anisotropy %.12g', (.5 * ((xx-yy)**2 + (yy-zz)**2 + (zz-xx)**2))**.5) log.debug('Static polarizability tensor\n%s', e2) return e2
def _response_dm1(mp, Xvo): nvir, nocc = Xvo.shape nmo = nocc + nvir with_frozen = not ((mp.frozen is None) or (isinstance(mp.frozen, (int, numpy.integer)) and mp.frozen == 0) or (len(mp.frozen) == 0)) mo_energy = mp._scf.mo_energy mo_occ = mp.mo_occ mo_coeff = mp.mo_coeff def fvind(x): x = x.reshape(Xvo.shape) dm = reduce(numpy.dot, (mo_coeff[:, nocc:], x, mo_coeff[:, :nocc].T)) v = mp._scf.get_veff(mp.mol, dm + dm.T) v = reduce(numpy.dot, (mo_coeff[:, nocc:].T, v, mo_coeff[:, :nocc])) return v * 2 dvo = cphf.solve(fvind, mo_energy, mo_occ, Xvo, max_cycle=30)[0] dm1 = numpy.zeros((nmo, nmo)) dm1[nocc:, :nocc] = dvo dm1[:nocc, nocc:] = dvo.T return dm1
def solve_mo1(self, mo_energy=None, mo_occ=None, nuc_pair=None, with_cphf=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ if nuc_pair is None: nuc_pair = self.nuc_pair if with_cphf is None: with_cphf = self.cphf atmlst = sorted(set([j for i,j in nuc_pair])) mol = self.mol h1 = numpy.asarray(make_h1_mo(mol, self._scf.mo_coeff, mo_occ, atmlst)) if with_cphf: vind = self.gen_vind(self._scf) mo1, mo_e1 = cphf.solve(vind, mo_energy, mo_occ, h1, None, self.max_cycle_cphf, self.conv_tol, verbose=log) else: e_ai = -1 / (mo_energy[mo_occ==0] - mo_energy[mo_oc>0]) mo1 = h1 * e_ai mo_e1 = None logger.timer(self, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def grad_elec(td_grad, x_y, singlet=True, atmlst=None, max_memory=2000, verbose=logger.INFO): ''' Electronic part of TDA, TDDFT nuclear gradients Args: td_grad : grad.tdrhf.Gradients or grad.tdrks.Gradients object. x_y : a two-element list of numpy arrays TDDFT X and Y amplitudes. If Y is set to 0, this function computes TDA energy gradients. ''' 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) dmxpy = reduce(numpy.dot, (orbv, xpy, orbo.T)) dmxmy = 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, dmxpy, dmzoo, True, True, singlet, max_memory) if abs(hyb) > 1e-10: dm = (dmzoo, dmxpy + dmxpy.T, dmxmy - dmxmy.T) vj, vk = mf.get_jk(mol, dm, hermi=0) vk *= hyb if abs(omega) > 1e-10: vk += mf.get_k(mol, dm, hermi=0, omega=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, dmxpy + dmxpy.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)) # set singlet=None, generate function for CPHF type response kernel vresp = mf.gen_response(singlet=None, hermi=1) def fvind(x): dm = reduce(numpy.dot, (orbv, x.reshape(nvir, nocc) * 2, orbo.T)) v1ao = vresp(dm + dm.T) return reduce(numpy.dot, (orbv.T, v1ao, 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)) veff = vresp(z1ao + z1ao.T) 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)) # Initialize hcore_deriv with the underlying SCF object because some # extensions (e.g. QM/MM, solvent) modifies the SCF object only. mf_grad = td_grad.base._scf.nuc_grad_method() hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) dmz1doo = z1ao + dmzoo oo0 = reduce(numpy.dot, (orbo, orbo.T)) if abs(hyb) > 1e-10: dm = (oo0, dmz1doo + dmz1doo.T, dmxpy + dmxpy.T, dmxmy - dmxmy.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, dmxpy + dmxpy.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 fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None, False, False, True, max_memory)[0] 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], dmxpy[p0:p1, :]) * 2 e1 += numpy.einsum('xij,ij->x', veff1[3, :, p0:p1], dmxmy[p0:p1, :]) * 2 e1 += numpy.einsum('xji,ij->x', veff1[2, :, p0:p1], dmxpy[:, p0:p1]) * 2 e1 -= numpy.einsum('xji,ij->x', veff1[3, :, p0:p1], dmxmy[:, p0:p1]) * 2 de[k] = e1 log.timer('TDDFT nuclear gradients', *time0) return de
def kernel(tdgrad, z, atmlst=None, mf_grad=None, max_memory=2000, verbose=logger.INFO): mol = tdgrad.mol mf = tdgrad._td._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 #eai = pyscf.lib.direct_sum('a-i->ai', mo_energy[nocc:], mo_energy[:nocc]) z = z.reshape(nvir,nocc) orbv = mo_coeff[:,nocc:] orbo = mo_coeff[:,:nocc] def fvind(x): dm = numpy.einsum('pi,xij,qj->xpq', orbv, x, orbo) v_ao = mf.get_veff(mol, (dm+dm.transpose(0,2,1)))*2 return numpy.einsum('pi,xpq,qj->xij', orbv, v_ao, orbo).reshape(3,-1) h1 = rhf_grad.get_hcore(mol) s1 = rhf_grad.get_ovlp(mol) eri1 = -mol.intor('cint2e_ip1_sph', aosym='s1', comp=3) eri1 = eri1.reshape(3,nao,nao,nao,nao) from pyscf import ao2mo eri0 = ao2mo.kernel(mol, mo_coeff) eri0 = ao2mo.restore(1, eri0, nmo).reshape(nmo,nmo,nmo,nmo) g = eri0 * 2 - eri0.transpose(0,3,2,1) zeta = pyscf.lib.direct_sum('i+j->ij', mo_energy, mo_energy) * .5 zeta[nocc:,:nocc] = mo_energy[:nocc] zeta[:nocc,nocc:] = mo_energy[nocc:] 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] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3) h1ao[:,p0:p1] += h1[:,p0:p1] h1ao = h1ao + h1ao.transpose(0,2,1) h1mo = numpy.einsum('pi,xpq,qj->xij', mo_coeff, h1ao, mo_coeff) s1mo = numpy.einsum('pi,xpq,qj->xij', mo_coeff[p0:p1], s1[:,p0:p1], mo_coeff) s1mo = s1mo + s1mo.transpose(0,2,1) f1 = h1mo - numpy.einsum('xpq,pq->xpq', s1mo, zeta) f1-= numpy.einsum('klpq,xlk->xpq', g[:nocc,:nocc], s1mo[:,:nocc,:nocc]) eri1a = eri1.copy() eri1a[:,:p0] = 0 eri1a[:,p1:] = 0 eri1a = eri1a + eri1a.transpose(0,2,1,3,4) eri1a = eri1a + eri1a.transpose(0,3,4,1,2) g1 = numpy.einsum('xpjkl,pi->xijkl', eri1a, mo_coeff) g1 = numpy.einsum('xipkl,pj->xijkl', g1, mo_coeff) g1 = numpy.einsum('xijpl,pk->xijkl', g1, mo_coeff) g1 = numpy.einsum('xijkp,pl->xijkl', g1, mo_coeff) g1 = g1 * 2 - g1.transpose(0,1,4,3,2) f1 += numpy.einsum('xkkpq->xpq', g1[:,:nocc,:nocc]) f1ai = f1[:,nocc:,:nocc].copy() c1 = s1mo * -.5 c1vo = cphf.solve(fvind, mo_energy, mo_occ, f1ai, max_cycle=50)[0] c1[:,nocc:,:nocc] = c1vo c1[:,:nocc,nocc:] = -(s1mo[:,nocc:,:nocc]+c1vo).transpose(0,2,1) f1 += numpy.einsum('kapq,xak->xpq', g[:nocc,nocc:], c1vo) f1 += numpy.einsum('akpq,xak->xpq', g[nocc:,:nocc], c1vo) e1 = numpy.einsum('xaijb,ai,bj->x', g1[:,nocc:,:nocc,:nocc,nocc:], z, z) e1 += numpy.einsum('xab,ai,bi->x', f1[:,nocc:,nocc:], z, z) e1 -= numpy.einsum('xij,ai,aj->x', f1[:,:nocc,:nocc], z, z) g1 = numpy.einsum('pjkl,xpi->xijkl', g, c1) g1 += numpy.einsum('ipkl,xpj->xijkl', g, c1) g1 += numpy.einsum('ijpl,xpk->xijkl', g, c1) g1 += numpy.einsum('ijkp,xpl->xijkl', g, c1) e1 += numpy.einsum('xaijb,ai,bj->x', g1[:,nocc:,:nocc,:nocc,nocc:], z, z) de[k] = e1 return de
def solve_mo1(mf, mo_energy, mo_coeff, mo_occ, h1ao_or_chkfile, fx=None, atmlst=None, max_memory=4000, verbose=None): '''Solve the first order equation Kwargs: fx : function(dm_mo) => v1_mo A function to generate the induced potential. See also the function gen_vind. ''' mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] if fx is None: fx = gen_vind(mf, mo_coeff, mo_occ) s1a = -mol.intor('int1e_ipovlp', comp=3) def _ao2mo(mat): return numpy.asarray([reduce(numpy.dot, (mo_coeff.T, x, mocc)) for x in mat]) mem_now = lib.current_memory()[0] max_memory = max(2000, max_memory*.9-mem_now) blksize = max(2, int(max_memory*1e6/8 / (nmo*nocc*3*6))) mo1s = [None] * mol.natm e1s = [None] * mol.natm aoslices = mol.aoslice_by_atom() for ia0, ia1 in lib.prange(0, len(atmlst), blksize): s1vo = [] h1vo = [] for i0 in range(ia0, ia1): ia = atmlst[i0] shl0, shl1, p0, p1 = aoslices[ia] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1vo.append(_ao2mo(s1ao)) if isinstance(h1ao_or_chkfile, str): key = 'scf_f1ao/%d' % ia h1ao = lib.chkfile.load(h1ao_or_chkfile, key) else: h1ao = h1ao_or_chkfile[ia] h1vo.append(_ao2mo(h1ao)) h1vo = numpy.vstack(h1vo) s1vo = numpy.vstack(s1vo) mo1, e1 = cphf.solve(fx, mo_energy, mo_occ, h1vo, s1vo) mo1 = numpy.einsum('pq,xqi->xpi', mo_coeff, mo1).reshape(-1,3,nao,nocc) e1 = e1.reshape(-1,3,nocc,nocc) for k in range(ia1-ia0): ia = atmlst[k+ia0] if isinstance(h1ao_or_chkfile, str): key = 'scf_mo1/%d' % ia lib.chkfile.save(h1ao_or_chkfile, key, mo1[k]) else: mo1s[ia] = mo1[k] e1s[ia] = e1[k].reshape(3,nocc,nocc) mo1 = e1 = None if isinstance(h1ao_or_chkfile, str): return h1ao_or_chkfile, e1s else: return mo1s, e1s
def kernel(mc, mo_coeff=None, ci=None, atmlst=None, mf_grad=None, verbose=None): if mo_coeff is None: mo_coeff = mc._scf.mo_coeff if ci is None: ci = mc.ci if mf_grad is None: mf_grad = mc._scf.nuc_grad_method() assert (isinstance(ci, numpy.ndarray)) mol = mc.mol ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas nelecas = mc.nelecas nao, nmo = mo_coeff.shape nao_pair = nao * (nao + 1) // 2 mo_energy = mc._scf.mo_energy mo_occ = mo_coeff[:, :nocc] mo_core = mo_coeff[:, :ncore] mo_cas = mo_coeff[:, ncore:nocc] neleca, nelecb = mol.nelec assert (neleca == nelecb) orbo = mo_coeff[:, :neleca] orbv = mo_coeff[:, neleca:] casdm1, casdm2 = mc.fcisolver.make_rdm12(ci, ncas, nelecas) dm_core = numpy.dot(mo_core, mo_core.T) * 2 dm_cas = reduce(numpy.dot, (mo_cas, casdm1, mo_cas.T)) aapa = ao2mo.kernel(mol, (mo_cas, mo_cas, mo_coeff, mo_cas), compact=False) aapa = aapa.reshape(ncas, ncas, nmo, ncas) vj, vk = mc._scf.get_jk(mol, (dm_core, dm_cas)) h1 = mc.get_hcore() vhf_c = vj[0] - vk[0] * .5 vhf_a = vj[1] - vk[1] * .5 # Imat = h1_{pi} gamma1_{iq} + h2_{pijk} gamma_{iqkj} Imat = numpy.zeros((nmo, nmo)) Imat[:, :nocc] = reduce(numpy.dot, (mo_coeff.T, h1 + vhf_c + vhf_a, mo_occ)) * 2 Imat[:, ncore:nocc] = reduce(numpy.dot, (mo_coeff.T, h1 + vhf_c, mo_cas, casdm1)) Imat[:, ncore:nocc] += lib.einsum('uviw,vuwt->it', aapa, casdm2) aapa = vj = vk = vhf_c = vhf_a = h1 = None ee = mo_energy[:, None] - mo_energy zvec = numpy.zeros_like(Imat) zvec[:ncore, ncore:neleca] = Imat[:ncore, ncore:neleca] / -ee[:ncore, ncore:neleca] zvec[ncore:neleca, :ncore] = Imat[ ncore:neleca, :ncore] / -ee[ncore:neleca, :ncore] zvec[nocc:, neleca:nocc] = Imat[nocc:, neleca:nocc] / -ee[nocc:, neleca:nocc] zvec[neleca:nocc, nocc:] = Imat[neleca:nocc, nocc:] / -ee[neleca:nocc, nocc:] zvec_ao = reduce(numpy.dot, (mo_coeff, zvec + zvec.T, mo_coeff.T)) vhf = mc._scf.get_veff(mol, zvec_ao) * 2 xvo = reduce(numpy.dot, (orbv.T, vhf, orbo)) xvo += Imat[neleca:, :neleca] - Imat[:neleca, neleca:].T def fvind(x): x = x.reshape(xvo.shape) dm = reduce(numpy.dot, (orbv, x, orbo.T)) v = mc._scf.get_veff(mol, dm + dm.T) v = reduce(numpy.dot, (orbv.T, v, orbo)) return v * 2 dm1resp = cphf.solve(fvind, mo_energy, mc._scf.mo_occ, xvo, max_cycle=30)[0] zvec[neleca:, :neleca] = dm1resp zeta = numpy.einsum('ij,j->ij', zvec, mo_energy) zeta = reduce(numpy.dot, (mo_coeff, zeta, mo_coeff.T)) zvec_ao = reduce(numpy.dot, (mo_coeff, zvec + zvec.T, mo_coeff.T)) p1 = numpy.dot(mo_coeff[:, :neleca], mo_coeff[:, :neleca].T) vhf_s1occ = reduce(numpy.dot, (p1, mc._scf.get_veff(mol, zvec_ao), p1)) Imat[:ncore, ncore:neleca] = 0 Imat[ncore:neleca, :ncore] = 0 Imat[nocc:, neleca:nocc] = 0 Imat[neleca:nocc, nocc:] = 0 Imat[neleca:, :neleca] = Imat[:neleca, neleca:].T im1 = reduce(numpy.dot, (mo_coeff, Imat, mo_coeff.T)) casci_dm1 = dm_core + dm_cas hf_dm1 = mc._scf.make_rdm1(mo_coeff, mc._scf.mo_occ) hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) diag_idx = numpy.arange(nao) diag_idx = diag_idx * (diag_idx + 1) // 2 + diag_idx casdm2_cc = casdm2 + casdm2.transpose(0, 1, 3, 2) dm2buf = ao2mo._ao2mo.nr_e2(casdm2_cc.reshape(ncas**2, ncas**2), mo_cas.T, (0, nao, 0, nao)).reshape(ncas**2, nao, nao) dm2buf = lib.pack_tril(dm2buf) dm2buf[:, diag_idx] *= .5 dm2buf = dm2buf.reshape(ncas, ncas, nao_pair) casdm2 = casdm2_cc = None if atmlst is None: atmlst = range(mol.natm) aoslices = mol.aoslice_by_atom() de = numpy.zeros((len(atmlst), 3)) max_memory = mc.max_memory - lib.current_memory()[0] blksize = int(max_memory * .9e6 / 8 / ((aoslices[:, 3] - aoslices[:, 2]).max() * nao_pair)) blksize = min(nao, max(2, blksize)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ij->x', h1ao, casci_dm1) de[k] += numpy.einsum('xij,ij->x', h1ao, zvec_ao) vhf1 = numpy.zeros((3, nao, nao)) q1 = 0 for b0, b1, nf in _shell_prange(mol, 0, mol.nbas, blksize): q0, q1 = q1, q1 + nf dm2_ao = lib.einsum('ijw,pi,qj->pqw', dm2buf, mo_cas[p0:p1], mo_cas[q0:q1]) shls_slice = (shl0, shl1, b0, b1, 0, mol.nbas, 0, mol.nbas) eri1 = mol.intor('int2e_ip1', comp=3, aosym='s2kl', shls_slice=shls_slice).reshape( 3, p1 - p0, nf, nao_pair) de[k] -= numpy.einsum('xijw,ijw->x', eri1, dm2_ao) * 2 for i in range(3): eri1tmp = lib.unpack_tril(eri1[i].reshape((p1 - p0) * nf, -1)) eri1tmp = eri1tmp.reshape(p1 - p0, nf, nao, nao) de[k, i] -= numpy.einsum('ijkl,ij,kl', eri1tmp, hf_dm1[p0:p1, q0:q1], zvec_ao) * 2 de[k, i] -= numpy.einsum('ijkl,kl,ij', eri1tmp, hf_dm1, zvec_ao[p0:p1, q0:q1]) * 2 de[k, i] += numpy.einsum('ijkl,il,kj', eri1tmp, hf_dm1[p0:p1], zvec_ao[q0:q1]) de[k, i] += numpy.einsum('ijkl,jk,il', eri1tmp, hf_dm1[q0:q1], zvec_ao[p0:p1]) #:vhf1c, vhf1a = mf_grad.get_veff(mol, (dm_core, dm_cas)) #:de[k] += numpy.einsum('xij,ij->x', vhf1c[:,p0:p1], casci_dm1[p0:p1]) * 2 #:de[k] += numpy.einsum('xij,ij->x', vhf1a[:,p0:p1], dm_core[p0:p1]) * 2 de[k, i] -= numpy.einsum('ijkl,lk,ij', eri1tmp, dm_core[q0:q1], casci_dm1[p0:p1]) * 2 de[k, i] += numpy.einsum('ijkl,jk,il', eri1tmp, dm_core[q0:q1], casci_dm1[p0:p1]) de[k, i] -= numpy.einsum('ijkl,lk,ij', eri1tmp, dm_cas[q0:q1], dm_core[p0:p1]) * 2 de[k, i] += numpy.einsum('ijkl,jk,il', eri1tmp, dm_cas[q0:q1], dm_core[p0:p1]) eri1 = eri1tmp = None de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], im1[p0:p1]) de[k] -= numpy.einsum('xij,ji->x', s1[:, p0:p1], im1[:, p0:p1]) de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], zeta[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ji->x', s1[:, p0:p1], zeta[:, p0:p1]) * 2 de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], vhf_s1occ[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ji->x', s1[:, p0:p1], vhf_s1occ[:, p0:p1]) * 2 de += rhf_grad.grad_nuc(mol, atmlst) 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(tdgrad, z, atmlst=None, mf_grad=None, max_memory=2000, verbose=logger.INFO): mol = tdgrad.mol mf = tdgrad.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 #eai = lib.direct_sum('a-i->ai', mo_energy[nocc:], mo_energy[:nocc]) z = z[0].reshape(nocc, nvir).T orbv = mo_coeff[:, nocc:] orbo = mo_coeff[:, :nocc] def fvind(x): dm = numpy.einsum('pi,xij,qj->xpq', orbv, x, orbo) v_ao = mf.get_veff(mol, (dm + dm.transpose(0, 2, 1))) * 2 return numpy.einsum('pi,xpq,qj->xij', orbv, v_ao, orbo).reshape(3, -1) h1 = rhf_grad.get_hcore(mol) s1 = rhf_grad.get_ovlp(mol) eri1 = -mol.intor('int2e_ip1', aosym='s1', comp=3) eri1 = eri1.reshape(3, nao, nao, nao, nao) eri0 = ao2mo.kernel(mol, mo_coeff) eri0 = ao2mo.restore(1, eri0, nmo).reshape(nmo, nmo, nmo, nmo) g = eri0 * 2 - eri0.transpose(0, 3, 2, 1) zeta = lib.direct_sum('i+j->ij', mo_energy, mo_energy) * .5 zeta[nocc:, :nocc] = mo_energy[:nocc] zeta[:nocc, nocc:] = mo_energy[nocc:] 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] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('int1e_iprinv', comp=3) h1ao[:, p0:p1] += h1[:, p0:p1] h1ao = h1ao + h1ao.transpose(0, 2, 1) h1mo = numpy.einsum('pi,xpq,qj->xij', mo_coeff, h1ao, mo_coeff) s1mo = numpy.einsum('pi,xpq,qj->xij', mo_coeff[p0:p1], s1[:, p0:p1], mo_coeff) s1mo = s1mo + s1mo.transpose(0, 2, 1) f1 = h1mo - numpy.einsum('xpq,pq->xpq', s1mo, zeta) f1 -= numpy.einsum('klpq,xlk->xpq', g[:nocc, :nocc], s1mo[:, :nocc, :nocc]) eri1a = eri1.copy() eri1a[:, :p0] = 0 eri1a[:, p1:] = 0 eri1a = eri1a + eri1a.transpose(0, 2, 1, 3, 4) eri1a = eri1a + eri1a.transpose(0, 3, 4, 1, 2) g1 = numpy.einsum('xpjkl,pi->xijkl', eri1a, mo_coeff) g1 = numpy.einsum('xipkl,pj->xijkl', g1, mo_coeff) g1 = numpy.einsum('xijpl,pk->xijkl', g1, mo_coeff) g1 = numpy.einsum('xijkp,pl->xijkl', g1, mo_coeff) g1 = g1 * 2 - g1.transpose(0, 1, 4, 3, 2) f1 += numpy.einsum('xkkpq->xpq', g1[:, :nocc, :nocc]) f1ai = f1[:, nocc:, :nocc].copy() c1 = s1mo * -.5 c1vo = cphf.solve(fvind, mo_energy, mo_occ, f1ai, max_cycle=50)[0] c1[:, nocc:, :nocc] = c1vo c1[:, :nocc, nocc:] = -(s1mo[:, nocc:, :nocc] + c1vo).transpose(0, 2, 1) f1 += numpy.einsum('kapq,xak->xpq', g[:nocc, nocc:], c1vo) f1 += numpy.einsum('akpq,xak->xpq', g[nocc:, :nocc], c1vo) e1 = numpy.einsum('xaijb,ai,bj->x', g1[:, nocc:, :nocc, :nocc, nocc:], z, z) e1 += numpy.einsum('xab,ai,bi->x', f1[:, nocc:, nocc:], z, z) e1 -= numpy.einsum('xij,ai,aj->x', f1[:, :nocc, :nocc], z, z) g1 = numpy.einsum('pjkl,xpi->xijkl', g, c1) g1 += numpy.einsum('ipkl,xpj->xijkl', g, c1) g1 += numpy.einsum('ijpl,xpk->xijkl', g, c1) g1 += numpy.einsum('ijkp,xpl->xijkl', g, c1) e1 += numpy.einsum('xaijb,ai,bj->x', g1[:, nocc:, :nocc, :nocc, nocc:], z, z) de[k] = e1 return de
def kernel(mc, mo_coeff=None, ci=None, atmlst=None, mf_grad=None, verbose=None): if mo_coeff is None: mo_coeff = mc._scf.mo_coeff if ci is None: ci = mc.ci if mf_grad is None: mf_grad = mc._scf.nuc_grad_method() assert(isinstance(ci, numpy.ndarray)) mol = mc.mol ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas nelecas = mc.nelecas nao, nmo = mo_coeff.shape nao_pair = nao * (nao+1) // 2 mo_energy = mc._scf.mo_energy mo_occ = mo_coeff[:,:nocc] mo_core = mo_coeff[:,:ncore] mo_cas = mo_coeff[:,ncore:nocc] neleca, nelecb = mol.nelec assert(neleca == nelecb) orbo = mo_coeff[:,:neleca] orbv = mo_coeff[:,neleca:] casdm1, casdm2 = mc.fcisolver.make_rdm12(ci, ncas, nelecas) dm_core = numpy.dot(mo_core, mo_core.T) * 2 dm_cas = reduce(numpy.dot, (mo_cas, casdm1, mo_cas.T)) aapa = ao2mo.kernel(mol, (mo_cas, mo_cas, mo_coeff, mo_cas), compact=False) aapa = aapa.reshape(ncas,ncas,nmo,ncas) vj, vk = mc._scf.get_jk(mol, (dm_core, dm_cas)) h1 = mc.get_hcore() vhf_c = vj[0] - vk[0] * .5 vhf_a = vj[1] - vk[1] * .5 # Imat = h1_{pi} gamma1_{iq} + h2_{pijk} gamma_{iqkj} Imat = numpy.zeros((nmo,nmo)) Imat[:,:nocc] = reduce(numpy.dot, (mo_coeff.T, h1 + vhf_c + vhf_a, mo_occ)) * 2 Imat[:,ncore:nocc] = reduce(numpy.dot, (mo_coeff.T, h1 + vhf_c, mo_cas, casdm1)) Imat[:,ncore:nocc] += lib.einsum('uviw,vuwt->it', aapa, casdm2) aapa = vj = vk = vhf_c = vhf_a = h1 = None ee = mo_energy[:,None] - mo_energy zvec = numpy.zeros_like(Imat) zvec[:ncore,ncore:neleca] = Imat[:ncore,ncore:neleca] / -ee[:ncore,ncore:neleca] zvec[ncore:neleca,:ncore] = Imat[ncore:neleca,:ncore] / -ee[ncore:neleca,:ncore] zvec[nocc:,neleca:nocc] = Imat[nocc:,neleca:nocc] / -ee[nocc:,neleca:nocc] zvec[neleca:nocc,nocc:] = Imat[neleca:nocc,nocc:] / -ee[neleca:nocc,nocc:] zvec_ao = reduce(numpy.dot, (mo_coeff, zvec+zvec.T, mo_coeff.T)) vhf = mc._scf.get_veff(mol, zvec_ao) * 2 xvo = reduce(numpy.dot, (orbv.T, vhf, orbo)) xvo += Imat[neleca:,:neleca] - Imat[:neleca,neleca:].T def fvind(x): x = x.reshape(xvo.shape) dm = reduce(numpy.dot, (orbv, x, orbo.T)) v = mc._scf.get_veff(mol, dm + dm.T) v = reduce(numpy.dot, (orbv.T, v, orbo)) return v * 2 dm1resp = cphf.solve(fvind, mo_energy, mc._scf.mo_occ, xvo, max_cycle=30)[0] zvec[neleca:,:neleca] = dm1resp zeta = numpy.einsum('ij,j->ij', zvec, mo_energy) zeta = reduce(numpy.dot, (mo_coeff, zeta, mo_coeff.T)) zvec_ao = reduce(numpy.dot, (mo_coeff, zvec+zvec.T, mo_coeff.T)) p1 = numpy.dot(mo_coeff[:,:neleca], mo_coeff[:,:neleca].T) vhf_s1occ = reduce(numpy.dot, (p1, mc._scf.get_veff(mol, zvec_ao), p1)) Imat[:ncore,ncore:neleca] = 0 Imat[ncore:neleca,:ncore] = 0 Imat[nocc:,neleca:nocc] = 0 Imat[neleca:nocc,nocc:] = 0 Imat[neleca:,:neleca] = Imat[:neleca,neleca:].T im1 = reduce(numpy.dot, (mo_coeff, Imat, mo_coeff.T)) casci_dm1 = dm_core + dm_cas hf_dm1 = mc._scf.make_rdm1(mo_coeff, mc._scf.mo_occ) hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) diag_idx = numpy.arange(nao) diag_idx = diag_idx * (diag_idx+1) // 2 + diag_idx casdm2_cc = casdm2 + casdm2.transpose(0,1,3,2) dm2buf = ao2mo._ao2mo.nr_e2(casdm2_cc.reshape(ncas**2,ncas**2), mo_cas.T, (0, nao, 0, nao)).reshape(ncas**2,nao,nao) dm2buf = lib.pack_tril(dm2buf) dm2buf[:,diag_idx] *= .5 dm2buf = dm2buf.reshape(ncas,ncas,nao_pair) casdm2 = casdm2_cc = None if atmlst is None: atmlst = range(mol.natm) aoslices = mol.aoslice_by_atom() de = numpy.zeros((len(atmlst),3)) max_memory = mc.max_memory - lib.current_memory()[0] blksize = int(max_memory*.9e6/8 / ((aoslices[:,3]-aoslices[:,2]).max()*nao_pair)) blksize = min(nao, max(2, blksize)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ij->x', h1ao, casci_dm1) de[k] += numpy.einsum('xij,ij->x', h1ao, zvec_ao) vhf1 = numpy.zeros((3,nao,nao)) q1 = 0 for b0, b1, nf in _shell_prange(mol, 0, mol.nbas, blksize): q0, q1 = q1, q1 + nf dm2_ao = lib.einsum('ijw,pi,qj->pqw', dm2buf, mo_cas[p0:p1], mo_cas[q0:q1]) shls_slice = (shl0,shl1,b0,b1,0,mol.nbas,0,mol.nbas) eri1 = mol.intor('int2e_ip1', comp=3, aosym='s2kl', shls_slice=shls_slice).reshape(3,p1-p0,nf,nao_pair) de[k] -= numpy.einsum('xijw,ijw->x', eri1, dm2_ao) * 2 for i in range(3): eri1tmp = lib.unpack_tril(eri1[i].reshape((p1-p0)*nf,-1)) eri1tmp = eri1tmp.reshape(p1-p0,nf,nao,nao) de[k,i] -= numpy.einsum('ijkl,ij,kl', eri1tmp, hf_dm1[p0:p1,q0:q1], zvec_ao) * 2 de[k,i] -= numpy.einsum('ijkl,kl,ij', eri1tmp, hf_dm1, zvec_ao[p0:p1,q0:q1]) * 2 de[k,i] += numpy.einsum('ijkl,il,kj', eri1tmp, hf_dm1[p0:p1], zvec_ao[q0:q1]) de[k,i] += numpy.einsum('ijkl,jk,il', eri1tmp, hf_dm1[q0:q1], zvec_ao[p0:p1]) #:vhf1c, vhf1a = mf_grad.get_veff(mol, (dm_core, dm_cas)) #:de[k] += numpy.einsum('xij,ij->x', vhf1c[:,p0:p1], casci_dm1[p0:p1]) * 2 #:de[k] += numpy.einsum('xij,ij->x', vhf1a[:,p0:p1], dm_core[p0:p1]) * 2 de[k,i] -= numpy.einsum('ijkl,lk,ij', eri1tmp, dm_core[q0:q1], casci_dm1[p0:p1]) * 2 de[k,i] += numpy.einsum('ijkl,jk,il', eri1tmp, dm_core[q0:q1], casci_dm1[p0:p1]) de[k,i] -= numpy.einsum('ijkl,lk,ij', eri1tmp, dm_cas[q0:q1], dm_core[p0:p1]) * 2 de[k,i] += numpy.einsum('ijkl,jk,il', eri1tmp, dm_cas[q0:q1], dm_core[p0:p1]) eri1 = eri1tmp = None de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], im1[p0:p1]) de[k] -= numpy.einsum('xij,ji->x', s1[:,p0:p1], im1[:,p0:p1]) de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], zeta[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ji->x', s1[:,p0:p1], zeta[:,p0:p1]) * 2 de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], vhf_s1occ[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ji->x', s1[:,p0:p1], vhf_s1occ[:,p0:p1]) * 2 de += mf_grad.grad_nuc(mol, atmlst) 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)) vj, vk = mf.get_jk(mol, (dmzoo, dmzvop+dmzvop.T, dmzvom-dmzvom.T), hermi=0) veff0doo = vj[0] * 2 - vk[0] wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - vk[1] else: veff = -vk[1] 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 def fvind(x): # For singlet, closed shell ground state dm = reduce(numpy.dot, (orbv, x.reshape(nvir,nocc), orbo.T)) vj, vk = mf.get_jk(mol, (dm+dm.T)) return reduce(numpy.dot, (orbv.T, vj*2-vk, 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)) vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj * 2 - vk 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)) vj, vk = td_grad.get_jk(mol, (oo0, dmz1doo+dmz1doo.T, dmzvop+dmzvop.T, dmzvom-dmzvom.T)) vj = vj.reshape(-1,3,nao,nao) vk = vk.reshape(-1,3,nao,nao) if singlet: vhf1 = vj * 2 - vk else: vhf1 = numpy.vstack((vj[:2]*2-vk[:2], -vk[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] += vhf1[0,:,p0:p1] h1ao[:,:,p0:p1] += vhf1[0,:,p0:p1].transpose(0,2,1) # oo0*2 for doubly occupied orbitals de[k] = numpy.einsum('xpq,pq->x', h1ao, oo0) * 2 de[k] += numpy.einsum('xpq,pq->x', h1ao, dmz1doo) 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', vhf1[1,:,p0:p1], oo0[p0:p1]) de[k] += numpy.einsum('xij,ij->x', vhf1[2,:,p0:p1], dmzvop[p0:p1,:]) * 2 de[k] += numpy.einsum('xij,ij->x', vhf1[3,:,p0:p1], dmzvom[p0:p1,:]) * 2 de[k] += numpy.einsum('xji,ij->x', vhf1[2,:,p0:p1], dmzvop[:,p0:p1]) * 2 de[k] -= numpy.einsum('xji,ij->x', vhf1[3,:,p0:p1], dmzvom[:,p0:p1]) * 2 log.timer('TDHF nuclear gradients', *time0) return de
def solve_mo1(mf, mo_energy, mo_coeff, mo_occ, h1ao_or_chkfile, fx=None, atmlst=None, max_memory=4000, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] if fx is None: def fx(mo1): dm1 = numpy.einsum('xai,pa,qi->xpq', mo1, mo_coeff, mocc*2) dm1 = dm1 + dm1.transpose(0,2,1) v1 = mf.get_veff(mol, dm1) return numpy.einsum('xpq,pa,qi->xai', v1, mo_coeff, mocc) offsetdic = mol.offset_nr_by_atom() mem_now = lib.current_memory()[0] max_memory = max(4000, max_memory*.9-mem_now) blksize = max(2, int(max_memory*1e6/8 / (nmo*nocc*3*6))) s1a =-mol.intor('cint1e_ipovlp_sph', comp=3) mo1s = [] e1s = [] for ia0, ia1 in prange(0, len(atmlst), blksize): s1vo = [] h1vo = [] for i0 in range(ia0, ia1): ia = atmlst[i0] shl0, shl1, p0, p1 = offsetdic[ia] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1vo.append(numpy.einsum('xpq,pi,qj->xij', s1ao, mo_coeff, mocc)) if isinstance(h1ao_or_chkfile, str): key = 'scf_h1ao/%d' % ia h1ao = lib.chkfile.load(h1ao_or_chkfile, key) else: h1ao = h1ao_or_chkfile[i0] h1vo.append(numpy.einsum('xpq,pi,qj->xij', h1ao, mo_coeff, mocc)) h1vo = numpy.vstack(h1vo) s1vo = numpy.vstack(s1vo) mo1, e1 = cphf.solve(fx, mo_energy, mo_occ, h1vo, s1vo) mo1 = numpy.einsum('pq,xqi->xpi', mo_coeff, mo1).reshape(-1,3,nmo,nocc) if isinstance(h1ao_or_chkfile, str): for k in range(ia1-ia0): key = 'scf_mo1/%d' % atmlst[k+ia0] lib.chkfile.save(h1ao_or_chkfile, key, mo1[k]) mo1s.append(key) else: mo1s.append(mo1) e1s.append(e1.reshape(-1,3,nocc,nocc)) e1s = numpy.vstack(e1s) if isinstance(h1ao_or_chkfile, str): return h1ao_or_chkfile, e1s else: return numpy.vstack(mo1s), e1s
def kernel(td_grad, x_y, singlet=True, atmlst=None, max_memory=2000, verbose=logger.INFO): x, y = x_y if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(td_grad.stdout, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad._td._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 xpy = (x + y).reshape(nvir, nocc) xmy = (x - y).reshape(nvir, nocc) 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 = pyscf.lib.current_memory()[0] max_memory = max(2000, td_grad.max_memory * .9 - mem_now) ni = mf._numint hyb = ni.hybrid_coeff(mf.xc, spin=mol.spin) dm0 = None # mf.make_rdm1(mo_coeff, mo_occ) 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: vj, vk = mf.get_jk(mol, (dmzoo, dmzvop + dmzvop.T, dmzvom - dmzvom.T), hermi=0) veff0doo = vj[0] * 2 - hyb * vk[0] + f1oo[0] + k1ao[0] * 2 wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - hyb * vk[1] + f1vo[0] * 2 else: veff = -hyb * 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 = -hyb * 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 ._td.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 + dm.T)) veff = vj * 2 - hyb * vk + vindxc else: vj = mf.get_j(mol, (dm + dm.T)) 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.max_cycle_cphf, tol=td_grad.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] 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 = pyscf.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)) h1 = td_grad.get_hcore(mol) s1 = td_grad.get_ovlp(mol) dmz1doo = z1ao + dmzoo oo0 = reduce(numpy.dot, (orbo, orbo.T)) if abs(hyb) > 1e-10: vj, vk = td_grad.get_jk( mol, (oo0, dmz1doo + dmz1doo.T, dmzvop + dmzvop.T, dmzvom - dmzvom.T)) vj = vj.reshape(-1, 3, nao, nao) vk = vk.reshape(-1, 3, nao, nao) if singlet: veff1 = vj * 2 - hyb * vk else: veff1 = numpy.vstack((vj[:2] * 2 - hyb * vk[:2], -hyb * 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] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('int1e_iprinv', comp=3) h1ao[:, p0:p1] += h1[:, p0:p1] + veff1[0, :, p0:p1] # Ground state gradients # h1ao*2 for +c.c, oo0*2 for doubly occupied orbitals e1 = numpy.einsum('xpq,pq->x', h1ao, oo0) * 4 e1 += numpy.einsum('xpq,pq->x', h1ao, dmz1doo) e1 += numpy.einsum('xqp,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, singlet=True, atmlst=None, max_memory=2000, verbose=logger.INFO): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(td_grad.stdout, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad._td._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(nvir, nocc) xmy = (x - y).reshape(nvir, nocc) 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)) vj, vk = mf.get_jk(mol, (dmzoo, dmzvop + dmzvop.T, dmzvom - dmzvom.T), hermi=0) veff0doo = vj[0] * 2 - vk[0] wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - vk[1] else: veff = -vk[1] 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 def fvind(x): # For singlet, closed shell ground state dm = reduce(numpy.dot, (orbv, x.reshape(nvir, nocc), orbo.T)) vj, vk = mf.get_jk(mol, (dm + dm.T)) return reduce(numpy.dot, (orbv.T, vj * 2 - vk, orbo)).ravel() z1 = cphf.solve(fvind, mo_energy, mo_occ, wvo, max_cycle=td_grad.max_cycle_cphf, tol=td_grad.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)) vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj * 2 - vk 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 = pyscf.lib.direct_sum("i+j->ij", mo_energy, mo_energy) * 0.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)) h1 = td_grad.get_hcore(mol) s1 = td_grad.get_ovlp(mol) dmz1doo = z1ao + dmzoo oo0 = reduce(numpy.dot, (orbo, orbo.T)) vj, vk = td_grad.get_jk(mol, (oo0, dmz1doo + dmz1doo.T, dmzvop + dmzvop.T, dmzvom - dmzvom.T)) vj = vj.reshape(-1, 3, nao, nao) vk = vk.reshape(-1, 3, nao, nao) if singlet: vhf1 = vj * 2 - vk else: vhf1 = numpy.vstack((vj[:2] * 2 - vk[:2], -vk[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] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor("cint1e_iprinv_sph", comp=3) h1ao[:, p0:p1] += h1[:, p0:p1] + vhf1[0, :, p0:p1] # Ground state gradients # h1ao*2 for +c.c, oo0*2 for doubly occupied orbitals de[k] = numpy.einsum("xpq,pq->x", h1ao, oo0) * 4 de[k] += numpy.einsum("xpq,pq->x", h1ao, dmz1doo) de[k] += numpy.einsum("xqp,pq->x", h1ao, dmz1doo) 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", vhf1[1, :, p0:p1], oo0[p0:p1]) de[k] += numpy.einsum("xij,ij->x", vhf1[2, :, p0:p1], dmzvop[p0:p1, :]) * 2 de[k] += numpy.einsum("xij,ij->x", vhf1[3, :, p0:p1], dmzvom[p0:p1, :]) * 2 de[k] += numpy.einsum("xji,ij->x", vhf1[2, :, p0:p1], dmzvop[:, p0:p1]) * 2 de[k] -= numpy.einsum("xji,ij->x", vhf1[3, :, p0:p1], dmzvom[:, p0:p1]) * 2 log.timer("TDHF nuclear gradients", *time0) return de
veff0mom = numpy.zeros((nmo,nmo)) def fvind(x): # Cannot make call to ._td.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)) # Call singlet XC kernel contraction, for closed shell ground state vindxc = rks._contract_xc_kernel(td_grad._td, x_code, c_code, [dm+dm.T], True, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, (dm+dm.T)) veff = vj * 2 - hyb * vk + vindxc else: vj = mf.get_j(mol, (dm+dm.T)) 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.max_cycle_cphf, tol=td_grad.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, x_code, c_code, 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] else: vj = mf.get_j(mol, z1ao, hermi=1) veff = vj * 2 + fxcz1[0] im0 = numpy.zeros((nmo,nmo))
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)) vj, vk = mf.get_jk(mol, (dmzoo, dmzvop + dmzvop.T, dmzvom - dmzvom.T), hermi=0) veff0doo = vj[0] * 2 - vk[0] wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - vk[1] else: veff = -vk[1] 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 def fvind(x): # For singlet, closed shell ground state dm = reduce(numpy.dot, (orbv, x.reshape(nvir, nocc), orbo.T)) vj, vk = mf.get_jk(mol, (dm + dm.T)) return reduce(numpy.dot, (orbv.T, vj * 2 - vk, 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)) vj, vk = mf.get_jk(mol, z1ao, hermi=0) veff = vj * 2 - vk 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)) vj, vk = td_grad.get_jk( mol, (oo0, dmz1doo + dmz1doo.T, dmzvop + dmzvop.T, dmzvom - dmzvom.T)) vj = vj.reshape(-1, 3, nao, nao) vk = vk.reshape(-1, 3, nao, nao) if singlet: vhf1 = vj * 2 - vk else: vhf1 = numpy.vstack((vj[:2] * 2 - vk[:2], -vk[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] += vhf1[0, :, p0:p1] h1ao[:, :, p0:p1] += vhf1[0, :, p0:p1].transpose(0, 2, 1) # oo0*2 for doubly occupied orbitals de[k] = numpy.einsum('xpq,pq->x', h1ao, oo0) * 2 de[k] += numpy.einsum('xpq,pq->x', h1ao, dmz1doo) 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', vhf1[1, :, p0:p1], oo0[p0:p1]) de[k] += numpy.einsum('xij,ij->x', vhf1[2, :, p0:p1], dmzvop[p0:p1, :]) * 2 de[k] += numpy.einsum('xij,ij->x', vhf1[3, :, p0:p1], dmzvom[p0:p1, :]) * 2 de[k] += numpy.einsum('xji,ij->x', vhf1[2, :, p0:p1], dmzvop[:, p0:p1]) * 2 de[k] -= numpy.einsum('xji,ij->x', vhf1[3, :, p0:p1], dmzvom[:, p0:p1]) * 2 log.timer('TDHF 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, singlet=True, atmlst=None, max_memory=2000, verbose=logger.INFO): x, y = x_y if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(td_grad.stdout, verbose) time0 = time.clock(), time.time() mol = td_grad.mol mf = td_grad._td._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 xpy = (x+y).reshape(nvir,nocc) xmy = (x-y).reshape(nvir,nocc) 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 = pyscf.lib.current_memory()[0] max_memory = max(2000, td_grad.max_memory*.9-mem_now) hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin>0)+1) f1vo, f1oo, vxc1, k1ao = \ _contract_xc_kernel(td_grad, mf.xc, dmzvop, dmzoo, True, True, singlet, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, (dmzoo, dmzvop+dmzvop.T, dmzvom-dmzvom.T), hermi=0) veff0doo = vj[0] * 2 - hyb * vk[0] + f1oo[0] + k1ao[0] * 2 wvo = reduce(numpy.dot, (orbv.T, veff0doo, orbo)) * 2 if singlet: veff = vj[1] * 2 - hyb * vk[1] + f1vo[0] * 2 else: veff = -hyb * 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 = -hyb * 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 ._td.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)) # Call singlet XC kernel contraction, for closed shell ground state vindxc = rks._contract_xc_kernel(td_grad._td, mf.xc, [dm+dm.T], True, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, (dm+dm.T)) veff = vj * 2 - hyb * vk + vindxc else: vj = mf.get_j(mol, (dm+dm.T)) 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.max_cycle_cphf, tol=td_grad.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] 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 = pyscf.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)) h1 = td_grad.get_hcore(mol) s1 = td_grad.get_ovlp(mol) dmz1doo = z1ao + dmzoo oo0 = reduce(numpy.dot, (orbo, orbo.T)) if abs(hyb) > 1e-10: vj, vk = td_grad.get_jk(mol, (oo0, dmz1doo+dmz1doo.T, dmzvop+dmzvop.T, dmzvom-dmzvom.T)) vj = vj.reshape(-1,3,nao,nao) vk = vk.reshape(-1,3,nao,nao) if singlet: veff1 = vj * 2 - hyb * vk else: veff1 = numpy.vstack((vj[:2]*2-hyb*vk[:2], -hyb*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] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3) h1ao[:,p0:p1] += h1[:,p0:p1] + veff1[0,:,p0:p1] # Ground state gradients # h1ao*2 for +c.c, oo0*2 for doubly occupied orbitals e1 = numpy.einsum('xpq,pq->x', h1ao, oo0) * 4 e1 += numpy.einsum('xpq,pq->x', h1ao, dmz1doo) e1 += numpy.einsum('xqp,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