Пример #1
0
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)
Пример #2
0
    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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
 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
Пример #6
0
 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
Пример #7
0
    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
Пример #8
0
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
Пример #9
0
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
Пример #10
0
 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
Пример #11
0
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
Пример #12
0
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
Пример #13
0
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
Пример #14
0
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
Пример #15
0
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
Пример #16
0
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
Пример #17
0
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
Пример #18
0
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
Пример #19
0
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
Пример #20
0
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
Пример #21
0
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