Пример #1
0
Файл: rhf.py Проект: xlzan/pyscf
def make_h1(mf,
            mo_coeff,
            mo_occ,
            chkfile=None,
            atmlst=None,
            verbose=logger.WARN):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, mf.verbose)
    mol = mf.mol
    if atmlst is None:
        atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    mocc = mo_coeff[:, mo_occ > 0]
    dm0 = numpy.dot(mocc, mocc.T) * 2

    h1a = -(mol.intor('int1e_ipkin', comp=3) +
            mol.intor('int1e_ipnuc', comp=3))

    offsetdic = mol.offset_nr_by_atom()
    h1aos = []
    int2e_ip1 = mol._add_suffix('int2e_ip1')
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        mol.set_rinv_origin(mol.atom_coord(ia))
        h1ao = -mol.atom_charge(ia) * mol.intor('int1e_iprinv', comp=3)
        h1ao[:, p0:p1] += h1a[:, p0:p1]
        h1ao = h1ao + h1ao.transpose(0, 2, 1)

        shls_slice = (shl0, shl1) + (0, mol.nbas) * 3
        vj1, vj2, vk1, vk2 = \
                _vhf.direct_bindm(int2e_ip1, 's2kl',
                                  ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'),
                                  (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0),
                                  3, mol._atm, mol._bas, mol._env,
                                  shls_slice=shls_slice)
        for i in range(3):
            lib.hermi_triu(vj1[i], 1)
        vhf = vj1 - vk1 * .5
        vhf[:, p0:p1] += vj2 - vk2 * .5
        vhf = vhf + vhf.transpose(0, 2, 1)

        if chkfile is None:
            h1aos.append(h1ao + vhf)
        else:
            key = 'scf_h1ao/%d' % ia
            lib.chkfile.save(chkfile, key, h1ao + vhf)
    if chkfile is None:
        return h1aos
    else:
        return chkfile
Пример #2
0
 def test_direct_bindm(self):
     numpy.random.seed(1)
     dm = numpy.random.random((nao, nao))
     vj0, vk0 = _vhf.direct_mapdm('int2e_ip1_sph', 's2kl',
                                  ('lk->s1ij', 'jk->s1il'), dm, 3, mol._atm,
                                  mol._bas, mol._env)
     dms = (dm, dm)
     vj1, vk1 = _vhf.direct_bindm('int2e_ip1_sph', 's2kl',
                                  ('lk->s1ij', 'jk->s1il'), dms, 3,
                                  mol._atm, mol._bas, mol._env)
     self.assertTrue(numpy.allclose(vj0, vj1))
     self.assertTrue(numpy.allclose(vk0, vk1))
Пример #3
0
 def test_direct_bindm(self):
     numpy.random.seed(1)
     dm = numpy.random.random((nao,nao))
     vj0, vk0 = _vhf.direct_mapdm('cint2e_ip1_sph', 's2kl',
                                  ('lk->s1ij', 'jk->s1il'),
                                  dm, 3, mol._atm, mol._bas, mol._env)
     dms = (dm,dm)
     vj1, vk1 = _vhf.direct_bindm('cint2e_ip1_sph', 's2kl',
                                  ('lk->s1ij', 'jk->s1il'),
                                  dms, 3, mol._atm, mol._bas, mol._env)
     self.assertTrue(numpy.allclose(vj0,vj1))
     self.assertTrue(numpy.allclose(vk0,vk1))
Пример #4
0
 def test_direct_bindm1(self):
     numpy.random.seed(1)
     nao = mol.nao_nr(cart=True)
     dm = numpy.random.random((nao,nao))
     vhfopt = _vhf.VHFOpt(mol, 'int2e_cart', 'CVHFnrs8_prescreen',
                          'CVHFsetnr_direct_scf',
                          'CVHFsetnr_direct_scf_dm')
     vj0, vk0 = _vhf.direct(dm, mol._atm, mol._bas, mol._env,
                            vhfopt=vhfopt, hermi=0, cart=True)
     vj = _vhf.direct_bindm('int2e_cart', 's1', 'kl->s1ij', dm, 1,
                            mol._atm, mol._bas, mol._env, vhfopt)
     self.assertTrue(numpy.allclose(vj0,vj))
Пример #5
0
def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, mf.verbose)
    mol = mf.mol
    if atmlst is None:
        atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    mocc = mo_coeff[:,mo_occ>0]
    dm0 = numpy.dot(mocc, mocc.T) * 2

    h1a =-(mol.intor('cint1e_ipkin_sph', comp=3) +
           mol.intor('cint1e_ipnuc_sph', comp=3))

    offsetdic = mol.offset_nr_by_atom()
    h1aos = []
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        mol.set_rinv_origin(mol.atom_coord(ia))
        h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3)
        h1ao[:,p0:p1] += h1a[:,p0:p1]
        h1ao = h1ao + h1ao.transpose(0,2,1)

        shls_slice = (shl0, shl1) + (0, mol.nbas)*3
        vj1, vj2, vk1, vk2 = \
                _vhf.direct_bindm('cint2e_ip1_sph', 's2kl',
                                  ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'),
                                  (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0),
                                  3, mol._atm, mol._bas, mol._env,
                                  shls_slice=shls_slice)
        for i in range(3):
            lib.hermi_triu(vj1[i], 1)
        vhf = vj1 - vk1*.5
        vhf[:,p0:p1] += vj2 - vk2*.5
        vhf = vhf + vhf.transpose(0,2,1)

        if chkfile is None:
            h1aos.append(h1ao+vhf)
        else:
            key = 'scf_h1ao/%d' % ia
            lib.chkfile.save(chkfile, key, h1ao+vhf)
    if chkfile is None:
        return h1aos
    else:
        return chkfile
Пример #6
0
def _get_jk(mol,
            intor,
            comp,
            aosym,
            script_dms,
            shls_slice=None,
            cintopt=None,
            vhfopt=None):
    intor = mol._add_suffix(intor)
    scripts = script_dms[::2]
    dms = script_dms[1::2]
    vs = _vhf.direct_bindm(intor,
                           aosym,
                           scripts,
                           dms,
                           comp,
                           mol._atm,
                           mol._bas,
                           mol._env,
                           vhfopt=vhfopt,
                           cintopt=cintopt,
                           shls_slice=shls_slice)
    for k, script in enumerate(scripts):
        if 's2' in script:
            hermi = 1
        elif 'a2' in script:
            hermi = 2
        else:
            continue

        shape = vs[k].shape
        if shape[-2] == shape[-1]:
            if comp > 1:
                for i in range(comp):
                    lib.hermi_triu(vs[k][i], hermi=hermi, inplace=True)
            else:
                lib.hermi_triu(vs[k], hermi=hermi, inplace=True)
    return vs
Пример #7
0
def _get_jk(mol, intor, comp, aosym, script_dms,
            shls_slice=None, cintopt=None):
    intor = mol._add_suffix(intor)
    scripts = script_dms[::2]
    dms = script_dms[1::2]
    vs = _vhf.direct_bindm(intor, aosym, scripts, dms, comp,
                           mol._atm, mol._bas, mol._env,
                           cintopt=cintopt, shls_slice=shls_slice)
    for k, script in enumerate(scripts):
        if 's2' in script:
            hermi = 1
        elif 'a2' in script:
            hermi = 2
        else:
            continue

        shape = vs[k].shape
        if shape[-2] == shape[-1]:
            if comp > 1:
                for i in range(comp):
                    lib.hermi_triu(vs[k][i], hermi=hermi, inplace=True)
            else:
                lib.hermi_triu(vs[k], hermi=hermi, inplace=True)
    return vs
Пример #8
0
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None,
              atmlst=None, max_memory=4000, verbose=None):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(hess_mf.stdout, hess_mf.verbose)

    time0 = (time.clock(), time.time())

    mf = hess_mf._scf
    mol = hess_mf.mol
    if mo_energy is None: mo_energy = mf.mo_energy
    if mo_occ is None:    mo_occ = mf.mo_occ
    if mo_coeff is None:  mo_coeff = mf.mo_coeff
    if atmlst is None: atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    mocc = mo_coeff[:,mo_occ>0]
    nocc = mocc.shape[1]
    dm0 = numpy.dot(mocc, mocc.T) * 2

    h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log)
    t1 = log.timer('making H1', *time0)
    mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos,
                                  None, atmlst, max_memory, log)
    t1 = log.timer('solving MO1', *t1)

    tmpf = tempfile.NamedTemporaryFile(dir=lib.param.TMPDIR)
    with h5py.File(tmpf.name, 'w') as f:
        for i0, ia in enumerate(atmlst):
            mol.set_rinv_origin(mol.atom_coord(ia))
            f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_ipiprinv_sph', comp=9))
            f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_iprinvip_sph', comp=9))

    h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) +
           mol.intor('cint1e_ipipnuc_sph', comp=9))
    h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) +
           mol.intor('cint1e_ipnucip_sph', comp=9))
    s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9)
    s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9)
    s1a =-mol.intor('cint1e_ipovlp_sph', comp=3)

    # Energy weighted density matrix
    dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2

    vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl',
                                 ('lk->s1ij', 'jk->s1il'), dm0, 9,
                                 mol._atm, mol._bas, mol._env)
    vhf1ii = vj1 - vk1*.5
    vj1 = vk1 = None
    t1 = log.timer('contracting cint2e_ipip1_sph', *t1)

    offsetdic = mol.offset_nr_by_atom()
    frinv = h5py.File(tmpf.name, 'r')
    rinv2aa = frinv['rinv2aa']
    rinv2ab = frinv['rinv2ab']

    de2 = numpy.zeros((mol.natm,mol.natm,3,3))
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1)
        h_2[:,p0:p1] += h1ab[:,p0:p1]
        s1ao = numpy.zeros((3,nao,nao))
        s1ao[:,p0:p1] += s1a[:,p0:p1]
        s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1)
        s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc)

        shls_slice = (shl0, shl1) + (0, mol.nbas)*3
        vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1',
                                          ('ji->s1kl', 'li->s1kj', 'lj->s1ki'),
                                          (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9,
                                          mol._atm, mol._bas, mol._env,
                                          shls_slice=shls_slice)
        vhf2 = vj1 * 2 - vk1 * .5
        vhf2[:,:,p0:p1] -= vk2 * .5
        t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1)

        vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl',
                                     ('lk->s1ij', 'li->s1kj'),
                                     (dm0, dm0[:,p0:p1]), 9,
                                     mol._atm, mol._bas, mol._env,
                                     shls_slice=shls_slice)
        vhf2[:,:,p0:p1] += vj1.transpose(0,2,1)
        vhf2 -= vk1.transpose(0,2,1) * .5
        vj1 = vk1 = vk2 = None
        t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1)

        for j0, ja in enumerate(atmlst):
            q0, q1 = offsetdic[ja][2:]
# *2 for double occupancy, *2 for +c.c.
            mo1  = lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja)
            h1ao = lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia)
            dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc)
            de  = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4
            dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc])
            de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4
            de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2

            de = de.reshape(-1)
            v2aa = rinv2aa[str(ja)].value
            v2ab = rinv2ab[str(ja)].value
            de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2
            de += numpy.einsum('xpq,pq->x', vhf2[:,q0:q1], dm0[q0:q1])*2
            de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2

            if ia == ja:
                de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2
                de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2
                de += numpy.einsum('xpq,pq->x', vhf1ii[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2

            de2[i0,j0] = de.reshape(3,3)

    frinv.close()
    log.timer('RHF hessian', *time0)
    return de2
Пример #9
0
def get_jk(mols, dms, scripts=['ijkl,ji->kl'], intor='int2e_sph',
           aosym='s1', comp=1, hermi=0, shls_slice=None, verbose=logger.WARN):
    '''Compute J/K matrices for the given density matrix

    Args:
        mols : an instance of :class:`Mole` or a list of `Mole` objects

        dms : ndarray or list of ndarrays
            A density matrix or a list of density matrices

    Kwargs:
        hermi : int
            Whether J/K matrix is hermitian

            | 0 : no hermitian or symmetric
            | 1 : hermitian
            | 2 : anti-hermitian

        intor : str
            2-electron integral name.  See :func:`getints` for the complete
            list of available 2-electron integral names
        aosym : int or str
            Permutation symmetry for the AO integrals

            | 4 or '4' or 's4': 4-fold symmetry (default)
            | '2ij' or 's2ij' : symmetry between i, j in (ij|kl)
            | '2kl' or 's2kl' : symmetry between k, l in (ij|kl)
            | 1 or '1' or 's1': no symmetry
            | 'a4ij' : 4-fold symmetry with anti-symmetry between i, j in (ij|kl)
            | 'a4kl' : 4-fold symmetry with anti-symmetry between k, l in (ij|kl)
            | 'a2ij' : anti-symmetry between i, j in (ij|kl)
            | 'a2kl' : anti-symmetry between k, l in (ij|kl)

        comp : int
            Components of the integrals, e.g. cint2e_ip_sph has 3 components.
        scripts : a list of strings
            Contraction description (following numpy.einsum convention) based on
            letters [ijkl].  Each script will be one-to-one applied to each
            entry of dms.  So it must have the same number of elements as the
            dms, len(scripts) == len(dms).
        shls_slice : 8-element list
            (ish_start, ish_end, jsh_start, jsh_end, ksh_start, ksh_end, lsh_start, lsh_end)

    Returns:
        Depending on the number of density matrices, the function returns one
        J/K matrix or a list of J/K matrices (the same number of entries as the
        input dms).
        Each JK matrices may be a 2D array or 3D array if the AO integral
        has multiple components.

    Examples:

    >>> from pyscf import gto
    >>> mol = gto.M(atom='H 0 -.5 0; H 0 .5 0', basis='cc-pvdz')
    >>> nao = mol.nao_nr()
    >>> dm = numpy.random.random((nao,nao))
    >>> # Default, Coulomb matrix
    >>> vj = get_jk(mol, dm)
    >>> # Coulomb matrix with 8-fold permutation symmetry for AO integrals
    >>> vj = get_jk(mol, dm, 'ijkl,ji->kl', aosym='s8')
    >>> # Exchange matrix with 8-fold permutation symmetry for AO integrals
    >>> vk = get_jk(mol, dm, 'ijkl,jk->il', aosym='s8')
    >>> # Compute coulomb and exchange matrices together
    >>> vj, vk = get_jk(mol, (dm,dm), ('ijkl,ji->kl','ijkl,li->kj'), aosym='s8')
    >>> # Analytical gradients for coulomb matrix
    >>> j1 = get_jk(mol, dm, 'ijkl,lk->ij', intor='int2e_ip1_sph', aosym='s2kl', comp=3)

    >>> # contraction across two molecules
    >>> mol1 = gto.M(atom='He 2 0 0', basis='6-31g')
    >>> nao1 = mol1.nao_nr()
    >>> dm1 = numpy.random.random((nao1,nao1))
    >>> # Coulomb interaction between two molecules, note 4-fold symmetry can be applied
    >>> jcross = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', aosym='s4')
    >>> ecoul = numpy.einsum('ij,ij', jcross, dm1)
    >>> # Exchange interaction between two molecules, no symmetry can be used
    >>> kcross = get_jk((mol1,mol,mol,mol1), dm, scripts='ijkl,jk->il')
    >>> ex = numpy.einsum('ij,ji', kcross, dm1)

    >>> # Analytical gradients for coulomb matrix between two molecules
    >>> jcros1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='int2e_ip1_sph', comp=3)
    >>> # Analytical gradients for coulomb interaction between 1s density and the other molecule
    >>> jpart1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='int2e_ip1_sph', comp=3,
    ...                 shls_slice=(0,1,0,1,0,mol.nbas,0,mol.nbas))
    '''
    if isinstance(mols, (tuple, list)):
        assert(len(mols) == 4)
        assert(mols[0].cart == mols[1].cart == mols[2].cart == mols[3].cart)
        if shls_slice is None:
            shls_slice = numpy.array([(0, mol.nbas) for mol in mols])
        else:
            shls_slice = numpy.asarray(shls_slice).reshape(4,2)
# concatenate unique mols and build corresponding shls_slice
        mol_ids = [id(mol) for mol in mols]
        atm, bas, env = mols[0]._atm, mols[0]._bas, mols[0]._env
        bas_start = numpy.zeros(4, dtype=int)
        for m in range(1,4):
            first = mol_ids.index(mol_ids[m])
            if first == m:  # the unique mol
                bas_start[m] = bas.shape[0]
                atm, bas, env = gto.conc_env(atm, bas, env, mols[m]._atm,
                                             mols[m]._bas, mols[m]._env)
            else:
                bas_start[m] = bas_start[first]
            shls_slice[m] += bas_start[m]
        shls_slice = shls_slice.flatten()
    else:
        atm, bas, env = mols._atm, mols._bas, mols._env
        if shls_slice is None:
            shls_slice = (0, mols.nbas) * 4

    if isinstance(scripts, str):
        scripts = [scripts]
    if isinstance(dms, numpy.ndarray) and dms.ndim == 2:
        dms = [dms]
    assert(len(scripts) == len(dms))

    #format scripts
    descript = []
    for script in scripts:
        dmsym, vsym = script.lower().split(',')[1].split('->')
        if hermi == 0:
            descript.append('->'.join((dmsym,'s1'+vsym)))
        else:
            descript.append('->'.join((dmsym,'s2'+vsym)))

    vs = _vhf.direct_bindm(intor, aosym, descript, dms, comp, atm, bas, env,
                           shls_slice=shls_slice)
    if hermi != 0:
        for v in vs:
            if v.ndim == 3:
                for vi in v:
                    pyscf.lib.hermi_triu(vi, hermi, inplace=True)
            else:
                pyscf.lib.hermi_triu(v, hermi, inplace=True)
    return vs
Пример #10
0
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None,
              atmlst=None, max_memory=4000, verbose=None):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(hess_mf.stdout, hess_mf.verbose)

    time0 = (time.clock(), time.time())

    mf = hess_mf._scf
    mol = hess_mf.mol
    if mo_energy is None: mo_energy = mf.mo_energy
    if mo_occ is None:    mo_occ = mf.mo_occ
    if mo_coeff is None:  mo_coeff = mf.mo_coeff
    if atmlst is None: atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    mocc = mo_coeff[:,mo_occ>0]
    nocc = mocc.shape[1]
    dm0 = numpy.dot(mocc, mocc.T) * 2

    h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log)
    t1 = log.timer('making H1', *time0)
    mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos,
                                  None, atmlst, max_memory, log)
    t1 = log.timer('solving MO1', *t1)

    tmpf = tempfile.NamedTemporaryFile()
    with h5py.File(tmpf.name, 'w') as f:
        for i0, ia in enumerate(atmlst):
            mol.set_rinv_origin(mol.atom_coord(ia))
            f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_ipiprinv_sph', comp=9))
            f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_iprinvip_sph', comp=9))

    h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) +
           mol.intor('cint1e_ipipnuc_sph', comp=9))
    h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) +
           mol.intor('cint1e_ipnucip_sph', comp=9))
    s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9)
    s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9)
    s1a =-mol.intor('cint1e_ipovlp_sph', comp=3)

    # Energy weighted density matrix
    dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2

    vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl',
                                 ('lk->s1ij', 'jk->s1il'), dm0, 9,
                                 mol._atm, mol._bas, mol._env)
    vhf1ii = vj1 - vk1*.5
    vj1 = vk1 = None
    t1 = log.timer('contracting cint2e_ipip1_sph', *t1)

    offsetdic = mol.offset_nr_by_atom()
    frinv = h5py.File(tmpf.name, 'r')
    rinv2aa = frinv['rinv2aa']
    rinv2ab = frinv['rinv2ab']

    de2 = numpy.zeros((mol.natm,mol.natm,3,3))
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1)
        h_2[:,p0:p1] += h1ab[:,p0:p1]
        s1ao = numpy.zeros((3,nao,nao))
        s1ao[:,p0:p1] += s1a[:,p0:p1]
        s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1)
        s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc)

        shls_slice = (shl0, shl1) + (0, mol.nbas)*3
        vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1',
                                          ('ji->s1kl', 'li->s1kj', 'lj->s1ki'),
                                          (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9,
                                          mol._atm, mol._bas, mol._env,
                                          shls_slice=shls_slice)
        vhf2 = vj1 * 2 - vk1 * .5
        vhf2[:,:,p0:p1] -= vk2 * .5
        t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1)

        vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl',
                                     ('lk->s1ij', 'li->s1kj'),
                                     (dm0, dm0[:,p0:p1]), 9,
                                     mol._atm, mol._bas, mol._env,
                                     shls_slice=shls_slice)
        vhf2[:,:,p0:p1] += vj1.transpose(0,2,1)
        vhf2 -= vk1.transpose(0,2,1) * .5
        vj1 = vk1 = vk2 = None
        t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1)

        for j0, ja in enumerate(atmlst):
            q0, q1 = offsetdic[ja][2:]
# *2 for double occupancy, *2 for +c.c.
            mo1  = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja)
            h1ao = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia)
            dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc)
            de  = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4
            dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc])
            de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4
            de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2

            de = de.reshape(-1)
            v2aa = rinv2aa[str(ja)].value
            v2ab = rinv2ab[str(ja)].value
            de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2
            de += numpy.einsum('xpq,pq->x', vhf2[:,q0:q1], dm0[q0:q1])*2
            de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2

            if ia == ja:
                de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2
                de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2
                de += numpy.einsum('xpq,pq->x', vhf1ii[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2

            de2[i0,j0] = de.reshape(3,3)

    frinv.close()
    log.timer('RHF hessian', *time0)
    return de2
Пример #11
0
def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, mf.verbose)
    mol = mf.mol
    if atmlst is None:
        atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    mocc = mo_coeff[:,mo_occ>0]
    dm0 = numpy.dot(mocc, mocc.T) * 2

    ni = copy.copy(mf._numint)
    if USE_XCFUN:
        try:
            ni.libxc = dft.xcfun
            xctype = ni._xc_type(mf.xc)
        except (ImportError, KeyError, NotImplementedError):
            ni.libxc = dft.libxc
            xctype = ni._xc_type(mf.xc)
    else:
        xctype = ni._xc_type(mf.xc)
    grids = mf.grids
    hyb = ni.libxc.hybrid_coeff(mf.xc)
    max_memory = 4000

    h1a =-(mol.intor('cint1e_ipkin_sph', comp=3) +
           mol.intor('cint1e_ipnuc_sph', comp=3))

    offsetdic = mol.offset_nr_by_atom()
    h1aos = []
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        mol.set_rinv_origin(mol.atom_coord(ia))
        h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3)
        h1ao[:,p0:p1] += h1a[:,p0:p1]
        h1ao = h1ao + h1ao.transpose(0,2,1)

        shls_slice = (shl0, shl1) + (0, mol.nbas)*3
        if abs(hyb) > 1e-10:
            vj1, vj2, vk1, vk2 = \
                    _vhf.direct_bindm('cint2e_ip1_sph', 's2kl',
                                      ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'),
                                      (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0),
                                      3, mol._atm, mol._bas, mol._env,
                                      shls_slice=shls_slice)
            for i in range(3):
                pyscf.lib.hermi_triu(vj1[i], 1)
            veff = vj1 - hyb*.5*vk1
            veff[:,p0:p1] += vj2 - hyb*.5*vk2
        else:
            vj1, vj2 = \
                    _vhf.direct_bindm('cint2e_ip1_sph', 's2kl',
                                      ('ji->s2kl', 'lk->s1ij'),
                                      (-dm0[:,p0:p1], -dm0),
                                      3, mol._atm, mol._bas, mol._env,
                                      shls_slice=shls_slice)
            for i in range(3):
                pyscf.lib.hermi_triu(vj1[i], 1)
            veff = vj1
            veff[:,p0:p1] += vj2

        if xctype == 'LDA':
            ao_deriv = 1
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho = vxc[0]
                frr = fxc[0]
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half)
                aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1)
                aow1 = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho)
                aow[:,:,p0:p1] += aow1
                veff[0] += pyscf.lib.dot(-aow[0].T, ao[0])
                veff[1] += pyscf.lib.dot(-aow[1].T, ao[0])
                veff[2] += pyscf.lib.dot(-aow[2].T, ao[0])
                half = aow = aow1 = None

        elif xctype == 'GGA':
            def get_wv(rho, rho1, weight, vxc, fxc):
                vgamma = vxc[1]
                frr, frg, fgg = fxc[:3]
                ngrid = weight.size
                sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:])
                wv = numpy.empty((4,ngrid))
                wv[0]  = frr * rho1[0]
                wv[0] += frg * sigma1 * 2
                wv[1:]  = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:]
                wv[1:] += vgamma * rho1[1:] * 2
                wv *= weight
                return wv
            ao_deriv = 2
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho, vgamma = vxc[:2]
                # (d_X \nabla_x mu) nu DM_{mu,nu}
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half)
                rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half)
                rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half)
                # (d_X mu) (\nabla_x nu) DM_{mu,nu}
                half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy())
                rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy())
                rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy())
                rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)

                wv = get_wv(rho, rho1X, weight, vxc, fxc)
                wv[0] *= .5
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[0] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0]))
                wv = get_wv(rho, rho1Y, weight, vxc, fxc)
                wv[0] *= .5
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[1] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0]))
                wv = get_wv(rho, rho1Z, weight, vxc, fxc)
                wv[0] *= .5
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[2] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0]))

                wv = numpy.empty_like(rho)
                wv[0]  = weight * vrho
                wv[1:] = rho[1:] * (weight * vgamma * 2)
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[0,p0:p1] -= pyscf.lib.dot(ao[1,:,p0:p1].T.copy(), aow)
                veff[1,p0:p1] -= pyscf.lib.dot(ao[2,:,p0:p1].T.copy(), aow)
                veff[2,p0:p1] -= pyscf.lib.dot(ao[3,:,p0:p1].T.copy(), aow)

                aow = numpy.einsum('npi,np->pi', ao[[XX,XY,XZ],:,p0:p1], wv[1:4])
                veff[0,p0:p1] -= pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[YX,YY,YZ],:,p0:p1], wv[1:4])
                veff[1,p0:p1] -= pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[ZX,ZY,ZZ],:,p0:p1], wv[1:4])
                veff[2,p0:p1] -= pyscf.lib.dot(aow.T, ao[0])
        else:
            raise NotImplementedError('meta-GGA')

        veff = veff + veff.transpose(0,2,1)

        if chkfile is None:
            h1aos.append(h1ao+veff)
        else:
            key = 'scf_h1ao/%d' % ia
            pyscf.lib.chkfile.save(chkfile, key, h1ao+veff)
    if chkfile is None:
        return h1aos
    else:
        return chkfile
Пример #12
0
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None,
              atmlst=None, max_memory=4000, verbose=None):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(hess_mf.stdout, hess_mf.verbose)

    time0 = (time.clock(), time.time())

    mf = hess_mf._scf
    mol = hess_mf.mol
    if mo_energy is None: mo_energy = mf.mo_energy
    if mo_occ is None:    mo_occ = mf.mo_occ
    if mo_coeff is None:  mo_coeff = mf.mo_coeff
    if atmlst is None: atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    nocc = int(mo_occ.sum()) // 2
    mocc = mo_coeff[:,:nocc]
    dm0 = mf.make_rdm1(mo_coeff, mo_occ)

    ni = copy.copy(mf._numint)
    if USE_XCFUN:
        try:
            ni.libxc = dft.xcfun
            xctype = ni._xc_type(mf.xc)
        except (ImportError, KeyError, NotImplementedError):
            ni.libxc = dft.libxc
            xctype = ni._xc_type(mf.xc)
    else:
        xctype = ni._xc_type(mf.xc)
    grids = mf.grids
    hyb = ni.libxc.hybrid_coeff(mf.xc)
    max_memory = 4000

    h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log)
    t1 = log.timer('making H1', *time0)
    def fx(mo1):
        # *2 for alpha + beta
        dm1 = numpy.einsum('xai,pa,qi->xpq', mo1, mo_coeff, mocc*2)
        dm1 = dm1 + dm1.transpose(0,2,1)
        vindxc = _contract_xc_kernel(mf, mf.xc, dm1, max_memory)
        if abs(hyb) > 1e-10:
            vj, vk = mf.get_jk(mol, dm1)
            veff = vj - hyb * .5 * vk + vindxc
        else:
            vj = mf.get_j(mol, dm1)
            veff = vj + vindxc
        v1 = numpy.einsum('xpq,pa,qi->xai', veff, mo_coeff, mocc)
        return v1.reshape(v1.shape[0],-1)
    mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos,
                                  fx, atmlst, max_memory, log)
    t1 = log.timer('solving MO1', *t1)

    tmpf = tempfile.NamedTemporaryFile()
    with h5py.File(tmpf.name, 'w') as f:
        for i0, ia in enumerate(atmlst):
            mol.set_rinv_origin(mol.atom_coord(ia))
            f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_ipiprinv_sph', comp=9))
            f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_iprinvip_sph', comp=9))

    h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) +
           mol.intor('cint1e_ipipnuc_sph', comp=9))
    h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) +
           mol.intor('cint1e_ipnucip_sph', comp=9))
    s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9)
    s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9)
    s1a =-mol.intor('cint1e_ipovlp_sph', comp=3)

    # Energy weighted density matrix
    dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2

    if abs(hyb) > 1e-10:
        vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl',
                                     ('lk->s1ij', 'jk->s1il'), dm0, 9,
                                     mol._atm, mol._bas, mol._env)
        veff1ii = vj1 - hyb * .5 * vk1
    else:
        vj1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', 'lk->s1ij', dm0, 9,
                                mol._atm, mol._bas, mol._env)
        veff1ii = vj1.copy()
    vj1[:] = 0
    if xctype == 'LDA':
        ao_deriv = 2
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
            rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA')
            vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1]
            vrho = vxc[0]
            aow = numpy.einsum('pi,p->pi', ao[0], weight*vrho)
            for i in range(6):
                vj1[i] += pyscf.lib.dot(ao[i+4].T, aow)
            aow = aow1 = None
    elif xctype == 'GGA':
        ao_deriv = 3
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
            rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA')
            vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1]
            vrho, vgamma = vxc[:2]
            wv = numpy.empty_like(rho)
            wv[0]  = weight * vrho
            wv[1:] = rho[1:] * (weight * vgamma * 2)
            aow = numpy.einsum('npi,np->pi', ao[:4], wv)
            for i in range(6):
                vj1[i] += pyscf.lib.dot(ao[i+4].T, aow)
            aow = numpy.einsum('npi,np->pi', ao[[XXX,XXY,XXZ]], wv[1:4])
            vj1[0] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XXY,XYY,XYZ]], wv[1:4])
            vj1[1] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XXZ,XYZ,XZZ]], wv[1:4])
            vj1[2] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XYY,YYY,YYZ]], wv[1:4])
            vj1[3] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XYZ,YYZ,YZZ]], wv[1:4])
            vj1[4] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XZZ,YZZ,ZZZ]], wv[1:4])
            vj1[5] += pyscf.lib.dot(aow.T, ao[0])
            rho = vxc = vrho = vgamma = wv = aow = None
    else:
        raise NotImplementedError('meta-GGA')
    veff1ii += vj1[[0,1,2,1,3,4,2,4,5]]
    vj1 = vk1 = None

    t1 = log.timer('contracting cint2e_ipip1_sph', *t1)

    offsetdic = mol.offset_nr_by_atom()
    frinv = h5py.File(tmpf.name, 'r')
    rinv2aa = frinv['rinv2aa']
    rinv2ab = frinv['rinv2ab']

    de2 = numpy.zeros((mol.natm,mol.natm,3,3))
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1)
        h_2[:,p0:p1] += h1ab[:,p0:p1]
        s1ao = numpy.zeros((3,nao,nao))
        s1ao[:,p0:p1] += s1a[:,p0:p1]
        s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1)
        s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc)

        shls_slice = (shl0, shl1) + (0, mol.nbas)*3
        if abs(hyb) > 1e-10:
            vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1',
                                              ('ji->s1kl', 'li->s1kj', 'lj->s1ki'),
                                              (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9,
                                              mol._atm, mol._bas, mol._env,
                                              shls_slice=shls_slice)
            veff2 = vj1 * 2 - hyb * .5 * vk1
            veff2[:,:,p0:p1] -= hyb * .5 * vk2
            t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1)

            vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl',
                                         ('lk->s1ij', 'li->s1kj'),
                                         (dm0, dm0[:,p0:p1]), 9,
                                         mol._atm, mol._bas, mol._env,
                                         shls_slice=shls_slice)
            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)
            veff2 -= hyb * .5 * vk1.transpose(0,2,1)
            vj1 = vk1 = vk2 = None
            t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1)
        else:
            vj1 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1',
                                    'ji->s1kl', dm0[:,p0:p1], 9,
                                    mol._atm, mol._bas, mol._env,
                                    shls_slice=shls_slice)
            veff2 = vj1 * 2
            t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1)

            vj1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl',
                                    'lk->s1ij', dm0, 9,
                                    mol._atm, mol._bas, mol._env,
                                    shls_slice=shls_slice)
            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)
            t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1)

        if xctype == 'LDA':
            ao_deriv = 1
            vj1[:] = 0
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho = vxc[0]
                frr = fxc[0]
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half)
                aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1)
                veff2[0] += pyscf.lib.dot(ao[1].T, aow[0]) * 2
                veff2[1] += pyscf.lib.dot(ao[1].T, aow[1]) * 2
                veff2[2] += pyscf.lib.dot(ao[1].T, aow[2]) * 2
                veff2[3] += pyscf.lib.dot(ao[2].T, aow[0]) * 2
                veff2[4] += pyscf.lib.dot(ao[2].T, aow[1]) * 2
                veff2[5] += pyscf.lib.dot(ao[2].T, aow[2]) * 2
                veff2[6] += pyscf.lib.dot(ao[3].T, aow[0]) * 2
                veff2[7] += pyscf.lib.dot(ao[3].T, aow[1]) * 2
                veff2[8] += pyscf.lib.dot(ao[3].T, aow[2]) * 2
                aow = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho)
                vj1[0] += pyscf.lib.dot(aow[0].T, ao[1])
                vj1[1] += pyscf.lib.dot(aow[0].T, ao[2])
                vj1[2] += pyscf.lib.dot(aow[0].T, ao[3])
                vj1[3] += pyscf.lib.dot(aow[1].T, ao[1])
                vj1[4] += pyscf.lib.dot(aow[1].T, ao[2])
                vj1[5] += pyscf.lib.dot(aow[1].T, ao[3])
                vj1[6] += pyscf.lib.dot(aow[2].T, ao[1])
                vj1[7] += pyscf.lib.dot(aow[2].T, ao[2])
                vj1[8] += pyscf.lib.dot(aow[2].T, ao[3])
                half = aow = None

            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)

        elif xctype == 'GGA':
            def get_wv(rho, rho1, weight, vxc, fxc):
                vgamma = vxc[1]
                frr, frg, fgg = fxc[:3]
                ngrid = weight.size
                sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:])
                wv = numpy.empty((4,ngrid))
                wv[0]  = frr * rho1[0]
                wv[0] += frg * sigma1 * 2
                wv[1:]  = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:]
                wv[1:] += vgamma * rho1[1:] * 2
                wv *= weight
                return wv
            ao_deriv = 2
            vj1[:] = 0
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho, vgamma = vxc[:2]
                # (d_X \nabla_x mu) nu DM_{mu,nu}
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half)
                rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half)
                rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half)
                # (d_X mu) (\nabla_x nu) DM_{mu,nu}
                half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy())
                rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy())
                rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy())
                rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)

                wv = get_wv(rho, rho1X, weight, vxc, fxc) * 2  # ~ vj1*2
                aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)  # dX
                veff2[0] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)  # dY
                veff2[3] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)  # dZ
                veff2[6] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4])
                veff2[0] += pyscf.lib.dot(ao[1].T, aow)
                veff2[3] += pyscf.lib.dot(ao[2].T, aow)
                veff2[6] += pyscf.lib.dot(ao[3].T, aow)
                wv = get_wv(rho, rho1Y, weight, vxc, fxc) * 2
                aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)
                veff2[1] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)
                veff2[4] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)
                veff2[7] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4])
                veff2[1] += pyscf.lib.dot(ao[1].T, aow)
                veff2[4] += pyscf.lib.dot(ao[2].T, aow)
                veff2[7] += pyscf.lib.dot(ao[3].T, aow)
                wv = get_wv(rho, rho1Z, weight, vxc, fxc) * 2
                aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)
                veff2[2] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)
                veff2[5] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)
                veff2[8] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4])
                veff2[2] += pyscf.lib.dot(ao[1].T, aow)
                veff2[5] += pyscf.lib.dot(ao[2].T, aow)
                veff2[8] += pyscf.lib.dot(ao[3].T, aow)

                wv = numpy.empty_like(rho)
                wv[0]  = weight * vrho * .5
                wv[1:] = rho[1:] * (weight * vgamma * 2)
                aowx = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)
                aowy = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)
                aowz = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)
                ao1 = aowx[:,p0:p1].T.copy()
                ao2 = aowy[:,p0:p1].T.copy()
                ao3 = aowz[:,p0:p1].T.copy()
                vj1[0] += pyscf.lib.dot(ao1, ao[1])
                vj1[1] += pyscf.lib.dot(ao1, ao[2])
                vj1[2] += pyscf.lib.dot(ao1, ao[3])
                vj1[3] += pyscf.lib.dot(ao2, ao[1])
                vj1[4] += pyscf.lib.dot(ao2, ao[2])
                vj1[5] += pyscf.lib.dot(ao2, ao[3])
                vj1[6] += pyscf.lib.dot(ao3, ao[1])
                vj1[7] += pyscf.lib.dot(ao3, ao[2])
                vj1[8] += pyscf.lib.dot(ao3, ao[3])
                ao1 = ao[1,:,p0:p1].T.copy()
                ao2 = ao[2,:,p0:p1].T.copy()
                ao3 = ao[3,:,p0:p1].T.copy()
                vj1[0] += pyscf.lib.dot(ao1, aowx)
                vj1[1] += pyscf.lib.dot(ao1, aowy)
                vj1[2] += pyscf.lib.dot(ao1, aowz)
                vj1[3] += pyscf.lib.dot(ao2, aowx)
                vj1[4] += pyscf.lib.dot(ao2, aowy)
                vj1[5] += pyscf.lib.dot(ao2, aowz)
                vj1[6] += pyscf.lib.dot(ao3, aowx)
                vj1[7] += pyscf.lib.dot(ao3, aowy)
                vj1[8] += pyscf.lib.dot(ao3, aowz)

            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)

        else:
            raise NotImplementedError('meta-GGA')

        for j0, ja in enumerate(atmlst):
            q0, q1 = offsetdic[ja][2:]
# *2 for double occupancy, *2 for +c.c.
            mo1  = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja)
            h1ao = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia)
            dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc)
            de  = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4
            dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc])
            de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4
            de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2

            de = de.reshape(-1)
            v2aa = rinv2aa[str(ja)].value
            v2ab = rinv2ab[str(ja)].value
            de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2
            de += numpy.einsum('xpq,pq->x', veff2[:,q0:q1], dm0[q0:q1])*2
            de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2

            if ia == ja:
                de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2
                de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2
                de += numpy.einsum('xpq,pq->x', veff1ii[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2

            de2[i0,j0] = de.reshape(3,3)

    frinv.close()
    log.timer('RHF hessian', *time0)
    return de2
Пример #13
0
Файл: jk.py Проект: eronca/pyscf
def get_jk(mols, dms, scripts=['ijkl,ji->kl'], intor='cint2e_sph',
           aosym='s1', comp=1, hermi=0, shls_slice=None, verbose=logger.WARN):
    '''Compute J/K matrices for the given density matrix

    Args:
        mols : an instance of :class:`Mole` or a list of `Mole` objects

        dms : ndarray or list of ndarrays
            A density matrix or a list of density matrices

    Kwargs:
        hermi : int
            Whether J/K matrix is hermitian

            | 0 : no hermitian or symmetric
            | 1 : hermitian
            | 2 : anti-hermitian

        intor : str
            2-electron integral name.  See :func:`getints` for the complete
            list of available 2-electron integral names
        aosym : int or str
            Permutation symmetry for the AO integrals

            | 4 or '4' or 's4': 4-fold symmetry (default)
            | '2ij' or 's2ij' : symmetry between i, j in (ij|kl)
            | '2kl' or 's2kl' : symmetry between k, l in (ij|kl)
            | 1 or '1' or 's1': no symmetry
            | 'a4ij' : 4-fold symmetry with anti-symmetry between i, j in (ij|kl)
            | 'a4kl' : 4-fold symmetry with anti-symmetry between k, l in (ij|kl)
            | 'a2ij' : anti-symmetry between i, j in (ij|kl)
            | 'a2kl' : anti-symmetry between k, l in (ij|kl)

        comp : int
            Components of the integrals, e.g. cint2e_ip_sph has 3 components.
        scripts : a list of strings
            Contraction description (following numpy.einsum convention) based on
            letters [ijkl].  Each script will be one-to-one applied to each
            entry of dms.  So it must have the same number of elements as the
            dms, len(scripts) == len(dms).
        shls_slice : 8-element list
            (ish_start, ish_end, jsh_start, jsh_end, ksh_start, ksh_end, lsh_start, lsh_end)

    Returns:
        Depending on the number of density matrices, the function returns one
        J/K matrix or a list of J/K matrices (the same number of entries as the
        input dms).
        Each JK matrices may be a 2D array or 3D array if the AO integral
        has multiple components.

    Examples:

    >>> from pyscf import gto
    >>> mol = gto.M(atom='H 0 -.5 0; H 0 .5 0', basis='cc-pvdz')
    >>> nao = mol.nao_nr()
    >>> dm = numpy.random.random((nao,nao))
    >>> # Default, Coulomb matrix
    >>> vj = get_jk(mol, dm)
    >>> # Coulomb matrix with 8-fold permutation symmetry for AO integrals
    >>> vj = get_jk(mol, dm, 'ijkl,ji->kl', aosym='s8')
    >>> # Exchange matrix with 8-fold permutation symmetry for AO integrals
    >>> vk = get_jk(mol, dm, 'ijkl,jk->il', aosym='s8')
    >>> # Compute coulomb and exchange matrices together
    >>> vj, vk = get_jk(mol, (dm,dm), ('ijkl,ji->kl','ijkl,li->kj'), aosym='s8')
    >>> # Analytical gradients for coulomb matrix
    >>> j1 = get_jk(mol, dm, 'ijkl,lk->ij', intor='cint2e_ip1_sph', aosym='s2kl', comp=3)

    >>> # contraction across two molecules
    >>> mol1 = gto.M(atom='He 2 0 0', basis='6-31g')
    >>> nao1 = mol1.nao_nr()
    >>> dm1 = numpy.random.random((nao1,nao1))
    >>> # Coulomb interaction between two molecules, note 4-fold symmetry can be applied
    >>> jcross = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', aosym='s4')
    >>> ecoul = numpy.einsum('ij,ij', jcross, dm1)
    >>> # Exchange interaction between two molecules, no symmetry can be used
    >>> kcross = get_jk((mol1,mol,mol,mol1), dm, scripts='ijkl,jk->il')
    >>> ex = numpy.einsum('ij,ji', kcross, dm1)

    >>> # Analytical gradients for coulomb matrix between two molecules
    >>> jcros1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='cint2e_ip1_sph', comp=3)
    >>> # Analytical gradients for coulomb interaction between 1s density and the other molecule
    >>> jpart1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='cint2e_ip1_sph', comp=3,
    ...                 shls_slice=(0,1,0,1,0,mol.nbas,0,mol.nbas))
    '''
    if isinstance(mols, (tuple, list)):
        assert(len(mols) == 4)
        if shls_slice is None:
            shls_slice = numpy.array([(0, mol.nbas) for mol in mols])
        else:
            shls_slice = numpy.asarray(shls_slice).reshape(4,2)
# concatenate unique mols and build corresponding shls_slice
        mol_ids = [id(mol) for mol in mols]
        atm, bas, env = mols[0]._atm, mols[0]._bas, mols[0]._env
        bas_start = numpy.zeros(4, dtype=int)
        for m in range(1,4):
            first = mol_ids.index(mol_ids[m])
            if first == m:  # the unique mol
                bas_start[m] = bas.shape[0]
                atm, bas, env = gto.conc_env(atm, bas, env, mols[m]._atm,
                                             mols[m]._bas, mols[m]._env)
            else:
                bas_start[m] = bas_start[first]
            shls_slice[m] += bas_start[m]
        shls_slice = shls_slice.flatten()
    else:
        atm, bas, env = mols._atm, mols._bas, mols._env
        if shls_slice is None:
            shls_slice = (0, mols.nbas) * 4

    if isinstance(scripts, str):
        scripts = [scripts]
    if isinstance(dms, numpy.ndarray) and dms.ndim == 2:
        dms = [dms]
    assert(len(scripts) == len(dms))

    #format scripts
    descript = []
    for script in scripts:
        dmsym, vsym = script.lower().split(',')[1].split('->')
        if hermi == 0:
            descript.append('->'.join((dmsym,'s1'+vsym)))
        else:
            descript.append('->'.join((dmsym,'s2'+vsym)))

    vs = _vhf.direct_bindm(intor, aosym, descript, dms, comp, atm, bas, env,
                           shls_slice=shls_slice)
    if hermi != 0:
        for v in vs:
            if v.ndim == 3:
                for vi in v:
                    pyscf.lib.hermi_triu(vi, hermi, inplace=True)
            else:
                pyscf.lib.hermi_triu(v, hermi, inplace=True)
    return vs
Пример #14
0
Файл: rks.py Проект: v1j4y/pyscf
def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(mf.stdout, mf.verbose)
    mol = mf.mol
    if atmlst is None:
        atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    mocc = mo_coeff[:,mo_occ>0]
    dm0 = numpy.dot(mocc, mocc.T) * 2

    ni = copy.copy(mf._numint)
    if USE_XCFUN:
        try:
            ni.libxc = dft.xcfun
            xctype = ni._xc_type(mf.xc)
        except (ImportError, KeyError, NotImplementedError):
            ni.libxc = dft.libxc
            xctype = ni._xc_type(mf.xc)
    else:
        xctype = ni._xc_type(mf.xc)
    grids = mf.grids
    hyb = ni.libxc.hybrid_coeff(mf.xc)
    max_memory = 4000

    h1a =-(mol.intor('cint1e_ipkin_sph', comp=3) +
           mol.intor('cint1e_ipnuc_sph', comp=3))

    offsetdic = mol.offset_nr_by_atom()
    h1aos = []
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        mol.set_rinv_origin_(mol.atom_coord(ia))
        h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3)
        h1ao[:,p0:p1] += h1a[:,p0:p1]
        h1ao = h1ao + h1ao.transpose(0,2,1)

        shls_offset = (shl0, shl1) + (0, mol.nbas)*3
        if abs(hyb) > 1e-10:
            vj1, vj2, vk1, vk2 = \
                    _vhf.direct_bindm('cint2e_ip1_sph', 's2kl',
                                      ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'),
                                      (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0),
                                      3, mol._atm, mol._bas, mol._env,
                                      shls_offset=shls_offset)
            for i in range(3):
                pyscf.lib.hermi_triu_(vj1[i], 1)
            veff = vj1 - hyb*.5*vk1
            veff[:,p0:p1] += vj2 - hyb*.5*vk2
        else:
            vj1, vj2 = \
                    _vhf.direct_bindm('cint2e_ip1_sph', 's2kl',
                                      ('ji->s2kl', 'lk->s1ij'),
                                      (-dm0[:,p0:p1], -dm0),
                                      3, mol._atm, mol._bas, mol._env,
                                      shls_offset=shls_offset)
            for i in range(3):
                pyscf.lib.hermi_triu_(vj1[i], 1)
            veff = vj1
            veff[:,p0:p1] += vj2

        if xctype == 'LDA':
            ao_deriv = 1
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho = vxc[0]
                frr = fxc[0]
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half)
                aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1)
                aow1 = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho)
                aow[:,:,p0:p1] += aow1
                veff[0] += pyscf.lib.dot(-aow[0].T, ao[0])
                veff[1] += pyscf.lib.dot(-aow[1].T, ao[0])
                veff[2] += pyscf.lib.dot(-aow[2].T, ao[0])
                half = aow = aow1 = None

        elif xctype == 'GGA':
            def get_wv(rho, rho1, weight, vxc, fxc):
                vgamma = vxc[1]
                frr, frg, fgg = fxc[:3]
                ngrid = weight.size
                sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:])
                wv = numpy.empty((4,ngrid))
                wv[0]  = frr * rho1[0]
                wv[0] += frg * sigma1 * 2
                wv[1:]  = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:]
                wv[1:] += vgamma * rho1[1:] * 2
                wv *= weight
                return wv
            ao_deriv = 2
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho, vgamma = vxc[:2]
                # (d_X \nabla_x mu) nu DM_{mu,nu}
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half)
                rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half)
                rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half)
                # (d_X mu) (\nabla_x nu) DM_{mu,nu}
                half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy())
                rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy())
                rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy())
                rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)

                wv = get_wv(rho, rho1X, weight, vxc, fxc)
                wv[0] *= .5
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[0] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0]))
                wv = get_wv(rho, rho1Y, weight, vxc, fxc)
                wv[0] *= .5
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[1] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0]))
                wv = get_wv(rho, rho1Z, weight, vxc, fxc)
                wv[0] *= .5
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[2] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0]))

                wv = numpy.empty_like(rho)
                wv[0]  = weight * vrho
                wv[1:] = rho[1:] * (weight * vgamma * 2)
                aow = numpy.einsum('npi,np->pi', ao[:4], wv)
                veff[0,p0:p1] -= pyscf.lib.dot(ao[1,:,p0:p1].T.copy(), aow)
                veff[1,p0:p1] -= pyscf.lib.dot(ao[2,:,p0:p1].T.copy(), aow)
                veff[2,p0:p1] -= pyscf.lib.dot(ao[3,:,p0:p1].T.copy(), aow)

                aow = numpy.einsum('npi,np->pi', ao[[XX,XY,XZ],:,p0:p1], wv[1:4])
                veff[0,p0:p1] -= pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[YX,YY,YZ],:,p0:p1], wv[1:4])
                veff[1,p0:p1] -= pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[ZX,ZY,ZZ],:,p0:p1], wv[1:4])
                veff[2,p0:p1] -= pyscf.lib.dot(aow.T, ao[0])
        else:
            raise NotImplementedError('meta-GGA')

        veff = veff + veff.transpose(0,2,1)

        if chkfile is None:
            h1aos.append(h1ao+veff)
        else:
            key = 'scf_h1ao/%d' % ia
            pyscf.lib.chkfile.save(chkfile, key, h1ao+veff)
    if chkfile is None:
        return h1aos
    else:
        return chkfile
Пример #15
0
Файл: rks.py Проект: v1j4y/pyscf
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None,
              atmlst=None, max_memory=4000, verbose=None):
    if isinstance(verbose, logger.Logger):
        log = verbose
    else:
        log = logger.Logger(hess_mf.stdout, hess_mf.verbose)

    time0 = (time.clock(), time.time())

    mf = hess_mf._scf
    mol = hess_mf.mol
    if mo_energy is None: mo_energy = mf.mo_energy
    if mo_occ is None:    mo_occ = mf.mo_occ
    if mo_coeff is None:  mo_coeff = mf.mo_coeff
    if atmlst is None: atmlst = range(mol.natm)

    nao, nmo = mo_coeff.shape
    nocc = int(mo_occ.sum()) // 2
    mocc = mo_coeff[:,:nocc]
    dm0 = mf.make_rdm1(mo_coeff, mo_occ)

    ni = copy.copy(mf._numint)
    if USE_XCFUN:
        try:
            ni.libxc = dft.xcfun
            xctype = ni._xc_type(mf.xc)
        except (ImportError, KeyError, NotImplementedError):
            ni.libxc = dft.libxc
            xctype = ni._xc_type(mf.xc)
    else:
        xctype = ni._xc_type(mf.xc)
    grids = mf.grids
    hyb = ni.libxc.hybrid_coeff(mf.xc)
    max_memory = 4000

    h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log)
    t1 = log.timer('making H1', *time0)
    def fx(mo1):
        # *2 for alpha + beta
        dm1 = numpy.einsum('xai,pa,qi->xpq', mo1, mo_coeff, mocc*2)
        dm1 = dm1 + dm1.transpose(0,2,1)
        vindxc = _contract_xc_kernel(mf, mf.xc, dm1, max_memory)
        if abs(hyb) > 1e-10:
            vj, vk = mf.get_jk(mol, dm1)
            veff = vj - hyb * .5 * vk + vindxc
        else:
            vj = mf.get_j(mol, dm1)
            veff = vj + vindxc
        v1 = numpy.einsum('xpq,pa,qi->xai', veff, mo_coeff, mocc)
        return v1.reshape(v1.shape[0],-1)
    mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos,
                                  fx, atmlst, max_memory, log)
    t1 = log.timer('solving MO1', *t1)

    tmpf = tempfile.NamedTemporaryFile()
    with h5py.File(tmpf.name, 'w') as f:
        for i0, ia in enumerate(atmlst):
            mol.set_rinv_origin_(mol.atom_coord(ia))
            f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_ipiprinv_sph', comp=9))
            f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) *
                                  mol.intor('cint1e_iprinvip_sph', comp=9))

    h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) +
           mol.intor('cint1e_ipipnuc_sph', comp=9))
    h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) +
           mol.intor('cint1e_ipnucip_sph', comp=9))
    s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9)
    s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9)
    s1a =-mol.intor('cint1e_ipovlp_sph', comp=3)

    # Energy weighted density matrix
    dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2

    if abs(hyb) > 1e-10:
        vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl',
                                     ('lk->s1ij', 'jk->s1il'), dm0, 9,
                                     mol._atm, mol._bas, mol._env)
        veff1ii = vj1 - hyb * .5 * vk1
    else:
        vj1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', 'lk->s1ij', dm0, 9,
                                mol._atm, mol._bas, mol._env)
        veff1ii = vj1.copy()
    vj1[:] = 0
    if xctype == 'LDA':
        ao_deriv = 2
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
            rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA')
            vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1]
            vrho = vxc[0]
            aow = numpy.einsum('pi,p->pi', ao[0], weight*vrho)
            for i in range(6):
                vj1[i] += pyscf.lib.dot(ao[i+4].T, aow)
            aow = aow1 = None
    elif xctype == 'GGA':
        ao_deriv = 3
        for ao, mask, weight, coords \
                in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
            rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA')
            vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1]
            vrho, vgamma = vxc[:2]
            wv = numpy.empty_like(rho)
            wv[0]  = weight * vrho
            wv[1:] = rho[1:] * (weight * vgamma * 2)
            aow = numpy.einsum('npi,np->pi', ao[:4], wv)
            for i in range(6):
                vj1[i] += pyscf.lib.dot(ao[i+4].T, aow)
            aow = numpy.einsum('npi,np->pi', ao[[XXX,XXY,XXZ]], wv[1:4])
            vj1[0] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XXY,XYY,XYZ]], wv[1:4])
            vj1[1] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XXZ,XYZ,XZZ]], wv[1:4])
            vj1[2] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XYY,YYY,YYZ]], wv[1:4])
            vj1[3] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XYZ,YYZ,YZZ]], wv[1:4])
            vj1[4] += pyscf.lib.dot(aow.T, ao[0])
            aow = numpy.einsum('npi,np->pi', ao[[XZZ,YZZ,ZZZ]], wv[1:4])
            vj1[5] += pyscf.lib.dot(aow.T, ao[0])
            rho = vxc = vrho = vgamma = wv = aow = None
    else:
        raise NotImplementedError('meta-GGA')
    veff1ii += vj1[[0,1,2,1,3,4,2,4,5]]
    vj1 = vk1 = None

    t1 = log.timer('contracting cint2e_ipip1_sph', *t1)

    offsetdic = mol.offset_nr_by_atom()
    frinv = h5py.File(tmpf.name, 'r')
    rinv2aa = frinv['rinv2aa']
    rinv2ab = frinv['rinv2ab']

    de2 = numpy.zeros((mol.natm,mol.natm,3,3))
    for i0, ia in enumerate(atmlst):
        shl0, shl1, p0, p1 = offsetdic[ia]

        h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1)
        h_2[:,p0:p1] += h1ab[:,p0:p1]
        s1ao = numpy.zeros((3,nao,nao))
        s1ao[:,p0:p1] += s1a[:,p0:p1]
        s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1)
        s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc)

        shls_offset = (shl0, shl1) + (0, mol.nbas)*3
        if abs(hyb) > 1e-10:
            vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1',
                                              ('ji->s1kl', 'li->s1kj', 'lj->s1ki'),
                                              (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9,
                                              mol._atm, mol._bas, mol._env,
                                              shls_offset=shls_offset)
            veff2 = vj1 * 2 - hyb * .5 * vk1
            veff2[:,:,p0:p1] -= hyb * .5 * vk2
            t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1)

            vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl',
                                         ('lk->s1ij', 'li->s1kj'),
                                         (dm0, dm0[:,p0:p1]), 9,
                                         mol._atm, mol._bas, mol._env,
                                         shls_offset=shls_offset)
            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)
            veff2 -= hyb * .5 * vk1.transpose(0,2,1)
            vj1 = vk1 = vk2 = None
            t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1)
        else:
            vj1 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1',
                                    'ji->s1kl', dm0[:,p0:p1], 9,
                                    mol._atm, mol._bas, mol._env,
                                    shls_offset=shls_offset)
            veff2 = vj1 * 2
            t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1)

            vj1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl',
                                    'lk->s1ij', dm0, 9,
                                    mol._atm, mol._bas, mol._env,
                                    shls_offset=shls_offset)
            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)
            t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1)

        if xctype == 'LDA':
            ao_deriv = 1
            vj1[:] = 0
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho = vxc[0]
                frr = fxc[0]
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half)
                aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1)
                veff2[0] += pyscf.lib.dot(ao[1].T, aow[0]) * 2
                veff2[1] += pyscf.lib.dot(ao[1].T, aow[1]) * 2
                veff2[2] += pyscf.lib.dot(ao[1].T, aow[2]) * 2
                veff2[3] += pyscf.lib.dot(ao[2].T, aow[0]) * 2
                veff2[4] += pyscf.lib.dot(ao[2].T, aow[1]) * 2
                veff2[5] += pyscf.lib.dot(ao[2].T, aow[2]) * 2
                veff2[6] += pyscf.lib.dot(ao[3].T, aow[0]) * 2
                veff2[7] += pyscf.lib.dot(ao[3].T, aow[1]) * 2
                veff2[8] += pyscf.lib.dot(ao[3].T, aow[2]) * 2
                aow = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho)
                vj1[0] += pyscf.lib.dot(aow[0].T, ao[1])
                vj1[1] += pyscf.lib.dot(aow[0].T, ao[2])
                vj1[2] += pyscf.lib.dot(aow[0].T, ao[3])
                vj1[3] += pyscf.lib.dot(aow[1].T, ao[1])
                vj1[4] += pyscf.lib.dot(aow[1].T, ao[2])
                vj1[5] += pyscf.lib.dot(aow[1].T, ao[3])
                vj1[6] += pyscf.lib.dot(aow[2].T, ao[1])
                vj1[7] += pyscf.lib.dot(aow[2].T, ao[2])
                vj1[8] += pyscf.lib.dot(aow[2].T, ao[3])
                half = aow = None

            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)

        elif xctype == 'GGA':
            def get_wv(rho, rho1, weight, vxc, fxc):
                vgamma = vxc[1]
                frr, frg, fgg = fxc[:3]
                ngrid = weight.size
                sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:])
                wv = numpy.empty((4,ngrid))
                wv[0]  = frr * rho1[0]
                wv[0] += frg * sigma1 * 2
                wv[1:]  = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:]
                wv[1:] += vgamma * rho1[1:] * 2
                wv *= weight
                return wv
            ao_deriv = 2
            vj1[:] = 0
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab):
                rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vrho, vgamma = vxc[:2]
                # (d_X \nabla_x mu) nu DM_{mu,nu}
                half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy())
                rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half)
                rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half)
                rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half)
                # (d_X mu) (\nabla_x nu) DM_{mu,nu}
                half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy())
                rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy())
                rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)
                half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy())
                rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half)
                rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half)
                rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half)

                wv = get_wv(rho, rho1X, weight, vxc, fxc) * 2  # ~ vj1*2
                aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)  # dX
                veff2[0] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)  # dY
                veff2[3] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)  # dZ
                veff2[6] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4])
                veff2[0] += pyscf.lib.dot(ao[1].T, aow)
                veff2[3] += pyscf.lib.dot(ao[2].T, aow)
                veff2[6] += pyscf.lib.dot(ao[3].T, aow)
                wv = get_wv(rho, rho1Y, weight, vxc, fxc) * 2
                aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)
                veff2[1] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)
                veff2[4] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)
                veff2[7] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4])
                veff2[1] += pyscf.lib.dot(ao[1].T, aow)
                veff2[4] += pyscf.lib.dot(ao[2].T, aow)
                veff2[7] += pyscf.lib.dot(ao[3].T, aow)
                wv = get_wv(rho, rho1Z, weight, vxc, fxc) * 2
                aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)
                veff2[2] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)
                veff2[5] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)
                veff2[8] += pyscf.lib.dot(aow.T, ao[0])
                aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4])
                veff2[2] += pyscf.lib.dot(ao[1].T, aow)
                veff2[5] += pyscf.lib.dot(ao[2].T, aow)
                veff2[8] += pyscf.lib.dot(ao[3].T, aow)

                wv = numpy.empty_like(rho)
                wv[0]  = weight * vrho * .5
                wv[1:] = rho[1:] * (weight * vgamma * 2)
                aowx = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv)
                aowy = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv)
                aowz = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv)
                ao1 = aowx[:,p0:p1].T.copy()
                ao2 = aowy[:,p0:p1].T.copy()
                ao3 = aowz[:,p0:p1].T.copy()
                vj1[0] += pyscf.lib.dot(ao1, ao[1])
                vj1[1] += pyscf.lib.dot(ao1, ao[2])
                vj1[2] += pyscf.lib.dot(ao1, ao[3])
                vj1[3] += pyscf.lib.dot(ao2, ao[1])
                vj1[4] += pyscf.lib.dot(ao2, ao[2])
                vj1[5] += pyscf.lib.dot(ao2, ao[3])
                vj1[6] += pyscf.lib.dot(ao3, ao[1])
                vj1[7] += pyscf.lib.dot(ao3, ao[2])
                vj1[8] += pyscf.lib.dot(ao3, ao[3])
                ao1 = ao[1,:,p0:p1].T.copy()
                ao2 = ao[2,:,p0:p1].T.copy()
                ao3 = ao[3,:,p0:p1].T.copy()
                vj1[0] += pyscf.lib.dot(ao1, aowx)
                vj1[1] += pyscf.lib.dot(ao1, aowy)
                vj1[2] += pyscf.lib.dot(ao1, aowz)
                vj1[3] += pyscf.lib.dot(ao2, aowx)
                vj1[4] += pyscf.lib.dot(ao2, aowy)
                vj1[5] += pyscf.lib.dot(ao2, aowz)
                vj1[6] += pyscf.lib.dot(ao3, aowx)
                vj1[7] += pyscf.lib.dot(ao3, aowy)
                vj1[8] += pyscf.lib.dot(ao3, aowz)

            veff2[:,:,p0:p1] += vj1.transpose(0,2,1)

        else:
            raise NotImplementedError('meta-GGA')

        for j0, ja in enumerate(atmlst):
            q0, q1 = offsetdic[ja][2:]
# *2 for double occupancy, *2 for +c.c.
            mo1  = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja)
            h1ao = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia)
            dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc)
            de  = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4
            dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc])
            de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4
            de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2

            de = de.reshape(-1)
            v2aa = rinv2aa[str(ja)].value
            v2ab = rinv2ab[str(ja)].value
            de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2
            de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2
            de += numpy.einsum('xpq,pq->x', veff2[:,q0:q1], dm0[q0:q1])*2
            de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2

            if ia == ja:
                de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2
                de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2
                de += numpy.einsum('xpq,pq->x', veff1ii[:,p0:p1], dm0[p0:p1])*2
                de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2

            de2[i0,j0] = de.reshape(3,3)

    frinv.close()
    log.timer('RHF hessian', *time0)
    return de2