def solve_mo1_fc(sscobj, h1): cput1 = (time.clock(), time.time()) log = logger.Logger(sscobj.stdout, sscobj.verbose) mol = sscobj.mol mo_energy = sscobj._scf.mo_energy mo_coeff = sscobj._scf.mo_coeff mo_occ = sscobj._scf.mo_occ nset = len(h1) eai = 1. / lib.direct_sum('a-i->ai', mo_energy[mo_occ==0], mo_energy[mo_occ>0]) mo1 = numpy.asarray(h1) * -eai if not sscobj.cphf: return mo1 orbo = mo_coeff[:,mo_occ> 0] orbv = mo_coeff[:,mo_occ==0] nocc = orbo.shape[1] nvir = orbv.shape[1] nmo = nocc + nvir vresp = _gen_rhf_response(sscobj._scf, singlet=False, hermi=1) mo_v_o = numpy.asarray(numpy.hstack((orbv,orbo)), order='F') def vind(mo1): dm1 = _dm1_mo2ao(mo1.reshape(nset,nvir,nocc), orbv, orbo*2) # *2 for double occupancy dm1 = dm1 + dm1.transpose(0,2,1) v1 = vresp(dm1) v1 = _ao2mo.nr_e2(v1, mo_v_o, (0,nvir,nvir,nmo)).reshape(nset,nvir,nocc) v1 *= eai return v1.ravel() mo1 = lib.krylov(vind, mo1.ravel(), tol=sscobj.conv_tol, max_cycle=sscobj.max_cycle_cphf, verbose=log) log.timer('solving FC CPHF eqn', *cput1) return mo1.reshape(nset,nvir,nocc)
def gen_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert (mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx, None] ^ orbsym[viridx]) != wfnsym e_ia = (mo_energy[viridx].reshape(-1, 1) - mo_energy[occidx]).T if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel()**2 vresp = _gen_rhf_response(mf, singlet=singlet, hermi=1) def vind(zs): nz = len(zs) dmov = numpy.empty((nz, nao, nao)) for i, z in enumerate(zs): # *2 for double occupancy dm = reduce(numpy.dot, (orbo, (d_ia * z).reshape(nocc, nvir) * 2, orbv.T)) dmov[ i] = dm + dm.T # +cc for A+B and K_{ai,jb} in A == K_{ai,bj} in B v1ao = vresp(dmov) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0, nocc, nocc, nmo)).reshape(-1, nocc * nvir) for i, z in enumerate(zs): # numpy.sqrt(e_ia) * (e_ia*d_ia*z + v1ov) v1ov[i] += ed_ia * z v1ov[i] *= d_ia return v1ov.reshape(nz, -1) return vind, hdiag
def gen_vind(mf, mo_coeff, mo_occ): '''Induced potential''' vresp = _gen_rhf_response(mf, singlet=True, hermi=2) occidx = mo_occ > 0 orbo = mo_coeff[:,occidx] nocc = orbo.shape[1] nao, nmo = mo_coeff.shape def vind(mo1): dm1 = [reduce(numpy.dot, (mo_coeff, x*2, orbo.T.conj())) for x in mo1.reshape(3,nmo,nocc)] dm1 = numpy.asarray([d1-d1.conj().T for d1 in dm1]) v1mo = lib.einsum('xpq,pi,qj->xij', vresp(dm1), mo_coeff.conj(), orbo) return v1mo.ravel() return vind
def gen_vind(mf, mo_coeff, mo_occ): '''Induced potential''' vresp = _gen_rhf_response(mf, singlet=True, hermi=2) occidx = mo_occ > 0 orbo = mo_coeff[:,occidx] nocc = orbo.shape[1] nao, nmo = mo_coeff.shape def vind(mo1): dm1 = [reduce(numpy.dot, (mo_coeff, x*2, orbo.T.conj())) for x in mo1.reshape(3,nmo,nocc)] dm1 = numpy.asarray([d1-d1.conj().T for d1 in dm1]) v1mo = lib.einsum('xpq,pi,qj->xij', vresp(dm1), mo_coeff.conj(), orbo) return v1mo.ravel() return vind
def gen_vind(self, mf, mo_coeff, mo_occ): '''Induced potential''' vresp = _gen_rhf_response(mf, hermi=1) occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] nocc = orbo.shape[1] nao, nmo = mo_coeff.shape def vind(mo1): dm1 = lib.einsum('xai,pa,qi->xpq', mo1.reshape(-1,nmo,nocc), mo_coeff, orbo.conj()) dm1 = (dm1 + dm1.transpose(0,2,1).conj()) * 2 v1mo = lib.einsum('xpq,pi,qj->xij', vresp(dm1), mo_coeff.conj(), orbo) return v1mo.ravel() return vind
def gen_vind(self, mf, mo_coeff, mo_occ): '''Induced potential''' vresp = _gen_rhf_response(mf, hermi=1) occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] nocc = orbo.shape[1] nao, nmo = mo_coeff.shape def vind(mo1): dm1 = lib.einsum('xai,pa,qi->xpq', mo1.reshape(-1,nmo,nocc), mo_coeff, orbo.conj()) dm1 = (dm1 + dm1.transpose(0,2,1).conj()) * 2 v1mo = lib.einsum('xpq,pi,qj->xij', vresp(dm1), mo_coeff.conj(), orbo) return v1mo.ravel() return vind
def gen_vind(self, mf): wfnsym = self.wfnsym singlet = self.singlet mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym e_ia = (mo_energy[viridx].reshape(-1,1) - mo_energy[occidx]).T if wfnsym is not None and mol.symmetry: e_ia[sym_forbid] = 0 d_ia = numpy.sqrt(e_ia).ravel() ed_ia = e_ia.ravel() * d_ia hdiag = e_ia.ravel() ** 2 vresp = _gen_rhf_response(mf, singlet=singlet, hermi=1) def vind(zs): nz = len(zs) dmov = numpy.empty((nz,nao,nao)) for i, z in enumerate(zs): # *2 for double occupancy dm = reduce(numpy.dot, (orbo, (d_ia*z).reshape(nocc,nvir)*2, orbv.T)) dmov[i] = dm + dm.T # +cc for A+B and K_{ai,jb} in A == K_{ai,bj} in B v1ao = vresp(dmov) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc*nvir) for i, z in enumerate(zs): # numpy.sqrt(e_ia) * (e_ia*d_ia*z + v1ov) v1ov[i] += ed_ia*z v1ov[i] *= d_ia return v1ov.reshape(nz,-1) return vind, hdiag
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 gen_vind(mf, mo_coeff, mo_occ): '''Induced potential associated with h1_PSO''' vresp = _gen_rhf_response(mf, singlet=True, hermi=2) occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] orbv = mo_coeff[:,~occidx] nocc = orbo.shape[1] nao, nmo = mo_coeff.shape nvir = nmo - nocc def vind(mo1): dm1 = [reduce(numpy.dot, (orbv, x*2, orbo.T.conj())) for x in mo1.reshape(-1,nvir,nocc)] dm1 = numpy.asarray([d1-d1.conj().T for d1 in dm1]) v1mo = numpy.asarray([reduce(numpy.dot, (orbv.T.conj(), x, orbo)) for x in vresp(dm1)]) return v1mo.ravel() return vind
def gen_vind(self, mf, mo_coeff, mo_occ): '''Induced potential''' vresp = _gen_rhf_response(mf, hermi=2) occidx = mo_occ > 0 orbo = mo_coeff[:,occidx] nocc = orbo.shape[1] nao, nmo = mo_coeff.shape def vind(mo1): #direct_scf_bak, mf.direct_scf = mf.direct_scf, False dm1 = [reduce(numpy.dot, (mo_coeff, x*2, orbo.T.conj())) for x in mo1.reshape(3,nmo,nocc)] dm1 = numpy.asarray([d1-d1.conj().T for d1 in dm1]) v1mo = numpy.asarray([reduce(numpy.dot, (mo_coeff.T.conj(), x, orbo)) for x in vresp(dm1)]) #mf.direct_scf = direct_scf_bak return v1mo.ravel() return vind
def gen_vind(mf, mo_coeff, mo_occ): nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] vresp = _gen_rhf_response(mf, mo_coeff, mo_occ, hermi=1) def fx(mo1): mo1 = mo1.reshape(-1,nmo,nocc) nset = len(mo1) dm1 = numpy.empty((nset,nao,nao)) for i, x in enumerate(mo1): dm = reduce(numpy.dot, (mo_coeff, x*2, mocc.T)) # *2 for double occupancy dm1[i] = dm + dm.T v1 = vresp(dm1) v1vo = numpy.empty_like(mo1) for i, x in enumerate(v1): v1vo[i] = reduce(numpy.dot, (mo_coeff.T, x, mocc)) return v1vo return fx
def gen_vind(mf, mo_coeff, mo_occ): nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] vresp = _gen_rhf_response(mf, mo_coeff, mo_occ, hermi=1) def fx(mo1): mo1 = mo1.reshape(-1,nmo,nocc) nset = len(mo1) dm1 = numpy.empty((nset,nao,nao)) for i, x in enumerate(mo1): dm = reduce(numpy.dot, (mo_coeff, x*2, mocc.T)) # *2 for double occupancy dm1[i] = dm + dm.T v1 = vresp(dm1) v1vo = numpy.empty_like(mo1) for i, x in enumerate(v1): v1vo[i] = reduce(numpy.dot, (mo_coeff.T, x, mocc)) return v1vo return fx
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 cphf_with_freq(mf, mo_energy, mo_occ, h1, freq=0, max_cycle=20, tol=1e-9, hermi=False, verbose=logger.WARN): log = logger.new_logger(verbose=verbose) t0 = (time.clock(), time.time()) occidx = mo_occ > 0 viridx = mo_occ == 0 e_ai = lib.direct_sum('a-i->ai', mo_energy[viridx], mo_energy[occidx]) # e_ai - freq may produce very small elements which can cause numerical # issue in krylov solver LEVEL_SHIF = 0.1 diag = (e_ai - freq, e_ai + freq) diag[0][diag[0] < LEVEL_SHIF] += LEVEL_SHIF diag[1][diag[1] < LEVEL_SHIF] += LEVEL_SHIF nvir, nocc = e_ai.shape mo_coeff = mf.mo_coeff nao, nmo = mo_coeff.shape orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] h1 = h1.reshape(-1,nvir,nocc) ncomp = h1.shape[0] mo1base = numpy.stack((-h1/diag[0], -h1/diag[1]), axis=1) mo1base = mo1base.reshape(ncomp,nocc*nvir*2) vresp = _gen_rhf_response(mf, hermi=0) def vind(xys): nz = len(xys) dms = numpy.empty((nz,nao,nao)) for i in range(nz): x, y = xys[i].reshape(2,nvir,nocc) # *2 for double occupancy dmx = reduce(numpy.dot, (orbv, x *2, orbo.T)) dmy = reduce(numpy.dot, (orbo, y.T*2, orbv.T)) dms[i] = dmx + dmy # AX + BY v1ao = vresp(dms) v1vo = lib.einsum('xpq,pi,qj->xij', v1ao, orbv, orbo) # ~c1 v1ov = lib.einsum('xpq,pi,qj->xji', v1ao, orbo, orbv) # ~c1^T for i in range(nz): x, y = xys[i].reshape(2,nvir,nocc) v1vo[i] += (e_ai - freq - diag[0]) * x v1vo[i] /= diag[0] v1ov[i] += (e_ai + freq - diag[1]) * y v1ov[i] /= diag[1] v = numpy.stack((v1vo, v1ov), axis=1) return v.reshape(nz,-1) # FIXME: krylov solver is not accurate enough for many freqs. Using tight # tol and lindep could offer small help. A better linear equation solver # is needed. mo1 = lib.krylov(vind, mo1base, tol=tol, max_cycle=max_cycle, hermi=hermi, lindep=1e-18, verbose=log) mo1 = mo1.reshape(-1,2,nvir,nocc) log.timer('krylov solver in CPHF', *t0) dms = numpy.empty((ncomp,nao,nao)) for i in range(ncomp): x, y = mo1[i] dmx = reduce(numpy.dot, (orbv, x *2, orbo.T)) dmy = reduce(numpy.dot, (orbo, y.T*2, orbv.T)) dms[i] = dmx + dmy mo_e1 = lib.einsum('xpq,pi,qj->xij', vresp(dms), orbo, orbo) mo1 = (mo1[:,0], mo1[:,1]) return mo1, mo_e1
def cphf_with_freq(mf, mo_energy, mo_occ, h1, freq=0, max_cycle=20, tol=1e-9, hermi=False, verbose=logger.WARN): log = logger.new_logger(verbose=verbose) t0 = (time.clock(), time.time()) occidx = mo_occ > 0 viridx = mo_occ == 0 e_ai = lib.direct_sum('a-i->ai', mo_energy[viridx], mo_energy[occidx]) # e_ai - freq may produce very small elements which can cause numerical # issue in krylov solver LEVEL_SHIF = 0.1 diag = (e_ai - freq, e_ai + freq) diag[0][diag[0] < LEVEL_SHIF] += LEVEL_SHIF diag[1][diag[1] < LEVEL_SHIF] += LEVEL_SHIF nvir, nocc = e_ai.shape mo_coeff = mf.mo_coeff nao, nmo = mo_coeff.shape orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] h1 = h1.reshape(-1,nvir,nocc) ncomp = h1.shape[0] mo1base = numpy.stack((-h1/diag[0], -h1/diag[1]), axis=1) mo1base = mo1base.reshape(ncomp,nocc*nvir*2) vresp = _gen_rhf_response(mf, hermi=0) def vind(xys): nz = len(xys) dms = numpy.empty((nz,nao,nao)) for i in range(nz): x, y = xys[i].reshape(2,nvir,nocc) # *2 for double occupancy dmx = reduce(numpy.dot, (orbv, x *2, orbo.T)) dmy = reduce(numpy.dot, (orbo, y.T*2, orbv.T)) dms[i] = dmx + dmy # AX + BY v1ao = vresp(dms) v1vo = lib.einsum('xpq,pi,qj->xij', v1ao, orbv, orbo) # ~c1 v1ov = lib.einsum('xpq,pi,qj->xji', v1ao, orbo, orbv) # ~c1^T for i in range(nz): x, y = xys[i].reshape(2,nvir,nocc) v1vo[i] += (e_ai - freq - diag[0]) * x v1vo[i] /= diag[0] v1ov[i] += (e_ai + freq - diag[1]) * y v1ov[i] /= diag[1] v = numpy.stack((v1vo, v1ov), axis=1) return v.reshape(nz,-1) # FIXME: krylov solver is not accurate enough for many freqs. Using tight # tol and lindep could offer small help. A better linear equation solver # is needed. mo1 = lib.krylov(vind, mo1base, tol=tol, max_cycle=max_cycle, hermi=hermi, lindep=1e-18, verbose=log) mo1 = mo1.reshape(-1,2,nvir,nocc) log.timer('krylov solver in CPHF', *t0) dms = numpy.empty((ncomp,nao,nao)) for i in range(ncomp): x, y = mo1[i] dmx = reduce(numpy.dot, (orbv, x *2, orbo.T)) dmy = reduce(numpy.dot, (orbo, y.T*2, orbv.T)) dms[i] = dmx + dmy mo_e1 = lib.einsum('xpq,pi,qj->xij', vresp(dms), orbo, orbo) mo1 = (mo1[:,0], mo1[:,1]) return mo1, mo_e1
def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute (A+B)x Kwargs: wfnsym : int or str Point group symmetry irrep symbol or ID for excited CIS wavefunction. ''' mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym if fock_ao is None: #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) else: fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] hdiag = (fvv.diagonal().reshape(-1,1) - foo.diagonal()).T if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = hdiag.ravel() mo_coeff = numpy.asarray(numpy.hstack((orbo,orbv)), order='F') vresp = _gen_rhf_response(mf, singlet=singlet, hermi=0) def vind(zs): nz = len(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs).reshape(-1,nocc,nvir) zs[:,sym_forbid] = 0 dmov = numpy.empty((nz,nao,nao)) for i, z in enumerate(zs): # *2 for double occupancy dmov[i] = reduce(numpy.dot, (orbo, z.reshape(nocc,nvir)*2, orbv.conj().T)) v1ao = vresp(dmov) #v1ov = numpy.asarray([reduce(numpy.dot, (orbo.T, v, orbv)) for v in v1ao]) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc,nvir) for i, z in enumerate(zs): v1ov[i]+= numpy.einsum('sp,qs->qp', fvv, z.reshape(nocc,nvir)) v1ov[i]-= numpy.einsum('sp,pr->sr', foo, z.reshape(nocc,nvir)) if wfnsym is not None and mol.symmetry: v1ov[:,sym_forbid] = 0 return v1ov.reshape(nz,-1) return vind, hdiag
def _gen_hop_rhf_external(mf, with_symmetry=True, verbose=None): mol = mf.mol mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = numpy.where(mo_occ == 2)[0] viridx = numpy.where(mo_occ == 0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:, viridx] orbo = mo_coeff[:, occidx] if with_symmetry and mol.symmetry: orbsym = hf_symm.get_orbsym(mol, mo_coeff) sym_forbid = orbsym[viridx].reshape(-1, 1) != orbsym[occidx] h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) foo = fock[occidx[:, None], occidx] fvv = fock[viridx[:, None], viridx] hdiag = fvv.diagonal().reshape(-1, 1) - foo.diagonal() if with_symmetry and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = hdiag.ravel() vrespz = _gen_rhf_response(mf, singlet=None, hermi=2) def hop_real2complex(x1): x1 = x1.reshape(nvir, nocc) if with_symmetry and mol.symmetry: x1 = x1.copy() x1[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x1) x2 -= numpy.einsum('ps,rp->rs', foo, x1) d1 = reduce(numpy.dot, (orbv, x1 * 2, orbo.T.conj())) dm1 = d1 - d1.T.conj() # No Coulomb and fxc contribution for anti-hermitian DM v1 = vrespz(dm1) x2 += reduce(numpy.dot, (orbv.T.conj(), v1, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.ravel() vresp1 = _gen_rhf_response(mf, singlet=False, hermi=1) def hop_rhf2uhf(x1): from pyscf.dft import numint # See also rhf.TDA triplet excitation x1 = x1.reshape(nvir, nocc) if with_symmetry and mol.symmetry: x1 = x1.copy() x1[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x1) x2 -= numpy.einsum('ps,rp->rs', foo, x1) d1 = reduce(numpy.dot, (orbv, x1 * 2, orbo.T.conj())) dm1 = d1 + d1.T.conj() v1ao = vresp1(dm1) x2 += reduce(numpy.dot, (orbv.T.conj(), v1ao, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.ravel() return hop_real2complex, hdiag, hop_rhf2uhf, hdiag
def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute [ A B][X] [-B -A][Y] ''' mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) #fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) #foo = fock[occidx[:,None],occidx] #fvv = fock[viridx[:,None],viridx] foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) hdiag = (fvv.diagonal().reshape(-1,1) - foo.diagonal()).T if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = numpy.hstack((hdiag.ravel(), hdiag.ravel())) mo_coeff = numpy.asarray(numpy.hstack((orbo,orbv)), order='F') vresp = _gen_rhf_response(mf, singlet=singlet, hermi=0) def vind(xys): nz = len(xys) if wfnsym is not None and mol.symmetry: # shape(nz,2,nocc,nvir): 2 ~ X,Y xys = numpy.copy(xys).reshape(nz,2,nocc,nvir) xys[:,:,sym_forbid] = 0 dms = numpy.empty((nz,nao,nao)) for i in range(nz): x, y = xys[i].reshape(2,nocc,nvir) # *2 for double occupancy dmx = reduce(numpy.dot, (orbo, x*2, orbv.T)) dmy = reduce(numpy.dot, (orbv, y.T*2, orbo.T)) dms[i] = dmx + dmy # AX + BY v1ao = vresp(dms) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc,nvir) v1vo = _ao2mo.nr_e2(v1ao, mo_coeff, (nocc,nmo,0,nocc)).reshape(-1,nvir,nocc) hx = numpy.empty((nz,2,nocc,nvir), dtype=v1ov.dtype) for i in range(nz): x, y = xys[i].reshape(2,nocc,nvir) hx[i,0] = v1ov[i] hx[i,0]+= numpy.einsum('sp,qs->qp', fvv, x) # AX hx[i,0]-= numpy.einsum('sp,pr->sr', foo, x) # AX hx[i,1] =-v1vo[i].T hx[i,1]-= numpy.einsum('sp,qs->qp', fvv, y) #-AY hx[i,1]+= numpy.einsum('sp,pr->sr', foo, y) #-AY if wfnsym is not None and mol.symmetry: hx[:,:,sym_forbid] = 0 return hx.reshape(nz,-1) return vind, hdiag
def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute (A+B)x Kwargs: wfnsym : int or str Point group symmetry irrep symbol or ID for excited CIS wavefunction. ''' mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym if fock_ao is None: #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) else: fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] hdiag = (fvv.diagonal().reshape(-1,1) - foo.diagonal()).T if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = hdiag.ravel() mo_coeff = numpy.asarray(numpy.hstack((orbo,orbv)), order='F') vresp = _gen_rhf_response(mf, singlet=singlet, hermi=0) def vind(zs): nz = len(zs) if wfnsym is not None and mol.symmetry: zs = numpy.copy(zs).reshape(-1,nocc,nvir) zs[:,sym_forbid] = 0 dmov = numpy.empty((nz,nao,nao)) for i, z in enumerate(zs): # *2 for double occupancy dmov[i] = reduce(numpy.dot, (orbo, z.reshape(nocc,nvir)*2, orbv.conj().T)) v1ao = vresp(dmov) #v1ov = numpy.asarray([reduce(numpy.dot, (orbo.T, v, orbv)) for v in v1ao]) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc,nvir) for i, z in enumerate(zs): v1ov[i]+= numpy.einsum('sp,qs->qp', fvv, z.reshape(nocc,nvir)) v1ov[i]-= numpy.einsum('sp,pr->sr', foo, z.reshape(nocc,nvir)) if wfnsym is not None and mol.symmetry: v1ov[:,sym_forbid] = 0 return v1ov.reshape(nz,-1) return vind, hdiag
def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None): '''Generate function to compute [ A B][X] [-B -A][Y] ''' mol = mf.mol mo_coeff = mf.mo_coeff assert(mo_coeff.dtype == numpy.double) mo_energy = mf.mo_energy mo_occ = mf.mo_occ nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if wfnsym is not None and mol.symmetry: if isinstance(wfnsym, str): wfnsym = symm.irrep_name2id(mol.groupname, wfnsym) wfnsym = wfnsym % 10 # convert to D2h subgroup orbsym = hf_symm.get_orbsym(mol, mo_coeff) % 10 sym_forbid = (orbsym[occidx,None] ^ orbsym[viridx]) != wfnsym #dm0 = mf.make_rdm1(mo_coeff, mo_occ) #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0) #fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff)) #foo = fock[occidx[:,None],occidx] #fvv = fock[viridx[:,None],viridx] foo = numpy.diag(mo_energy[occidx]) fvv = numpy.diag(mo_energy[viridx]) hdiag = (fvv.diagonal().reshape(-1,1) - foo.diagonal()).T if wfnsym is not None and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = numpy.hstack((hdiag.ravel(), hdiag.ravel())) mo_coeff = numpy.asarray(numpy.hstack((orbo,orbv)), order='F') vresp = _gen_rhf_response(mf, singlet=singlet, hermi=0) def vind(xys): nz = len(xys) if wfnsym is not None and mol.symmetry: # shape(nz,2,nocc,nvir): 2 ~ X,Y xys = numpy.copy(xys).reshape(nz,2,nocc,nvir) xys[:,:,sym_forbid] = 0 dms = numpy.empty((nz,nao,nao)) for i in range(nz): x, y = xys[i].reshape(2,nocc,nvir) # *2 for double occupancy dmx = reduce(numpy.dot, (orbo, x*2, orbv.T)) dmy = reduce(numpy.dot, (orbv, y.T*2, orbo.T)) dms[i] = dmx + dmy # AX + BY v1ao = vresp(dms) v1ov = _ao2mo.nr_e2(v1ao, mo_coeff, (0,nocc,nocc,nmo)).reshape(-1,nocc,nvir) v1vo = _ao2mo.nr_e2(v1ao, mo_coeff, (nocc,nmo,0,nocc)).reshape(-1,nvir,nocc) hx = numpy.empty((nz,2,nocc,nvir), dtype=v1ov.dtype) for i in range(nz): x, y = xys[i].reshape(2,nocc,nvir) hx[i,0] = v1ov[i] hx[i,0]+= numpy.einsum('sp,qs->qp', fvv, x) # AX hx[i,0]-= numpy.einsum('sp,pr->sr', foo, x) # AX hx[i,1] =-v1vo[i].T hx[i,1]-= numpy.einsum('sp,qs->qp', fvv, y) #-AY hx[i,1]+= numpy.einsum('sp,pr->sr', foo, y) #-AY if wfnsym is not None and mol.symmetry: hx[:,:,sym_forbid] = 0 return hx.reshape(nz,-1) return vind, hdiag
def _gen_hop_rhf_external(mf, with_symmetry=True, verbose=None): mol = mf.mol mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] nocc = len(occidx) nvir = len(viridx) orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] if with_symmetry and mol.symmetry: orbsym = hf_symm.get_orbsym(mol, mo_coeff) sym_forbid = orbsym[viridx].reshape(-1,1) != orbsym[occidx] h1e = mf.get_hcore() dm0 = mf.make_rdm1(mo_coeff, mo_occ) fock_ao = h1e + mf.get_veff(mol, dm0) fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff)) foo = fock[occidx[:,None],occidx] fvv = fock[viridx[:,None],viridx] hdiag = fvv.diagonal().reshape(-1,1) - foo.diagonal() if with_symmetry and mol.symmetry: hdiag[sym_forbid] = 0 hdiag = hdiag.ravel() vrespz = _gen_rhf_response(mf, singlet=None, hermi=2) def hop_real2complex(x1): x1 = x1.reshape(nvir,nocc) if with_symmetry and mol.symmetry: x1 = x1.copy() x1[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x1) x2-= numpy.einsum('ps,rp->rs', foo, x1) d1 = reduce(numpy.dot, (orbv, x1*2, orbo.conj().T)) dm1 = d1 - d1.conj().T # No Coulomb and fxc contribution for anti-hermitian DM v1 = vrespz(dm1) x2 += reduce(numpy.dot, (orbv.conj().T, v1, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.ravel() vresp1 = _gen_rhf_response(mf, singlet=False, hermi=1) def hop_rhf2uhf(x1): from pyscf.dft import numint # See also rhf.TDA triplet excitation x1 = x1.reshape(nvir,nocc) if with_symmetry and mol.symmetry: x1 = x1.copy() x1[sym_forbid] = 0 x2 = numpy.einsum('ps,sq->pq', fvv, x1) x2-= numpy.einsum('ps,rp->rs', foo, x1) d1 = reduce(numpy.dot, (orbv, x1*2, orbo.conj().T)) dm1 = d1 + d1.conj().T v1ao = vresp1(dm1) x2 += reduce(numpy.dot, (orbv.conj().T, v1ao, orbo)) if with_symmetry and mol.symmetry: x2[sym_forbid] = 0 return x2.real.ravel() return hop_real2complex, hdiag, hop_rhf2uhf, hdiag