Exemple #1
0
    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
        orboa = mo_coeff[0][:,mo_occ[0]>0]
        orbob = mo_coeff[1][:,mo_occ[1]>0]
        if h1 is None:
            dm0 = self._scf.make_rdm1(mo_coeff, mo_occ)
            h1 = self.make_h10(mol, dm0)
            h1a = [reduce(numpy.dot, (mo_coeff[0].T.conj(), x, orboa)) for x in h1[0]]
            h1b = [reduce(numpy.dot, (mo_coeff[1].T.conj(), x, orbob)) for x in h1[1]]
            h1 = (numpy.asarray(h1a), numpy.asarray(h1b))
        if s1 is None:
            s1 = self.make_s10(mol)
            s1a = [reduce(numpy.dot, (mo_coeff[0].T.conj(), x, orboa)) for x in s1]
            s1b = [reduce(numpy.dot, (mo_coeff[1].T.conj(), x, orbob)) for x in s1]
            s1 = (numpy.asarray(s1a), numpy.asarray(s1b))

        cput1 = log.timer('first order Fock matrix', *cput1)
        if self.cphf:
            vind = self.gen_vind(self._scf, mo_coeff, mo_occ)
            mo10, mo_e10 = ucphf.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
Exemple #2
0
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]))
        h1a, h1b = make_h1_pso(mol, sscobj._scf.mo_coeff, mo_occ, atmlst)
    else:
        h1a, h1b = h1
    h1a = numpy.asarray(h1a)
    h1b = numpy.asarray(h1b)

    if with_cphf:
        if callable(with_cphf):
            vind = with_cphf
        else:
            vind = gen_vind(sscobj._scf, mo_coeff, mo_occ)
        mo1, mo_e1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), None,
                                 sscobj.max_cycle_cphf, sscobj.conv_tol,
                                 verbose=log)
    else:
        eai_aa = lib.direct_sum('i-a->ai', mo_energy[0][mo_occ[0]>0], mo_energy[0][mo_occ[0]==0])
        eai_bb = lib.direct_sum('i-a->ai', mo_energy[1][mo_occ[1]>0], mo_energy[1][mo_occ[1]==0])
        mo1 = (h1a * (1/eai_aa), h1b * (1/eai_bb))
        mo_e1 = None

    logger.timer(sscobj, 'solving mo1 eqn', *cput1)
    return mo1, mo_e1
Exemple #3
0
def _response_dm1(mp, Xvo):
    Xvo, XVO = Xvo
    nvira, nocca = Xvo.shape
    nvirb, noccb = XVO.shape
    nmoa = nocca + nvira
    nmob = noccb + nvirb
    nova = nocca * nvira
    mo_energy = mp._scf.mo_energy
    mo_occ = mp.mo_occ
    mo_a, mo_b = mp.mo_coeff
    def fvind(x):
        x1a = x[0,:nova].reshape(Xvo.shape)
        x1b = x[0,nova:].reshape(XVO.shape)
        dm1a = reduce(numpy.dot, (mo_a[:,nocca:], x1a, mo_a[:,:nocca].T))
        dm1b = reduce(numpy.dot, (mo_b[:,noccb:], x1b, mo_b[:,:noccb].T))
        va, vb = mp._scf.get_veff(mp.mol, (dm1a+dm1a.T, dm1b+dm1b.T))
        va = reduce(numpy.dot, (mo_a[:,nocca:].T, va, mo_a[:,:nocca]))
        vb = reduce(numpy.dot, (mo_b[:,noccb:].T, vb, mo_b[:,:noccb]))
        return numpy.hstack((va.ravel(), vb.ravel()))
    dvo = ucphf.solve(fvind, mo_energy, mo_occ, (Xvo,XVO), max_cycle=30)[0]
    dm1a = numpy.zeros((nmoa,nmoa))
    dm1a[nocca:,:nocca] = dvo[0]
    dm1a[:nocca,nocca:] = dvo[0].T
    dm1b = numpy.zeros((nmob,nmob))
    dm1b[noccb:,:noccb] = dvo[1]
    dm1b[:noccb,noccb:] = dvo[1].T
    return dm1a, dm1b
Exemple #4
0
    def Z(self):
        so, sv = self.so, self.sv
        nocc, nvir = self.nocc, self.nvir
        Ax0_Core = self.Ax0_Core
        e, mo_occ = self.e, self.mo_occ
        F_0_mo = self.nc_deriv.F_0_mo

        def fx(X):
            X_ = (X[:, :nocc[0] * nvir[0]].reshape(
                (nvir[0], nocc[0])), X[:, nocc[0] * nvir[0]:].reshape(
                    (nvir[1], nocc[1])))
            return np.concatenate([
                v.ravel() for v in Ax0_Core(sv, so, sv, so, in_cphf=True)(X_)
            ])

        Z = ucphf.solve(
            fx,
            e,
            mo_occ,
            (F_0_mo[0, None, sv[0], so[0]], F_0_mo[1, None, sv[1], so[1]]),
            max_cycle=100,
            tol=self.cphf_tol)[0]
        # output Z shape is (1, nvir, nocc), we remove the first dimension
        Z = (Z[0][0], Z[1][0])
        return Z
Exemple #5
0
    def D_r(self) -> np.ndarray:
        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
        nvir, nocc, nmo = self.nvir, self.nocc, self.nmo

        def fx(X):
            X_alpha = X[:, :nocc[0] * nvir[0]].reshape((nvir[0], nocc[0]))
            X_beta = X[:, nocc[0] * nvir[0]:].reshape((nvir[1], nocc[1]))
            Ax = Ax0_Core(sv, so, sv, so, in_cphf=True)((X_alpha, X_beta))
            result = np.concatenate([Ax[0].reshape(-1), Ax[1].reshape(-1)])
            return result

        D_r_vo = ucphf.solve(fx,
                             e,
                             mo_occ,
                             L,
                             max_cycle=100,
                             tol=self.cphf_tol)[0]
        D_r[0][sv[0], so[0]] = D_r_vo[0]
        D_r[1][sv[1], so[1]] = D_r_vo[1]
        return D_r
Exemple #6
0
def _response_dm1(mp, Xvo):
    Xvo, XVO = Xvo
    nvira, nocca = Xvo.shape
    nvirb, noccb = XVO.shape
    nmoa = nocca + nvira
    nmob = noccb + nvirb
    nova = nocca * nvira
    mo_energy = mp._scf.mo_energy
    mo_occ = mp.mo_occ
    mo_a, mo_b = mp.mo_coeff
    def fvind(x):
        x1a = x[0,:nova].reshape(Xvo.shape)
        x1b = x[0,nova:].reshape(XVO.shape)
        dm1a = reduce(numpy.dot, (mo_a[:,nocca:], x1a, mo_a[:,:nocca].T))
        dm1b = reduce(numpy.dot, (mo_b[:,noccb:], x1b, mo_b[:,:noccb].T))
        va, vb = mp._scf.get_veff(mp.mol, (dm1a+dm1a.T, dm1b+dm1b.T))
        va = reduce(numpy.dot, (mo_a[:,nocca:].T, va, mo_a[:,:nocca]))
        vb = reduce(numpy.dot, (mo_b[:,noccb:].T, vb, mo_b[:,:noccb]))
        return numpy.hstack((va.ravel(), vb.ravel()))
    dvo = ucphf.solve(fvind, mo_energy, mo_occ, (Xvo,XVO), max_cycle=30)[0]
    dm1a = numpy.zeros((nmoa,nmoa))
    dm1a[nocca:,:nocca] = dvo[0]
    dm1a[:nocca,nocca:] = dvo[0].T
    dm1b = numpy.zeros((nmob,nmob))
    dm1b[noccb:,:noccb] = dvo[1]
    dm1b[:noccb,noccb:] = dvo[1].T
    return dm1a, dm1b
Exemple #7
0
def _response_dm1(mycc, Xvo, eris=None):
    Xvo, XVO = Xvo
    nvira, nocca = Xvo.shape
    nvirb, noccb = XVO.shape
    nmoa = nocca + nvira
    nmob = noccb + nvirb
    nova = nocca * nvira
    with_frozen = not ((mycc.frozen is None) or
                       (isinstance(mycc.frozen,
                                   (int, numpy.integer)) and mycc.frozen == 0)
                       or (len(mycc.frozen) == 0))
    if eris is None or with_frozen:
        mo_energy = mycc._scf.mo_energy
        mo_occ = mycc.mo_occ
        mo_a, mo_b = mycc.mo_coeff

        def fvind(x):
            x1a = x[0, :nova].reshape(Xvo.shape)
            x1b = x[0, nova:].reshape(XVO.shape)
            dm1a = reduce(numpy.dot, (mo_a[:, nocca:], x1a, mo_a[:, :nocca].T))
            dm1b = reduce(numpy.dot, (mo_b[:, noccb:], x1b, mo_b[:, :noccb].T))
            va, vb = mycc._scf.get_veff(mycc.mol,
                                        (dm1a + dm1a.T, dm1b + dm1b.T))
            va = reduce(numpy.dot, (mo_a[:, nocca:].T, va, mo_a[:, :nocca]))
            vb = reduce(numpy.dot, (mo_b[:, noccb:].T, vb, mo_b[:, :noccb]))
            return numpy.hstack((va.ravel(), vb.ravel()))
    else:
        moidx = mycc.get_frozen_mask()
        mo_energy = eris.mo_energy
        mo_occ = (mycc.mo_occ[0][moidx[0]], mycc.mo_occ[1][moidx[1]])
        ovvo = numpy.empty((nocca, nvira, nvira, nocca))
        ovVO = numpy.empty((nocca, nvira, nvirb, noccb))
        OVVO = numpy.empty((noccb, nvirb, nvirb, noccb))
        for i in range(nocca):
            ovvo[i] = eris.ovvo[i]
            ovvo[i] = ovvo[i] * 2 - ovvo[i].transpose(1, 0, 2)
            ovvo[i] -= eris.oovv[i].transpose(2, 1, 0)
            ovVO[i] = eris.ovVO[i] * 2
        for i in range(noccb):
            OVVO[i] = eris.OVVO[i]
            OVVO[i] = OVVO[i] * 2 - OVVO[i].transpose(1, 0, 2)
            OVVO[i] -= eris.OOVV[i].transpose(2, 1, 0)

        def fvind(x):
            x1a = x[0, :nova].reshape(Xvo.shape)
            x1b = x[0, nova:].reshape(XVO.shape)
            va = numpy.einsum('iabj,bj->ai', ovvo, x1a)
            va += numpy.einsum('iabj,bj->ai', ovVO, x1b)
            vb = numpy.einsum('iabj,bj->ai', OVVO, x1b)
            vb += numpy.einsum('jbai,bj->ai', ovVO, x1a)
            return numpy.hstack((va.ravel(), vb.ravel()))

    dvo = ucphf.solve(fvind, mo_energy, mo_occ, (Xvo, XVO), max_cycle=30)[0]
    dm1a = numpy.zeros((nmoa, nmoa))
    dm1a[nocca:, :nocca] = dvo[0]
    dm1a[:nocca, nocca:] = dvo[0].T
    dm1b = numpy.zeros((nmob, nmob))
    dm1b[noccb:, :noccb] = dvo[1]
    dm1b[:noccb, noccb:] = dvo[1].T
    return dm1a, dm1b
Exemple #8
0
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]))
        h1a, h1b = make_h1_pso(mol, sscobj._scf.mo_coeff, mo_occ, atmlst)
    else:
        h1a, h1b = h1
    h1a = numpy.asarray(h1a)
    h1b = numpy.asarray(h1b)

    if with_cphf:
        if callable(with_cphf):
            vind = with_cphf
        else:
            vind = gen_vind(sscobj._scf, mo_coeff, mo_occ)
        mo1, mo_e1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), None,
                                 sscobj.max_cycle_cphf, sscobj.conv_tol,
                                 verbose=log)
    else:
        eai_aa = lib.direct_sum('i-a->ai', mo_energy[0][mo_occ[0]>0], mo_energy[0][mo_occ[0]==0])
        eai_bb = lib.direct_sum('i-a->ai', mo_energy[1][mo_occ[1]>0], mo_energy[1][mo_occ[1]==0])
        mo1 = (h1a * (1/eai_aa), h1b * (1/eai_bb))
        mo_e1 = None

    logger.timer(sscobj, 'solving mo1 eqn', *cput1)
    return mo1, mo_e1
Exemple #9
0
def hyper_polarizability(polobj, with_cphf=True):
    from pyscf.prop.nmr import uhf as uhf_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
    occidxa = mo_occ[0] > 0
    occidxb = mo_occ[1] > 0
    mo0a, mo0b = mo_coeff
    orboa = mo0a[:, occidxa]
    orbva = mo0a[:, ~occidxa]
    orbob = mo0b[:, occidxb]
    orbvb = mo0b[:, ~occidxb]

    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)

    h1a = lib.einsum('xpq,pi,qj->xij', int_r, mo0a.conj(), orboa)
    h1b = lib.einsum('xpq,pi,qj->xij', int_r, mo0b.conj(), orbob)
    s1a = numpy.zeros_like(h1a)
    s1b = numpy.zeros_like(h1b)
    vind = polobj.gen_vind(mf, mo_coeff, mo_occ)
    if with_cphf:
        mo1, e1 = ucphf.solve(vind,
                              mo_energy,
                              mo_occ, (h1a, h1b), (s1a, s1b),
                              polobj.max_cycle_cphf,
                              polobj.conv_tol,
                              verbose=log)
    else:
        mo1, e1 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h1a, h1b),
                                               (s1a, s1b))
    mo1a = lib.einsum('xqi,pq->xpi', mo1[0], mo0a)
    mo1b = lib.einsum('xqi,pq->xpi', mo1[1], mo0b)

    dm1a = lib.einsum('xpi,qi->xpq', mo1a, orboa)
    dm1b = lib.einsum('xpi,qi->xpq', mo1b, orbob)
    dm1a = dm1a + dm1a.transpose(0, 2, 1)
    dm1b = dm1b + dm1b.transpose(0, 2, 1)
    vresp = _gen_uhf_response(mf, hermi=1)
    h1ao = int_r + vresp(numpy.stack((dm1a, dm1b)))
    s0 = mf.get_ovlp()
    e3 = lib.einsum('xpq,ypi,zqi->xyz', h1ao[0], mo1a, mo1a)
    e3 += lib.einsum('xpq,ypi,zqi->xyz', h1ao[1], mo1b, mo1b)
    e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', s0, mo1a, mo1a, e1[0])
    e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', s0, mo1b, mo1b, e1[1])
    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
Exemple #10
0
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
    '''
    cput1 = (time.clock(), time.time())
    log = logger.Logger(nmrobj.stdout, nmrobj.verbose)
    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

    mol = nmrobj.mol
    orboa = mo_coeff[0][:, mo_occ[0] > 0]
    orbob = mo_coeff[1][:, mo_occ[1] > 0]
    if h1 is None:
        dm0 = nmrobj._scf.make_rdm1(mo_coeff, mo_occ)
        h1 = nmrobj.get_fock(dm0)
        h1 = (lib.einsum('xpq,pi,qj->xij', h1[0], mo_coeff[0].conj(), orboa),
              lib.einsum('xpq,pi,qj->xij', h1[1], mo_coeff[1].conj(), orbob))
        cput1 = log.timer('first order Fock matrix', *cput1)
    if s1 is None:
        s1 = nmrobj.get_ovlp(mol)
        s1 = (lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[0].conj(), orboa),
              lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[1].conj(), orbob))

    if with_cphf:
        if callable(with_cphf):
            vind = with_cphf
        else:
            vind = gen_vind(nmrobj._scf, mo_coeff, mo_occ)
        mo10, mo_e10 = ucphf.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)

    logger.timer(nmrobj, 'solving mo1 eqn', *cput1)
    return mo10, mo_e10
Exemple #11
0
def _response_dm1(mycc, Xvo, eris=None):
    Xvo, XVO = Xvo
    nvira, nocca = Xvo.shape
    nvirb, noccb = XVO.shape
    nmoa = nocca + nvira
    nmob = noccb + nvirb
    nova = nocca * nvira
    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_a, mo_b = mycc.mo_coeff
        def fvind(x):
            x1a = x[0,:nova].reshape(Xvo.shape)
            x1b = x[0,nova:].reshape(XVO.shape)
            dm1a = reduce(numpy.dot, (mo_a[:,nocca:], x1a, mo_a[:,:nocca].T))
            dm1b = reduce(numpy.dot, (mo_b[:,noccb:], x1b, mo_b[:,:noccb].T))
            va, vb = mycc._scf.get_veff(mycc.mol, (dm1a+dm1a.T, dm1b+dm1b.T))
            va = reduce(numpy.dot, (mo_a[:,nocca:].T, va, mo_a[:,:nocca]))
            vb = reduce(numpy.dot, (mo_b[:,noccb:].T, vb, mo_b[:,:noccb]))
            return numpy.hstack((va.ravel(), vb.ravel()))
    else:
        moidx = mycc.get_frozen_mask()
        mo_energy = eris.mo_energy
        mo_occ = (mycc.mo_occ[0][moidx[0]], mycc.mo_occ[1][moidx[1]])
        ovvo = numpy.empty((nocca,nvira,nvira,nocca))
        ovVO = numpy.empty((nocca,nvira,nvirb,noccb))
        OVVO = numpy.empty((noccb,nvirb,nvirb,noccb))
        for i in range(nocca):
            ovvo[i] = eris.ovvo[i]
            ovvo[i] = ovvo[i] * 2 - ovvo[i].transpose(1,0,2)
            ovvo[i]-= eris.oovv[i].transpose(2,1,0)
            ovVO[i] = eris.ovVO[i] * 2
        for i in range(noccb):
            OVVO[i] = eris.OVVO[i]
            OVVO[i] = OVVO[i] * 2 - OVVO[i].transpose(1,0,2)
            OVVO[i]-= eris.OOVV[i].transpose(2,1,0)
        def fvind(x):
            x1a = x[0,:nova].reshape(Xvo.shape)
            x1b = x[0,nova:].reshape(XVO.shape)
            va = numpy.einsum('iabj,bj->ai', ovvo, x1a)
            va+= numpy.einsum('iabj,bj->ai', ovVO, x1b)
            vb = numpy.einsum('iabj,bj->ai', OVVO, x1b)
            vb+= numpy.einsum('jbai,bj->ai', ovVO, x1a)
            return numpy.hstack((va.ravel(), vb.ravel()))
    dvo = ucphf.solve(fvind, mo_energy, mo_occ, (Xvo,XVO), max_cycle=30)[0]
    dm1a = numpy.zeros((nmoa,nmoa))
    dm1a[nocca:,:nocca] = dvo[0]
    dm1a[:nocca,nocca:] = dvo[0].T
    dm1b = numpy.zeros((nmob,nmob))
    dm1b[noccb:,:noccb] = dvo[1]
    dm1b[:noccb,noccb:] = dvo[1].T
    return dm1a, dm1b
Exemple #12
0
def hyper_polarizability(polobj, with_cphf=True):
    from pyscf.prop.nmr import uhf as uhf_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
    occidxa = mo_occ[0] > 0
    occidxb = mo_occ[1] > 0
    mo0a, mo0b = mo_coeff
    orboa = mo0a[:, occidxa]
    orbva = mo0a[:,~occidxa]
    orbob = mo0b[:, occidxb]
    orbvb = mo0b[:,~occidxb]

    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)

    h1a = lib.einsum('xpq,pi,qj->xij', int_r, mo0a.conj(), orboa)
    h1b = lib.einsum('xpq,pi,qj->xij', int_r, mo0b.conj(), orbob)
    s1a = numpy.zeros_like(h1a)
    s1b = numpy.zeros_like(h1b)
    vind = polobj.gen_vind(mf, mo_coeff, mo_occ)
    if with_cphf:
        mo1, e1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), (s1a,s1b),
                              polobj.max_cycle_cphf, polobj.conv_tol, verbose=log)
    else:
        mo1, e1 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h1a,h1b),
                                               (s1a,s1b))
    mo1a = lib.einsum('xqi,pq->xpi', mo1[0], mo0a)
    mo1b = lib.einsum('xqi,pq->xpi', mo1[1], mo0b)

    dm1a = lib.einsum('xpi,qi->xpq', mo1a, orboa)
    dm1b = lib.einsum('xpi,qi->xpq', mo1b, orbob)
    dm1a = dm1a + dm1a.transpose(0,2,1)
    dm1b = dm1b + dm1b.transpose(0,2,1)
    vresp = _gen_uhf_response(mf, hermi=1)
    h1ao = int_r + vresp(numpy.stack((dm1a, dm1b)))
    s0 = mf.get_ovlp()
    e3  = lib.einsum('xpq,ypi,zqi->xyz', h1ao[0], mo1a, mo1a)
    e3 += lib.einsum('xpq,ypi,zqi->xyz', h1ao[1], mo1b, mo1b)
    e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', s0, mo1a, mo1a, e1[0])
    e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', s0, mo1b, mo1b, e1[1])
    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
Exemple #13
0
def polarizability(polobj, with_cphf=True):
    from pyscf.prop.nmr import uhf as uhf_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
    occidxa = mo_occ[0] > 0
    occidxb = mo_occ[1] > 0
    mo0a, mo0b = mo_coeff
    orboa = mo0a[:, occidxa]
    orbva = mo0a[:, ~occidxa]
    orbob = mo0b[:, occidxb]
    orbvb = mo0b[:, ~occidxb]

    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)

    h1a = lib.einsum('xpq,pi,qj->xij', int_r, mo0a.conj(), orboa)
    h1b = lib.einsum('xpq,pi,qj->xij', int_r, mo0b.conj(), orbob)
    s1a = numpy.zeros_like(h1a)
    s1b = numpy.zeros_like(h1b)
    vind = polobj.gen_vind(mf, mo_coeff, mo_occ)
    if with_cphf:
        mo1 = ucphf.solve(vind,
                          mo_energy,
                          mo_occ, (h1a, h1b), (s1a, s1b),
                          polobj.max_cycle_cphf,
                          polobj.conv_tol,
                          verbose=log)[0]
    else:
        mo1 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h1a, h1b),
                                           (s1a, s1b))[0]

    e2 = numpy.einsum('xpi,ypi->xy', h1a, mo1[0])
    e2 += numpy.einsum('xpi,ypi->xy', h1b, mo1[1])
    e2 = -(e2 + e2.T)

    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
Exemple #14
0
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
    '''
    cput1 = (time.clock(), time.time())
    log = logger.Logger(nmrobj.stdout, nmrobj.verbose)
    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

    mol = nmrobj.mol
    orboa = mo_coeff[0][:,mo_occ[0]>0]
    orbob = mo_coeff[1][:,mo_occ[1]>0]
    if h1 is None:
        dm0 = nmrobj._scf.make_rdm1(mo_coeff, mo_occ)
        h1 = nmrobj.get_fock(dm0)
        h1 = (lib.einsum('xpq,pi,qj->xij', h1[0], mo_coeff[0].conj(), orboa),
              lib.einsum('xpq,pi,qj->xij', h1[1], mo_coeff[1].conj(), orbob))
        cput1 = log.timer('first order Fock matrix', *cput1)
    if s1 is None:
        s1 = nmrobj.get_ovlp(mol)
        s1 = (lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[0].conj(), orboa),
              lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[1].conj(), orbob))

    if with_cphf:
        if callable(with_cphf):
            vind = with_cphf
        else:
            vind = gen_vind(nmrobj._scf, mo_coeff, mo_occ)
        mo10, mo_e10 = ucphf.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)

    logger.timer(nmrobj, 'solving mo1 eqn', *cput1)
    return mo10, mo_e10
Exemple #15
0
def polarizability(polobj, with_cphf=True):
    from pyscf.prop.nmr import uhf as uhf_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
    occidxa = mo_occ[0] > 0
    occidxb = mo_occ[1] > 0
    mo0a, mo0b = mo_coeff
    orboa = mo0a[:, occidxa]
    orbva = mo0a[:,~occidxa]
    orbob = mo0b[:, occidxb]
    orbvb = mo0b[:,~occidxb]

    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)

    h1a = lib.einsum('xpq,pi,qj->xij', int_r, mo0a.conj(), orboa)
    h1b = lib.einsum('xpq,pi,qj->xij', int_r, mo0b.conj(), orbob)
    s1a = numpy.zeros_like(h1a)
    s1b = numpy.zeros_like(h1b)
    vind = polobj.gen_vind(mf, mo_coeff, mo_occ)
    if with_cphf:
        mo1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), (s1a,s1b),
                          polobj.max_cycle_cphf, polobj.conv_tol,
                          verbose=log)[0]
    else:
        mo1 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h1a,h1b),
                                           (s1a,s1b))[0]

    e2 = numpy.einsum('xpi,ypi->xy', h1a, mo1[0])
    e2+= numpy.einsum('xpi,ypi->xy', h1b, mo1[1])
    e2 = -(e2 + e2.T)

    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
Exemple #16
0
    def h_op(x):
        x = x.reshape(natm,3)
        hx = numpy.einsum('abxy,ax->by', de2, x)
        h1aoa = 0
        h1aob = 0
        s1ao = 0
        for ia in range(natm):
            shl0, shl1, p0, p1 = aoslices[ia]
            h1ao_i = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/0/%d' % ia)
            h1aoa += numpy.einsum('x,xij->ij', x[ia], h1ao_i)
            h1ao_i = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/1/%d' % ia)
            h1aob += 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)

        s1voa = reduce(numpy.dot, (mo_coeff[0].T, s1ao, mocca))
        s1vob = reduce(numpy.dot, (mo_coeff[1].T, s1ao, moccb))
        h1voa = reduce(numpy.dot, (mo_coeff[0].T, h1aoa, mocca))
        h1vob = reduce(numpy.dot, (mo_coeff[1].T, h1aob, moccb))
        mo1, mo_e1 = ucphf.solve(fvind, mo_energy, mo_occ,
                                 (h1voa,h1vob), (s1voa,s1vob))
        mo1a = numpy.dot(mo_coeff[0], mo1[0])
        mo1b = numpy.dot(mo_coeff[1], mo1[1])
        mo_e1a = mo_e1[0].reshape(nocca,nocca)
        mo_e1b = mo_e1[1].reshape(noccb,noccb)
        dm1a = numpy.einsum('pi,qi->pq', mo1a, mocca)
        dm1b = numpy.einsum('pi,qi->pq', mo1b, moccb)
        dme1a = numpy.einsum('pi,qi,i->pq', mo1a, mocca, mo_ea)
        dme1a = dme1a + dme1a.T + reduce(numpy.dot, (mocca, mo_e1a, mocca.T))
        dme1b = numpy.einsum('pi,qi,i->pq', mo1b, moccb, mo_eb)
        dme1b = dme1b + dme1b.T + reduce(numpy.dot, (moccb, mo_e1b, moccb.T))
        dme1 = dme1a + dme1b

        for ja in range(natm):
            q0, q1 = aoslices[ja][2:]
            h1aoa = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/0/%d' % ja)
            h1aob = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/1/%d' % ja)
            hx[ja] += numpy.einsum('xpq,pq->x', h1aoa, dm1a) * 2
            hx[ja] += numpy.einsum('xpq,pq->x', h1aob, dm1b) * 2
            hx[ja] -= numpy.einsum('xpq,pq->x', s1a[:,q0:q1], dme1[q0:q1])
            hx[ja] -= numpy.einsum('xpq,qp->x', s1a[:,q0:q1], dme1[:,q0:q1])
        return hx.ravel()
Exemple #17
0
    def h_op(x):
        x = x.reshape(natm, 3)
        hx = numpy.einsum('abxy,ax->by', de2, x)
        h1aoa = 0
        h1aob = 0
        s1ao = 0
        for ia in range(natm):
            shl0, shl1, p0, p1 = aoslices[ia]
            h1ao_i = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/0/%d' % ia)
            h1aoa += numpy.einsum('x,xij->ij', x[ia], h1ao_i)
            h1ao_i = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/1/%d' % ia)
            h1aob += 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)

        s1voa = reduce(numpy.dot, (mo_coeff[0].T, s1ao, mocca))
        s1vob = reduce(numpy.dot, (mo_coeff[1].T, s1ao, moccb))
        h1voa = reduce(numpy.dot, (mo_coeff[0].T, h1aoa, mocca))
        h1vob = reduce(numpy.dot, (mo_coeff[1].T, h1aob, moccb))
        mo1, mo_e1 = ucphf.solve(fvind, mo_energy, mo_occ, (h1voa, h1vob),
                                 (s1voa, s1vob))
        mo1a = numpy.dot(mo_coeff[0], mo1[0])
        mo1b = numpy.dot(mo_coeff[1], mo1[1])
        mo_e1a = mo_e1[0].reshape(nocca, nocca)
        mo_e1b = mo_e1[1].reshape(noccb, noccb)
        dm1a = numpy.einsum('pi,qi->pq', mo1a, mocca)
        dm1b = numpy.einsum('pi,qi->pq', mo1b, moccb)
        dme1a = numpy.einsum('pi,qi,i->pq', mo1a, mocca, mo_ea)
        dme1a = dme1a + dme1a.T + reduce(numpy.dot, (mocca, mo_e1a, mocca.T))
        dme1b = numpy.einsum('pi,qi,i->pq', mo1b, moccb, mo_eb)
        dme1b = dme1b + dme1b.T + reduce(numpy.dot, (moccb, mo_e1b, moccb.T))
        dme1 = dme1a + dme1b

        for ja in range(natm):
            q0, q1 = aoslices[ja][2:]
            h1aoa = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/0/%d' % ja)
            h1aob = lib.chkfile.load(hobj.chkfile, 'scf_f1ao/1/%d' % ja)
            hx[ja] += numpy.einsum('xpq,pq->x', h1aoa, dm1a) * 2
            hx[ja] += numpy.einsum('xpq,pq->x', h1aob, dm1b) * 2
            hx[ja] -= numpy.einsum('xpq,pq->x', s1a[:, q0:q1], dme1[q0:q1])
            hx[ja] -= numpy.einsum('xpq,qp->x', s1a[:, q0:q1], dme1[:, q0:q1])
        return hx.ravel()
Exemple #18
0
def solve_cphf_uhf(mf, Lvo, max_cycle, tol, logger):
    '''
    Solve the CPHF equations.

    Args:
        mf : a UHF 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

    nva, noa = Lvo[0].shape
    nvb, nob = Lvo[1].shape

    def fvind(zflat):
        za = zflat[0, :noa * nva].reshape(nva, noa)
        zb = zflat[0, -nob * nvb:].reshape(nvb, nob)
        ra, rb = fock_response_uhf(mf, [za, zb], full=False)
        rflat = np.hstack(
            [ra.reshape((1, noa * nva)),
             rb.reshape((1, nob * nvb))])
        return rflat

    zvo = ucphf.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
Exemple #19
0
def solve_mo1_pso(hfcobj, hfc_nuc=None, with_cphf=None):
    if hfc_nuc   is None: hfc_nuc  = hfcobj.hfc_nuc
    if with_cphf is None: with_cphf = hfcobj.cphf

    mf = hfcobj._scf
    mo_energy = mf.mo_energy
    mo_coeff = mf.mo_coeff
    mo_occ = mf.mo_occ
    mol = hfcobj.mol
    h1a, h1b = uhf_ssc.make_h1_pso(mol, mo_coeff, mo_occ, hfc_nuc)
    h1a = numpy.asarray(h1a)
    h1b = numpy.asarray(h1b)

    if with_cphf:
        vind = gen_vind(mf, mo_coeff, mo_occ)
        mo1, mo_e1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), None,
                                 hfcobj.max_cycle_cphf, hfcobj.conv_tol)
    else:
        eai_aa = lib.direct_sum('i-a->ai', mo_energy[0][mo_occ[0]>0], mo_energy[0][mo_occ[0]==0])
        eai_bb = lib.direct_sum('i-a->ai', mo_energy[1][mo_occ[1]>0], mo_energy[1][mo_occ[1]==0])
        mo1 = (h1a * (1/eai_aa), h1b * (1/eai_bb))
    return mo1
Exemple #20
0
def solve_mo1_pso(hfcobj, hfc_nuc=None, with_cphf=None):
    if hfc_nuc is None: hfc_nuc = hfcobj.hfc_nuc
    if with_cphf is None: with_cphf = hfcobj.cphf

    mf = hfcobj._scf
    mo_energy = mf.mo_energy
    mo_coeff = mf.mo_coeff
    mo_occ = mf.mo_occ
    mol = hfcobj.mol
    h1a, h1b = uhf_ssc.make_h1_pso(mol, mo_coeff, mo_occ, hfc_nuc)
    h1a = numpy.asarray(h1a)
    h1b = numpy.asarray(h1b)

    if with_cphf:
        vind = gen_vind(mf, mo_coeff, mo_occ)
        mo1, mo_e1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a, h1b), None,
                                 hfcobj.max_cycle_cphf, hfcobj.conv_tol)
    else:
        eai_aa = lib.direct_sum('i-a->ai', mo_energy[0][mo_occ[0] > 0],
                                mo_energy[0][mo_occ[0] == 0])
        eai_bb = lib.direct_sum('i-a->ai', mo_energy[1][mo_occ[1] > 0],
                                mo_energy[1][mo_occ[1] == 0])
        mo1 = (h1a * (1 / eai_aa), h1b * (1 / eai_bb))
    return mo1
Exemple #21
0
def kernel(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO):
    log = logger.new_logger(td_grad, verbose)
    time0 = time.clock(), time.time()

    mol = td_grad.mol
    mf = td_grad.base._scf
    mo_coeff = mf.mo_coeff
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    occidxa = numpy.where(mo_occ[0]>0)[0]
    occidxb = numpy.where(mo_occ[1]>0)[0]
    viridxa = numpy.where(mo_occ[0]==0)[0]
    viridxb = numpy.where(mo_occ[1]==0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:,occidxa]
    orbob = mo_coeff[1][:,occidxb]
    orbva = mo_coeff[0][:,viridxa]
    orbvb = mo_coeff[1][:,viridxb]
    nao = mo_coeff[0].shape[0]
    nmoa = nocca + nvira
    nmob = noccb + nvirb

    (xa, xb), (ya, yb) = x_y
    xpya = (xa+ya).reshape(nocca,nvira).T
    xpyb = (xb+yb).reshape(noccb,nvirb).T
    xmya = (xa-ya).reshape(nocca,nvira).T
    xmyb = (xb-yb).reshape(noccb,nvirb).T

    dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum('ai,bi->ab', xmya, xmya)
    dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum('ai,bi->ab', xmyb, xmyb)
    dooa =-numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum('ai,aj->ij', xmya, xmya)
    doob =-numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum('ai,aj->ij', xmyb, xmyb)
    dmzvopa = reduce(numpy.dot, (orbva, xpya, orboa.T))
    dmzvopb = reduce(numpy.dot, (orbvb, xpyb, orbob.T))
    dmzvoma = reduce(numpy.dot, (orbva, xmya, orboa.T))
    dmzvomb = reduce(numpy.dot, (orbvb, xmyb, orbob.T))
    dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T))
    dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T))
    dmzooa+= reduce(numpy.dot, (orbva, dvva, orbva.T))
    dmzoob+= reduce(numpy.dot, (orbvb, dvvb, orbvb.T))

    vj, vk = mf.get_jk(mol, (dmzooa, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T,
                             dmzoob, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T), hermi=0)
    vj = vj.reshape(2,3,nao,nao)
    vk = vk.reshape(2,3,nao,nao)
    veff0doo = vj[0,0]+vj[1,0] - vk[:,0]
    wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
    wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
    veff = vj[0,1]+vj[1,1] - vk[:,1]
    veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
    veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
    wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) * 2
    wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) * 2
    wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:,nocca:], xpya) * 2
    wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:,noccb:], xpyb) * 2
    veff = -vk[:,2]
    veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
    veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
    wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya) * 2
    wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb) * 2
    wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:,nocca:], xmya) * 2
    wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:,noccb:], xmyb) * 2
    def fvind(x):
        dm1 = numpy.empty((2,nao,nao))
        xa = x[0,:nvira*nocca].reshape(nvira,nocca)
        xb = x[0,nvira*nocca:].reshape(nvirb,noccb)
        dma = reduce(numpy.dot, (orbva, xa, orboa.T))
        dmb = reduce(numpy.dot, (orbvb, xb, orbob.T))
        dm1[0] = dma + dma.T
        dm1[1] = dmb + dmb.T
        vj, vk = mf.get_jk(mol, dm1)
        v1 = vj[0] + vj[1] - vk
        v1a = reduce(numpy.dot, (orbva.T, v1[0], orboa))
        v1b = reduce(numpy.dot, (orbvb.T, v1[1], orbob))
        return numpy.hstack((v1a.ravel(), v1b.ravel()))
    z1a, z1b = ucphf.solve(fvind, mo_energy, mo_occ, (wvoa,wvob),
                           max_cycle=td_grad.cphf_max_cycle,
                           tol=td_grad.cphf_conv_tol)[0]
    time1 = log.timer('Z-vector using UCPHF solver', *time0)

    z1ao = numpy.empty((2,nao,nao))
    z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T))
    z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T))
    vj, vk = mf.get_jk(mol, z1ao, hermi=0)
    veff = vj[0]+vj[1] - vk

    im0a = numpy.zeros((nmoa,nmoa))
    im0b = numpy.zeros((nmob,nmob))
    im0a[:nocca,:nocca] = reduce(numpy.dot, (orboa.T, veff0doo[0]+veff[0], orboa)) * .5
    im0b[:noccb,:noccb] = reduce(numpy.dot, (orbob.T, veff0doo[1]+veff[1], orbob)) * .5
    im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0mopa[nocca:,:nocca], xpya) * .5
    im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0mopb[noccb:,:noccb], xpyb) * .5
    im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0moma[nocca:,:nocca], xmya) * .5
    im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0momb[noccb:,:noccb], xmyb) * .5
    im0a[nocca:,nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:,:nocca], xpya) * .5
    im0b[noccb:,noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:,:noccb], xpyb) * .5
    im0a[nocca:,nocca:]+= numpy.einsum('ci,ai->ac', veff0moma[nocca:,:nocca], xmya) * .5
    im0b[noccb:,noccb:]+= numpy.einsum('ci,ai->ac', veff0momb[noccb:,:noccb], xmyb) * .5
    im0a[nocca:,:nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya)
    im0b[noccb:,:noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb)
    im0a[nocca:,:nocca]+= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya)
    im0b[noccb:,:noccb]+= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb)

    zeta_a = (mo_energy[0][:,None] + mo_energy[0]) * .5
    zeta_b = (mo_energy[1][:,None] + mo_energy[1]) * .5
    zeta_a[nocca:,:nocca] = mo_energy[0][:nocca]
    zeta_b[noccb:,:noccb] = mo_energy[1][:noccb]
    zeta_a[:nocca,nocca:] = mo_energy[0][nocca:]
    zeta_b[:noccb,noccb:] = mo_energy[1][noccb:]
    dm1a = numpy.zeros((nmoa,nmoa))
    dm1b = numpy.zeros((nmob,nmob))
    dm1a[:nocca,:nocca] = dooa * .5
    dm1b[:noccb,:noccb] = doob * .5
    dm1a[nocca:,nocca:] = dvva * .5
    dm1b[noccb:,noccb:] = dvvb * .5
    dm1a[nocca:,:nocca] = z1a * .5
    dm1b[noccb:,:noccb] = z1b * .5
    dm1a[:nocca,:nocca] += numpy.eye(nocca) # for ground state
    dm1b[:noccb,:noccb] += numpy.eye(noccb)
    im0a = reduce(numpy.dot, (mo_coeff[0], im0a+zeta_a*dm1a, mo_coeff[0].T))
    im0b = reduce(numpy.dot, (mo_coeff[1], im0b+zeta_b*dm1b, mo_coeff[1].T))
    im0 = im0a + im0b

    hcore_deriv = td_grad.hcore_generator(mol)
    s1 = td_grad.get_ovlp(mol)

    dmz1dooa = z1ao[0] + dmzooa
    dmz1doob = z1ao[1] + dmzoob
    oo0a = reduce(numpy.dot, (orboa, orboa.T))
    oo0b = reduce(numpy.dot, (orbob, orbob.T))
    as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5
    vj, vk = td_grad.get_jk(mol, (oo0a, dmz1dooa+dmz1dooa.T, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T,
                                  oo0b, dmz1doob+dmz1doob.T, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T))
    vj = vj.reshape(2,4,3,nao,nao)
    vk = vk.reshape(2,4,3,nao,nao)
    vhf1a, vhf1b = vj[0] + vj[1] - vk
    time1 = log.timer('2e AO integral derivatives', *time1)

    if atmlst is None:
        atmlst = range(mol.natm)
    offsetdic = mol.offset_nr_by_atom()
    de = numpy.zeros((len(atmlst),3))
    for k, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        # Ground state gradients
        h1ao = hcore_deriv(ia)
        de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1)

        de[k] += numpy.einsum('xpq,pq->x', vhf1a[0,:,p0:p1], oo0a[p0:p1])
        de[k] += numpy.einsum('xpq,pq->x', vhf1b[0,:,p0:p1], oo0b[p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', vhf1a[0,:,p0:p1], oo0a[:,p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', vhf1b[0,:,p0:p1], oo0b[:,p0:p1])

        de[k] += numpy.einsum('xpq,pq->x', vhf1a[0,:,p0:p1], dmz1dooa[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,pq->x', vhf1b[0,:,p0:p1], dmz1doob[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', vhf1a[0,:,p0:p1], dmz1dooa[:,p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', vhf1b[0,:,p0:p1], dmz1doob[:,p0:p1]) * .5

        de[k] -= numpy.einsum('xpq,pq->x', s1[:,p0:p1], im0[p0:p1])
        de[k] -= numpy.einsum('xqp,pq->x', s1[:,p0:p1], im0[:,p0:p1])

        de[k] += numpy.einsum('xij,ij->x', vhf1a[1,:,p0:p1], oo0a[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', vhf1b[1,:,p0:p1], oo0b[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', vhf1a[2,:,p0:p1], dmzvopa[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', vhf1b[2,:,p0:p1], dmzvopb[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', vhf1a[3,:,p0:p1], dmzvoma[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', vhf1b[3,:,p0:p1], dmzvomb[p0:p1,:])
        de[k] += numpy.einsum('xji,ij->x', vhf1a[2,:,p0:p1], dmzvopa[:,p0:p1])
        de[k] += numpy.einsum('xji,ij->x', vhf1b[2,:,p0:p1], dmzvopb[:,p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', vhf1a[3,:,p0:p1], dmzvoma[:,p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', vhf1b[3,:,p0:p1], dmzvomb[:,p0:p1])

    log.timer('TDUHF nuclear gradients', *time0)
    return de
Exemple #22
0
def kernel(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO):
    log = logger.new_logger(td_grad, verbose)
    time0 = time.clock(), time.time()

    mol = td_grad.mol
    mf = td_grad.base._scf
    mo_coeff = mf.mo_coeff
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    occidxa = numpy.where(mo_occ[0]>0)[0]
    occidxb = numpy.where(mo_occ[1]>0)[0]
    viridxa = numpy.where(mo_occ[0]==0)[0]
    viridxb = numpy.where(mo_occ[1]==0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:,occidxa]
    orbob = mo_coeff[1][:,occidxb]
    orbva = mo_coeff[0][:,viridxa]
    orbvb = mo_coeff[1][:,viridxb]
    nao = mo_coeff[0].shape[0]
    nmoa = nocca + nvira
    nmob = noccb + nvirb

    (xa, xb), (ya, yb) = x_y
    xpya = (xa+ya).reshape(nocca,nvira).T
    xpyb = (xb+yb).reshape(noccb,nvirb).T
    xmya = (xa-ya).reshape(nocca,nvira).T
    xmyb = (xb-yb).reshape(noccb,nvirb).T

    dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum('ai,bi->ab', xmya, xmya)
    dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum('ai,bi->ab', xmyb, xmyb)
    dooa =-numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum('ai,aj->ij', xmya, xmya)
    doob =-numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum('ai,aj->ij', xmyb, xmyb)
    dmzvopa = reduce(numpy.dot, (orbva, xpya, orboa.T))
    dmzvopb = reduce(numpy.dot, (orbvb, xpyb, orbob.T))
    dmzvoma = reduce(numpy.dot, (orbva, xmya, orboa.T))
    dmzvomb = reduce(numpy.dot, (orbvb, xmyb, orbob.T))
    dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T))
    dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T))
    dmzooa+= reduce(numpy.dot, (orbva, dvva, orbva.T))
    dmzoob+= reduce(numpy.dot, (orbvb, dvvb, orbvb.T))

    ni = mf._numint
    ni.libxc.test_deriv_order(mf.xc, 3, raise_error=True)
    omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin)
    # dm0 = mf.make_rdm1(mo_coeff, mo_occ), but it is not used when computing
    # fxc since rho0 is passed to fxc function.
    dm0 = None
    rho0, vxc, fxc = ni.cache_xc_kernel(mf.mol, mf.grids, mf.xc,
                                        mo_coeff, mo_occ, spin=1)
    f1vo, f1oo, vxc1, k1ao = \
            _contract_xc_kernel(td_grad, mf.xc, (dmzvopa,dmzvopb),
                                (dmzooa,dmzoob), True, True, max_memory)

    if abs(hyb) > 1e-10:
        dm = (dmzooa, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T,
              dmzoob, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T)
        vj, vk = mf.get_jk(mol, dm, hermi=0)
        vj = vj.reshape(2,3,nao,nao)
        vk = vk.reshape(2,3,nao,nao) * hyb
        if abs(omega) > 1e-10:
            vk += rks._get_k_lr(mol, dm, omega).reshape(2,3,nao,nao) * (alpha-hyb)

        veff0doo = vj[0,0]+vj[1,0] - vk[:,0] + f1oo[:,0] + k1ao[:,0] * 2
        wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
        wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
        veff = vj[0,1]+vj[1,1] - vk[:,1] + f1vo[:,0] * 2
        veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
        veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
        wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) * 2
        wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) * 2
        wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:,nocca:], xpya) * 2
        wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:,noccb:], xpyb) * 2
        veff = -vk[:,2]
        veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
        veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
        wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya) * 2
        wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb) * 2
        wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:,nocca:], xmya) * 2
        wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:,noccb:], xmyb) * 2
    else:
        dm = (dmzooa, dmzvopa+dmzvopa.T,
              dmzoob, dmzvopb+dmzvopb.T)
        vj = mf.get_j(mol, dm, hermi=1).reshape(2,2,nao,nao)

        veff0doo = vj[0,0]+vj[1,0] + f1oo[:,0] + k1ao[:,0] * 2
        wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
        wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
        veff = vj[0,1]+vj[1,1] + f1vo[:,0] * 2
        veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
        veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
        wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) * 2
        wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) * 2
        wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:,nocca:], xpya) * 2
        wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:,noccb:], xpyb) * 2
        veff0moma = numpy.zeros((nmoa,nmoa))
        veff0momb = numpy.zeros((nmob,nmob))

    def fvind(x):
        dm1 = numpy.empty((2,nao,nao))
        xa = x[0,:nvira*nocca].reshape(nvira,nocca)
        xb = x[0,nvira*nocca:].reshape(nvirb,noccb)
        dma = reduce(numpy.dot, (orbva, xa, orboa.T))
        dmb = reduce(numpy.dot, (orbvb, xb, orbob.T))
        dm1[0] = dma + dma.T
        dm1[1] = dmb + dmb.T
        relativity = 0
        hermi = 1
        vindxc = numint.nr_uks_fxc(ni, mol, mf.grids, mf.xc, dm0, dm1, relativity,
                                   hermi, rho0, vxc, fxc, max_memory)
        if abs(hyb) > 1e-10:
            vj, vk = mf.get_jk(mol, dm1)
            veff = vj[0] + vj[1] - hyb * vk + vindxc
            if abs(omega) > 1e-10:
                veff -= rks._get_k_lr(mol, dm1, omega, hermi=1) * (alpha-hyb)
        else:
            vj = mf.get_j(mol, dm1)
            veff = vj[0] + vj[1] + vindxc
        v1a = reduce(numpy.dot, (orbva.T, veff[0], orboa))
        v1b = reduce(numpy.dot, (orbvb.T, veff[1], orbob))
        return numpy.hstack((v1a.ravel(), v1b.ravel()))
    z1a, z1b = ucphf.solve(fvind, mo_energy, mo_occ, (wvoa,wvob),
                           max_cycle=td_grad.cphf_max_cycle,
                           tol=td_grad.cphf_conv_tol)[0]
    time1 = log.timer('Z-vector using UCPHF solver', *time0)

    z1ao = numpy.empty((2,nao,nao))
    z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T))
    z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T))

    fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None,
                                False, False, max_memory)[0]
    if abs(hyb) > 1e-10:
        vj, vk = mf.get_jk(mol, z1ao, hermi=0)
        veff = vj[0]+vj[1] - hyb * vk + fxcz1[:,0]
        if abs(omega) > 1e-10:
            veff -= rks._get_k_lr(mol, z1ao, omega) * (alpha-hyb)
    else:
        vj = mf.get_j(mol, z1ao, hermi=1)
        veff = vj[0]+vj[1] + fxcz1[:,0]

    im0a = numpy.zeros((nmoa,nmoa))
    im0b = numpy.zeros((nmob,nmob))
    im0a[:nocca,:nocca] = reduce(numpy.dot, (orboa.T, veff0doo[0]+veff[0], orboa)) * .5
    im0b[:noccb,:noccb] = reduce(numpy.dot, (orbob.T, veff0doo[1]+veff[1], orbob)) * .5
    im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0mopa[nocca:,:nocca], xpya) * .5
    im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0mopb[noccb:,:noccb], xpyb) * .5
    im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0moma[nocca:,:nocca], xmya) * .5
    im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0momb[noccb:,:noccb], xmyb) * .5
    im0a[nocca:,nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:,:nocca], xpya) * .5
    im0b[noccb:,noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:,:noccb], xpyb) * .5
    im0a[nocca:,nocca:]+= numpy.einsum('ci,ai->ac', veff0moma[nocca:,:nocca], xmya) * .5
    im0b[noccb:,noccb:]+= numpy.einsum('ci,ai->ac', veff0momb[noccb:,:noccb], xmyb) * .5
    im0a[nocca:,:nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya)
    im0b[noccb:,:noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb)
    im0a[nocca:,:nocca]+= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya)
    im0b[noccb:,:noccb]+= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb)

    zeta_a = (mo_energy[0][:,None] + mo_energy[0]) * .5
    zeta_b = (mo_energy[1][:,None] + mo_energy[1]) * .5
    zeta_a[nocca:,:nocca] = mo_energy[0][:nocca]
    zeta_b[noccb:,:noccb] = mo_energy[1][:noccb]
    zeta_a[:nocca,nocca:] = mo_energy[0][nocca:]
    zeta_b[:noccb,noccb:] = mo_energy[1][noccb:]
    dm1a = numpy.zeros((nmoa,nmoa))
    dm1b = numpy.zeros((nmob,nmob))
    dm1a[:nocca,:nocca] = dooa * .5
    dm1b[:noccb,:noccb] = doob * .5
    dm1a[nocca:,nocca:] = dvva * .5
    dm1b[noccb:,noccb:] = dvvb * .5
    dm1a[nocca:,:nocca] = z1a * .5
    dm1b[noccb:,:noccb] = z1b * .5
    dm1a[:nocca,:nocca] += numpy.eye(nocca) # for ground state
    dm1b[:noccb,:noccb] += numpy.eye(noccb)
    im0a = reduce(numpy.dot, (mo_coeff[0], im0a+zeta_a*dm1a, mo_coeff[0].T))
    im0b = reduce(numpy.dot, (mo_coeff[1], im0b+zeta_b*dm1b, mo_coeff[1].T))
    im0 = im0a + im0b

    hcore_deriv = td_grad.hcore_generator(mol)
    s1 = td_grad.get_ovlp(mol)

    dmz1dooa = z1ao[0] + dmzooa
    dmz1doob = z1ao[1] + dmzoob
    oo0a = reduce(numpy.dot, (orboa, orboa.T))
    oo0b = reduce(numpy.dot, (orbob, orbob.T))
    as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5

    if abs(hyb) > 1e-10:
        dm = (oo0a, dmz1dooa+dmz1dooa.T, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T,
              oo0b, dmz1doob+dmz1doob.T, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T)
        vj, vk = td_grad.get_jk(mol, dm)
        vj = vj.reshape(2,4,3,nao,nao)
        vk = vk.reshape(2,4,3,nao,nao) * hyb
        if abs(omega) > 1e-10:
            with mol.with_range_coulomb(omega):
                vk += td_grad.get_k(mol, dm).reshape(2,4,3,nao,nao) * (alpha-hyb)
        veff1 = vj[0] + vj[1] - vk
    else:
        dm = (oo0a, dmz1dooa+dmz1dooa.T, dmzvopa+dmzvopa.T,
              oo0b, dmz1doob+dmz1doob.T, dmzvopb+dmzvopb.T)
        vj = td_grad.get_j(mol, dm).reshape(2,3,3,nao,nao)
        veff1 = numpy.zeros((2,4,3,nao,nao))
        veff1[:,:3] = vj[0] + vj[1]
    veff1[:,0] += vxc1[:,1:]
    veff1[:,1] +=(f1oo[:,1:] + fxcz1[:,1:] + k1ao[:,1:]*2)*2 # *2 for dmz1doo+dmz1oo.T
    veff1[:,2] += f1vo[:,1:] * 2
    veff1a, veff1b = veff1
    time1 = log.timer('2e AO integral derivatives', *time1)

    if atmlst is None:
        atmlst = range(mol.natm)
    offsetdic = mol.offset_nr_by_atom()
    de = numpy.zeros((len(atmlst),3))
    for k, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        # Ground state gradients
        h1ao = hcore_deriv(ia)
        de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1)

        de[k] += numpy.einsum('xpq,pq->x', veff1a[0,:,p0:p1], oo0a[p0:p1])
        de[k] += numpy.einsum('xpq,pq->x', veff1b[0,:,p0:p1], oo0b[p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', veff1a[0,:,p0:p1], oo0a[:,p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', veff1b[0,:,p0:p1], oo0b[:,p0:p1])

        de[k] += numpy.einsum('xpq,pq->x', veff1a[0,:,p0:p1], dmz1dooa[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,pq->x', veff1b[0,:,p0:p1], dmz1doob[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', veff1a[0,:,p0:p1], dmz1dooa[:,p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', veff1b[0,:,p0:p1], dmz1doob[:,p0:p1]) * .5

        de[k] -= numpy.einsum('xpq,pq->x', s1[:,p0:p1], im0[p0:p1])
        de[k] -= numpy.einsum('xqp,pq->x', s1[:,p0:p1], im0[:,p0:p1])

        de[k] += numpy.einsum('xij,ij->x', veff1a[1,:,p0:p1], oo0a[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', veff1b[1,:,p0:p1], oo0b[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', veff1a[2,:,p0:p1], dmzvopa[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', veff1b[2,:,p0:p1], dmzvopb[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', veff1a[3,:,p0:p1], dmzvoma[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', veff1b[3,:,p0:p1], dmzvomb[p0:p1,:])
        de[k] += numpy.einsum('xji,ij->x', veff1a[2,:,p0:p1], dmzvopa[:,p0:p1])
        de[k] += numpy.einsum('xji,ij->x', veff1b[2,:,p0:p1], dmzvopb[:,p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', veff1a[3,:,p0:p1], dmzvoma[:,p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', veff1b[3,:,p0:p1], dmzvomb[:,p0:p1])

    log.timer('TDUHF nuclear gradients', *time0)
    return de
Exemple #23
0
def grad_elec(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO):
    log = logger.new_logger(td_grad, verbose)
    time0 = time.clock(), time.time()

    mol = td_grad.mol
    mf = td_grad.base._scf
    mo_coeff = mf.mo_coeff
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    occidxa = numpy.where(mo_occ[0] > 0)[0]
    occidxb = numpy.where(mo_occ[1] > 0)[0]
    viridxa = numpy.where(mo_occ[0] == 0)[0]
    viridxb = numpy.where(mo_occ[1] == 0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:, occidxa]
    orbob = mo_coeff[1][:, occidxb]
    orbva = mo_coeff[0][:, viridxa]
    orbvb = mo_coeff[1][:, viridxb]
    nao = mo_coeff[0].shape[0]
    nmoa = nocca + nvira
    nmob = noccb + nvirb

    (xa, xb), (ya, yb) = x_y
    xpya = (xa + ya).reshape(nocca, nvira).T
    xpyb = (xb + yb).reshape(noccb, nvirb).T
    xmya = (xa - ya).reshape(nocca, nvira).T
    xmyb = (xb - yb).reshape(noccb, nvirb).T

    dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum(
        'ai,bi->ab', xmya, xmya)
    dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum(
        'ai,bi->ab', xmyb, xmyb)
    dooa = -numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum(
        'ai,aj->ij', xmya, xmya)
    doob = -numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum(
        'ai,aj->ij', xmyb, xmyb)
    dmzvopa = reduce(numpy.dot, (orbva, xpya, orboa.T))
    dmzvopb = reduce(numpy.dot, (orbvb, xpyb, orbob.T))
    dmzvoma = reduce(numpy.dot, (orbva, xmya, orboa.T))
    dmzvomb = reduce(numpy.dot, (orbvb, xmyb, orbob.T))
    dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T))
    dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T))
    dmzooa += reduce(numpy.dot, (orbva, dvva, orbva.T))
    dmzoob += reduce(numpy.dot, (orbvb, dvvb, orbvb.T))

    ni = mf._numint
    ni.libxc.test_deriv_order(mf.xc, 3, raise_error=True)
    omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin)
    # dm0 = mf.make_rdm1(mo_coeff, mo_occ), but it is not used when computing
    # fxc since rho0 is passed to fxc function.
    dm0 = None
    rho0, vxc, fxc = ni.cache_xc_kernel(mf.mol,
                                        mf.grids,
                                        mf.xc,
                                        mo_coeff,
                                        mo_occ,
                                        spin=1)
    f1vo, f1oo, vxc1, k1ao = \
            _contract_xc_kernel(td_grad, mf.xc, (dmzvopa,dmzvopb),
                                (dmzooa,dmzoob), True, True, max_memory)

    if abs(hyb) > 1e-10:
        dm = (dmzooa, dmzvopa + dmzvopa.T, dmzvoma - dmzvoma.T, dmzoob,
              dmzvopb + dmzvopb.T, dmzvomb - dmzvomb.T)
        vj, vk = mf.get_jk(mol, dm, hermi=0)
        vk *= hyb
        if abs(omega) > 1e-10:
            vk += mf.get_k(mol, dm, hermi=0, omega=omega) * (alpha - hyb)
        vj = vj.reshape(2, 3, nao, nao)
        vk = vk.reshape(2, 3, nao, nao)

        veff0doo = vj[0, 0] + vj[1, 0] - vk[:, 0] + f1oo[:, 0] + k1ao[:, 0] * 2
        wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
        wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
        veff = vj[0, 1] + vj[1, 1] - vk[:, 1] + f1vo[:, 0] * 2
        veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
        veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
        wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca], xpya) * 2
        wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb], xpyb) * 2
        wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:, nocca:], xpya) * 2
        wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:, noccb:], xpyb) * 2
        veff = -vk[:, 2]
        veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
        veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
        wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca, :nocca], xmya) * 2
        wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb, :noccb], xmyb) * 2
        wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:, nocca:], xmya) * 2
        wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:, noccb:], xmyb) * 2
    else:
        dm = (dmzooa, dmzvopa + dmzvopa.T, dmzoob, dmzvopb + dmzvopb.T)
        vj = mf.get_j(mol, dm, hermi=1).reshape(2, 2, nao, nao)

        veff0doo = vj[0, 0] + vj[1, 0] + f1oo[:, 0] + k1ao[:, 0] * 2
        wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
        wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
        veff = vj[0, 1] + vj[1, 1] + f1vo[:, 0] * 2
        veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
        veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
        wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca], xpya) * 2
        wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb], xpyb) * 2
        wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:, nocca:], xpya) * 2
        wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:, noccb:], xpyb) * 2
        veff0moma = numpy.zeros((nmoa, nmoa))
        veff0momb = numpy.zeros((nmob, nmob))

    def fvind(x):
        dm1 = numpy.empty((2, nao, nao))
        xa = x[0, :nvira * nocca].reshape(nvira, nocca)
        xb = x[0, nvira * nocca:].reshape(nvirb, noccb)
        dma = reduce(numpy.dot, (orbva, xa, orboa.T))
        dmb = reduce(numpy.dot, (orbvb, xb, orbob.T))
        dm1[0] = dma + dma.T
        dm1[1] = dmb + dmb.T
        relativity = 0
        hermi = 1
        vindxc = numint.nr_uks_fxc(ni, mol, mf.grids, mf.xc, dm0, dm1,
                                   relativity, hermi, rho0, vxc, fxc,
                                   max_memory)
        if abs(hyb) > 1e-10:
            vj, vk = mf.get_jk(mol, dm1)
            veff = vj[0] + vj[1] - hyb * vk + vindxc
            if abs(omega) > 1e-10:
                veff -= mf.get_k(mol, dm1, hermi=1,
                                 omega=omega) * (alpha - hyb)
        else:
            vj = mf.get_j(mol, dm1)
            veff = vj[0] + vj[1] + vindxc
        v1a = reduce(numpy.dot, (orbva.T, veff[0], orboa))
        v1b = reduce(numpy.dot, (orbvb.T, veff[1], orbob))
        return numpy.hstack((v1a.ravel(), v1b.ravel()))

    z1a, z1b = ucphf.solve(fvind,
                           mo_energy,
                           mo_occ, (wvoa, wvob),
                           max_cycle=td_grad.cphf_max_cycle,
                           tol=td_grad.cphf_conv_tol)[0]
    time1 = log.timer('Z-vector using UCPHF solver', *time0)

    z1ao = numpy.empty((2, nao, nao))
    z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T))
    z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T))

    fxcz1 = _contract_xc_kernel(td_grad, mf.xc, z1ao, None, False, False,
                                max_memory)[0]
    if abs(hyb) > 1e-10:
        vj, vk = mf.get_jk(mol, z1ao, hermi=0)
        veff = vj[0] + vj[1] - hyb * vk + fxcz1[:, 0]
        if abs(omega) > 1e-10:
            veff -= mf.get_k(mol, z1ao, hermi=0, omega=omega) * (alpha - hyb)
    else:
        vj = mf.get_j(mol, z1ao, hermi=1)
        veff = vj[0] + vj[1] + fxcz1[:, 0]

    im0a = numpy.zeros((nmoa, nmoa))
    im0b = numpy.zeros((nmob, nmob))
    im0a[:nocca, :nocca] = reduce(numpy.dot,
                                  (orboa.T, veff0doo[0] + veff[0], orboa)) * .5
    im0b[:noccb, :noccb] = reduce(numpy.dot,
                                  (orbob.T, veff0doo[1] + veff[1], orbob)) * .5
    im0a[:nocca, :nocca] += numpy.einsum('ak,ai->ki',
                                         veff0mopa[nocca:, :nocca], xpya) * .5
    im0b[:noccb, :noccb] += numpy.einsum('ak,ai->ki',
                                         veff0mopb[noccb:, :noccb], xpyb) * .5
    im0a[:nocca, :nocca] += numpy.einsum('ak,ai->ki',
                                         veff0moma[nocca:, :nocca], xmya) * .5
    im0b[:noccb, :noccb] += numpy.einsum('ak,ai->ki',
                                         veff0momb[noccb:, :noccb], xmyb) * .5
    im0a[nocca:, nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:, :nocca],
                                        xpya) * .5
    im0b[noccb:, noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:, :noccb],
                                        xpyb) * .5
    im0a[nocca:, nocca:] += numpy.einsum('ci,ai->ac',
                                         veff0moma[nocca:, :nocca], xmya) * .5
    im0b[noccb:, noccb:] += numpy.einsum('ci,ai->ac',
                                         veff0momb[noccb:, :noccb], xmyb) * .5
    im0a[nocca:, :nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca],
                                        xpya)
    im0b[noccb:, :noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb],
                                        xpyb)
    im0a[nocca:, :nocca] += numpy.einsum('ki,ai->ak',
                                         veff0moma[:nocca, :nocca], xmya)
    im0b[noccb:, :noccb] += numpy.einsum('ki,ai->ak',
                                         veff0momb[:noccb, :noccb], xmyb)

    zeta_a = (mo_energy[0][:, None] + mo_energy[0]) * .5
    zeta_b = (mo_energy[1][:, None] + mo_energy[1]) * .5
    zeta_a[nocca:, :nocca] = mo_energy[0][:nocca]
    zeta_b[noccb:, :noccb] = mo_energy[1][:noccb]
    zeta_a[:nocca, nocca:] = mo_energy[0][nocca:]
    zeta_b[:noccb, noccb:] = mo_energy[1][noccb:]
    dm1a = numpy.zeros((nmoa, nmoa))
    dm1b = numpy.zeros((nmob, nmob))
    dm1a[:nocca, :nocca] = dooa * .5
    dm1b[:noccb, :noccb] = doob * .5
    dm1a[nocca:, nocca:] = dvva * .5
    dm1b[noccb:, noccb:] = dvvb * .5
    dm1a[nocca:, :nocca] = z1a * .5
    dm1b[noccb:, :noccb] = z1b * .5
    dm1a[:nocca, :nocca] += numpy.eye(nocca)  # for ground state
    dm1b[:noccb, :noccb] += numpy.eye(noccb)
    im0a = reduce(numpy.dot,
                  (mo_coeff[0], im0a + zeta_a * dm1a, mo_coeff[0].T))
    im0b = reduce(numpy.dot,
                  (mo_coeff[1], im0b + zeta_b * dm1b, mo_coeff[1].T))
    im0 = im0a + im0b

    # 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)

    dmz1dooa = z1ao[0] + dmzooa
    dmz1doob = z1ao[1] + dmzoob
    oo0a = reduce(numpy.dot, (orboa, orboa.T))
    oo0b = reduce(numpy.dot, (orbob, orbob.T))
    as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5

    if abs(hyb) > 1e-10:
        dm = (oo0a, dmz1dooa + dmz1dooa.T, dmzvopa + dmzvopa.T,
              dmzvoma - dmzvoma.T, oo0b, dmz1doob + dmz1doob.T,
              dmzvopb + dmzvopb.T, dmzvomb - dmzvomb.T)
        vj, vk = td_grad.get_jk(mol, dm)
        vj = vj.reshape(2, 4, 3, nao, nao)
        vk = vk.reshape(2, 4, 3, nao, nao) * hyb
        if abs(omega) > 1e-10:
            with mol.with_range_coulomb(omega):
                vk += td_grad.get_k(mol, dm).reshape(2, 4, 3, nao,
                                                     nao) * (alpha - hyb)
        veff1 = vj[0] + vj[1] - vk
    else:
        dm = (oo0a, dmz1dooa + dmz1dooa.T, dmzvopa + dmzvopa.T, oo0b,
              dmz1doob + dmz1doob.T, dmzvopb + dmzvopb.T)
        vj = td_grad.get_j(mol, dm).reshape(2, 3, 3, nao, nao)
        veff1 = numpy.zeros((2, 4, 3, nao, nao))
        veff1[:, :3] = vj[0] + vj[1]
    veff1[:, 0] += vxc1[:, 1:]
    veff1[:, 1] += (f1oo[:, 1:] + fxcz1[:, 1:] +
                    k1ao[:, 1:] * 2) * 2  # *2 for dmz1doo+dmz1oo.T
    veff1[:, 2] += f1vo[:, 1:] * 2
    veff1a, veff1b = veff1
    time1 = log.timer('2e AO integral derivatives', *time1)

    if atmlst is None:
        atmlst = range(mol.natm)
    offsetdic = mol.offset_nr_by_atom()
    de = numpy.zeros((len(atmlst), 3))
    for k, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        # Ground state gradients
        h1ao = hcore_deriv(ia)
        de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1)

        de[k] += numpy.einsum('xpq,pq->x', veff1a[0, :, p0:p1], oo0a[p0:p1])
        de[k] += numpy.einsum('xpq,pq->x', veff1b[0, :, p0:p1], oo0b[p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', veff1a[0, :, p0:p1], oo0a[:, p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', veff1b[0, :, p0:p1], oo0b[:, p0:p1])

        de[k] += numpy.einsum('xpq,pq->x', veff1a[0, :, p0:p1],
                              dmz1dooa[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,pq->x', veff1b[0, :, p0:p1],
                              dmz1doob[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', veff1a[0, :, p0:p1],
                              dmz1dooa[:, p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', veff1b[0, :, p0:p1],
                              dmz1doob[:, p0:p1]) * .5

        de[k] -= numpy.einsum('xpq,pq->x', s1[:, p0:p1], im0[p0:p1])
        de[k] -= numpy.einsum('xqp,pq->x', s1[:, p0:p1], im0[:, p0:p1])

        de[k] += numpy.einsum('xij,ij->x', veff1a[1, :, p0:p1],
                              oo0a[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', veff1b[1, :, p0:p1],
                              oo0b[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', veff1a[2, :, p0:p1],
                              dmzvopa[p0:p1, :])
        de[k] += numpy.einsum('xij,ij->x', veff1b[2, :, p0:p1],
                              dmzvopb[p0:p1, :])
        de[k] += numpy.einsum('xij,ij->x', veff1a[3, :, p0:p1],
                              dmzvoma[p0:p1, :])
        de[k] += numpy.einsum('xij,ij->x', veff1b[3, :, p0:p1],
                              dmzvomb[p0:p1, :])
        de[k] += numpy.einsum('xji,ij->x', veff1a[2, :, p0:p1], dmzvopa[:,
                                                                        p0:p1])
        de[k] += numpy.einsum('xji,ij->x', veff1b[2, :, p0:p1], dmzvopb[:,
                                                                        p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', veff1a[3, :, p0:p1], dmzvoma[:,
                                                                        p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', veff1b[3, :, p0:p1], dmzvomb[:,
                                                                        p0:p1])

    log.timer('TDUHF nuclear gradients', *time0)
    return de
Exemple #24
0
    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, so = self.sv, self.so
        nocc, nvir, nmo = self.nocc, self.nvir, self.nmo
        e, eo, ev, mo_occ = self.e, self.eo, self.ev, self.mo_occ
        prop_dim = B_1.shape[1]

        # Calculate U_1_vo
        def fx(X):
            prop_dim = X.shape[0]
            X_alpha = X[:, :nocc[0] * nvir[0]].reshape(
                (prop_dim, nvir[0], nocc[0]))
            X_beta = X[:, nocc[0] * nvir[0]:].reshape(
                (prop_dim, nvir[1], nocc[1]))
            Ax = Ax0_Core(sv, so, sv, so, in_cphf=True)((X_alpha, X_beta))
            result = np.concatenate(
                [Ax[0].reshape(prop_dim, -1), Ax[1].reshape(prop_dim, -1)],
                axis=1)
            return result

        U_1_vo = ucphf.solve(
            fx,
            e,
            mo_occ, (B_1[0, :, sv[0], so[0]], B_1[1, :, sv[1], so[1]]),
            max_cycle=100,
            tol=self.cphf_tol)[0]

        # Additional Iteration by newton_krylov
        def get_conv(U_1_vo):
            Ax_U = Ax0_Core(sv, so, sv, so, in_cphf=True)(U_1_vo)
            return (
                (ev[0][:, None] - eo[0][None, :]) * U_1_vo[0] + Ax_U[0] +
                B_1[0][:, sv[0], so[0]],
                (ev[1][:, None] - eo[1][None, :]) * U_1_vo[1] + Ax_U[1] +
                B_1[1][:, sv[1], so[1]],
            )

        # def vind(guess):
        #     U_1_vo_inner = (
        #         guess[:3 * nocc[0] * nvir[0]].reshape(3, nvir[0], nocc[0]),
        #         guess[3 * nocc[0] * nvir[0]:].reshape(3, nvir[1], nocc[1]))
        #     conv = get_conv(U_1_vo_inner)
        #     return np.concatenate([conv[0].ravel(), conv[1].ravel()])
        #
        # guess = (
        #     B_1[0, :, sv[0], so[0]] / (ev[0][:, None] - eo[0][None, :]),
        #     B_1[1, :, sv[1], so[1]] / (ev[1][:, None] - eo[1][None, :]))
        # guess = np.concatenate([guess[0].ravel(), guess[1].ravel()])
        # res = newton_krylov(vind, guess, f_tol=1e-10)
        # U_1_vo = (
        #     res[:3 * nocc[0] * nvir[0]].reshape(3, nvir[0], nocc[0]),
        #     res[3 * nocc[0] * nvir[0]:].reshape(3, nvir[1], nocc[1]))
        # Check sanity
        conv = get_conv(U_1_vo)
        if np.abs(conv[0]).max() > 1e-8 or np.abs(conv[1]).max() > 1e-8:
            msg = "\nget_U_1: CP-HF not converged well!\nMaximum deviation: " + str(
                np.abs(conv[0]).max()) + ", " + str(np.abs(conv[1]).max())
            warnings.warn(msg)
        # Build rest of U_1
        U_1 = np.zeros((2, prop_dim, nmo, nmo))
        if self.rotation:
            U_1 = -0.5 * S_1_mo
            U_1[0, :, sv[0], so[0]] = U_1_vo[0]
            U_1[1, :, sv[1], so[1]] = U_1_vo[1]
            U_1[0, :, so[0],
                sv[0]] = -S_1_mo[0, :, so[0], sv[0]] - U_1_vo[0].swapaxes(
                    -1, -2)
            U_1[1, :, so[1],
                sv[1]] = -S_1_mo[1, :, so[1], sv[1]] - U_1_vo[1].swapaxes(
                    -1, -2)
        else:
            U_1[0, :, sv[0], so[0]] = U_1_vo[0]
            U_1[1, :, sv[1], so[1]] = U_1_vo[1]
            U_1[0, :, so[0],
                sv[0]] = -S_1_mo[0, :, so[0], sv[0]] - U_1_vo[0].swapaxes(
                    -1, -2)
            U_1[1, :, so[1],
                sv[1]] = -S_1_mo[1, :, so[1], sv[1]] - U_1_vo[1].swapaxes(
                    -1, -2)
            Ax_oo = Ax0_Core(so, so, sv, so)(U_1_vo)
            Ax_vv = Ax0_Core(sv, sv, sv, so)(U_1_vo)
            U_1[0, :, so[0], so[0]] = -(Ax_oo[0] + B_1[0, :, so[0], so[0]]) / (
                eo[0][:, None] - eo[0][None, :])
            U_1[1, :, so[1], so[1]] = -(Ax_oo[1] + B_1[1, :, so[1], so[1]]) / (
                eo[1][:, None] - eo[1][None, :])
            U_1[0, :, sv[0], sv[0]] = -(Ax_vv[0] + B_1[0, :, sv[0], sv[0]]) / (
                ev[0][:, None] - ev[0][None, :])
            U_1[1, :, sv[1], sv[1]] = -(Ax_vv[1] + B_1[1, :, sv[1], sv[1]]) / (
                ev[1][:, None] - ev[1][None, :])
            for p in range(nmo):
                U_1[:, :, p, p] = -S_1_mo[:, :, p, p] / 2
            U_1 -= (U_1 + U_1.swapaxes(-1, -2) + S_1_mo) / 2
            U_1 -= (U_1 + U_1.swapaxes(-1, -2) + S_1_mo) / 2

        return U_1
Exemple #25
0
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[0].shape
    mocca = mo_coeff[0][:, mo_occ[0] > 0]
    moccb = mo_coeff[1][:, mo_occ[1] > 0]
    nocca = mocca.shape[1]
    noccb = moccb.shape[1]

    if fx is None:
        fx = gen_vind(mf, mo_coeff, mo_occ)
    s1a = -mol.intor('int1e_ipovlp', comp=3)

    def _ao2mo(mat, mo_coeff, mocc):
        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 / (nao * (nocca + noccb) * 3 * 6)))
    mo1sa = [None] * mol.natm
    mo1sb = [None] * mol.natm
    e1sa = [None] * mol.natm
    e1sb = [None] * mol.natm
    aoslices = mol.aoslice_by_atom()
    for ia0, ia1 in lib.prange(0, len(atmlst), blksize):
        s1voa = []
        s1vob = []
        h1voa = []
        h1vob = []
        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)
            s1voa.append(_ao2mo(s1ao, mo_coeff[0], mocca))
            s1vob.append(_ao2mo(s1ao, mo_coeff[1], moccb))
            if isinstance(h1ao_or_chkfile, str):
                h1aoa = lib.chkfile.load(h1ao_or_chkfile, 'scf_f1ao/0/%d' % ia)
                h1aob = lib.chkfile.load(h1ao_or_chkfile, 'scf_f1ao/1/%d' % ia)
            else:
                h1aoa = h1ao_or_chkfile[0][ia]
                h1aob = h1ao_or_chkfile[1][ia]
            h1voa.append(_ao2mo(h1aoa, mo_coeff[0], mocca))
            h1vob.append(_ao2mo(h1aob, mo_coeff[1], moccb))

        h1vo = (numpy.vstack(h1voa), numpy.vstack(h1vob))
        s1vo = (numpy.vstack(s1voa), numpy.vstack(s1vob))
        mo1, e1 = ucphf.solve(fx, mo_energy, mo_occ, h1vo, s1vo)
        mo1a = numpy.einsum('pq,xqi->xpi', mo_coeff[0],
                            mo1[0]).reshape(-1, 3, nao, nocca)
        mo1b = numpy.einsum('pq,xqi->xpi', mo_coeff[1],
                            mo1[1]).reshape(-1, 3, nao, noccb)
        e1a = e1[0].reshape(-1, 3, nocca, nocca)
        e1b = e1[1].reshape(-1, 3, noccb, noccb)

        for k in range(ia1 - ia0):
            ia = atmlst[k + ia0]
            if isinstance(h1ao_or_chkfile, str):
                lib.chkfile.save(h1ao_or_chkfile, 'scf_mo1/0/%d' % ia, mo1a[k])
                lib.chkfile.save(h1ao_or_chkfile, 'scf_mo1/1/%d' % ia, mo1b[k])
            else:
                mo1sa[ia] = mo1a[k]
                mo1sb[ia] = mo1b[k]
            e1sa[ia] = e1a[k].reshape(3, nocca, nocca)
            e1sb[ia] = e1b[k].reshape(3, noccb, noccb)
        mo1 = e1 = mo1a = mo1b = e1a = e1b = None

    if isinstance(h1ao_or_chkfile, str):
        return h1ao_or_chkfile, (e1sa, e1sb)
    else:
        return (mo1sa, mo1sb), (e1sa, e1sb)
Exemple #26
0
def grad_elec(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO):
    '''
    Electronic part of TDA, TDHF nuclear gradients

    Args:
        td_grad : grad.tduhf.Gradients or grad.tduks.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
    occidxa = numpy.where(mo_occ[0] > 0)[0]
    occidxb = numpy.where(mo_occ[1] > 0)[0]
    viridxa = numpy.where(mo_occ[0] == 0)[0]
    viridxb = numpy.where(mo_occ[1] == 0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:, occidxa]
    orbob = mo_coeff[1][:, occidxb]
    orbva = mo_coeff[0][:, viridxa]
    orbvb = mo_coeff[1][:, viridxb]
    nao = mo_coeff[0].shape[0]
    nmoa = nocca + nvira
    nmob = noccb + nvirb

    (xa, xb), (ya, yb) = x_y
    xpya = (xa + ya).reshape(nocca, nvira).T
    xpyb = (xb + yb).reshape(noccb, nvirb).T
    xmya = (xa - ya).reshape(nocca, nvira).T
    xmyb = (xb - yb).reshape(noccb, nvirb).T

    dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum(
        'ai,bi->ab', xmya, xmya)
    dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum(
        'ai,bi->ab', xmyb, xmyb)
    dooa = -numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum(
        'ai,aj->ij', xmya, xmya)
    doob = -numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum(
        'ai,aj->ij', xmyb, xmyb)
    dmxpya = reduce(numpy.dot, (orbva, xpya, orboa.T))
    dmxpyb = reduce(numpy.dot, (orbvb, xpyb, orbob.T))
    dmxmya = reduce(numpy.dot, (orbva, xmya, orboa.T))
    dmxmyb = reduce(numpy.dot, (orbvb, xmyb, orbob.T))
    dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T))
    dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T))
    dmzooa += reduce(numpy.dot, (orbva, dvva, orbva.T))
    dmzoob += reduce(numpy.dot, (orbvb, dvvb, orbvb.T))

    vj, vk = mf.get_jk(mol, (dmzooa, dmxpya + dmxpya.T, dmxmya - dmxmya.T,
                             dmzoob, dmxpyb + dmxpyb.T, dmxmyb - dmxmyb.T),
                       hermi=0)
    vj = vj.reshape(2, 3, nao, nao)
    vk = vk.reshape(2, 3, nao, nao)
    veff0doo = vj[0, 0] + vj[1, 0] - vk[:, 0]
    wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
    wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
    veff = vj[0, 1] + vj[1, 1] - vk[:, 1]
    veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
    veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
    wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca], xpya) * 2
    wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb], xpyb) * 2
    wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:, nocca:], xpya) * 2
    wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:, noccb:], xpyb) * 2
    veff = -vk[:, 2]
    veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
    veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
    wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca, :nocca], xmya) * 2
    wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb, :noccb], xmyb) * 2
    wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:, nocca:], xmya) * 2
    wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:, noccb:], xmyb) * 2

    vresp = mf.gen_response(hermi=1)

    def fvind(x):
        dm1 = numpy.empty((2, nao, nao))
        xa = x[0, :nvira * nocca].reshape(nvira, nocca)
        xb = x[0, nvira * nocca:].reshape(nvirb, noccb)
        dma = reduce(numpy.dot, (orbva, xa, orboa.T))
        dmb = reduce(numpy.dot, (orbvb, xb, orbob.T))
        dm1[0] = dma + dma.T
        dm1[1] = dmb + dmb.T
        v1 = vresp(dm1)
        v1a = reduce(numpy.dot, (orbva.T, v1[0], orboa))
        v1b = reduce(numpy.dot, (orbvb.T, v1[1], orbob))
        return numpy.hstack((v1a.ravel(), v1b.ravel()))

    z1a, z1b = ucphf.solve(fvind,
                           mo_energy,
                           mo_occ, (wvoa, wvob),
                           max_cycle=td_grad.cphf_max_cycle,
                           tol=td_grad.cphf_conv_tol)[0]
    time1 = log.timer('Z-vector using UCPHF solver', *time0)

    z1ao = numpy.empty((2, nao, nao))
    z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T))
    z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T))
    veff = vresp((z1ao + z1ao.transpose(0, 2, 1)) * .5)

    im0a = numpy.zeros((nmoa, nmoa))
    im0b = numpy.zeros((nmob, nmob))
    im0a[:nocca, :nocca] = reduce(numpy.dot,
                                  (orboa.T, veff0doo[0] + veff[0], orboa)) * .5
    im0b[:noccb, :noccb] = reduce(numpy.dot,
                                  (orbob.T, veff0doo[1] + veff[1], orbob)) * .5
    im0a[:nocca, :nocca] += numpy.einsum('ak,ai->ki',
                                         veff0mopa[nocca:, :nocca], xpya) * .5
    im0b[:noccb, :noccb] += numpy.einsum('ak,ai->ki',
                                         veff0mopb[noccb:, :noccb], xpyb) * .5
    im0a[:nocca, :nocca] += numpy.einsum('ak,ai->ki',
                                         veff0moma[nocca:, :nocca], xmya) * .5
    im0b[:noccb, :noccb] += numpy.einsum('ak,ai->ki',
                                         veff0momb[noccb:, :noccb], xmyb) * .5
    im0a[nocca:, nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:, :nocca],
                                        xpya) * .5
    im0b[noccb:, noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:, :noccb],
                                        xpyb) * .5
    im0a[nocca:, nocca:] += numpy.einsum('ci,ai->ac',
                                         veff0moma[nocca:, :nocca], xmya) * .5
    im0b[noccb:, noccb:] += numpy.einsum('ci,ai->ac',
                                         veff0momb[noccb:, :noccb], xmyb) * .5
    im0a[nocca:, :nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca, :nocca],
                                        xpya)
    im0b[noccb:, :noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb, :noccb],
                                        xpyb)
    im0a[nocca:, :nocca] += numpy.einsum('ki,ai->ak',
                                         veff0moma[:nocca, :nocca], xmya)
    im0b[noccb:, :noccb] += numpy.einsum('ki,ai->ak',
                                         veff0momb[:noccb, :noccb], xmyb)

    zeta_a = (mo_energy[0][:, None] + mo_energy[0]) * .5
    zeta_b = (mo_energy[1][:, None] + mo_energy[1]) * .5
    zeta_a[nocca:, :nocca] = mo_energy[0][:nocca]
    zeta_b[noccb:, :noccb] = mo_energy[1][:noccb]
    zeta_a[:nocca, nocca:] = mo_energy[0][nocca:]
    zeta_b[:noccb, noccb:] = mo_energy[1][noccb:]
    dm1a = numpy.zeros((nmoa, nmoa))
    dm1b = numpy.zeros((nmob, nmob))
    dm1a[:nocca, :nocca] = dooa * .5
    dm1b[:noccb, :noccb] = doob * .5
    dm1a[nocca:, nocca:] = dvva * .5
    dm1b[noccb:, noccb:] = dvvb * .5
    dm1a[nocca:, :nocca] = z1a * .5
    dm1b[noccb:, :noccb] = z1b * .5
    dm1a[:nocca, :nocca] += numpy.eye(nocca)  # for ground state
    dm1b[:noccb, :noccb] += numpy.eye(noccb)
    im0a = reduce(numpy.dot,
                  (mo_coeff[0], im0a + zeta_a * dm1a, mo_coeff[0].T))
    im0b = reduce(numpy.dot,
                  (mo_coeff[1], im0b + zeta_b * dm1b, mo_coeff[1].T))
    im0 = im0a + im0b

    # 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)

    dmz1dooa = z1ao[0] + dmzooa
    dmz1doob = z1ao[1] + dmzoob
    oo0a = reduce(numpy.dot, (orboa, orboa.T))
    oo0b = reduce(numpy.dot, (orbob, orbob.T))
    as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5
    vj, vk = td_grad.get_jk(
        mol,
        (oo0a, dmz1dooa + dmz1dooa.T, dmxpya + dmxpya.T, dmxmya - dmxmya.T,
         oo0b, dmz1doob + dmz1doob.T, dmxpyb + dmxpyb.T, dmxmyb - dmxmyb.T))
    vj = vj.reshape(2, 4, 3, nao, nao)
    vk = vk.reshape(2, 4, 3, nao, nao)
    vhf1a, vhf1b = vj[0] + vj[1] - vk
    time1 = log.timer('2e AO integral derivatives', *time1)

    if atmlst is None:
        atmlst = range(mol.natm)
    offsetdic = mol.offset_nr_by_atom()
    de = numpy.zeros((len(atmlst), 3))
    for k, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        # Ground state gradients
        h1ao = hcore_deriv(ia)
        de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1)

        de[k] += numpy.einsum('xpq,pq->x', vhf1a[0, :, p0:p1], oo0a[p0:p1])
        de[k] += numpy.einsum('xpq,pq->x', vhf1b[0, :, p0:p1], oo0b[p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', vhf1a[0, :, p0:p1], oo0a[:, p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', vhf1b[0, :, p0:p1], oo0b[:, p0:p1])

        de[k] += numpy.einsum('xpq,pq->x', vhf1a[0, :, p0:p1],
                              dmz1dooa[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,pq->x', vhf1b[0, :, p0:p1],
                              dmz1doob[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', vhf1a[0, :, p0:p1],
                              dmz1dooa[:, p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', vhf1b[0, :, p0:p1],
                              dmz1doob[:, p0:p1]) * .5

        de[k] -= numpy.einsum('xpq,pq->x', s1[:, p0:p1], im0[p0:p1])
        de[k] -= numpy.einsum('xqp,pq->x', s1[:, p0:p1], im0[:, p0:p1])

        de[k] += numpy.einsum('xij,ij->x', vhf1a[1, :, p0:p1],
                              oo0a[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', vhf1b[1, :, p0:p1],
                              oo0b[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', vhf1a[2, :, p0:p1],
                              dmxpya[p0:p1, :])
        de[k] += numpy.einsum('xij,ij->x', vhf1b[2, :, p0:p1],
                              dmxpyb[p0:p1, :])
        de[k] += numpy.einsum('xij,ij->x', vhf1a[3, :, p0:p1],
                              dmxmya[p0:p1, :])
        de[k] += numpy.einsum('xij,ij->x', vhf1b[3, :, p0:p1],
                              dmxmyb[p0:p1, :])
        de[k] += numpy.einsum('xji,ij->x', vhf1a[2, :, p0:p1], dmxpya[:,
                                                                      p0:p1])
        de[k] += numpy.einsum('xji,ij->x', vhf1b[2, :, p0:p1], dmxpyb[:,
                                                                      p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', vhf1a[3, :, p0:p1], dmxmya[:,
                                                                      p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', vhf1b[3, :, p0:p1], dmxmyb[:,
                                                                      p0:p1])

    log.timer('TDUHF nuclear gradients', *time0)
    return de
Exemple #27
0
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[0].shape
    mocca = mo_coeff[0][:,mo_occ[0]>0]
    moccb = mo_coeff[1][:,mo_occ[1]>0]
    nocca = mocca.shape[1]
    noccb = moccb.shape[1]

    if fx is None:
        fx = gen_vind(mf, mo_coeff, mo_occ)
    s1a = -mol.intor('int1e_ipovlp', comp=3)

    def _ao2mo(mat, mo_coeff, mocc):
        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 / (nao*(nocca+noccb)*3*6)))
    mo1sa = [None] * mol.natm
    mo1sb = [None] * mol.natm
    e1sa = [None] * mol.natm
    e1sb = [None] * mol.natm
    aoslices = mol.aoslice_by_atom()
    for ia0, ia1 in lib.prange(0, len(atmlst), blksize):
        s1voa = []
        s1vob = []
        h1voa = []
        h1vob = []
        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)
            s1voa.append(_ao2mo(s1ao, mo_coeff[0], mocca))
            s1vob.append(_ao2mo(s1ao, mo_coeff[1], moccb))
            if isinstance(h1ao_or_chkfile, str):
                h1aoa = lib.chkfile.load(h1ao_or_chkfile, 'scf_f1ao/0/%d'%ia)
                h1aob = lib.chkfile.load(h1ao_or_chkfile, 'scf_f1ao/1/%d'%ia)
            else:
                h1aoa = h1ao_or_chkfile[0][ia]
                h1aob = h1ao_or_chkfile[1][ia]
            h1voa.append(_ao2mo(h1aoa, mo_coeff[0], mocca))
            h1vob.append(_ao2mo(h1aob, mo_coeff[1], moccb))

        h1vo = (numpy.vstack(h1voa), numpy.vstack(h1vob))
        s1vo = (numpy.vstack(s1voa), numpy.vstack(s1vob))
        mo1, e1 = ucphf.solve(fx, mo_energy, mo_occ, h1vo, s1vo)
        mo1a = numpy.einsum('pq,xqi->xpi', mo_coeff[0], mo1[0]).reshape(-1,3,nao,nocca)
        mo1b = numpy.einsum('pq,xqi->xpi', mo_coeff[1], mo1[1]).reshape(-1,3,nao,noccb)
        e1a = e1[0].reshape(-1,3,nocca,nocca)
        e1b = e1[1].reshape(-1,3,noccb,noccb)

        for k in range(ia1-ia0):
            ia = atmlst[k+ia0]
            if isinstance(h1ao_or_chkfile, str):
                lib.chkfile.save(h1ao_or_chkfile, 'scf_mo1/0/%d'%ia, mo1a[k])
                lib.chkfile.save(h1ao_or_chkfile, 'scf_mo1/1/%d'%ia, mo1b[k])
            else:
                mo1sa[ia] = mo1a[k]
                mo1sb[ia] = mo1b[k]
            e1sa[ia] = e1a[k].reshape(3,nocca,nocca)
            e1sb[ia] = e1b[k].reshape(3,noccb,noccb)
        mo1 = e1 = mo1a = mo1b = e1a = e1b = None

    if isinstance(h1ao_or_chkfile, str):
        return h1ao_or_chkfile, (e1sa,e1sb)
    else:
        return (mo1sa,mo1sb), (e1sa,e1sb)
Exemple #28
0
def kernel(td_grad, x_y, atmlst=None, max_memory=2000, verbose=logger.INFO):
    log = logger.new_logger(td_grad, verbose)
    time0 = time.clock(), time.time()

    mol = td_grad.mol
    mf = td_grad.base._scf
    mo_coeff = mf.mo_coeff
    mo_energy = mf.mo_energy
    mo_occ = mf.mo_occ
    occidxa = numpy.where(mo_occ[0]>0)[0]
    occidxb = numpy.where(mo_occ[1]>0)[0]
    viridxa = numpy.where(mo_occ[0]==0)[0]
    viridxb = numpy.where(mo_occ[1]==0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:,occidxa]
    orbob = mo_coeff[1][:,occidxb]
    orbva = mo_coeff[0][:,viridxa]
    orbvb = mo_coeff[1][:,viridxb]
    nao = mo_coeff[0].shape[0]
    nmoa = nocca + nvira
    nmob = noccb + nvirb

    (xa, xb), (ya, yb) = x_y
    xpya = (xa+ya).reshape(nocca,nvira).T
    xpyb = (xb+yb).reshape(noccb,nvirb).T
    xmya = (xa-ya).reshape(nocca,nvira).T
    xmyb = (xb-yb).reshape(noccb,nvirb).T

    dvva = numpy.einsum('ai,bi->ab', xpya, xpya) + numpy.einsum('ai,bi->ab', xmya, xmya)
    dvvb = numpy.einsum('ai,bi->ab', xpyb, xpyb) + numpy.einsum('ai,bi->ab', xmyb, xmyb)
    dooa =-numpy.einsum('ai,aj->ij', xpya, xpya) - numpy.einsum('ai,aj->ij', xmya, xmya)
    doob =-numpy.einsum('ai,aj->ij', xpyb, xpyb) - numpy.einsum('ai,aj->ij', xmyb, xmyb)
    dmzvopa = reduce(numpy.dot, (orbva, xpya, orboa.T))
    dmzvopb = reduce(numpy.dot, (orbvb, xpyb, orbob.T))
    dmzvoma = reduce(numpy.dot, (orbva, xmya, orboa.T))
    dmzvomb = reduce(numpy.dot, (orbvb, xmyb, orbob.T))
    dmzooa = reduce(numpy.dot, (orboa, dooa, orboa.T))
    dmzoob = reduce(numpy.dot, (orbob, doob, orbob.T))
    dmzooa+= reduce(numpy.dot, (orbva, dvva, orbva.T))
    dmzoob+= reduce(numpy.dot, (orbvb, dvvb, orbvb.T))

    vj, vk = mf.get_jk(mol, (dmzooa, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T,
                             dmzoob, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T), hermi=0)
    vj = vj.reshape(2,3,nao,nao)
    vk = vk.reshape(2,3,nao,nao)
    veff0doo = vj[0,0]+vj[1,0] - vk[:,0]
    wvoa = reduce(numpy.dot, (orbva.T, veff0doo[0], orboa)) * 2
    wvob = reduce(numpy.dot, (orbvb.T, veff0doo[1], orbob)) * 2
    veff = vj[0,1]+vj[1,1] - vk[:,1]
    veff0mopa = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
    veff0mopb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
    wvoa -= numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya) * 2
    wvob -= numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb) * 2
    wvoa += numpy.einsum('ac,ai->ci', veff0mopa[nocca:,nocca:], xpya) * 2
    wvob += numpy.einsum('ac,ai->ci', veff0mopb[noccb:,noccb:], xpyb) * 2
    veff = -vk[:,2]
    veff0moma = reduce(numpy.dot, (mo_coeff[0].T, veff[0], mo_coeff[0]))
    veff0momb = reduce(numpy.dot, (mo_coeff[1].T, veff[1], mo_coeff[1]))
    wvoa -= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya) * 2
    wvob -= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb) * 2
    wvoa += numpy.einsum('ac,ai->ci', veff0moma[nocca:,nocca:], xmya) * 2
    wvob += numpy.einsum('ac,ai->ci', veff0momb[noccb:,noccb:], xmyb) * 2
    def fvind(x):
        dm1 = numpy.empty((2,nao,nao))
        xa = x[0,:nvira*nocca].reshape(nvira,nocca)
        xb = x[0,nvira*nocca:].reshape(nvirb,noccb)
        dma = reduce(numpy.dot, (orbva, xa, orboa.T))
        dmb = reduce(numpy.dot, (orbvb, xb, orbob.T))
        dm1[0] = dma + dma.T
        dm1[1] = dmb + dmb.T
        vj, vk = mf.get_jk(mol, dm1)
        v1 = vj[0] + vj[1] - vk
        v1a = reduce(numpy.dot, (orbva.T, v1[0], orboa))
        v1b = reduce(numpy.dot, (orbvb.T, v1[1], orbob))
        return numpy.hstack((v1a.ravel(), v1b.ravel()))
    z1a, z1b = ucphf.solve(fvind, mo_energy, mo_occ, (wvoa,wvob),
                           max_cycle=td_grad.cphf_max_cycle,
                           tol=td_grad.cphf_conv_tol)[0]
    time1 = log.timer('Z-vector using UCPHF solver', *time0)

    z1ao = numpy.empty((2,nao,nao))
    z1ao[0] = reduce(numpy.dot, (orbva, z1a, orboa.T))
    z1ao[1] = reduce(numpy.dot, (orbvb, z1b, orbob.T))
    vj, vk = mf.get_jk(mol, z1ao, hermi=0)
    veff = vj[0]+vj[1] - vk

    im0a = numpy.zeros((nmoa,nmoa))
    im0b = numpy.zeros((nmob,nmob))
    im0a[:nocca,:nocca] = reduce(numpy.dot, (orboa.T, veff0doo[0]+veff[0], orboa)) * .5
    im0b[:noccb,:noccb] = reduce(numpy.dot, (orbob.T, veff0doo[1]+veff[1], orbob)) * .5
    im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0mopa[nocca:,:nocca], xpya) * .5
    im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0mopb[noccb:,:noccb], xpyb) * .5
    im0a[:nocca,:nocca]+= numpy.einsum('ak,ai->ki', veff0moma[nocca:,:nocca], xmya) * .5
    im0b[:noccb,:noccb]+= numpy.einsum('ak,ai->ki', veff0momb[noccb:,:noccb], xmyb) * .5
    im0a[nocca:,nocca:] = numpy.einsum('ci,ai->ac', veff0mopa[nocca:,:nocca], xpya) * .5
    im0b[noccb:,noccb:] = numpy.einsum('ci,ai->ac', veff0mopb[noccb:,:noccb], xpyb) * .5
    im0a[nocca:,nocca:]+= numpy.einsum('ci,ai->ac', veff0moma[nocca:,:nocca], xmya) * .5
    im0b[noccb:,noccb:]+= numpy.einsum('ci,ai->ac', veff0momb[noccb:,:noccb], xmyb) * .5
    im0a[nocca:,:nocca] = numpy.einsum('ki,ai->ak', veff0mopa[:nocca,:nocca], xpya)
    im0b[noccb:,:noccb] = numpy.einsum('ki,ai->ak', veff0mopb[:noccb,:noccb], xpyb)
    im0a[nocca:,:nocca]+= numpy.einsum('ki,ai->ak', veff0moma[:nocca,:nocca], xmya)
    im0b[noccb:,:noccb]+= numpy.einsum('ki,ai->ak', veff0momb[:noccb,:noccb], xmyb)

    zeta_a = (mo_energy[0][:,None] + mo_energy[0]) * .5
    zeta_b = (mo_energy[1][:,None] + mo_energy[1]) * .5
    zeta_a[nocca:,:nocca] = mo_energy[0][:nocca]
    zeta_b[noccb:,:noccb] = mo_energy[1][:noccb]
    zeta_a[:nocca,nocca:] = mo_energy[0][nocca:]
    zeta_b[:noccb,noccb:] = mo_energy[1][noccb:]
    dm1a = numpy.zeros((nmoa,nmoa))
    dm1b = numpy.zeros((nmob,nmob))
    dm1a[:nocca,:nocca] = dooa * .5
    dm1b[:noccb,:noccb] = doob * .5
    dm1a[nocca:,nocca:] = dvva * .5
    dm1b[noccb:,noccb:] = dvvb * .5
    dm1a[nocca:,:nocca] = z1a * .5
    dm1b[noccb:,:noccb] = z1b * .5
    dm1a[:nocca,:nocca] += numpy.eye(nocca) # for ground state
    dm1b[:noccb,:noccb] += numpy.eye(noccb)
    im0a = reduce(numpy.dot, (mo_coeff[0], im0a+zeta_a*dm1a, mo_coeff[0].T))
    im0b = reduce(numpy.dot, (mo_coeff[1], im0b+zeta_b*dm1b, mo_coeff[1].T))
    im0 = im0a + im0b

    hcore_deriv = td_grad.hcore_generator(mol)
    s1 = td_grad.get_ovlp(mol)

    dmz1dooa = z1ao[0] + dmzooa
    dmz1doob = z1ao[1] + dmzoob
    oo0a = reduce(numpy.dot, (orboa, orboa.T))
    oo0b = reduce(numpy.dot, (orbob, orbob.T))
    as_dm1 = oo0a + oo0b + (dmz1dooa + dmz1doob) * .5
    vj, vk = td_grad.get_jk(mol, (oo0a, dmz1dooa+dmz1dooa.T, dmzvopa+dmzvopa.T, dmzvoma-dmzvoma.T,
                                  oo0b, dmz1doob+dmz1doob.T, dmzvopb+dmzvopb.T, dmzvomb-dmzvomb.T))
    vj = vj.reshape(2,4,3,nao,nao)
    vk = vk.reshape(2,4,3,nao,nao)
    vhf1a, vhf1b = vj[0] + vj[1] - vk
    time1 = log.timer('2e AO integral derivatives', *time1)

    if atmlst is None:
        atmlst = range(mol.natm)
    offsetdic = mol.offset_nr_by_atom()
    de = numpy.zeros((len(atmlst),3))
    for k, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        # Ground state gradients
        h1ao = hcore_deriv(ia)
        de[k] = numpy.einsum('xpq,pq->x', h1ao, as_dm1)

        de[k] += numpy.einsum('xpq,pq->x', vhf1a[0,:,p0:p1], oo0a[p0:p1])
        de[k] += numpy.einsum('xpq,pq->x', vhf1b[0,:,p0:p1], oo0b[p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', vhf1a[0,:,p0:p1], oo0a[:,p0:p1])
        de[k] += numpy.einsum('xpq,qp->x', vhf1b[0,:,p0:p1], oo0b[:,p0:p1])

        de[k] += numpy.einsum('xpq,pq->x', vhf1a[0,:,p0:p1], dmz1dooa[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,pq->x', vhf1b[0,:,p0:p1], dmz1doob[p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', vhf1a[0,:,p0:p1], dmz1dooa[:,p0:p1]) * .5
        de[k] += numpy.einsum('xpq,qp->x', vhf1b[0,:,p0:p1], dmz1doob[:,p0:p1]) * .5

        de[k] -= numpy.einsum('xpq,pq->x', s1[:,p0:p1], im0[p0:p1])
        de[k] -= numpy.einsum('xqp,pq->x', s1[:,p0:p1], im0[:,p0:p1])

        de[k] += numpy.einsum('xij,ij->x', vhf1a[1,:,p0:p1], oo0a[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', vhf1b[1,:,p0:p1], oo0b[p0:p1]) * .5
        de[k] += numpy.einsum('xij,ij->x', vhf1a[2,:,p0:p1], dmzvopa[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', vhf1b[2,:,p0:p1], dmzvopb[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', vhf1a[3,:,p0:p1], dmzvoma[p0:p1,:])
        de[k] += numpy.einsum('xij,ij->x', vhf1b[3,:,p0:p1], dmzvomb[p0:p1,:])
        de[k] += numpy.einsum('xji,ij->x', vhf1a[2,:,p0:p1], dmzvopa[:,p0:p1])
        de[k] += numpy.einsum('xji,ij->x', vhf1b[2,:,p0:p1], dmzvopb[:,p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', vhf1a[3,:,p0:p1], dmzvoma[:,p0:p1])
        de[k] -= numpy.einsum('xji,ij->x', vhf1b[3,:,p0:p1], dmzvomb[:,p0:p1])

    log.timer('TDUHF nuclear gradients', *time0)
    return de