Exemple #1
0
def _nao_sub(mol, pre_occ, pre_nao, s=None):
    if s is None:
        s = mol.intor_symmetric('cint1e_ovlp_sph')
    core_lst, val_lst, rydbg_lst = _core_val_ryd_list(mol)
    nbf = mol.nao_nr()
    cnao = numpy.empty((nbf,nbf))

    if core_lst:
        c = pre_nao[:,core_lst]
        s1 = reduce(numpy.dot, (c.T, s, c))
        cnao[:,core_lst] = c1 = numpy.dot(c, orth.lowdin(s1))
        c = pre_nao[:,val_lst]
        c -= reduce(numpy.dot, (c1, c1.T, s, c))
    else:
        c = pre_nao[:,val_lst]

    s1 = reduce(numpy.dot, (c.T, s, c))
    wt = pre_occ[val_lst]
    cnao[:,val_lst] = numpy.dot(c, orth.weight_orth(s1, wt))

    if rydbg_lst:
        cvlst = core_lst + val_lst
        c1 = cnao[:,cvlst]
        c = pre_nao[:,rydbg_lst]
        c -= reduce(numpy.dot, (c1, c1.T, s, c))
        s1 = reduce(numpy.dot, (c.T, s, c))
        cnao[:,rydbg_lst] = numpy.dot(c, orth.lowdin(s1))
    snorm = numpy.linalg.norm(reduce(numpy.dot, (cnao.T, s, cnao)) - numpy.eye(nbf))
    if snorm > 1e-9:
        logger.warn(mol, 'Weak orthogonality for localized orbitals %s', snorm)
    return cnao
Exemple #2
0
def _get_basis_type(mol):
    def classify(mol_basis):
        basis_type = 'other'
        if isinstance(mol_basis, (str, unicode)):
            mol_basis = gto.basis._format_basis_name(mol_basis)
            if mol_basis[:6] == 'def2tz':
                basis_type = 'def2-TZ'
            elif mol_basis[:6] == 'def2sv':
                basis_type = 'sv'
            elif mol_basis[:5] == '631g*':
                basis_type = '6-31gd'
            elif mol_basis[:4] == '631g' and 'd' in mol_basis:
                basis_type = '6-31gd'
        return basis_type

    if isinstance(mol.basis, dict):
        basis_types = [classify(b) for b in mol.basis.values()]
        basis_type = 'other'
        for bt in basis_types:
            if bt != 'other':
                basis_type = bt
                break
        if (len(basis_types) > 1 and
            all(b == basis_type for b in basis_types)):
            logger.warn('Mutliple types of basis found in mol.basis. '
                        'Type %s is applied\n' % basis_type)
    else:
        basis_type = classify(mol.basis)
    return basis_type
Exemple #3
0
def get_occ(mf, mo_energy=None, mo_coeff=None):
    '''Label the occupancies for each orbital.
    NOTE the occupancies are not assigned based on the orbital energy ordering.
    The first N orbitals are assigned to be occupied orbitals.

    Examples:

    >>> mol = gto.M(atom='H 0 0 0; O 0 0 1.1', spin=1)
    >>> mf = scf.hf.SCF(mol)
    >>> energy = numpy.array([-10., -1., 1, -2., 0, -3])
    >>> mf.get_occ(energy)
    array([2, 2, 2, 2, 1, 0])
    '''

    if mo_energy is None: mo_energy = mf.mo_energy
    if getattr(mo_energy, 'mo_ea', None) is not None:
        mo_ea = mo_energy.mo_ea
        mo_eb = mo_energy.mo_eb
    else:
        mo_ea = mo_eb = mo_energy
    nmo = mo_ea.size
    mo_occ = numpy.zeros(nmo)
    if getattr(mf, 'nelec', None) is None:
        nelec = mf.mol.nelec
    else:
        nelec = mf.nelec
    ncore = nelec[1]
    nocc  = nelec[0]
    nopen = abs(nocc - ncore)
    mo_occ = _fill_rohf_occ(mo_energy, mo_ea, mo_eb, ncore, nopen)

    if mf.verbose >= logger.INFO and nocc < nmo and ncore > 0:
        ehomo = max(mo_energy[mo_occ> 0])
        elumo = min(mo_energy[mo_occ==0])
        if ehomo+1e-3 > elumo:
            logger.warn(mf, 'H**O %.15g >= LUMO %.15g', ehomo, elumo)
        else:
            logger.info(mf, '  H**O = %.15g  LUMO = %.15g', ehomo, elumo)
        if nopen > 0 and mf.verbose >= logger.DEBUG:
            core_idx = mo_occ == 2
            open_idx = mo_occ == 1
            vir_idx = mo_occ == 0
            logger.debug(mf, '                  Roothaan           | alpha              | beta')
            logger.debug(mf, '  Highest 2-occ = %18.15g | %18.15g | %18.15g',
                         max(mo_energy[core_idx]),
                         max(mo_ea[core_idx]), max(mo_eb[core_idx]))
            logger.debug(mf, '  Lowest 0-occ =  %18.15g | %18.15g | %18.15g',
                         min(mo_energy[vir_idx]),
                         min(mo_ea[vir_idx]), min(mo_eb[vir_idx]))
            for i in numpy.where(open_idx)[0]:
                logger.debug(mf, '  1-occ =         %18.15g | %18.15g | %18.15g',
                             mo_energy[i], mo_ea[i], mo_eb[i])

        if mf.verbose >= logger.DEBUG:
            numpy.set_printoptions(threshold=nmo)
            logger.debug(mf, '  Roothaan mo_energy =\n%s', mo_energy)
            logger.debug1(mf, '  alpha mo_energy =\n%s', mo_ea)
            logger.debug1(mf, '  beta  mo_energy =\n%s', mo_eb)
            numpy.set_printoptions(threshold=1000)
    return mo_occ
Exemple #4
0
def label_orb_symm(mol, irrep_name, symm_orb, mo, s=None, check=True):
    '''Label the symmetry of given orbitals

    irrep_name can be either the symbol or the ID of the irreducible
    representation.  If the ID is provided, it returns the numeric code
    associated with XOR operator, see :py:meth:`symm.param.IRREP_ID_TABLE`

    Args:
        mol : an instance of :class:`Mole`

        irrep_name : list of str or int
            A list of irrep ID or name,  it can be either mol.irrep_id or
            mol.irrep_name.  It can affect the return "label".
        symm_orb : list of 2d array
            the symmetry adapted basis
        mo : 2d array
            the orbitals to label

    Returns:
        list of symbols or integers to represent the irreps for the given
        orbitals

    Examples:

    >>> from pyscf import gto, scf, symm
    >>> mol = gto.M(atom='H 0 0 0; H 0 0 1', basis='ccpvdz',verbose=0, symmetry=1)
    >>> mf = scf.RHF(mol)
    >>> mf.kernel()
    >>> symm.label_orb_symm(mol, mol.irrep_name, mol.symm_orb, mf.mo_coeff)
    ['Ag', 'B1u', 'Ag', 'B1u', 'B2u', 'B3u', 'Ag', 'B2g', 'B3g', 'B1u']
    >>> symm.label_orb_symm(mol, mol.irrep_id, mol.symm_orb, mf.mo_coeff)
    [0, 5, 0, 5, 6, 7, 0, 2, 3, 5]
    '''
    nmo = mo.shape[1]
    if s is None:
        s = mol.intor_symmetric('cint1e_ovlp_sph')
    mo_s = numpy.dot(mo.T, s)
    norm = numpy.empty((len(irrep_name), nmo))
    for i,ir in enumerate(irrep_name):
        moso = numpy.dot(mo_s, symm_orb[i])
        norm[i] = numpy.einsum('ij,ij->i', moso, moso)
    iridx = numpy.argmax(norm, axis=0)
    orbsym = [irrep_name[i] for i in iridx]
    logger.debug(mol, 'irreps of each MO %s', str(orbsym))
    if check:
        norm[iridx,numpy.arange(nmo)] = 0
        orbidx = numpy.where(norm > THRESHOLD)
        if orbidx[1].size > 0:
            idx = numpy.where(norm > THRESHOLD*1e2)
            if idx[1].size > 0:
                logger.error(mol, 'orbitals %s not symmetrized, norm = %s',
                             idx[1], norm[idx])
                raise ValueError('orbitals %s not symmetrized' % idx[1])
            else:
                logger.warn(mol, 'orbitals %s not strictly symmetrized.',
                            orbidx[1])
                logger.warn(mol, 'They can be symmetrized with '
                            'pyscf.symm.symmetrize_orb function.')
                logger.debug(mol, 'norm = %s', norm[orbidx])
    return orbsym
Exemple #5
0
    def _common_init_(self, mycc, mo_coeff=None):
        if mo_coeff is None:
            mo_coeff = mycc.mo_coeff
        mo_idx = ccsd.get_frozen_mask(mycc)
        if getattr(mo_coeff, 'orbspin', None) is not None:
            self.orbspin = mo_coeff.orbspin[mo_idx]
            mo_coeff = lib.tag_array(mo_coeff[:,mo_idx], orbspin=self.orbspin)
            self.mo_coeff = mo_coeff
        else:
            orbspin = scf.ghf.guess_orbspin(mo_coeff)
            self.mo_coeff = mo_coeff = mo_coeff[:,mo_idx]
            if not np.any(orbspin == -1):
                self.orbspin = orbspin[mo_idx]
                self.mo_coeff = lib.tag_array(mo_coeff, orbspin=self.orbspin)

        # Note: Recomputed fock matrix since SCF may not be fully converged.
        dm = mycc._scf.make_rdm1(mycc.mo_coeff, mycc.mo_occ)
        fockao = mycc._scf.get_fock(dm=dm)
        self.fock = reduce(np.dot, (mo_coeff.conj().T, fockao, mo_coeff))
        self.nocc = mycc.nocc

        mo_e = self.mo_energy = self.fock.diagonal().real
        gap = abs(mo_e[:self.nocc,None] - mo_e[None,self.nocc:]).min()
        if gap < 1e-5:
            logger.warn(mycc, 'H**O-LUMO gap %s too small for GCCSD', gap)
        return self
Exemple #6
0
def makov_payne_correction(mf):
    '''Makov-Payne correction (Phys. Rev. B, 51, 4014)
    '''
    cell = mf.cell
    logger.note(mf, 'Makov-Payne correction for charged 3D PBC systems')
    # PRB 51 (1995), 4014
    # PRB 77 (2008), 115139
    if cell.dimension != 3:
        logger.warn(mf, 'Correction for low-dimension PBC systems'
                    'is not available.')
        return 0

    de_mono, de_dip, de_quad, de = _dip_correction(mf)

    if mf.verbose >= logger.NOTE:
        write = mf.stdout.write
        write('Corrections (AU)\n')
        write('       Monopole      Dipole          Quadrupole    total\n')
        write('SC   %12.8f   %12.8f   %12.8f   %12.8f\n' %
              (de_mono[0], de_dip   , de_quad   , de[0]))
        write('BCC  %12.8f   %12.8f   %12.8f   %12.8f\n' %
              (de_mono[1], de_dip   , de_quad   , de[1]))
        write('FCC  %12.8f   %12.8f   %12.8f   %12.8f\n' %
              (de_mono[2], de_dip   , de_quad   , de[2]))
    return de
Exemple #7
0
    def get_occ(self, mo_energy=None, mo_coeff=None):
        '''Label the occupancies for each orbital.
        NOTE the occupancies are not assigned based on the orbital energy ordering.
        The first N orbitals are assigned to be occupied orbitals.

        Examples:

        >>> mol = gto.M(atom='H 0 0 0; O 0 0 1.1', spin=1)
        >>> mf = scf.hf.SCF(mol)
        >>> energy = numpy.array([-10., -1., 1, -2., 0, -3])
        >>> mf.get_occ(energy)
        array([2, 2, 2, 2, 1, 0])
        '''

        if mo_energy is None: mo_energy = self.mo_energy
        mo_occ = numpy.zeros_like(mo_energy)
        ncore = self.nelec[1]
        nopen = self.nelec[0] - ncore
        nocc = ncore + nopen
        mo_occ[:ncore] = 2
        mo_occ[ncore:nocc] = 1
        if nocc < len(mo_energy):
            logger.info(self, 'H**O = %.12g  LUMO = %.12g',
                        mo_energy[nocc-1], mo_energy[nocc])
            if mo_energy[nocc-1]+1e-3 > mo_energy[nocc]:
                logger.warn(self.mol, '!! H**O %.12g == LUMO %.12g',
                            mo_energy[nocc-1], mo_energy[nocc])
        else:
            logger.info(self, 'H**O = %.12g  no LUMO', mo_energy[nocc-1])
        if nopen > 0:
            for i in range(ncore, nocc):
                logger.debug(self, 'singly occupied orbital energy = %.12g',
                             mo_energy[i])
        logger.debug(self, '  mo_energy = %s', mo_energy)
        return mo_occ
Exemple #8
0
    def build(self, mol=None):
        if mol is None: mol = self.mol
        if mol.symmetry:
            for irname in self.irrep_nelec:
                if irname not in mol.irrep_name:
                    logger.warn(self, 'Molecule does not have irrep %s', irname)

            nelec_fix = self.irrep_nelec.values()
            if any(isinstance(x, (tuple, list)) for x in nelec_fix):
                msg =('Number of alpha/beta electrons cannot be assigned '
                      'separately in GHF.  irrep_nelec = %s' % self.irrep_nelec)
                raise ValueError(msg)
            nelec_fix = sum(nelec_fix)
            float_irname = set(mol.irrep_name) - set(self.irrep_nelec)
            if nelec_fix > mol.nelectron:
                msg =('More electrons defined by irrep_nelec than total num electrons. '
                      'mol.nelectron = %d  irrep_nelec = %s' %
                      (mol.nelectron, self.irrep_nelec))
                raise ValueError(msg)
            else:
                logger.info(mol, 'Freeze %d electrons in irreps %s',
                            nelec_fix, self.irrep_nelec.keys())

            if len(float_irname) == 0 and nelec_fix != mol.nelectron:
                msg =('Num electrons defined by irrep_nelec != total num electrons. '
                      'mol.nelectron = %d  irrep_nelec = %s' %
                      (mol.nelectron, self.irrep_nelec))
                raise ValueError(msg)
            else:
                logger.info(mol, '    %d free electrons in irreps %s',
                            mol.nelectron-nelec_fix, ' '.join(float_irname))
        return ghf.GHF.build(self, mol)
Exemple #9
0
    def get_occ(self, mo_energy=None, mo_coeff=None):
        '''Label the occupancies for each orbital

        Kwargs:
            mo_energy : 1D ndarray
                Obital energies

            mo_coeff : 2D ndarray
                Obital coefficients

        Examples:

        >>> from pyscf import gto, scf
        >>> mol = gto.M(atom='H 0 0 0; F 0 0 1.1')
        >>> mf = scf.hf.SCF(mol)
        >>> mf.get_occ(numpy.arange(mol.nao_nr()))
        array([2, 2, 2, 2, 2, 0])
        '''
        if mo_energy is None: mo_energy = self.mo_energy
        mo_occ = numpy.zeros_like(mo_energy)
        nocc = self.mol.nelectron // 2
        mo_occ[:nocc] = 2
        if nocc < mo_occ.size:
            logger.info(self, 'H**O = %.12g, LUMO = %.12g,',
                        mo_energy[nocc-1], mo_energy[nocc])
            if mo_energy[nocc-1]+1e-3 > mo_energy[nocc]:
                logger.warn(self, '!! H**O %.12g == LUMO %.12g',
                            mo_energy[nocc-1], mo_energy[nocc])
        else:
            logger.info(self, 'H**O = %.12g,', mo_energy[nocc-1])
        if self.verbose >= logger.DEBUG:
            numpy.set_printoptions(threshold=len(mo_energy))
            logger.debug(self, '  mo_energy = %s', mo_energy)
            numpy.set_printoptions()
        return mo_occ
Exemple #10
0
 def get_init_guess(self, mol=None, key='minao'):
     if mol is None:
         mol = self.mol
     if callable(key):
         dm = key(mol)
     elif key.lower() == '1e':
         dm = self.init_guess_by_1e(mol)
     elif getattr(mol, 'natm', 0) == 0:
         logger.info(self, 'No atom found in mol. Use 1e initial guess')
         dm = self.init_guess_by_1e(mol)
     elif key.lower() == 'atom':
         dm = self.init_guess_by_atom(mol)
     elif key.lower() == 'chkfile':
         try:
             dm = self.init_guess_by_chkfile()
         except (IOError, KeyError):
             logger.warn(self, 'Fail in reading %s. Use MINAO initial guess',
                         self.chkfile)
             dm = self.init_guess_by_minao(mol)
     else:
         dm = self.init_guess_by_minao(mol)
     if self.verbose >= logger.DEBUG1:
         logger.debug1(self, 'Nelec from initial guess = %g',
                       (dm*self.get_ovlp()).sum().real)
     return dm
Exemple #11
0
    def get_occ(mo_energy_kpts=None, mo_coeff=None):
        if mo_energy_kpts is None: mo_energy_kpts = mf.mo_energy

        if nelec is None:
            cell_nelec = mf.cell.nelec
        else:
            cell_nelec = nelec

        h**o=[-1e8,-1e8]
        lumo=[1e8,1e8]
        mo_occ_kpts = [[], []]
        for s in [0,1]:
            for k, mo_energy in enumerate(mo_energy_kpts[s]):
                e_idx = numpy.argsort(mo_energy)
                e_sort = mo_energy[e_idx]
                n = cell_nelec[s]
                mo_occ = numpy.zeros_like(mo_energy)
                mo_occ[e_idx[:n]] = 1
                h**o[s] = max(h**o[s], e_sort[n-1])
                lumo[s] = min(lumo[s], e_sort[n])
                mo_occ_kpts[s].append(mo_occ)

        for nm,s in zip(['alpha','beta'],[0,1]):
            logger.info(mf, nm+' H**O = %.12g  LUMO = %.12g', h**o[s], lumo[s])
            if h**o[s] > lumo[s]:
                logger.warn(mf, "WARNING! H**O is greater than LUMO! "
                            "This may lead to incorrect canonical occupation.")

        return mo_occ_kpts
Exemple #12
0
def orbital_coeff(mol, fout, mo_coeff, spin='Alpha', symm=None, ene=None,
                  occ=None, ignore_h=False):
    from pyscf.symm import label_orb_symm
    if ignore_h:
        mol, mo_coeff = remove_high_l(mol, mo_coeff)
    aoidx = order_ao_index(mol)
    nmo = mo_coeff.shape[1]
    if symm is None:
        symm = ['A']*nmo
        if mol.symmetry:
            try:
                symm = label_orb_symm(mol, mol.irrep_name, mol.symm_orb,
                                      mo_coeff, tol=1e-5)
            except ValueError as e:
                logger.warn(mol, str(e))
    if ene is None:
        ene = numpy.arange(nmo)
    assert(spin == 'Alpha' or spin == 'Beta')
    if occ is None:
        occ = numpy.zeros(nmo)
        neleca, nelecb = mol.nelec
        if spin == 'Alpha':
            occ[:neleca] = 1
        else:
            occ[:nelecb] = 1
    fout.write('[MO]\n')
    for imo in range(nmo):
        fout.write(' Sym= %s\n' % symm[imo])
        fout.write(' Ene= %15.10g\n' % ene[imo])
        fout.write(' Spin= %s\n' % spin)
        fout.write(' Occup= %10.5f\n' % occ[imo])
        for i,j in enumerate(aoidx):
            fout.write(' %3d    %18.14g\n' % (i+1, mo_coeff[j,imo]))
Exemple #13
0
    def _common_init_(self, mycc, mo_coeff=None):
        if mo_coeff is None:
            mo_coeff = mycc.mo_coeff
        mo_idx = mycc.get_frozen_mask()
        self.mo_coeff = mo_coeff = \
                (mo_coeff[0][:,mo_idx[0]], mo_coeff[1][:,mo_idx[1]])
# Note: Recomputed fock matrix since SCF may not be fully converged.
        dm = mycc._scf.make_rdm1(mycc.mo_coeff, mycc.mo_occ)
        fockao = mycc._scf.get_fock(dm=dm)
        self.focka = reduce(np.dot, (mo_coeff[0].conj().T, fockao[0], mo_coeff[0]))
        self.fockb = reduce(np.dot, (mo_coeff[1].conj().T, fockao[1], mo_coeff[1]))
        self.fock = (self.focka, self.fockb)
        nocca, noccb = self.nocc = mycc.nocc
        self.mol = mycc.mol

        mo_ea = self.focka.diagonal().real
        mo_eb = self.fockb.diagonal().real
        self.mo_energy = (mo_ea, mo_eb)
        gap_a = abs(mo_ea[:nocca,None] - mo_ea[None,nocca:])
        gap_b = abs(mo_eb[:noccb,None] - mo_eb[None,noccb:])
        if gap_a.size > 0:
            gap_a = gap_a.min()
        else:
            gap_a = 1e9
        if gap_b.size > 0:
            gap_b = gap_b.min()
        else:
            gap_b = 1e9
        if gap_a < 1e-5 or gap_b < 1e-5:
            logger.warn(mycc, 'H**O-LUMO gap (%s,%s) too small for UCCSD',
                        gap_a, gap_b)
        return self
Exemple #14
0
def energy(cc, t1=None, t2=None, eris=None):
    '''UCCSD correlation energy'''
    if t1 is None: t1 = cc.t1
    if t2 is None: t2 = cc.t2
    if eris is None: eris = cc.ao2mo()

    t1a, t1b = t1
    t2aa, t2ab, t2bb = t2
    nocca, noccb, nvira, nvirb = t2ab.shape
    eris_ovov = np.asarray(eris.ovov)
    eris_OVOV = np.asarray(eris.OVOV)
    eris_ovOV = np.asarray(eris.ovOV)
    fova = eris.focka[:nocca,nocca:]
    fovb = eris.fockb[:noccb,noccb:]
    e  = np.einsum('ia,ia', fova, t1a)
    e += np.einsum('ia,ia', fovb, t1b)
    e += 0.25*np.einsum('ijab,iajb',t2aa,eris_ovov)
    e -= 0.25*np.einsum('ijab,ibja',t2aa,eris_ovov)
    e += 0.25*np.einsum('ijab,iajb',t2bb,eris_OVOV)
    e -= 0.25*np.einsum('ijab,ibja',t2bb,eris_OVOV)
    e +=      np.einsum('iJaB,iaJB',t2ab,eris_ovOV)
    e += 0.5*np.einsum('ia,jb,iajb',t1a,t1a,eris_ovov)
    e -= 0.5*np.einsum('ia,jb,ibja',t1a,t1a,eris_ovov)
    e += 0.5*np.einsum('ia,jb,iajb',t1b,t1b,eris_OVOV)
    e -= 0.5*np.einsum('ia,jb,ibja',t1b,t1b,eris_OVOV)
    e +=     np.einsum('ia,jb,iajb',t1a,t1b,eris_ovOV)
    if abs(e.imag) > 1e-4:
        logger.warn(cc, 'Non-zero imaginary part found in UCCSD energy %s', e)
    return e.real
Exemple #15
0
def get_fermi(mf, mo_energy_kpts=None, mo_occ_kpts=None):
    '''A pair of Fermi level for spin-up and spin-down orbitals
    '''
    if mo_energy_kpts is None: mo_energy_kpts = mf.mo_energy
    if mo_occ_kpts is None: mo_occ_kpts = mf.mo_occ

    # mo_energy_kpts and mo_occ_kpts are k-point UHF quantities
    assert(mo_energy_kpts[0][0].ndim == 1)
    assert(mo_occ_kpts[0][0].ndim == 1)

    nocca = sum(mo_occ.sum() for mo_occ in mo_occ_kpts[0])
    noccb = sum(mo_occ.sum() for mo_occ in mo_occ_kpts[1])
    # nocc may not be perfect integer when smearing is enabled
    nocca = int(nocca.round(3))
    noccb = int(noccb.round(3))

    fermi_a = np.sort(np.hstack(mo_energy_kpts[0]))[nocca-1]
    fermi_b = np.sort(np.hstack(mo_energy_kpts[1]))[noccb-1]

    for k, mo_e in enumerate(mo_energy_kpts[0]):
        mo_occ = mo_occ_kpts[0][k]
        if mo_occ[mo_e > fermi_a].sum() > 0.5:
            logger.warn(mf, 'Alpha occupied band above Fermi level: \n'
                        'k=%d, mo_e=%s, mo_occ=%s', k, mo_e, mo_occ)
    for k, mo_e in enumerate(mo_energy_kpts[1]):
        mo_occ = mo_occ_kpts[1][k]
        if mo_occ[mo_e > fermi_b].sum() > 0.5:
            logger.warn(mf, 'Beta occupied band above Fermi level: \n'
                        'k=%d, mo_e=%s, mo_occ=%s', k, mo_e, mo_occ)
    return (fermi_a, fermi_b)
Exemple #16
0
 def dump_flags(self):
     rhf_mag.Magnetizability.dump_flags(self)
     if self.gauge_orig is not None:
         logger.warn(self, 'Rotational g-tensor with '
                     'perturbation-independent basis is in testing.\n'
                     'Results do not fully agree with those in '
                     'JCP, 105, 2804.')
     return self
Exemple #17
0
 def dump_flags(self, verbose=None):
     oldCAS.dump_flags(self)
     self.with_solvent.check_sanity()
     self.with_solvent.dump_flags()
     if self.conv_tol < 1e-7:
         logger.warn(self, 'CASSCF+ddCOSMO may not be able to '
                     'converge to conv_tol=%g', self.conv_tol)
     return self
Exemple #18
0
 def shielding(self, mo1=None):
     if getattr(self._scf, 'spin_square', None):
         s2 = self._scf.spin_square()[0]
         if s2 > 1e-4:
             logger.warn(self, '<S^2> = %s. UHF-NMR shielding may have large error.\n'
                         'paramagnetic NMR should include this result plus '
                         'g-tensor and HFC tensors.', s2)
     return rhf_nmr.NMR.shielding(self, mo1)
Exemple #19
0
 def check_sanity(self):
     mol_hf.SCF.check_sanity(self)
     self.with_df.check_sanity()
     if (isinstance(self.exxdiv, str) and self.exxdiv.lower() != 'ewald' and
         isinstance(self.with_df, df.df.DF)):
         logger.warn(self, 'exxdiv %s is not supported in DF or MDF',
                     self.exxdiv)
     return self
Exemple #20
0
 def dump_flags(self):
     if hasattr(self, "nelectron_alpha"):
         logger.warn(self, "Note the API updates: attribute nelectron_alpha was replaced by attribute nelec")
         # raise RuntimeError('API updates')
         self.nelec = (self.nelectron_alpha, self.mol.nelectron - self.nelectron_alpha)
         delattr(self, "nelectron_alpha")
     hf.SCF.dump_flags(self)
     logger.info(self, "number electrons alpha = %d  beta = %d", *self.nelec)
Exemple #21
0
def gen_atomic_grids(mol, atom_grid={}, radi_method=radi.gauss_chebyshev,
                     level=3, prune=nwchem_prune, **kwargs):
    '''Generate number of radial grids and angular grids for the given molecule.

    Returns:
        A dict, with the atom symbol for the dict key.  For each atom type,
        the dict value has two items: one is the meshgrid coordinates wrt the
        atom center; the second is the volume of that grid.
    '''
    if isinstance(atom_grid, (list, tuple)):
        atom_grid = dict([(mol.atom_symbol(ia), atom_grid)
                          for ia in range(mol.natm)])
    atom_grids_tab = {}
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)

        if symb not in atom_grids_tab:
            chg = gto.charge(symb)
            if symb in atom_grid:
                n_rad, n_ang = atom_grid[symb]
                if n_ang not in LEBEDEV_NGRID:
                    if n_ang in LEBEDEV_ORDER:
                        logger.warn(mol, 'n_ang %d for atom %d %s is not '
                                    'the supported Lebedev angular grids. '
                                    'Set n_ang to %d', n_ang, ia, symb,
                                    LEBEDEV_ORDER[n_ang])
                        n_ang = LEBEDEV_ORDER[n_ang]
                    else:
                        raise ValueError('Unsupported angular grids %d' % n_ang)
            else:
                n_rad = _default_rad(chg, level)
                n_ang = _default_ang(chg, level)
            rad, dr = radi_method(n_rad, chg, ia, **kwargs)

            rad_weight = 4*numpy.pi * rad**2 * dr

            if callable(prune):
                angs = prune(chg, rad, n_ang)
            else:
                angs = [n_ang] * n_rad
            logger.debug(mol, 'atom %s rad-grids = %d, ang-grids = %s',
                         symb, n_rad, angs)

            angs = numpy.array(angs)
            coords = []
            vol = []
            for n in sorted(set(angs)):
                grid = numpy.empty((n,4))
                libdft.MakeAngularGrid(grid.ctypes.data_as(ctypes.c_void_p),
                                       ctypes.c_int(n))
                idx = numpy.where(angs==n)[0]
                for i0, i1 in prange(0, len(idx), 12):  # 12 radi-grids as a group
                    coords.append(numpy.einsum('i,jk->jik',rad[idx[i0:i1]],
                                               grid[:,:3]).reshape(-1,3))
                    vol.append(numpy.einsum('i,j->ji', rad_weight[idx[i0:i1]],
                                            grid[:,3]).ravel())
            atom_grids_tab[symb] = (numpy.vstack(coords), numpy.hstack(vol))
    return atom_grids_tab
Exemple #22
0
def check_irrep_nelec(mol, irrep_nelec, nelec):
    for irname in irrep_nelec.keys():
        if irname not in mol.irrep_name:
            logger.warn(mol, 'Molecule does not have irrep %s', irname)

    float_irname = []
    fix_na = 0
    fix_nb = 0
    for i, irname in enumerate(mol.irrep_name):
        if irname in irrep_nelec:
            if isinstance(irrep_nelec[irname], (int, numpy.integer)):
                nelecb = irrep_nelec[irname] // 2
                neleca = irrep_nelec[irname] - nelecb
            else:
                neleca, nelecb = irrep_nelec[irname]
            norb = mol.symm_orb[i].shape[1]
            if neleca > norb or nelecb > norb:
                msg =('More electrons than orbitals for irrep %s '
                      'nelec = %d + %d, norb = %d' %
                      (irname, neleca,nelecb, norb))
                raise ValueError(msg)
            fix_na += neleca
            fix_nb += nelecb
        else:
            float_irname.append(irname)
    if fix_na < fix_nb:
        raise ValueError('alpha electrons %d < beta electrons %d\n'
                         'irrep_nelec %s' % (fix_na, fix_nb, irrep_nelec))
    if mol.spin < fix_na-fix_nb:
        raise ValueError('alpha electrons %d - beta electrons %d > mol.spin %d\n'
                         'irrep_nelec %s' % (fix_na, fix_nb, mol.spin, irrep_nelec))

    if isinstance(nelec, (int, numpy.integer)):
        nelecb = nelec // 2
        neleca = nelec - nelecb
    else:
        neleca, nelecb = nelec
    fix_ne = fix_na + fix_nb
    if ((fix_na > neleca) or (fix_nb > nelecb) or
        (fix_na+nelecb > mol.nelectron) or
        (fix_nb+neleca > mol.nelectron)):
        msg =('More electrons defined by irrep_nelec than total num electrons. '
              'mol.nelectron = %d  irrep_nelec = %s' %
              (mol.nelectron, irrep_nelec))
        raise ValueError(msg)
    else:
        logger.info(mol, 'fix %d electrons in irreps %s',
                    fix_ne, irrep_nelec.items())

    if len(set(float_irname)) == 0 and fix_ne != mol.nelectron:
        msg =('Num electrons defined by irrep_nelec != total num electrons. '
              'mol.nelectron = %d  irrep_nelec = %s' %
              (mol.nelectron, irrep_nelec))
        raise ValueError(msg)
    else:
        logger.info(mol, '    %d free electrons in irreps %s',
                    mol.nelectron-fix_ne, ' '.join(float_irname))
    return fix_na, fix_nb, float_irname
Exemple #23
0
def init_guess_by_chkfile(mol, chkfile_name, project=None):
    '''Read SCF chkfile and make the density matrix for UHF initial guess.

    Kwargs:
        project : None or bool
            Whether to project chkfile's orbitals to the new basis.  Note when
            the geometry of the chkfile and the given molecule are very
            different, this projection can produce very poor initial guess.
            In PES scanning, it is recommended to swith off project.

            If project is set to None, the projection is only applied when the
            basis sets of the chkfile's molecule are different to the basis
            sets of the given molecule (regardless whether the geometry of
            the two molecules are different).  Note the basis sets are
            considered to be different if the two molecules are derived from
            the same molecule with different ordering of atoms.
    '''
    from pyscf.scf import addons
    chk_mol, scf_rec = chkfile.load_scf(chkfile_name)
    if project is None:
        project = not gto.same_basis_set(chk_mol, mol)

    # Check whether the two molecules are similar
    im1 = scipy.linalg.eigvalsh(mol.inertia_moment())
    im2 = scipy.linalg.eigvalsh(chk_mol.inertia_moment())
    # im1+1e-7 to avoid 'divide by zero' error
    if abs((im1-im2)/(im1+1e-7)).max() > 0.01:
        logger.warn(mol, "Large deviations found between the input "
                    "molecule and the molecule from chkfile\n"
                    "Initial guess density matrix may have large error.")

    if project:
        s = hf.get_ovlp(mol)

    def fproj(mo):
        if project:
            mo = addons.project_mo_nr2nr(chk_mol, mo, mol)
            norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo))
            mo /= numpy.sqrt(norm)
        return mo

    mo = scf_rec['mo_coeff']
    mo_occ = scf_rec['mo_occ']
    if getattr(mo[0], 'ndim', None) == 1:  # RHF
        if numpy.iscomplexobj(mo):
            raise NotImplementedError('TODO: project DHF orbital to UHF orbital')
        mo_coeff = fproj(mo)
        mo_occa = (mo_occ>1e-8).astype(numpy.double)
        mo_occb = mo_occ - mo_occa
        dm = make_rdm1([mo_coeff,mo_coeff], [mo_occa,mo_occb])
    else: #UHF
        if getattr(mo[0][0], 'ndim', None) == 2:  # KUHF
            logger.warn(mol, 'k-point UHF results are found.  Density matrix '
                        'at Gamma point is used for the molecular SCF initial guess')
            mo = mo[0]
        dm = make_rdm1([fproj(mo[0]),fproj(mo[1])], mo_occ)
    return dm
Exemple #24
0
    def build(self, mol=None):
        if mol is None: mol = self.mol
        if mol.symmetry:
            for irname in self.irrep_nelec:
                if irname not in self.mol.irrep_name:
                    logger.warn(self, 'No irrep %s', irname)

            hf_symm.check_irrep_nelec(mol, self.irrep_nelec, self.nelec)
        return uhf.UHF.build(self, mol)
Exemple #25
0
def DFCASCI(mf, ncas, nelecas, auxbasis='weigend', **kwargs):
    if not hasattr(mf, '_tag_df') or not mf._tag_df:
        from pyscf.lib import logger
        logger.warn(mf, 'DFCASCI: the first argument%s is not density-fitting SCF object. '
                    'Only orbital hessian are computed with density-fitting integrals. '
                    'JK matrix and 2e MO integrals are computed with exact 2e integrals.',
                    mf.__class__)
    mc = CASCI(mf, ncas, nelecas, **kwargs)
    return density_fit(mc, auxbasis)
Exemple #26
0
 def build_(self, mol=None):
     # specify alpha,beta for same irreps
     na = sum([x[0] for x in self.irrep_nelec.values()])
     nb = sum([x[1] for x in self.irrep_nelec.values()])
     nopen = self.mol.spin
     assert(na >= nb and nopen >= na-nb)
     for irname in self.irrep_nelec.keys():
         if irname not in self.mol.irrep_name:
             logger.warn(self, '!! No irrep %s', irname)
     return hf.RHF.build_(self, mol)
Exemple #27
0
def energy(cc, t1, t2, eris):
    nocc, nvir = t1.shape
    fock = eris.fock
    e = einsum('ia,ia', fock[:nocc,nocc:], t1)
    eris_oovv = np.array(eris.oovv)
    e += 0.25*np.einsum('ijab,ijab', t2, eris_oovv)
    e += 0.5 *np.einsum('ia,jb,ijab', t1, t1, eris_oovv)
    if abs(e.imag) > 1e-4:
        logger.warn(cc, 'Non-zero imaginary part found in GCCSD energy %s', e)
    return e.real
Exemple #28
0
 def dump_flags(self):
     hf.SCF.dump_flags(self)
     if hasattr(self, 'nelectron_alpha'):
         logger.warn(self, 'Note the API updates: attribute nelectron_alpha was replaced by attribute nelec')
         #raise RuntimeError('API updates')
         self.nelec = (self.nelectron_alpha,
                       self.mol.nelectron-self.nelectron_alpha)
         delattr(self, 'nelectron_alpha')
     logger.info(self, 'num. doubly occ = %d  num. singly occ = %d',
                 self.nelec[1], self.nelec[0]-self.nelec[1])
Exemple #29
0
def mo_comps(aolabels_or_baslst, mol, mo_coeff, cart=False,
             orth_method=ORTH_METHOD):
    '''Given AO(s), show how the AO(s) are distributed in MOs.

    Args:
        aolabels_or_baslst : filter function or AO labels or AO index
            If it's a function,  the AO indices are the items for which the
            function return value is true.

    Kwargs:
        cart : bool
            whether the orbital coefficients are based on cartesian basis.
        orth_method : str
            The localization method to generated orthogonal AO upon which the AO
            contribution are computed.  It can be one of 'meta_lowdin',
            'lowdin' or 'nao'.

    Returns:
        A list of float to indicate the total contributions (normalized to 1) of
        localized AOs

    Examples:

    >>> from pyscf import gto, scf
    >>> from pyscf.tools import mo_mapping
    >>> mol = gto.M(atom='H 0 0 0; F 0 0 1', basis='6-31g')
    >>> mf = scf.RHF(mol).run()
    >>> comp = mo_mapping.mo_comps('F 2s', mol, mf.mo_coeff)
    >>> print('MO-id    F-2s components')
    >>> for i,c in enumerate(comp):
    ...     print('%-3d      %.10f' % (i, c))
    MO-id    components
    0        0.0000066344
    1        0.8796915532
    2        0.0590259826
    3        0.0000000000
    4        0.0000000000
    5        0.0435028851
    6        0.0155889103
    7        0.0000000000
    8        0.0000000000
    9        0.0000822361
    10       0.0021017982
    '''
    with lib.temporary_env(mol, cart=cart):
        assert(mo_coeff.shape[0] == mol.nao)
        s = mol.intor_symmetric('int1e_ovlp')
        lao = lo.orth.orth_ao(mol, orth_method, s=s)

        idx = gto.mole._aolabels2baslst(mol, aolabels_or_baslst)
        if len(idx) == 0:
            logger.warn(mol, 'Required orbitals are not found')
        mo1 = reduce(numpy.dot, (lao[:,idx].T, s, mo_coeff))
        s1 = numpy.einsum('ki,ki->i', mo1, mo1)
    return s1
Exemple #30
0
def _make_eris(mp, mo_coeff=None, ao2mofn=None, verbose=None):
    log = logger.new_logger(mp, verbose)
    time0 = (time.clock(), time.time())
    eris = _ChemistsERIs(mp, mo_coeff)

    nocca, noccb = mp.get_nocc()
    nmoa, nmob = mp.get_nmo()
    nvira, nvirb = nmoa-nocca, nmob-noccb
    nao = eris.mo_coeff[0].shape[0]
    nmo_pair = nmoa * (nmoa+1) // 2
    nao_pair = nao * (nao+1) // 2
    mem_incore = (nao_pair**2 + nmo_pair**2) * 8/1e6
    mem_now = lib.current_memory()[0]
    max_memory = max(0, mp.max_memory-mem_now)

    moa = eris.mo_coeff[0]
    mob = eris.mo_coeff[1]
    orboa = moa[:,:nocca]
    orbob = mob[:,:noccb]
    orbva = moa[:,nocca:]
    orbvb = mob[:,noccb:]

    if (mp.mol.incore_anyway or
        (mp._scf._eri is not None and mem_incore+mem_now < mp.max_memory)):
        log.debug('transform (ia|jb) incore')
        if callable(ao2mofn):
            eris.ovov = ao2mofn((orboa,orbva,orboa,orbva)).reshape(nocca*nvira,nocca*nvira)
            eris.ovOV = ao2mofn((orboa,orbva,orbob,orbvb)).reshape(nocca*nvira,noccb*nvirb)
            eris.OVOV = ao2mofn((orbob,orbvb,orbob,orbvb)).reshape(noccb*nvirb,noccb*nvirb)
        else:
            eris.ovov = ao2mo.general(mp._scf._eri, (orboa,orbva,orboa,orbva))
            eris.ovOV = ao2mo.general(mp._scf._eri, (orboa,orbva,orbob,orbvb))
            eris.OVOV = ao2mo.general(mp._scf._eri, (orbob,orbvb,orbob,orbvb))

    elif getattr(mp._scf, 'with_df', None):
        logger.warn(mp, 'UMP2 detected DF being used in the HF object. '
                    'MO integrals are computed based on the DF 3-index tensors.\n'
                    'It\'s recommended to use DF-UMP2 module.')
        log.debug('transform (ia|jb) with_df')
        eris.ovov = mp._scf.with_df.ao2mo((orboa,orbva,orboa,orbva))
        eris.ovOV = mp._scf.with_df.ao2mo((orboa,orbva,orbob,orbvb))
        eris.OVOV = mp._scf.with_df.ao2mo((orbob,orbvb,orbob,orbvb))

    else:
        log.debug('transform (ia|jb) outcore')
        eris.feri = lib.H5TmpFile()
        _ao2mo_ovov(mp, (orboa,orbva,orbob,orbvb), eris.feri,
                    max(2000, max_memory), log)
        eris.ovov = eris.feri['ovov']
        eris.ovOV = eris.feri['ovOV']
        eris.OVOV = eris.feri['OVOV']

    time1 = log.timer('Integral transformation', *time0)
    return eris
Exemple #31
0
def kernel(imds,
           orbs=None,
           linearized=False,
           eta=1e-3,
           tol=1e-9,
           method="fallback"):
    """
    Calculates GW energies.
    Args:
        imds (AbstractIMDS): GW intermediates;
        orbs (Iterable): indexes of MO orbitals to correct;
        linearized (bool): whether to apply a single-step linearized correction to energies instead of iterative
        procedure;
        eta (float): imaginary energy for the Green's function;
        tol (float): tolerance for the search of zero;
        method (str): 'bisect' finds roots no matter what but, potentially, wrong ones, 'newton' finding roots close to
        the correct one but, potentially, failing during iterations, or 'fallback' using 'newton' and proceeding to
        'bisect' in case of failure;

    Returns:
        Corrected orbital energies.
    """
    if method not in ('newton', 'bisect', 'fallback'):
        raise ValueError("Cannot recognize method='{}'".format(method))

    # Check implementation consistency
    _orbs = imds.entire_space
    if not isinstance(_orbs, list) or not len(_orbs) == imds.orb_dims:
        raise RuntimeError(
            "The object returned by 'imds.entire_space' is not a list of length {:d}: {}"
            .format(
                imds.orb_dims,
                repr(_orbs),
            ))

    # Assign default value
    if orbs is None:
        orbs = _orbs

    # Make sure it is a list
    if not isinstance(orbs, list):
        orbs = [orbs]

    # Add missing dimensions
    if len(orbs) < imds.orb_dims:
        orbs = _orbs[:-len(orbs)] + orbs

    shape = tuple(len(i) for i in orbs)
    gw_energies = numpy.zeros(shape, dtype=float)

    for i_p in product(*tuple(numpy.arange(i) for i in shape)):
        p = tuple(i[j] for i, j in zip(orbs, i_p))
        if imds.orb_dims == 1:
            p = p[0]
        if linearized:
            raise NotImplementedError
            # v_mf = imds.vmf
            # vk = imds.vk
            # de = 1e-6
            # ep = imds.e_mf[p]
            # # TODO: analytic sigma derivative
            # sigma = imds.get_sigma_element(ep, p, eta).real
            # dsigma = imds.get_sigma_element(ep + de, p, eta).real - sigma
            # zn = 1.0 / (1 - dsigma / de)
            # e = ep + zn * (sigma.real + vk[p] - v_mf[p])
            # gw_energies[i_p] = e
        else:
            debug = LoggingFunction(imds.quasiparticle_eq(p, eta=eta))

            if method == "newton":
                try:
                    gw_energies[i_p] = newton(debug,
                                              imds.initial_guess(p),
                                              tol=tol,
                                              maxiter=100)
                except Exception as e:
                    e.message = "When calculating root @p={} the following exception occurred:\n\n{}".format(
                        repr(p),
                        e.message,
                    )
                    debug.plot_call_history("Exception during Newton " +
                                            str(p))
                    raise

            elif method == "bisect":
                gw_energies[i_p] = bisect(debug,
                                          -100,
                                          100,
                                          xtol=tol,
                                          maxiter=100)

            elif method == "fallback":
                try:
                    gw_energies[i_p] = newton(debug,
                                              imds.initial_guess(p),
                                              tol=tol,
                                              maxiter=100)
                except RuntimeError:
                    logger.warn(
                        imds.td._scf,
                        "Failed to converge with newton, using bisect on the interval [{:.3e}, {:.3e}]"
                        .format(
                            min(debug.x),
                            max(debug.x),
                        ))
                    gw_energies[i_p] = bisect(debug,
                                              min(debug.x),
                                              max(debug.x),
                                              xtol=tol,
                                              maxiter=100)

    return gw_energies
Exemple #32
0
 def check_sanity(self):
     cell = self.cell
     if cell.spin != 0 and len(self.kpts) % 2 != 0:
         logger.warn(self, 'Problematic nelec %s and number of k-points %d '
                     'found in KRHF method.', cell.nelec, len(self.kpts))
     return KSCF.check_sanity(self)
Exemple #33
0
def kernel(mycc, eris, t1=None, t2=None, verbose=logger.NOTE):
    cpu1 = cpu0 = (logger.process_clock(), logger.perf_counter())
    log = logger.new_logger(mycc, verbose)
    if t1 is None: t1 = mycc.t1
    if t2 is None: t2 = mycc.t2

    nocc, nvir = t1.shape
    nmo = nocc + nvir

    dtype = numpy.result_type(t1, t2, eris.ovoo.dtype)
    if mycc.incore_complete:
        ftmp = None
        eris_vvop = numpy.zeros((nvir, nvir, nocc, nmo), dtype)
    else:
        ftmp = lib.H5TmpFile()
        eris_vvop = ftmp.create_dataset('vvop', (nvir, nvir, nocc, nmo), dtype)

    orbsym = _sort_eri(mycc, eris, nocc, nvir, eris_vvop, log)

    mo_energy, t1T, t2T, vooo, fvo, restore_t2_inplace = \
            _sort_t2_vooo_(mycc, orbsym, t1, t2, eris)
    cpu1 = log.timer_debug1('QCISD(T) sort_eri', *cpu1)

    cpu2 = list(cpu1)
    orbsym = numpy.hstack(
        (numpy.sort(orbsym[:nocc]), numpy.sort(orbsym[nocc:])))
    o_ir_loc = numpy.append(
        0, numpy.cumsum(numpy.bincount(orbsym[:nocc], minlength=8)))
    v_ir_loc = numpy.append(
        0, numpy.cumsum(numpy.bincount(orbsym[nocc:], minlength=8)))
    o_sym = orbsym[:nocc]
    oo_sym = (o_sym[:, None] ^ o_sym).ravel()
    oo_ir_loc = numpy.append(0,
                             numpy.cumsum(numpy.bincount(oo_sym, minlength=8)))
    nirrep = max(oo_sym) + 1

    orbsym = orbsym.astype(numpy.int32)
    o_ir_loc = o_ir_loc.astype(numpy.int32)
    v_ir_loc = v_ir_loc.astype(numpy.int32)
    oo_ir_loc = oo_ir_loc.astype(numpy.int32)
    if dtype == numpy.complex:
        drv = _ccsd.libcc.QCIsd_t_zcontract
    else:
        drv = _ccsd.libcc.QCIsd_t_contract
    et_sum = numpy.zeros(1, dtype=dtype)

    def contract(a0, a1, b0, b1, cache):
        cache_row_a, cache_col_a, cache_row_b, cache_col_b = cache
        drv(et_sum.ctypes.data_as(ctypes.c_void_p),
            mo_energy.ctypes.data_as(ctypes.c_void_p),
            t1T.ctypes.data_as(ctypes.c_void_p),
            t2T.ctypes.data_as(ctypes.c_void_p),
            vooo.ctypes.data_as(ctypes.c_void_p),
            fvo.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(nocc),
            ctypes.c_int(nvir), ctypes.c_int(a0), ctypes.c_int(a1),
            ctypes.c_int(b0), ctypes.c_int(b1), ctypes.c_int(nirrep),
            o_ir_loc.ctypes.data_as(ctypes.c_void_p),
            v_ir_loc.ctypes.data_as(ctypes.c_void_p),
            oo_ir_loc.ctypes.data_as(ctypes.c_void_p),
            orbsym.ctypes.data_as(ctypes.c_void_p),
            cache_row_a.ctypes.data_as(ctypes.c_void_p),
            cache_col_a.ctypes.data_as(ctypes.c_void_p),
            cache_row_b.ctypes.data_as(ctypes.c_void_p),
            cache_col_b.ctypes.data_as(ctypes.c_void_p))
        cpu2[:] = log.timer_debug1('contract %d:%d,%d:%d' % (a0, a1, b0, b1),
                                   *cpu2)

    # The rest 20% memory for cache b
    mem_now = lib.current_memory()[0]
    max_memory = max(0, mycc.max_memory - mem_now)
    bufsize = (max_memory * .5e6 / 8 - nocc**3 * 3 * lib.num_threads()) / (
        nocc * nmo)  #*.5 for async_io
    bufsize *= .5  #*.5 upper triangular part is loaded
    bufsize *= .8  #*.8 for [a0:a1]/[b0:b1] partition
    bufsize = max(8, bufsize)
    log.debug('max_memory %d MB (%d MB in use)', max_memory, mem_now)
    with lib.call_in_background(contract,
                                sync=not mycc.async_io) as async_contract:
        for a0, a1 in reversed(list(lib.prange_tril(0, nvir, bufsize))):
            cache_row_a = numpy.asarray(eris_vvop[a0:a1, :a1], order='C')
            if a0 == 0:
                cache_col_a = cache_row_a
            else:
                cache_col_a = numpy.asarray(eris_vvop[:a0, a0:a1], order='C')
            async_contract(
                a0, a1, a0, a1,
                (cache_row_a, cache_col_a, cache_row_a, cache_col_a))

            for b0, b1 in lib.prange_tril(0, a0, bufsize / 8):
                cache_row_b = numpy.asarray(eris_vvop[b0:b1, :b1], order='C')
                if b0 == 0:
                    cache_col_b = cache_row_b
                else:
                    cache_col_b = numpy.asarray(eris_vvop[:b0, b0:b1],
                                                order='C')
                async_contract(
                    a0, a1, b0, b1,
                    (cache_row_a, cache_col_a, cache_row_b, cache_col_b))

    t2 = restore_t2_inplace(t2T)
    et_sum *= 2
    if abs(et_sum[0].imag) > 1e-4:
        logger.warn(mycc,
                    'Non-zero imaginary part of QCISD(T) energy was found %s',
                    et_sum[0])
    et = et_sum[0].real
    log.timer('QCISD(T)', *cpu0)
    log.note('QCISD(T) correction = %.15g', et)
    return et
Exemple #34
0
def fast_scf(mf):
    from pyscf.lib import logger
    logger.warn(
        mf, 'NOTE function fast_scf will be removed in the next release. '
        'Use function fast_newton instead')
    return fast_newton(mf)
Exemple #35
0
def ipccsd_star_contract(eom,
                         ipccsd_evals,
                         ipccsd_evecs,
                         lipccsd_evecs,
                         imds=None):
    """
    Returns:
        e_star (list of float):
            The IP-CCSD* energy.

    Notes:
        The user should check to make sure the right and left eigenvalues
        before running the perturbative correction.

        The 2hp right amplitudes are assumed to be of the form s^{a }_{ij}, i.e.
        the (ia) indices are coupled while the left are assumed to be of the form
        s^{ b}_{ij}, i.e. the (jb) indices are coupled.

    Reference:
        Saeh, Stanton "...energy surfaces of radicals" JCP 111, 8275 (1999); DOI:10.1063/1.480171
    """
    assert eom.partition is None
    if imds is None:
        imds = eom.make_imds()
    t1, t2 = imds.t1, imds.t2
    eris = imds.eris
    assert (isinstance(eris, gccsd._PhysicistsERIs))
    fock = eris.fock
    nocc, nvir = t1.shape
    nmo = nocc + nvir

    #fov = fock[:nocc, nocc:]
    foo = fock[:nocc, :nocc].diagonal()
    fvv = fock[nocc:, nocc:].diagonal()

    oovv = _cp(eris.oovv)
    ovvv = _cp(eris.ovvv)
    ovov = _cp(eris.ovov)
    #ovvo = -_cp(eris.ovov).transpose(0,1,3,2)
    ooov = _cp(eris.ooov)
    vooo = _cp(ooov).conj().transpose(3, 2, 1, 0)
    vvvo = _cp(ovvv).conj().transpose(3, 2, 1, 0)
    oooo = _cp(eris.oooo)

    # Create denominator
    eijk = foo[:, None, None] + foo[None, :, None] + foo[None, None, :]
    eab = fvv[:, None] + fvv[None, :]
    eijkab = eijk[:, :, :, None, None] - eab[None, None, None, :, :]

    # Permutation operators
    def pijk(tmp):
        '''P(ijk)'''
        return tmp + tmp.transpose(1, 2, 0, 3, 4) + tmp.transpose(
            2, 0, 1, 3, 4)

    def pab(tmp):
        '''P(ab)'''
        return tmp - tmp.transpose(0, 1, 2, 4, 3)

    def pij(tmp):
        '''P(ij)'''
        return tmp - tmp.transpose(1, 0, 2, 3, 4)

    ipccsd_evecs = np.array(ipccsd_evecs)
    lipccsd_evecs = np.array(lipccsd_evecs)
    e_star = []
    ipccsd_evecs, lipccsd_evecs = [
        np.atleast_2d(x) for x in [ipccsd_evecs, lipccsd_evecs]
    ]
    ipccsd_evals = np.atleast_1d(ipccsd_evals)
    for ip_eval, ip_evec, ip_levec in zip(ipccsd_evals, ipccsd_evecs,
                                          lipccsd_evecs):
        # Enforcing <L|R> = 1
        l1, l2 = vector_to_amplitudes_ip(ip_levec, nmo, nocc)
        r1, r2 = vector_to_amplitudes_ip(ip_evec, nmo, nocc)
        ldotr = np.dot(l1, r1) + 0.5 * np.dot(l2.ravel(), r2.ravel())

        logger.info(eom, 'Left-right amplitude overlap : %14.8e', ldotr)
        if abs(ldotr) < 1e-7:
            logger.warn(
                eom, 'Small %s left-right amplitude overlap. Results '
                'may be inaccurate.', ldotr)

        l1 /= ldotr
        l2 /= ldotr

        # Denominator + eigenvalue(IP-CCSD)
        denom = eijkab + ip_eval
        denom = 1. / denom

        tmp = lib.einsum('ijab,k->ijkab', oovv, l1)
        lijkab = pijk(tmp)
        tmp = -lib.einsum('jima,mkb->ijkab', ooov, l2)
        tmp = pijk(tmp)
        lijkab += pab(tmp)
        tmp = lib.einsum('ieab,jke->ijkab', ovvv, l2)
        lijkab += pijk(tmp)

        tmp = lib.einsum('mbke,m->bke', ovov, r1)
        tmp = lib.einsum('bke,ijae->ijkab', tmp, t2)
        tmp = pijk(tmp)
        rijkab = -pab(tmp)
        tmp = lib.einsum('mnjk,n->mjk', oooo, r1)
        tmp = lib.einsum('mjk,imab->ijkab', tmp, t2)
        rijkab += pijk(tmp)
        tmp = lib.einsum('amij,mkb->ijkab', vooo, r2)
        tmp = pijk(tmp)
        rijkab -= pab(tmp)
        tmp = lib.einsum('baei,jke->ijkab', vvvo, r2)
        rijkab += pijk(tmp)

        deltaE = (1. / 12) * lib.einsum('ijkab,ijkab,ijkab', lijkab, rijkab,
                                        denom)
        deltaE = deltaE.real
        logger.info(eom, "Exc. energy, delta energy = %16.12f, %16.12f",
                    ip_eval + deltaE, deltaE)
        e_star.append(ip_eval + deltaE)
    return e_star
Exemple #36
0
def eval_ao(mol, coords, deriv=0, relativity=0, shls_slice=None,
            non0tab=None, out=None, verbose=None):
    '''Evaluate AO function value on the given grids.

    Args:
        mol : an instance of :class:`Mole`

        coords : 2D array, shape (N,3)
            The coordinates of the grids.

    Kwargs:
        deriv : int
            AO derivative order.  It affects the shape of the return array.
            If deriv=0, the returned AO values are stored in a (N,nao) array.
            Otherwise the AO values are stored in an array of shape (M,N,nao).
            Here N is the number of grids, nao is the number of AO functions,
            M is the size associated to the derivative deriv.
        relativity : bool
            No effects.
        shls_slice : 2-element list
            (shl_start, shl_end).
            If given, only part of AOs (shl_start <= shell_id < shl_end) are
            evaluated.  By default, all shells defined in mol will be evaluated.
        non0tab : 2D bool array
            mask array to indicate whether the AO values are zero.  The mask
            array can be obtained by calling :func:`make_mask`
        out : ndarray
            If provided, results are written into this array.
        verbose : int or object of :class:`Logger`
            No effects.

    Returns:
        2D array of shape (N,nao) for AO values if deriv = 0.
        Or 3D array of shape (:,N,nao) for AO values and AO derivatives if deriv > 0.
        In the 3D array, the first (N,nao) elements are the AO values,
        followed by (3,N,nao) for x,y,z compoents;
        Then 2nd derivatives (6,N,nao) for xx, xy, xz, yy, yz, zz;
        Then 3rd derivatives (10,N,nao) for xxx, xxy, xxz, xyy, xyz, xzz, yyy, yyz, yzz, zzz;
        ...

    Examples:

    >>> mol = gto.M(atom='O 0 0 0; H 0 0 1; H 0 1 0', basis='ccpvdz')
    >>> coords = numpy.random.random((100,3))  # 100 random points
    >>> ao_value = eval_ao(mol, coords)
    >>> print(ao_value.shape)
    (100, 24)
    >>> ao_value = eval_ao(mol, coords, deriv=1, shls_slice=(1,4))
    >>> print(ao_value.shape)
    (4, 100, 7)
    >>> ao_value = eval_ao(mol, coords, deriv=2, shls_slice=(1,4))
    >>> print(ao_value.shape)
    (10, 100, 7)
    '''
    if isinstance(deriv, bool):
        logger.warn(mol, '''
You see this error message because of the API updates in pyscf v1.1.
Argument "isgga" is replaced by argument "deriv", to support high order AO derivatives''')

    comp = (deriv+1)*(deriv+2)*(deriv+3)//6
    feval = 'GTOval_sph_deriv%d' % deriv
    return mol.eval_gto(feval, coords, comp, shls_slice, non0tab, out)
Exemple #37
0
def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None):
    r'''A and B matrices for TDDFT response function.

    A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj)
    B[i,a,j,b] = (ia||jb)
    '''
    if mo_energy is None: mo_energy = mf.mo_energy
    if mo_coeff is None: mo_coeff = mf.mo_coeff
    if mo_occ is None: mo_occ = mf.mo_occ
    assert(mo_coeff.dtype == numpy.double)

    mol = mf.mol
    nao, nmo = mo_coeff.shape
    occidx = numpy.where(mo_occ==2)[0]
    viridx = numpy.where(mo_occ==0)[0]
    orbv = mo_coeff[:,viridx]
    orbo = mo_coeff[:,occidx]
    nvir = orbv.shape[1]
    nocc = orbo.shape[1]
    mo = numpy.hstack((orbo,orbv))
    nmo = nocc + nvir

    e_ia = lib.direct_sum('a-i->ia', mo_energy[viridx], mo_energy[occidx])
    a = numpy.diag(e_ia.ravel()).reshape(nocc,nvir,nocc,nvir)
    b = numpy.zeros_like(a)

    def add_hf_(a, b, hyb=1):
        eri_mo = ao2mo.general(mol, [orbo,mo,mo,mo], compact=False)
        eri_mo = eri_mo.reshape(nocc,nmo,nmo,nmo)
        a += numpy.einsum('iabj->iajb', eri_mo[:nocc,nocc:,nocc:,:nocc]) * 2
        a -= numpy.einsum('ijba->iajb', eri_mo[:nocc,:nocc,nocc:,nocc:]) * hyb

        b += numpy.einsum('iajb->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * 2
        b -= numpy.einsum('jaib->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * hyb

    if getattr(mf, 'xc', None) and getattr(mf, '_numint', None):
        from pyscf.dft import rks
        from pyscf.dft import numint
        ni = mf._numint
        ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True)
        if getattr(mf, 'nlc', '') != '':
            logger.warn(mf, 'NLC functional found in DFT object.  Its second '
                        'deriviative is not available. Its contribution is '
                        'not included in the response function.')
        omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin)

        add_hf_(a, b, hyb)

        xctype = ni._xc_type(mf.xc)
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        make_rho = ni._gen_rho_evaluator(mol, dm0, hermi=1)[0]
        mem_now = lib.current_memory()[0]
        max_memory = max(2000, mf.max_memory*.8-mem_now)

        if xctype == 'LDA':
            ao_deriv = 0
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory):
                rho = make_rho(0, ao, mask, 'LDA')
                fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[2]
                frr = fxc[0]

                rho_o = lib.einsum('rp,pi->ri', ao, orbo)
                rho_v = lib.einsum('rp,pi->ri', ao, orbv)
                rho_ov = numpy.einsum('ri,ra->ria', rho_o, rho_v)
                w_ov = numpy.einsum('ria,r->ria', rho_ov, weight*frr)
                iajb = lib.einsum('ria,rjb->iajb', rho_ov, w_ov) * 2
                a += iajb
                b += iajb

        elif xctype == 'GGA':
            ao_deriv = 1
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory):
                rho = make_rho(0, ao, mask, 'GGA')
                vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3]
                vgamma = vxc[1]
                frho, frhogamma, fgg = fxc[:3]

                rho_o = lib.einsum('xrp,pi->xri', ao, orbo)
                rho_v = lib.einsum('xrp,pi->xri', ao, orbv)
                rho_ov = numpy.einsum('xri,ra->xria', rho_o, rho_v[0])
                rho_ov[1:4] += numpy.einsum('ri,xra->xria', rho_o[0], rho_v[1:4])
                # sigma1 ~ \nabla(\rho_\alpha+\rho_\beta) dot \nabla(|b><j|) z_{bj}
                sigma1 = numpy.einsum('xr,xria->ria', rho[1:4], rho_ov[1:4])

                w_ov = numpy.empty_like(rho_ov)
                w_ov[0]  = numpy.einsum('r,ria->ria', frho, rho_ov[0])
                w_ov[0] += numpy.einsum('r,ria->ria', 2*frhogamma, sigma1)
                f_ov = numpy.einsum('r,ria->ria', 4*fgg, sigma1)
                f_ov+= numpy.einsum('r,ria->ria', 2*frhogamma, rho_ov[0])
                w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov, rho[1:4])
                w_ov[1:]+= numpy.einsum('r,xria->xria', 2*vgamma, rho_ov[1:4])
                w_ov *= weight[:,None,None]
                iajb = lib.einsum('xria,xrjb->iajb', rho_ov, w_ov) * 2
                a += iajb
                b += iajb

        elif xctype == 'NLC':
            raise NotImplementedError('NLC')
        elif xctype == 'MGGA':
            raise NotImplementedError('meta-GGA')

    else:
        add_hf_(a, b)

    return a, b
Exemple #38
0
def _dip_correction(mf):
    '''Makov-Payne corrections for charged systems.'''
    from pyscf.pbc import gto
    from pyscf.pbc import tools
    from pyscf.pbc.dft import gen_grid
    log = logger.new_logger(mf)
    cell = mf.cell
    a = cell.lattice_vectors()
    b = np.linalg.inv(a).T

    grids = gen_grid.UniformGrids(cell)
    ke_cutoff = gto.estimate_ke_cutoff(cell, 1e-5)
    grids.mesh = tools.cutoff_to_mesh(a, ke_cutoff)

    dm = mf.make_rdm1()
    rho = mf.get_rho(dm, grids, mf.kpt)
    origin = _search_dipole_gauge_origin(cell, grids, rho, log)

    def shift_grids(r):
        r_frac = lib.dot(r - origin, b.T)
        # Grids on the boundary (r_frac == +/-0.5) of the new cell may lead to
        # unbalanced contributions to the dipole moment. Exclude them from the
        # dipole and quadrupole
        r_frac[r_frac == 0.5] = 0
        r_frac[r_frac == -0.5] = 0
        r_frac[r_frac > 0.5] -= 1
        r_frac[r_frac < -0.5] += 1
        r = lib.dot(r_frac, a)
        return r

    #           SC              BCC             FCC
    madelung = (-2.83729747948, -3.63923344951, -4.58486207411)
    vol = cell.vol
    L = vol**(1. / 3)
    chg = cell.charge

    # epsilon is the dielectric constant of the system. For systems
    # surrounded by vacuum, epsilon = 1.
    epsilon = 1

    # Energy correction of point charges of a simple cubic lattice.
    de_mono = -chg**2 * np.array(madelung) / (2 * L * epsilon)

    # dipole energy correction
    r_e = shift_grids(grids.coords)
    r_nuc = shift_grids(cell.atom_coords())
    charges = cell.atom_charges()
    e_dip = np.einsum('g,g,gx->x', rho, grids.weights, r_e)
    nuc_dip = np.einsum('g,gx->x', charges, r_nuc)
    dip = nuc_dip - e_dip
    de_dip = -2. * np.pi / (3 * cell.vol) * np.linalg.norm(dip)**2

    # quadrupole energy correction
    if abs(a - np.eye(3) * L).max() > 1e-5:
        logger.warn(
            mf, 'System is not cubic cell. Quadrupole energy '
            'correction is inaccurate since it is developed based on '
            'cubic cell.')
    e_quad = np.einsum('g,g,gx,gx->', rho, grids.weights, r_e, r_e)
    nuc_quad = np.einsum('g,gx,gx->', charges, r_nuc, r_nuc)
    quad = nuc_quad - e_quad
    de_quad = 2. * np.pi / (3 * cell.vol) * quad

    de = de_mono + de_dip + de_quad
    return de_mono, de_dip, de_quad, de
Exemple #39
0
def _make_eris_incore(cc, mo_coeff=None):
    from pyscf.pbc import tools
    from pyscf.pbc.cc.ccsd import _adjust_occ

    log = logger.Logger(cc.stdout, cc.verbose)
    cput0 = (time.clock(), time.time())
    eris = gccsd._PhysicistsERIs()
    cell = cc._scf.cell
    kpts = cc.kpts
    nkpts = cc.nkpts
    nocc = cc.nocc
    nmo = cc.nmo
    nvir = nmo - nocc
    eris.nocc = nocc

    #if any(nocc != numpy.count_nonzero(cc._scf.mo_occ[k] > 0) for k in range(nkpts)):
    #    raise NotImplementedError('Different occupancies found for different k-points')

    if mo_coeff is None:
        mo_coeff = cc.mo_coeff

    nao = mo_coeff[0].shape[0]
    dtype = mo_coeff[0].dtype

    moidx = get_frozen_mask(cc)
    nocc_per_kpt = numpy.asarray(get_nocc(cc, per_kpoint=True))
    nmo_per_kpt = numpy.asarray(get_nmo(cc, per_kpoint=True))

    padded_moidx = []
    for k in range(nkpts):
        kpt_nocc = nocc_per_kpt[k]
        kpt_nvir = nmo_per_kpt[k] - kpt_nocc
        kpt_padded_moidx = numpy.concatenate(
            (numpy.ones(kpt_nocc, dtype=numpy.bool),
             numpy.zeros(nmo - kpt_nocc - kpt_nvir, dtype=numpy.bool),
             numpy.ones(kpt_nvir, dtype=numpy.bool)))
        padded_moidx.append(kpt_padded_moidx)

    eris.mo_coeff = []
    eris.orbspin = []
    # Generate the molecular orbital coefficients with the frozen orbitals masked.
    # Each MO is tagged with orbspin, a list of 0's and 1's that give the overall
    # spin of each MO.
    #
    # Here we will work with two index arrays; one is for our original (small) moidx
    # array while the next is for our new (large) padded array.
    for k in range(nkpts):
        kpt_moidx = moidx[k]
        kpt_padded_moidx = padded_moidx[k]

        mo = numpy.zeros((nao, nmo), dtype=dtype)
        mo[:, kpt_padded_moidx] = mo_coeff[k][:, kpt_moidx]
        if getattr(mo_coeff[k], 'orbspin', None) is not None:
            orbspin_dtype = mo_coeff[k].orbspin[kpt_moidx].dtype
            orbspin = numpy.zeros(nmo, dtype=orbspin_dtype)
            orbspin[kpt_padded_moidx] = mo_coeff[k].orbspin[kpt_moidx]
            mo = lib.tag_array(mo, orbspin=orbspin)
            eris.orbspin.append(orbspin)
        # FIXME: What if the user freezes all up spin orbitals in
        # an RHF calculation?  The number of electrons will still be
        # even.
        else:  # guess orbital spin - assumes an RHF calculation
            assert (numpy.count_nonzero(kpt_moidx) % 2 == 0)
            orbspin = numpy.zeros(mo.shape[1], dtype=int)
            orbspin[1::2] = 1
            mo = lib.tag_array(mo, orbspin=orbspin)
            eris.orbspin.append(orbspin)
        eris.mo_coeff.append(mo)

    # Re-make our fock MO matrix elements from density and fock AO
    dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ)
    with lib.temporary_env(cc._scf, exxdiv=None):
        # _scf.exxdiv affects eris.fock. HF exchange correction should be
        # excluded from the Fock matrix.
        fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm)
    eris.fock = numpy.asarray([
        reduce(numpy.dot, (mo.T.conj(), fockao[k], mo))
        for k, mo in enumerate(eris.mo_coeff)
    ])

    eris.mo_energy = [eris.fock[k].diagonal().real for k in range(nkpts)]
    # Add HFX correction in the eris.mo_energy to improve convergence in
    # CCSD iteration. It is useful for the 2D systems since their occupied and
    # the virtual orbital energies may overlap which may lead to numerical
    # issue in the CCSD iterations.
    # FIXME: Whether to add this correction for other exxdiv treatments?
    # Without the correction, MP2 energy may be largely off the correct value.
    madelung = tools.madelung(cell, kpts)
    eris.mo_energy = [
        _adjust_occ(mo_e, nocc, -madelung)
        for k, mo_e in enumerate(eris.mo_energy)
    ]

    # Get location of padded elements in occupied and virtual space.
    nocc_per_kpt = get_nocc(cc, per_kpoint=True)
    nonzero_padding = padding_k_idx(cc, kind="joint")

    # Check direct and indirect gaps for possible issues with CCSD convergence.
    mo_e = [eris.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)]
    mo_e = numpy.sort([y for x in mo_e for y in x])  # Sort de-nested array
    gap = mo_e[numpy.sum(nocc_per_kpt)] - mo_e[numpy.sum(nocc_per_kpt) - 1]
    if gap < 1e-5:
        logger.warn(
            cc, 'H**O-LUMO gap %s too small for KCCSD. '
            'May cause issues in convergence.', gap)

    kconserv = kpts_helper.get_kconserv(cell, kpts)
    if getattr(mo_coeff[0], 'orbspin', None) is None:
        # The bottom nao//2 coefficients are down (up) spin while the top are up (down).
        mo_a_coeff = [mo[:nao // 2] for mo in eris.mo_coeff]
        mo_b_coeff = [mo[nao // 2:] for mo in eris.mo_coeff]

        eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo),
                          dtype=numpy.complex128)
        fao2mo = cc._scf.with_df.ao2mo
        for kp, kq, kr in kpts_helper.loop_kkk(nkpts):
            ks = kconserv[kp, kq, kr]
            eri_kpt = fao2mo((mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr],
                              mo_a_coeff[ks]),
                             (kpts[kp], kpts[kq], kpts[kr], kpts[ks]),
                             compact=False)
            eri_kpt += fao2mo((mo_b_coeff[kp], mo_b_coeff[kq], mo_b_coeff[kr],
                               mo_b_coeff[ks]),
                              (kpts[kp], kpts[kq], kpts[kr], kpts[ks]),
                              compact=False)
            eri_kpt += fao2mo((mo_a_coeff[kp], mo_a_coeff[kq], mo_b_coeff[kr],
                               mo_b_coeff[ks]),
                              (kpts[kp], kpts[kq], kpts[kr], kpts[ks]),
                              compact=False)
            eri_kpt += fao2mo((mo_b_coeff[kp], mo_b_coeff[kq], mo_a_coeff[kr],
                               mo_a_coeff[ks]),
                              (kpts[kp], kpts[kq], kpts[kr], kpts[ks]),
                              compact=False)

            eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo)
            eri[kp, kq, kr] = eri_kpt
    else:
        mo_a_coeff = [mo[:nao // 2] + mo[nao // 2:] for mo in eris.mo_coeff]

        eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo),
                          dtype=numpy.complex128)
        fao2mo = cc._scf.with_df.ao2mo
        for kp, kq, kr in kpts_helper.loop_kkk(nkpts):
            ks = kconserv[kp, kq, kr]
            eri_kpt = fao2mo((mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr],
                              mo_a_coeff[ks]),
                             (kpts[kp], kpts[kq], kpts[kr], kpts[ks]),
                             compact=False)

            eri_kpt[(eris.orbspin[kp][:, None] !=
                     eris.orbspin[kq]).ravel()] = 0
            eri_kpt[:,
                    (eris.orbspin[kr][:,
                                      None] != eris.orbspin[ks]).ravel()] = 0
            eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo)
            eri[kp, kq, kr] = eri_kpt

    # Check some antisymmetrized properties of the integrals
    if DEBUG:
        check_antisymm_3412(cc, cc.kpts, eri)

    # Antisymmetrizing (pq|rs)-(ps|rq), where the latter integral is equal to
    # (rq|ps); done since we aren't tracking the kpoint of orbital 's'
    eri = eri - eri.transpose(2, 1, 0, 5, 4, 3, 6)
    # Chemist -> physics notation
    eri = eri.transpose(0, 2, 1, 3, 5, 4, 6)

    # Set the various integrals
    eris.dtype = eri.dtype
    eris.oooo = eri[:, :, :, :nocc, :nocc, :nocc, :nocc].copy() / nkpts
    eris.ooov = eri[:, :, :, :nocc, :nocc, :nocc, nocc:].copy() / nkpts
    eris.ovoo = eri[:, :, :, :nocc, nocc:, :nocc, :nocc].copy() / nkpts
    eris.oovv = eri[:, :, :, :nocc, :nocc, nocc:, nocc:].copy() / nkpts
    eris.ovov = eri[:, :, :, :nocc, nocc:, :nocc, nocc:].copy() / nkpts
    eris.ovvv = eri[:, :, :, :nocc, nocc:, nocc:, nocc:].copy() / nkpts
    eris.vvvv = eri[:, :, :, nocc:, nocc:, nocc:, nocc:].copy() / nkpts

    log.timer('CCSD integral transformation', *cput0)
    return eris
Exemple #40
0
def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None):
    r'''A and B matrices for TDDFT response function.

    A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj)
    B[i,a,j,b] = (ia||jb)

    Spin symmetry is considered in the returned A, B lists.  List A has three
    items: (A_aaaa, A_aabb, A_bbbb). A_bbaa = A_aabb.transpose(2,3,0,1).
    B has three items: (B_aaaa, B_aabb, B_bbbb).
    B_bbaa = B_aabb.transpose(2,3,0,1).
    '''
    if mo_energy is None: mo_energy = mf.mo_energy
    if mo_coeff is None: mo_coeff = mf.mo_coeff
    if mo_occ is None: mo_occ = mf.mo_occ

    mol = mf.mol
    nao = mol.nao_nr()
    occidx_a = numpy.where(mo_occ[0] == 1)[0]
    viridx_a = numpy.where(mo_occ[0] == 0)[0]
    occidx_b = numpy.where(mo_occ[1] == 1)[0]
    viridx_b = numpy.where(mo_occ[1] == 0)[0]
    orbo_a = mo_coeff[0][:, occidx_a]
    orbv_a = mo_coeff[0][:, viridx_a]
    orbo_b = mo_coeff[1][:, occidx_b]
    orbv_b = mo_coeff[1][:, viridx_b]
    nocc_a = orbo_a.shape[1]
    nvir_a = orbv_a.shape[1]
    nocc_b = orbo_b.shape[1]
    nvir_b = orbv_b.shape[1]
    mo_a = numpy.hstack((orbo_a, orbv_a))
    mo_b = numpy.hstack((orbo_b, orbv_b))
    nmo_a = nocc_a + nvir_a
    nmo_b = nocc_b + nvir_b

    e_ia_a = (mo_energy[0][viridx_a, None] - mo_energy[0][occidx_a]).T
    e_ia_b = (mo_energy[1][viridx_b, None] - mo_energy[1][occidx_b]).T
    a_aa = numpy.diag(e_ia_a.ravel()).reshape(nocc_a, nvir_a, nocc_a, nvir_a)
    a_bb = numpy.diag(e_ia_b.ravel()).reshape(nocc_b, nvir_b, nocc_b, nvir_b)
    a_ab = numpy.zeros((nocc_a, nvir_a, nocc_b, nvir_b))
    b_aa = numpy.zeros_like(a_aa)
    b_ab = numpy.zeros_like(a_ab)
    b_bb = numpy.zeros_like(a_bb)
    a = (a_aa, a_ab, a_bb)
    b = (b_aa, b_ab, b_bb)

    def add_hf_(a, b, hyb=1):
        eri_aa = ao2mo.general(mol, [orbo_a, mo_a, mo_a, mo_a], compact=False)
        eri_ab = ao2mo.general(mol, [orbo_a, mo_a, mo_b, mo_b], compact=False)
        eri_bb = ao2mo.general(mol, [orbo_b, mo_b, mo_b, mo_b], compact=False)
        eri_aa = eri_aa.reshape(nocc_a, nmo_a, nmo_a, nmo_a)
        eri_ab = eri_ab.reshape(nocc_a, nmo_a, nmo_b, nmo_b)
        eri_bb = eri_bb.reshape(nocc_b, nmo_b, nmo_b, nmo_b)
        a_aa, a_ab, a_bb = a
        b_aa, b_ab, b_bb = b

        a_aa += numpy.einsum('iabj->iajb', eri_aa[:nocc_a, nocc_a:,
                                                  nocc_a:, :nocc_a])
        a_aa -= numpy.einsum('ijba->iajb', eri_aa[:nocc_a, :nocc_a, nocc_a:,
                                                  nocc_a:]) * hyb
        b_aa += numpy.einsum('iajb->iajb', eri_aa[:nocc_a, nocc_a:, :nocc_a,
                                                  nocc_a:])
        b_aa -= numpy.einsum('jaib->iajb', eri_aa[:nocc_a, nocc_a:, :nocc_a,
                                                  nocc_a:]) * hyb

        a_bb += numpy.einsum('iabj->iajb', eri_bb[:nocc_b, nocc_b:,
                                                  nocc_b:, :nocc_b])
        a_bb -= numpy.einsum('ijba->iajb', eri_bb[:nocc_b, :nocc_b, nocc_b:,
                                                  nocc_b:]) * hyb
        b_bb += numpy.einsum('iajb->iajb', eri_bb[:nocc_b, nocc_b:, :nocc_b,
                                                  nocc_b:])
        b_bb -= numpy.einsum('jaib->iajb', eri_bb[:nocc_b, nocc_b:, :nocc_b,
                                                  nocc_b:]) * hyb

        a_ab += numpy.einsum('iabj->iajb', eri_ab[:nocc_a, nocc_a:,
                                                  nocc_b:, :nocc_b])
        b_ab += numpy.einsum('iajb->iajb', eri_ab[:nocc_a, nocc_a:, :nocc_b,
                                                  nocc_b:])

    if getattr(mf, 'xc', None) and getattr(mf, '_numint', None):
        from pyscf.dft import rks
        from pyscf.dft import numint
        ni = mf._numint
        ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True)
        if getattr(mf, 'nlc', '') != '':
            logger.warn(
                mf, 'NLC functional found in DFT object.  Its second '
                'deriviative is not available. Its contribution is '
                'not included in the response function.')
        omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin)

        add_hf_(a, b, hyb)

        xctype = ni._xc_type(mf.xc)
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        make_rho = ni._gen_rho_evaluator(mol, dm0, hermi=1)[0]
        mem_now = lib.current_memory()[0]
        max_memory = max(2000, mf.max_memory * .8 - mem_now)

        if xctype == 'LDA':
            ao_deriv = 0
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory):
                rho0a = make_rho(0, ao, mask, 'LDA')
                rho0b = make_rho(1, ao, mask, 'LDA')
                fxc = ni.eval_xc(mf.xc, (rho0a, rho0b), 1, deriv=2)[2]
                u_u, u_d, d_d = fxc[0].T

                rho_o_a = lib.einsum('rp,pi->ri', ao, orbo_a)
                rho_v_a = lib.einsum('rp,pi->ri', ao, orbv_a)
                rho_o_b = lib.einsum('rp,pi->ri', ao, orbo_b)
                rho_v_b = lib.einsum('rp,pi->ri', ao, orbv_b)
                rho_ov_a = numpy.einsum('ri,ra->ria', rho_o_a, rho_v_a)
                rho_ov_b = numpy.einsum('ri,ra->ria', rho_o_b, rho_v_b)

                w_ov = numpy.einsum('ria,r->ria', rho_ov_a, weight * u_u)
                iajb = lib.einsum('ria,rjb->iajb', rho_ov_a, w_ov)
                a_aa += iajb
                b_aa += iajb

                w_ov = numpy.einsum('ria,r->ria', rho_ov_b, weight * u_d)
                iajb = lib.einsum('ria,rjb->iajb', rho_ov_a, w_ov)
                a_ab += iajb
                b_ab += iajb

                w_ov = numpy.einsum('ria,r->ria', rho_ov_b, weight * d_d)
                iajb = lib.einsum('ria,rjb->iajb', rho_ov_b, w_ov)
                a_bb += iajb
                b_bb += iajb

        elif xctype == 'GGA':
            ao_deriv = 1
            for ao, mask, weight, coords \
                    in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory):
                rho0a = make_rho(0, ao, mask, 'GGA')
                rho0b = make_rho(1, ao, mask, 'GGA')
                vxc, fxc = ni.eval_xc(mf.xc, (rho0a, rho0b), 1, deriv=2)[1:3]
                uu, ud, dd = vxc[1].T
                u_u, u_d, d_d = fxc[0].T
                u_uu, u_ud, u_dd, d_uu, d_ud, d_dd = fxc[1].T
                uu_uu, uu_ud, uu_dd, ud_ud, ud_dd, dd_dd = fxc[2].T

                rho_o_a = lib.einsum('xrp,pi->xri', ao, orbo_a)
                rho_v_a = lib.einsum('xrp,pi->xri', ao, orbv_a)
                rho_o_b = lib.einsum('xrp,pi->xri', ao, orbo_b)
                rho_v_b = lib.einsum('xrp,pi->xri', ao, orbv_b)
                rho_ov_a = numpy.einsum('xri,ra->xria', rho_o_a, rho_v_a[0])
                rho_ov_b = numpy.einsum('xri,ra->xria', rho_o_b, rho_v_b[0])
                rho_ov_a[1:4] += numpy.einsum('ri,xra->xria', rho_o_a[0],
                                              rho_v_a[1:4])
                rho_ov_b[1:4] += numpy.einsum('ri,xra->xria', rho_o_b[0],
                                              rho_v_b[1:4])
                # sigma1 ~ \nabla(\rho_\alpha+\rho_\beta) dot \nabla(|b><j|) z_{bj}
                a0a1 = numpy.einsum('xr,xria->ria', rho0a[1:4], rho_ov_a[1:4])
                a0b1 = numpy.einsum('xr,xria->ria', rho0a[1:4], rho_ov_b[1:4])
                b0a1 = numpy.einsum('xr,xria->ria', rho0b[1:4], rho_ov_a[1:4])
                b0b1 = numpy.einsum('xr,xria->ria', rho0b[1:4], rho_ov_b[1:4])

                w_ov = numpy.empty_like(rho_ov_a)
                w_ov[0] = numpy.einsum('r,ria->ria', u_u, rho_ov_a[0])
                w_ov[0] += numpy.einsum('r,ria->ria', 2 * u_uu, a0a1)
                w_ov[0] += numpy.einsum('r,ria->ria', u_ud, b0a1)
                f_ov_a = numpy.einsum('r,ria->ria', 4 * uu_uu, a0a1)
                f_ov_b = numpy.einsum('r,ria->ria', 2 * uu_ud, a0a1)
                f_ov_a += numpy.einsum('r,ria->ria', 2 * uu_ud, b0a1)
                f_ov_b += numpy.einsum('r,ria->ria', ud_ud, b0a1)
                f_ov_a += numpy.einsum('r,ria->ria', 2 * u_uu, rho_ov_a[0])
                f_ov_b += numpy.einsum('r,ria->ria', u_ud, rho_ov_a[0])
                w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov_a, rho0a[1:4])
                w_ov[1:] += numpy.einsum('ria,xr->xria', f_ov_b, rho0b[1:4])
                w_ov[1:] += numpy.einsum('r,xria->xria', 2 * uu, rho_ov_a[1:4])
                w_ov *= weight[:, None, None]
                iajb = lib.einsum('xria,xrjb->iajb', rho_ov_a, w_ov)
                a_aa += iajb
                b_aa += iajb

                w_ov = numpy.empty_like(rho_ov_b)
                w_ov[0] = numpy.einsum('r,ria->ria', d_d, rho_ov_b[0])
                w_ov[0] += numpy.einsum('r,ria->ria', 2 * d_dd, b0b1)
                w_ov[0] += numpy.einsum('r,ria->ria', d_ud, a0b1)
                f_ov_b = numpy.einsum('r,ria->ria', 4 * dd_dd, b0b1)
                f_ov_a = numpy.einsum('r,ria->ria', 2 * ud_dd, b0b1)
                f_ov_b += numpy.einsum('r,ria->ria', 2 * ud_dd, a0b1)
                f_ov_a += numpy.einsum('r,ria->ria', ud_ud, a0b1)
                f_ov_b += numpy.einsum('r,ria->ria', 2 * d_dd, rho_ov_b[0])
                f_ov_a += numpy.einsum('r,ria->ria', d_ud, rho_ov_b[0])
                w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov_a, rho0a[1:4])
                w_ov[1:] += numpy.einsum('ria,xr->xria', f_ov_b, rho0b[1:4])
                w_ov[1:] += numpy.einsum('r,xria->xria', 2 * dd, rho_ov_b[1:4])
                w_ov *= weight[:, None, None]
                iajb = lib.einsum('xria,xrjb->iajb', rho_ov_b, w_ov)
                a_bb += iajb
                b_bb += iajb

                w_ov = numpy.empty_like(rho_ov_b)
                w_ov[0] = numpy.einsum('r,ria->ria', u_d, rho_ov_b[0])
                w_ov[0] += numpy.einsum('r,ria->ria', 2 * u_dd, b0b1)
                w_ov[0] += numpy.einsum('r,ria->ria', u_ud, a0b1)
                f_ov_a = numpy.einsum('r,ria->ria', 4 * uu_dd, b0b1)
                f_ov_b = numpy.einsum('r,ria->ria', 2 * ud_dd, b0b1)
                f_ov_a += numpy.einsum('r,ria->ria', 2 * uu_ud, a0b1)
                f_ov_b += numpy.einsum('r,ria->ria', ud_ud, a0b1)
                f_ov_a += numpy.einsum('r,ria->ria', 2 * d_uu, rho_ov_b[0])
                f_ov_b += numpy.einsum('r,ria->ria', d_ud, rho_ov_b[0])
                w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov_a, rho0a[1:4])
                w_ov[1:] += numpy.einsum('ria,xr->xria', f_ov_b, rho0b[1:4])
                w_ov[1:] += numpy.einsum('r,xria->xria', ud, rho_ov_b[1:4])
                w_ov *= weight[:, None, None]
                iajb = lib.einsum('xria,xrjb->iajb', rho_ov_a, w_ov)
                a_ab += iajb
                b_ab += iajb

        elif xctype == 'NLC':
            raise NotImplementedError('NLC')
        elif xctype == 'MGGA':
            raise NotImplementedError('meta-GGA')

    else:
        add_hf_(a, b)

    return a, b
Exemple #41
0
def get_nto(tdobj, state=1, threshold=OUTPUT_THRESHOLD, verbose=None):
    r'''
    Natural transition orbital analysis.

    The natural transition density matrix between ground state and excited
    state :math:`Tia = \langle \Psi_{ex} | i a^\dagger | \Psi_0 \rangle` can
    be transformed to diagonal form through SVD
    :math:`T = O \sqrt{\lambda} V^\dagger`. O and V are occupied and virtual
    natural transition orbitals. The diagonal elements :math:`\lambda` are the
    weights of the occupied-virtual orbital pair in the excitation.

    Ref: Martin, R. L., JCP, 118, 4775-4777

    Note in the TDHF/TDDFT calculations, the excitation part (X) is
    interpreted as the CIS coefficients and normalized to 1. The de-excitation
    part (Y) is ignored.

    Args:
        state : int
            Excited state ID.  state = 1 means the first excited state.
            If state < 0, state ID is counted from the last excited state.

    Kwargs:
        threshold : float
            Above which the NTO coefficients will be printed in the output.

    Returns:
        A list (weights, NTOs).  NTOs are natural orbitals represented in AO
        basis. The first N_occ NTOs are occupied NTOs and the rest are virtual
        NTOs.
    '''
    if state == 0:
        logger.warn(
            tdobj, 'Excited state starts from 1. '
            'Set state=1 for first excited state.')
        state_id = state
    elif state < 0:
        state_id = state
    else:
        state_id = state - 1

    mol = tdobj.mol
    mo_coeff = tdobj._scf.mo_coeff
    mo_occ = tdobj._scf.mo_occ
    orbo_a = mo_coeff[0][:, mo_occ[0] == 1]
    orbv_a = mo_coeff[0][:, mo_occ[0] == 0]
    orbo_b = mo_coeff[1][:, mo_occ[1] == 1]
    orbv_b = mo_coeff[1][:, mo_occ[1] == 0]
    nocc_a = orbo_a.shape[1]
    nvir_a = orbv_a.shape[1]
    nocc_b = orbo_b.shape[1]
    nvir_b = orbv_b.shape[1]

    cis_t1a, cis_t1b = tdobj.xy[state_id][0]
    norm = numpy.linalg.norm(cis_t1a)**2 + numpy.linalg.norm(cis_t1b)**2
    cis_t1a *= 1. / norm
    cis_t1b *= 1. / norm

    if mol.symmetry:
        orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff)
        o_sym_a = orbsyma[mo_occ[0] == 1]
        v_sym_a = orbsyma[mo_occ[0] == 0]
        o_sym_b = orbsymb[mo_occ[1] == 1]
        v_sym_b = orbsymb[mo_occ[1] == 0]
        nto_o_a = numpy.eye(nocc_a)
        nto_v_a = numpy.eye(nvir_a)
        nto_o_b = numpy.eye(nocc_b)
        nto_v_b = numpy.eye(nvir_b)
        weights_o_a = numpy.zeros(nocc_a)
        weights_v_a = numpy.zeros(nvir_a)
        weights_o_b = numpy.zeros(nocc_b)
        weights_v_b = numpy.zeros(nvir_b)

        for ir in set(orbsyma):
            idx = numpy.where(o_sym_a == ir)[0]
            if idx.size > 0:
                dm_oo = numpy.dot(cis_t1a[idx], cis_t1a[idx].T)
                weights_o_a[idx], nto_o_a[idx[:, None],
                                          idx] = numpy.linalg.eigh(dm_oo)

            idx = numpy.where(v_sym_a == ir)[0]
            if idx.size > 0:
                dm_vv = numpy.dot(cis_t1a[:, idx].T, cis_t1a[:, idx])
                weights_v_a[idx], nto_v_a[idx[:, None],
                                          idx] = numpy.linalg.eigh(dm_vv)

        for ir in set(orbsymb):
            idx = numpy.where(o_sym_b == ir)[0]
            if idx.size > 0:
                dm_oo = numpy.dot(cis_t1b[idx], cis_t1b[idx].T)
                weights_o_b[idx], nto_o_b[idx[:, None],
                                          idx] = numpy.linalg.eigh(dm_oo)

            idx = numpy.where(v_sym_b == ir)[0]
            if idx.size > 0:
                dm_vv = numpy.dot(cis_t1b[:, idx].T, cis_t1b[:, idx])
                weights_v_b[idx], nto_v_b[idx[:, None],
                                          idx] = numpy.linalg.eigh(dm_vv)

        def sort(weights, nto, sym):
            # weights in descending order
            idx = numpy.argsort(-weights)
            weights = weights[idx]
            nto = nto[:, idx]
            sym = sym[idx]
            return weights, nto, sym

        weights_o_a, nto_o_a, o_sym_a = sort(weights_o_a, nto_o_a, o_sym_a)
        weights_v_a, nto_v_a, v_sym_a = sort(weights_v_a, nto_v_a, v_sym_a)
        weights_o_b, nto_o_b, o_sym_b = sort(weights_o_b, nto_o_b, o_sym_b)
        weights_v_b, nto_v_b, v_sym_b = sort(weights_v_b, nto_v_b, v_sym_b)

        nto_orbsyma = numpy.hstack((o_sym_a, v_sym_a))
        nto_orbsymb = numpy.hstack((o_sym_b, v_sym_b))

        if nocc_a < nvir_a:
            weights_a = weights_o_a
        else:
            weights_a = weights_v_a
        if nocc_b < nvir_b:
            weights_b = weights_o_b
        else:
            weights_b = weights_v_b

    else:
        nto_o_a, w_a, nto_v_aT = numpy.linalg.svd(cis_t1a)
        nto_o_b, w_b, nto_v_bT = numpy.linalg.svd(cis_t1b)
        nto_v_a = nto_v_aT.conj().T
        nto_v_b = nto_v_bT.conj().T
        weights_a = w_a**2
        weights_b = w_b**2
        nto_orbsyma = nto_orbsymb = None

    def _set_phase_(c):
        idx = numpy.argmax(abs(c.real), axis=0)
        c[:, c[idx, numpy.arange(c.shape[1])].real < 0] *= -1

    _set_phase_(nto_o_a)
    _set_phase_(nto_o_b)
    _set_phase_(nto_v_a)
    _set_phase_(nto_v_b)

    occupied_nto_a = numpy.dot(orbo_a, nto_o_a)
    occupied_nto_b = numpy.dot(orbo_b, nto_o_b)
    virtual_nto_a = numpy.dot(orbv_a, nto_v_a)
    virtual_nto_b = numpy.dot(orbv_b, nto_v_b)
    nto_coeff = (numpy.hstack((occupied_nto_a, virtual_nto_a)),
                 numpy.hstack((occupied_nto_b, virtual_nto_b)))

    if mol.symmetry:
        nto_coeff = (lib.tag_array(nto_coeff[0], orbsym=nto_orbsyma),
                     lib.tag_array(nto_coeff[1], orbsym=nto_orbsymb))

    log = logger.new_logger(tdobj, verbose)
    if log.verbose >= logger.INFO:
        log.info('State %d: %g eV  NTO largest component %s', state_id + 1,
                 tdobj.e[state_id] * nist.HARTREE2EV,
                 weights_a[0] + weights_b[0])
        fmt = '%' + str(lib.param.OUTPUT_DIGITS) + 'f (MO #%d)'
        o_idx_a = numpy.where(abs(nto_o_a[:, 0]) > threshold)[0]
        v_idx_a = numpy.where(abs(nto_v_a[:, 0]) > threshold)[0]
        o_idx_b = numpy.where(abs(nto_o_b[:, 0]) > threshold)[0]
        v_idx_b = numpy.where(abs(nto_v_b[:, 0]) > threshold)[0]
        log.info('    alpha occ-NTO: ' +
                 ' + '.join([(fmt % (nto_o_a[i, 0], i + MO_BASE))
                             for i in o_idx_a]))
        log.info('    alpha vir-NTO: ' +
                 ' + '.join([(fmt % (nto_v_a[i, 0], i + MO_BASE + nocc_a))
                             for i in v_idx_a]))
        log.info('    beta occ-NTO: ' +
                 ' + '.join([(fmt % (nto_o_b[i, 0], i + MO_BASE))
                             for i in o_idx_b]))
        log.info('    beta vir-NTO: ' +
                 ' + '.join([(fmt % (nto_v_b[i, 0], i + MO_BASE + nocc_b))
                             for i in v_idx_b]))
    return (weights_a, weights_b), nto_coeff
Exemple #42
0
def get_nuc(mydf, kpts=None):
    cell = mydf.cell
    if kpts is None:
        kpts_lst = numpy.zeros((1, 3))
    else:
        kpts_lst = numpy.reshape(kpts, (-1, 3))

    log = logger.Logger(mydf.stdout, mydf.verbose)
    t1 = (time.clock(), time.time())

    nkpts = len(kpts_lst)
    nao = cell.nao_nr()
    nao_pair = nao * (nao + 1) // 2

    Gv, Gvbase, kws = cell.get_Gv_weights(mydf.gs)
    kpt_allow = numpy.zeros(3)
    if mydf.eta == 0:
        vpplocG = pseudo.pp_int.get_gth_vlocG_part1(cell, Gv)
        vpplocG = -numpy.einsum('ij,ij->j', cell.get_SI(Gv), vpplocG)
        vpplocG *= kws
        vG = vpplocG
        vj = numpy.zeros((nkpts, nao_pair), dtype=numpy.complex128)
    else:
        if cell.dimension > 0:
            ke_guess = estimate_ke_cutoff_for_eta(cell, mydf.eta,
                                                  cell.precision)
            gs_guess = tools.cutoff_to_gs(cell.lattice_vectors(), ke_guess)
            if numpy.any(mydf.gs < gs_guess * .8):
                logger.warn(
                    mydf, 'gs %s is not enough for AFTDF.get_nuc function '
                    'to get integral accuracy %g.\nRecomended gs is %s.',
                    mydf.gs, cell.precision, gs_guess)

        nuccell = copy.copy(cell)
        half_sph_norm = .5 / numpy.sqrt(numpy.pi)
        norm = half_sph_norm / gto.mole._gaussian_int(2, mydf.eta)
        chg_env = [mydf.eta, norm]
        ptr_eta = cell._env.size
        ptr_norm = ptr_eta + 1
        chg_bas = [[ia, 0, 1, 1, 0, ptr_eta, ptr_norm, 0]
                   for ia in range(cell.natm)]
        nuccell._atm = cell._atm
        nuccell._bas = numpy.asarray(chg_bas, dtype=numpy.int32)
        nuccell._env = numpy.hstack((cell._env, chg_env))

        # PP-loc part1 is handled by fakenuc in _int_nuc_vloc
        vj = lib.asarray(mydf._int_nuc_vloc(nuccell, kpts_lst))
        t1 = log.timer_debug1('vnuc pass1: analytic int', *t1)

        charge = -cell.atom_charges()
        coulG = tools.get_coulG(cell, kpt_allow, gs=mydf.gs, Gv=Gv)
        coulG *= kws
        aoaux = ft_ao.ft_ao(nuccell, Gv)
        vG = numpy.einsum('i,xi->x', charge, aoaux) * coulG

    max_memory = max(2000, mydf.max_memory - lib.current_memory()[0])
    for aoaoks, p0, p1 in mydf.ft_loop(mydf.gs,
                                       kpt_allow,
                                       kpts_lst,
                                       max_memory=max_memory,
                                       aosym='s2'):
        for k, aoao in enumerate(aoaoks):
            # rho_ij(G) nuc(-G) / G^2
            # = [Re(rho_ij(G)) + Im(rho_ij(G))*1j] [Re(nuc(G)) - Im(nuc(G))*1j] / G^2
            if gamma_point(kpts_lst[k]):
                vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].real, aoao.real)
                vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].imag, aoao.imag)
            else:
                vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].conj(), aoao)
    t1 = log.timer_debug1('contracting Vnuc', *t1)

    vj_kpts = []
    for k, kpt in enumerate(kpts_lst):
        if gamma_point(kpt):
            vj_kpts.append(lib.unpack_tril(vj[k].real.copy()))
        else:
            vj_kpts.append(lib.unpack_tril(vj[k]))

    if kpts is None or numpy.shape(kpts) == (3, ):
        vj_kpts = vj_kpts[0]
    return numpy.asarray(vj_kpts)
Exemple #43
0
 def init_guess_by_1e(self, cell=None):
     if cell is None: cell = self.cell
     if cell.dimension < 3:
         logger.warn(self, 'Hcore initial guess is not recommended in '
                     'the SCF of low-dimensional systems.')
     return mol_uhf.UHF.init_guess_by_1e(self, cell)
Exemple #44
0
def DMRG_COMPRESS_NEVPT(mc,
                        maxM=500,
                        root=0,
                        nevptsolver=None,
                        tol=1e-7,
                        nevpt_integral=None):

    if isinstance(nevpt_integral, str) and h5py.is_hdf5(nevpt_integral):
        nevpt_integral_file = os.path.abspath(nevpt_integral)
        mol = chkfile.load_mol(nevpt_integral_file)

        fh5 = h5py.File(nevpt_integral_file, 'r')
        ncas = fh5['mc/ncas'][()]
        ncore = fh5['mc/ncore'][()]
        nvirt = fh5['mc/nvirt'][()]
        nelecas = fh5['mc/nelecas'][()]
        nroots = fh5['mc/nroots'][()]
        wfnsym = fh5['mc/wfnsym'][()]
        fh5.close()
    else:
        mol = mc.mol
        ncas = mc.ncas
        ncore = mc.ncore
        nvirt = mc.mo_coeff.shape[1] - mc.ncas - mc.ncore
        nelecas = mc.nelecas
        nroots = mc.fcisolver.nroots
        wfnsym = mc.fcisolver.wfnsym
        nevpt_integral_file = None

    if nevptsolver is None:
        nevptsolver = default_nevpt_schedule(mc.fcisolver, maxM, tol)
        #nevptsolver.__dict__.update(mc.fcisolver.__dict__)
        nevptsolver.wfnsym = wfnsym
        nevptsolver.block_extra_keyword = mc.fcisolver.block_extra_keyword
    nevptsolver.nroots = nroots
    nevptsolver.executable = settings.BLOCKEXE_COMPRESS_NEVPT
    if nevptsolver.executable == getattr(mc.fcisolver, 'executable', None):
        logger.warn(
            mc, 'DMRG executable file for nevptsolver is the same '
            'to the executable file for DMRG solver. If they are '
            'both compiled by MPI compilers, they may cause error or '
            'random results in DMRG-NEVPT calculation.')

    nevpt_scratch = os.path.abspath(nevptsolver.scratchDirectory)
    dmrg_scratch = os.path.abspath(mc.fcisolver.scratchDirectory)

    # Integrals are not given by the kwarg nevpt_integral
    if nevpt_integral_file is None:
        nevpt_integral_file = os.path.join(nevpt_scratch,
                                           'nevpt_perturb_integral')
        write_chk(mc, root, nevpt_integral_file)

    conf = dmrgci.writeDMRGConfFile(
        nevptsolver,
        nelecas,
        False,
        with_2pdm=False,
        extraline=['fullrestart', 'nevpt_state_num %d' % root])
    with open(conf, 'r') as f:
        block_conf = f.readlines()
        block_conf = [l for l in block_conf if 'prefix' not in l]
        block_conf = ''.join(block_conf)

    with h5py.File(nevpt_integral_file, 'a') as fh5:
        if 'dmrg.conf' in fh5:
            del (fh5['dmrg.conf'])
        fh5['dmrg.conf'] = block_conf

    if nevptsolver.verbose >= logger.DEBUG1:
        logger.debug1(nevptsolver, 'Block Input conf')
        logger.debug1(nevptsolver, block_conf)

    t0 = (time.clock(), time.time())

    # function nevpt_integral_mpi is called in this cmd
    cmd = ' '.join(
        (nevptsolver.mpiprefix,
         os.path.realpath(os.path.join(__file__, '..',
                                       'nevpt_mpi.py')), nevpt_integral_file,
         nevptsolver.executable, dmrg_scratch, nevpt_scratch))
    logger.debug(nevptsolver, 'DMRG_COMPRESS_NEVPT cmd %s', cmd)

    try:
        output = subprocess.check_call(cmd, shell=True)
    except subprocess.CalledProcessError as err:
        logger.error(nevptsolver, cmd)
        raise err

    if nevptsolver.verbose >= logger.DEBUG1:
        logger.debug1(
            nevptsolver,
            open(os.path.join(nevpt_scratch, '0', 'dmrg.out')).read())

    perturb_file = os.path.join(nevpt_scratch, '0', 'Perturbation_%d' % root)
    fh5 = h5py.File(perturb_file, 'r')
    Vi_e = fh5['Vi/energy'][()]
    Vr_e = fh5['Vr/energy'][()]
    fh5.close()
    logger.note(nevptsolver, 'Nevpt Energy:')
    logger.note(nevptsolver, 'Sr Subspace:  E = %.14f' % (Vr_e))
    logger.note(nevptsolver, 'Si Subspace:  E = %.14f' % (Vi_e))

    logger.timer(nevptsolver, 'MPS NEVPT calculation time', *t0)
    return perturb_file
Exemple #45
0
    def __init__(self, cis, mo_coeff=None, method="incore"):
        log = logger.Logger(cis.stdout, cis.verbose)
        cput0 = (time.clock(), time.time())

        moidx = get_frozen_mask(cis)
        cell = cis._scf.cell
        nocc = cis.nocc
        nmo = cis.nmo
        nvir = nmo - nocc
        nkpts = cis.nkpts
        kpts = cis.kpts

        if mo_coeff is None:
            mo_coeff = cis.mo_coeff
        dtype = mo_coeff[0].dtype

        mo_coeff = self.mo_coeff = padded_mo_coeff(cis, mo_coeff)

        # Re-make our fock MO matrix elements from density and fock AO
        dm = cis._scf.make_rdm1(cis.mo_coeff, cis.mo_occ)
        exxdiv = cis._scf.exxdiv if cis.keep_exxdiv else None
        with lib.temporary_env(cis._scf, exxdiv=exxdiv):
            # _scf.exxdiv affects eris.fock. HF exchange correction should be
            # excluded from the Fock matrix.
            fockao = cis._scf.get_hcore() + cis._scf.get_veff(cell, dm)
        self.fock = np.asarray([reduce(np.dot, (mo.T.conj(), fockao[k], mo))
                                for k, mo in enumerate(mo_coeff)])

        self.mo_energy = [self.fock[k].diagonal().real for k in range(nkpts)]

        if not cis.keep_exxdiv:
            # Add HFX correction in the self.mo_energy to improve convergence in
            # CCSD iteration. It is useful for the 2D systems since their occupied and
            # the virtual orbital energies may overlap which may lead to numerical
            # issue in the CCSD iterations.
            # FIXME: Whether to add this correction for other exxdiv treatments?
            # Without the correction, MP2 energy may be largely off the correct value.
            madelung = tools.madelung(cell, kpts)
            self.mo_energy = [
                _adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(self.mo_energy)
            ]

        # Get location of padded elements in occupied and virtual space.
        nocc_per_kpt = get_nocc(cis, per_kpoint=True)
        nonzero_padding = padding_k_idx(cis, kind="joint")

        # Check direct and indirect gaps for possible issues with CCSD convergence.
        mo_e = [self.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)]
        mo_e = np.sort([y for x in mo_e for y in x])  # Sort de-nested array
        gap = mo_e[np.sum(nocc_per_kpt)] - mo_e[np.sum(nocc_per_kpt) - 1]
        if gap < 1e-5:
            logger.warn(
                cis,
                "H**O-LUMO gap %s too small for KCCSD. "
                "May cause issues in convergence.",
                gap,
            )

        memory_needed = (nkpts ** 3 * nocc ** 2 * nvir ** 2) * 16 / 1e6
        # CIS only needs two terms: <aj|ib> and <aj|bi>; another factor of two for safety
        memory_needed *= 4

        memory_now = lib.current_memory()[0]
        fao2mo = cis._scf.with_df.ao2mo

        kconserv = cis.khelper.kconserv
        khelper = cis.khelper

        if cis.direct and type(cis._scf.with_df) is not df.GDF:
            raise ValueError("CIS direct method must be used with GDF")

        if (cis.direct and type(cis._scf.with_df) is df.GDF 
            and cell.dimension != 2):
            # cis._scf.with_df needs to be df.GDF only (not MDF)
            _init_cis_df_eris(cis, self)
        else:
            if (
                method == "incore"
                and (memory_needed + memory_now < cis.max_memory)
                or cell.incore_anyway
            ):
                log.info("using incore ERI storage")
                self.ovov = np.empty(
                    (nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), dtype=dtype
                )
                self.voov = np.empty(
                    (nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), dtype=dtype
                )

                for (ikp, ikq, ikr) in khelper.symm_map.keys():
                    iks = kconserv[ikp, ikq, ikr]
                    eri_kpt = fao2mo(
                        (mo_coeff[ikp], mo_coeff[ikq], mo_coeff[ikr], mo_coeff[iks]),
                        (kpts[ikp], kpts[ikq], kpts[ikr], kpts[iks]),
                        compact=False,
                    )
                    if dtype == np.float:
                        eri_kpt = eri_kpt.real
                    eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo)
                    for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]:
                        eri_kpt_symm = khelper.transform_symm(
                            eri_kpt, kp, kq, kr
                        ).transpose(0, 2, 1, 3)
                        self.ovov[kp, kr, kq] = (
                            eri_kpt_symm[:nocc, nocc:, :nocc, nocc:] / nkpts
                        )
                        self.voov[kp, kr, kq] = (
                            eri_kpt_symm[nocc:, :nocc, :nocc, nocc:] / nkpts
                        )

                self.dtype = dtype
            else:
                log.info("using HDF5 ERI storage")
                self.feri1 = lib.H5TmpFile()

                self.ovov = self.feri1.create_dataset(
                    "ovov", (nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), dtype.char
                )
                self.voov = self.feri1.create_dataset(
                    "voov", (nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), dtype.char
                )

                # <ia|pq> = (ip|aq)
                cput1 = time.clock(), time.time()
                for kp in range(nkpts):
                    for kq in range(nkpts):
                        for kr in range(nkpts):
                            ks = kconserv[kp, kq, kr]
                            orbo_p = mo_coeff[kp][:, :nocc]
                            orbv_r = mo_coeff[kr][:, nocc:]
                            buf_kpt = fao2mo(
                                (orbo_p, mo_coeff[kq], orbv_r, mo_coeff[ks]),
                                (kpts[kp], kpts[kq], kpts[kr], kpts[ks]),
                                compact=False,
                            )
                            if mo_coeff[0].dtype == np.float:
                                buf_kpt = buf_kpt.real
                            buf_kpt = buf_kpt.reshape(nocc, nmo, nvir, nmo).transpose(
                                0, 2, 1, 3
                            )
                            self.dtype = buf_kpt.dtype
                            self.ovov[kp, kr, kq, :, :, :, :] = (
                                buf_kpt[:, :, :nocc, nocc:] / nkpts
                            )
                            self.voov[kr, kp, ks, :, :, :, :] = (
                                buf_kpt[:, :, nocc:, :nocc].transpose(1, 0, 3, 2) / nkpts
                            )
                cput1 = log.timer_debug1("transforming ovpq", *cput1)

        log.timer("CIS integral transformation", *cput0)
Exemple #46
0
def get_occ(mf, mo_energy=None, mo_coeff=None):
    if mo_energy is None: mo_energy = mf.mo_energy
    e_idx_a = numpy.argsort(mo_energy[0])
    e_idx_b = numpy.argsort(mo_energy[1])
    e_sort_a = mo_energy[0][e_idx_a]
    e_sort_b = mo_energy[1][e_idx_b]
    e_a = numpy.array(mo_energy[0][e_idx_a[:]])
    e_b = numpy.array(mo_energy[1][e_idx_b[:]])
    nmo = mo_energy[0].size
    n_a, n_b = mf.nelec
    mo_occ = numpy.zeros_like(mo_energy)

    # MP 2019
    if not mf.mol.smearing:
        #print("Aufbau case")
        mo_occ[0, e_idx_a[:n_a]] = 1
        mo_occ[1, e_idx_b[:n_b]] = 1
    else:
        #print("Smearing case")
        if mf.verbose >= logger.INFO:
            logger.warn(mf, "WARNING: experimental, use at your own risk")
        mf.mol.FermiEnergy = numpy.zeros(2)
        mf.mol.FermiEnergy[0] = e_a[n_a]
        mf.mol.FermiEnergy[1] = e_b[n_b]
        from pyscf.scf.addons import fermi_smearing_mo_occ

        def nelec_cost_fn_a(e_f):
            mo_occ[0, :] = fermi_smearing_mo_occ(e_f, numpy.array(e_a),
                                                 mf.mol.tau)
            nelec = numpy.sum(mo_occ[0, :])
            return (nelec - n_a)**2

        def nelec_cost_fn_b(e_f):
            mo_occ[1, :] = fermi_smearing_mo_occ(e_f, numpy.array(e_b),
                                                 mf.mol.tau)
            nelec = numpy.sum(mo_occ[1, :])
            return (nelec - n_b)**2

        res = scipy.optimize.minimize(nelec_cost_fn_a,
                                      mf.mol.FermiEnergy[0],
                                      method='Powell',
                                      options={'maxiter': 2000})
        mf.mol.FermiEnergy[0] = res.x
        res = scipy.optimize.minimize(nelec_cost_fn_b,
                                      mf.mol.FermiEnergy[1],
                                      method='Powell',
                                      options={'maxiter': 2000})
        mf.mol.FermiEnergy[1] = res.x

        if n_a > 0:
            mo_occ[0, e_idx_a] = fermi_smearing_mo_occ(
                mf.mol.FermiEnergy[0], numpy.array(e_a), mf.mol.tau, n_a) * 2
        else:
            mo_occ[0, :] = 0.0
        if n_b > 0:
            mo_occ[1, e_idx_b] = fermi_smearing_mo_occ(mf.mol.FermiEnergy[1],
                                                       numpy.array(e_b),
                                                       mf.mol.tau, n_b)
        else:
            mo_occ[1, :] = 0.0
        #print(mo_occ)

        if not numpy.isclose(numpy.sum(mo_occ), n_a + n_b):
            print('Fermi-Dirac did not converge. Try raising mol.tau.')
            mo_occ[0, e_idx_a[:n_a]] = 1
            mo_occ[1, e_idx_b[:n_b]] = 1
    return mo_occ

    if mf.verbose >= logger.INFO and n_a < nmo and n_b > 0 and n_b < nmo:
        if e_sort_a[n_a - 1] + 1e-3 > e_sort_a[n_a]:
            logger.warn(mf, 'alpha nocc = %d  H**O %.15g >= LUMO %.15g', n_a,
                        e_sort_a[n_a - 1], e_sort_a[n_a])
        else:
            logger.info(mf, '  alpha nocc = %d  H**O = %.15g  LUMO = %.15g',
                        n_a, e_sort_a[n_a - 1], e_sort_a[n_a])

        if e_sort_b[n_b - 1] + 1e-3 > e_sort_b[n_b]:
            logger.warn(mf, 'beta  nocc = %d  H**O %.15g >= LUMO %.15g', n_b,
                        e_sort_b[n_b - 1], e_sort_b[n_b])
        else:
            logger.info(mf, '  beta  nocc = %d  H**O = %.15g  LUMO = %.15g',
                        n_b, e_sort_b[n_b - 1], e_sort_b[n_b])

        if e_sort_a[n_a - 1] + 1e-3 > e_sort_b[n_b]:
            logger.warn(mf, 'system H**O %.15g >= system LUMO %.15g',
                        e_sort_b[n_a - 1], e_sort_b[n_b])

        numpy.set_printoptions(threshold=nmo)
        logger.debug(mf, '  alpha mo_energy =\n%s', mo_energy[0])
        logger.debug(mf, '  beta  mo_energy =\n%s', mo_energy[1])
        numpy.set_printoptions(threshold=1000)

    if mo_coeff is not None and mf.verbose >= logger.DEBUG:
        ss, s = mf.spin_square(
            (mo_coeff[0][:, mo_occ[0] > 0], mo_coeff[1][:, mo_occ[1] > 0]),
            mf.get_ovlp())
        logger.debug(mf, 'multiplicity <S^2> = %.8g  2S+1 = %.8g', ss, s)
    return mo_occ
Exemple #47
0
def get_nto(tdobj, state=1, threshold=OUTPUT_THRESHOLD, verbose=None):
    r'''
    Natural transition orbital analysis.

    The natural transition density matrix between ground state and excited
    state :math:`Tia = \langle \Psi_{ex} | i a^\dagger | \Psi_0 \rangle` can
    be transformed to diagonal form through SVD
    :math:`T = O \sqrt{\lambda} V^\dagger`. O and V are occupied and virtual
    natural transition orbitals. The diagonal elements :math:`\lambda` are the
    weights of the occupied-virtual orbital pair in the excitation.

    Ref: Martin, R. L., JCP, 118, 4775-4777

    Note in the TDHF/TDDFT calculations, the excitation part (X) is
    interpreted as the CIS coefficients and normalized to 1. The de-excitation
    part (Y) is ignored.

    Args:
        state : int
            Excited state ID.  state = 1 means the first excited state.
            If state < 0, state ID is counted from the last excited state.

    Kwargs:
        threshold : float
            Above which the NTO coefficients will be printed in the output.

    Returns:
        A list (weights, NTOs).  NTOs are natural orbitals represented in AO
        basis. The first N_occ NTOs are occupied NTOs and the rest are virtual
        NTOs.
    '''
    if state == 0:
        logger.warn(tdobj, 'Excited state starts from 1. '
                    'Set state=1 for first excited state.')
        state_id = state
    elif state < 0:
        state_id = state
    else:
        state_id = state - 1

    mol = tdobj.mol
    mo_coeff = tdobj._scf.mo_coeff
    mo_occ = tdobj._scf.mo_occ
    orbo = mo_coeff[:,mo_occ==2]
    orbv = mo_coeff[:,mo_occ==0]
    nocc = orbo.shape[1]
    nvir = orbv.shape[1]

    cis_t1 = tdobj.xy[state_id][0]
    # TDDFT (X,Y) has X^2-Y^2=1.
    # Renormalizing X (X^2=1) to map it to CIS coefficients
    cis_t1 *= 1. / numpy.linalg.norm(cis_t1)

# TODO: Comparing to the NTOs defined in JCP, 142, 244103.  JCP, 142, 244103
# provides a method to incorporate the Y matrix in the transition density
# matrix.  However, it may break the point group symmetry of the NTO orbitals
# when the system has degenerated irreducible representations.

    if mol.symmetry:
        orbsym = hf_symm.get_orbsym(mol, mo_coeff)
        o_sym = orbsym[mo_occ==2]
        v_sym = orbsym[mo_occ==0]
        nto_o = numpy.eye(nocc)
        nto_v = numpy.eye(nvir)
        weights_o = numpy.zeros(nocc)
        weights_v = numpy.zeros(nvir)
        for ir in set(orbsym):
            idx = numpy.where(o_sym == ir)[0]
            if idx.size > 0:
                dm_oo = numpy.dot(cis_t1[idx], cis_t1[idx].T)
                weights_o[idx], nto_o[idx[:,None],idx] = numpy.linalg.eigh(dm_oo)

            idx = numpy.where(v_sym == ir)[0]
            if idx.size > 0:
                dm_vv = numpy.dot(cis_t1[:,idx].T, cis_t1[:,idx])
                weights_v[idx], nto_v[idx[:,None],idx] = numpy.linalg.eigh(dm_vv)

        # weights in descending order
        idx = numpy.argsort(-weights_o)
        weights_o = weights_o[idx]
        nto_o = nto_o[:,idx]
        o_sym = o_sym[idx]

        idx = numpy.argsort(-weights_v)
        weights_v = weights_v[idx]
        nto_v = nto_v[:,idx]
        v_sym = v_sym[idx]

        nto_orbsym = numpy.hstack((o_sym, v_sym))

        if nocc < nvir:
            weights = weights_o
        else:
            weights = weights_v

    else:
        nto_o, w, nto_vT = numpy.linalg.svd(cis_t1)
        nto_v = nto_vT.conj().T
        weights = w**2
        nto_orbsym = None

    idx = numpy.argmax(abs(nto_o.real), axis=0)
    nto_o[:,nto_o[idx,numpy.arange(nocc)].real<0] *= -1
    idx = numpy.argmax(abs(nto_v.real), axis=0)
    nto_v[:,nto_v[idx,numpy.arange(nvir)].real<0] *= -1

    occupied_nto = numpy.dot(orbo, nto_o)
    virtual_nto = numpy.dot(orbv, nto_v)
    nto_coeff = numpy.hstack((occupied_nto, virtual_nto))

    if mol.symmetry:
        nto_coeff = lib.tag_array(nto_coeff, orbsym=nto_orbsym)

    log = logger.new_logger(tdobj, verbose)
    if log.verbose >= logger.INFO:
        log.info('State %d: %g eV  NTO largest component %s',
                 state_id+1, tdobj.e[state_id]*nist.HARTREE2EV, weights[0])
        o_idx = numpy.where(abs(nto_o[:,0]) > threshold)[0]
        v_idx = numpy.where(abs(nto_v[:,0]) > threshold)[0]
        fmt = '%' + str(lib.param.OUTPUT_DIGITS) + 'f (MO #%d)'
        log.info('    occ-NTO: ' +
                 ' + '.join([(fmt % (nto_o[i,0], i+MO_BASE))
                             for i in o_idx]))
        log.info('    vir-NTO: ' +
                 ' + '.join([(fmt % (nto_v[i,0], i+MO_BASE+nocc))
                             for i in v_idx]))
    return weights, nto_coeff
Exemple #48
0
def get_occ(mf, mo_energy=None, mo_coeff=None):
    '''Label the occupancies for each orbital.
    NOTE the occupancies are not assigned based on the orbital energy ordering.
    The first N orbitals are assigned to be occupied orbitals.

    Examples:

    >>> mol = gto.M(atom='H 0 0 0; O 0 0 1.1', spin=1)
    >>> mf = scf.hf.SCF(mol)
    >>> energy = numpy.array([-10., -1., 1, -2., 0, -3])
    >>> mf.get_occ(energy)
    array([2, 2, 2, 2, 1, 0])
    '''

    if mo_energy is None: mo_energy = mf.mo_energy
    if getattr(mo_energy, 'mo_ea', None) is not None:
        mo_ea = mo_energy.mo_ea
        mo_eb = mo_energy.mo_eb
    else:
        mo_ea = mo_eb = mo_energy
    nmo = mo_ea.size
    mo_occ = numpy.zeros(nmo)
    if getattr(mf, 'nelec', None) is None:
        nelec = mf.mol.nelec
    else:
        nelec = mf.nelec
    ncore = nelec[1]
    nocc = nelec[0]
    nopen = abs(nocc - ncore)
    mo_occ = _fill_rohf_occ(mo_energy, mo_ea, mo_eb, ncore, nopen)

    if mf.verbose >= logger.INFO and nocc < nmo and ncore > 0:
        ehomo = max(mo_energy[mo_occ > 0])
        elumo = min(mo_energy[mo_occ == 0])
        if ehomo + 1e-3 > elumo:
            logger.warn(mf, 'H**O %.15g >= LUMO %.15g', ehomo, elumo)
        else:
            logger.info(mf, '  H**O = %.15g  LUMO = %.15g', ehomo, elumo)
        if nopen > 0 and mf.verbose >= logger.DEBUG:
            core_idx = mo_occ == 2
            open_idx = mo_occ == 1
            vir_idx = mo_occ == 0
            logger.debug(
                mf,
                '                  Roothaan           | alpha              | beta'
            )
            logger.debug(mf, '  Highest 2-occ = %18.15g | %18.15g | %18.15g',
                         max(mo_energy[core_idx]), max(mo_ea[core_idx]),
                         max(mo_eb[core_idx]))
            logger.debug(mf, '  Lowest 0-occ =  %18.15g | %18.15g | %18.15g',
                         min(mo_energy[vir_idx]), min(mo_ea[vir_idx]),
                         min(mo_eb[vir_idx]))
            for i in numpy.where(open_idx)[0]:
                logger.debug(mf,
                             '  1-occ =         %18.15g | %18.15g | %18.15g',
                             mo_energy[i], mo_ea[i], mo_eb[i])

        if mf.verbose >= logger.DEBUG:
            numpy.set_printoptions(threshold=nmo)
            logger.debug(mf, '  Roothaan mo_energy =\n%s', mo_energy)
            logger.debug1(mf, '  alpha mo_energy =\n%s', mo_ea)
            logger.debug1(mf, '  beta  mo_energy =\n%s', mo_eb)
            numpy.set_printoptions(threshold=1000)
    return mo_occ
Exemple #49
0
def init_guess_by_chkfile(mol, chkfile_name, project=None):
    '''Read SCF chkfile and make the density matrix for GHF initial guess.

    Kwargs:
        project : None or bool
            Whether to project chkfile's orbitals to the new basis.  Note when
            the geometry of the chkfile and the given molecule are very
            different, this projection can produce very poor initial guess.
            In PES scanning, it is recommended to swith off project.

            If project is set to None, the projection is only applied when the
            basis sets of the chkfile's molecule are different to the basis
            sets of the given molecule (regardless whether the geometry of
            the two molecules are different).  Note the basis sets are
            considered to be different if the two molecules are derived from
            the same molecule with different ordering of atoms.
    '''
    from pyscf.scf import addons
    chk_mol, scf_rec = chkfile.load_scf(chkfile_name)
    if project is None:
        project = not gto.same_basis_set(chk_mol, mol)

    # Check whether the two molecules are similar enough
    def inertia_momentum(mol):
        im = gto.inertia_momentum(mol._atom, mol.atom_charges(),
                                  mol.atom_coords())
        return scipy.linalg.eigh(im)[0]

    if abs(inertia_momentum(mol) - inertia_momentum(chk_mol)).sum() > 0.5:
        logger.warn(
            mol, "Large deviations found between the input "
            "molecule and the molecule from chkfile\n"
            "Initial guess density matrix may have large error.")

    if project:
        s = hf.get_ovlp(mol)

    def fproj(mo):
        if project:
            mo = addons.project_mo_nr2nr(chk_mol, mo, mol)
            norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo))
            mo /= numpy.sqrt(norm)
        return mo

    nao = chk_mol.nao_nr()
    mo = scf_rec['mo_coeff']
    mo_occ = scf_rec['mo_occ']
    if hasattr(mo[0], 'ndim') and mo[0].ndim == 1:  # RHF/GHF/DHF
        if nao * 2 == mo.shape[0]:  # GHF or DHF
            if project:
                raise NotImplementedError('Project initial guess from '
                                          'different geometry')
            else:
                dm = hf.make_rdm1(mo, mo_occ)
        else:  # RHF
            mo_coeff = fproj(mo)
            mo_occa = (mo_occ > 1e-8).astype(numpy.double)
            mo_occb = mo_occ - mo_occa
            dma, dmb = uhf.make_rdm1([mo_coeff] * 2, (mo_occa, mo_occb))
            dm = scipy.linalg.block_diag(dma, dmb)
    else:  #UHF
        if hasattr(mo[0][0], 'ndim') and mo[0][0].ndim == 2:  # KUHF
            logger.warn(
                mol, 'k-point UHF results are found.  Density matrix '
                'at Gamma point is used for the molecular SCF initial guess')
            mo = mo[0]
        dma, dmb = uhf.make_rdm1([fproj(mo[0]), fproj(mo[1])], mo_occ)
        dm = scipy.linalg.block_diag(dma, dmb)
    return dm
Exemple #50
0
 def nelectron_alpha(self, x):
     logger.warn(
         self, 'WARN: Attribute .nelectron_alpha is deprecated. '
         'Set .nelec instead')
     #raise RuntimeError('API updates')
     self.nelec = (x, self.mol.nelectron - x)
Exemple #51
0
    def get_jk(self,
               dm_kpts,
               hermi=1,
               kpts=None,
               kpts_band=None,
               with_j=True,
               with_k=True,
               omega=None,
               exxdiv=None):
        if omega is not None:  # J/K for RSH functionals
            # TODO: call AFTDF.get_jk function
            raise NotImplementedError

        # Does not support to specify arbitrary kpts
        if kpts is not None and abs(kpts - self.kpts).max() > 1e-7:
            raise RuntimeError('kpts error')
        kpts = self.kpts

        if kpts_band is not None:
            raise NotImplementedError

        cpu0 = (time.clock(), time.time())
        if self.supmol is None:
            self.build()

        nkpts = kpts.shape[0]
        vhfopt = self.vhfopt
        supmol = self.supmol
        bvkcell = self.bvkcell
        phase = self.phase
        cell = self.cell_rs
        nao = cell.nao
        orig_nao = self.cell.nao

        # * dense_bvk_ao_loc are the AOs which appear in supmol (some basis
        # are removed)
        # * sparse_ao_loc has dimension (Nk,nbas), corresponding to the
        # bvkcell with all basis
        dense_bvk_ao_loc = bvkcell.ao_loc
        sparse_ao_loc = nao * np.arange(nkpts)[:, None] + cell.ao_loc[:-1]
        sparse_ao_loc = np.append(sparse_ao_loc.ravel(), nao * nkpts)
        nbands = nkpts

        if dm_kpts.ndim != 4:
            dm = dm_kpts.reshape(-1, nkpts, orig_nao, orig_nao)
        else:
            dm = dm_kpts
        n_dm = dm.shape[0]

        rs_c_coeff = cell._contr_coeff
        sc_dm = lib.einsum('nkij,pi,qj->nkpq', dm, rs_c_coeff, rs_c_coeff)
        # Utilized symmetry sc_dm[R,S] = sc_dm[S-R] = sc_dm[(S-R)%N]
        #:sc_dm = lib.einsum('Rk,nkuv,Sk->nRuSv', phase, sc_dm, phase.conj())
        sc_dm = lib.einsum('k,Sk,nkuv->nSuv', phase[0], phase.conj(), sc_dm)
        dm_translation = k2gamma.double_translation_indices(
            self.bvk_kmesh).astype(np.int32)
        dm_imag_max = abs(sc_dm.imag).max()
        is_complex_dm = dm_imag_max > 1e-6
        if is_complex_dm:
            if dm_imag_max < 1e-2:
                logger.warn(
                    self, 'DM in (BvK) cell has small imaginary part.  '
                    'It may be a signal of symmetry broken in k-point symmetry'
                )
            sc_dm = np.vstack([sc_dm.real, sc_dm.imag])
        else:
            sc_dm = sc_dm.real
        sc_dm = np.asarray(sc_dm.reshape(-1, nkpts, nao, nao), order='C')
        n_sc_dm = sc_dm.shape[0]

        dm_cond = [
            lib.condense('NP_absmax', d, sparse_ao_loc,
                         sparse_ao_loc[:cell.nbas + 1]) for d in sc_dm
        ]
        dm_cond = np.asarray(np.max(dm_cond, axis=0), order='C')
        libpbc.CVHFset_dm_cond(vhfopt._this,
                               dm_cond.ctypes.data_as(ctypes.c_void_p),
                               dm_cond.size)
        dm_cond = None

        bvk_nbas = bvkcell.nbas
        shls_slice = (0, cell.nbas, 0, bvk_nbas, 0, bvk_nbas, 0, bvk_nbas)

        if hermi:
            fdot_suffix = 's2kl'
        else:
            fdot_suffix = 's1'
        if with_j and with_k:
            fdot = 'PBCVHF_contract_jk_' + fdot_suffix
            vs = np.zeros((2, n_sc_dm, nao, nkpts, nao))
        elif with_j:
            fdot = 'PBCVHF_contract_j_' + fdot_suffix
            vs = np.zeros((1, n_sc_dm, nao, nkpts, nao))
        else:  # with_k
            fdot = 'PBCVHF_contract_k_' + fdot_suffix
            vs = np.zeros((1, n_sc_dm, nao, nkpts, nao))

        drv = libpbc.PBCVHF_direct_drv
        drv(getattr(libpbc, fdot), vs.ctypes.data_as(ctypes.c_void_p),
            sc_dm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(n_dm),
            ctypes.c_int(nkpts), ctypes.c_int(nbands), ctypes.c_int(cell.nbas),
            self.ovlp_mask.ctypes.data_as(ctypes.c_void_p),
            self.bvk_cell_id.ctypes.data_as(ctypes.c_void_p),
            self.cell0_shl_id.ctypes.data_as(ctypes.c_void_p),
            supmol._images_loc.ctypes.data_as(ctypes.c_void_p),
            (ctypes.c_int * 8)(*shls_slice),
            dense_bvk_ao_loc.ctypes.data_as(ctypes.c_void_p),
            dm_translation.ctypes.data_as(ctypes.c_void_p), vhfopt._cintopt,
            vhfopt._this, supmol._atm.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_int(supmol.natm),
            supmol._bas.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_int(supmol.nbas),
            supmol._env.ctypes.data_as(ctypes.c_void_p))

        if is_complex_dm:
            vs = vs[:, :n_dm] + vs[:, n_dm:] * 1j

        if with_j and with_k:
            vj, vk = vs
        elif with_j:
            vj, vk = vs[0], None
        else:
            vj, vk = None, vs[0]
        cpu1 = logger.timer(self, 'short range part vj and vk', *cpu0)

        lr_c_coeff = self.lr_aft.cell._contr_coeff
        lr_dm = lib.einsum('nkij,pi,qj->nkpq', dm, lr_c_coeff, lr_c_coeff)
        # For rho product other than diffused-diffused block, construct LR
        # parts in terms of full ERIs and SR ERIs
        vj1, vk1 = self.lr_aft.get_jk(lr_dm,
                                      hermi,
                                      kpts,
                                      kpts_band,
                                      with_j,
                                      with_k,
                                      exxdiv=exxdiv)
        cpu1 = logger.timer(self, 'AFT-vj and AFT-vk', *cpu1)

        # expRk is almost the same to phase, except a normalization factor
        expRk = np.exp(1j * np.dot(self.bvkmesh_Ls, kpts.T))

        if with_j:
            vj = lib.einsum('npRq,pi,qj,Rk->nkij', vj, rs_c_coeff, rs_c_coeff,
                            expRk)
            vj += lib.einsum('nkpq,pi,qj->nkij', vj1, lr_c_coeff, lr_c_coeff)
            if self.purify and kpts_band is None:
                vj = _purify(vj, phase)
            if gamma_point(kpts) and dm_kpts.dtype == np.double:
                vj = vj.real
            if hermi:
                vj = (vj + vj.conj().transpose(0, 1, 3, 2)) * .5
            vj = vj.reshape(dm_kpts.shape)

        if with_k:
            vk = lib.einsum('npRq,pi,qj,Rk->nkij', vk, rs_c_coeff, rs_c_coeff,
                            expRk)
            vk += lib.einsum('nkpq,pi,qj->nkij', vk1, lr_c_coeff, lr_c_coeff)
            if self.purify and kpts_band is None:
                vk = _purify(vk, phase)
            if gamma_point(kpts) and dm_kpts.dtype == np.double:
                vk = vk.real
            if hermi:
                vk = (vk + vk.conj().transpose(0, 1, 3, 2)) * .5
            vk = vk.reshape(dm_kpts.shape)

        return vj, vk
Exemple #52
0
def kernel(mf,
           mo_coeff=None,
           mo_occ=None,
           dm=None,
           conv_tol=1e-10,
           conv_tol_grad=None,
           max_cycle=50,
           dump_chk=True,
           callback=None,
           verbose=logger.NOTE):
    cput0 = (time.clock(), time.time())
    log = logger.new_logger(mf, verbose)
    mol = mf._scf.mol
    if mol != mf.mol:
        logger.warn(
            mf, 'dual-basis SOSCF is an experimental feature. It is '
            'still in testing.')

    if conv_tol_grad is None:
        conv_tol_grad = numpy.sqrt(conv_tol)
        log.info('Set conv_tol_grad to %g', conv_tol_grad)

# call mf._scf.get_hcore, mf._scf.get_ovlp because they might be overloaded
    h1e = mf._scf.get_hcore(mol)
    s1e = mf._scf.get_ovlp(mol)

    if mo_coeff is not None and mo_occ is not None:
        dm = mf.make_rdm1(mo_coeff, mo_occ)
        # call mf._scf.get_veff, to avoid "newton().density_fit()" polluting get_veff
        vhf = mf._scf.get_veff(mol, dm)
        fock = mf.get_fock(h1e, s1e, vhf, dm, level_shift_factor=0)
        mo_energy, mo_tmp = mf.eig(fock, s1e)
        mf.get_occ(mo_energy, mo_tmp)
        mo_tmp = None

    else:
        if dm is None:
            logger.debug(
                mf, 'Initial guess density matrix is not given. '
                'Generating initial guess from %s', mf.init_guess)
            dm = mf.get_init_guess(mf._scf.mol, mf.init_guess)
        vhf = mf._scf.get_veff(mol, dm)
        fock = mf.get_fock(h1e, s1e, vhf, dm, level_shift_factor=0)
        mo_energy, mo_coeff = mf.eig(fock, s1e)
        mo_occ = mf.get_occ(mo_energy, mo_coeff)
        dm, dm_last = mf.make_rdm1(mo_coeff, mo_occ), dm
        vhf = mf._scf.get_veff(mol, dm, dm_last=dm_last, vhf_last=vhf)

    # Save mo_coeff and mo_occ because they are needed by function rotate_mo
    mf.mo_coeff, mf.mo_occ = mo_coeff, mo_occ

    e_tot = mf._scf.energy_tot(dm, h1e, vhf)
    fock = mf.get_fock(h1e, s1e, vhf, dm, level_shift_factor=0)
    log.info('Initial guess E= %.15g  |g|= %g', e_tot,
             numpy.linalg.norm(mf._scf.get_grad(mo_coeff, mo_occ, fock)))

    if dump_chk and mf.chkfile:
        chkfile.save_mol(mol, mf.chkfile)

# Copy the integral file to soscf object to avoid the integrals being cached
# twice.
    if mol is mf.mol and not getattr(mf, 'with_df', None):
        mf._eri = mf._scf._eri
        # If different direct_scf_cutoff is assigned to newton_ah mf.opt
        # object, mf.opt should be different to mf._scf.opt
        #mf.opt = mf._scf.opt

    rotaiter = _rotate_orb_cc(mf, h1e, s1e, conv_tol_grad, verbose=log)
    next(rotaiter)  # start the iterator
    kftot = jktot = 0
    scf_conv = False
    cput1 = log.timer('initializing second order scf', *cput0)

    for imacro in range(max_cycle):
        u, g_orb, kfcount, jkcount, dm_last, vhf = \
                rotaiter.send((mo_coeff, mo_occ, dm, vhf, e_tot))
        kftot += kfcount + 1
        jktot += jkcount + 1

        last_hf_e = e_tot
        norm_gorb = numpy.linalg.norm(g_orb)
        mo_coeff = mf.rotate_mo(mo_coeff, u, log)
        dm = mf.make_rdm1(mo_coeff, mo_occ)
        vhf = mf._scf.get_veff(mol, dm, dm_last=dm_last, vhf_last=vhf)
        fock = mf.get_fock(h1e, s1e, vhf, dm, level_shift_factor=0)
        # NOTE: DO NOT change the initial guess mo_occ, mo_coeff
        if mf.verbose >= logger.DEBUG:
            mo_energy, mo_tmp = mf.eig(fock, s1e)
            mf.get_occ(mo_energy, mo_tmp)
# call mf._scf.energy_tot for dft, because the (dft).get_veff step saved _exc in mf._scf
        e_tot = mf._scf.energy_tot(dm, h1e, vhf)

        log.info('macro= %d  E= %.15g  delta_E= %g  |g|= %g  %d KF %d JK',
                 imacro, e_tot, e_tot - last_hf_e, norm_gorb, kfcount + 1,
                 jkcount)
        cput1 = log.timer('cycle= %d' % (imacro + 1), *cput1)

        if callable(mf.check_convergence):
            scf_conv = mf.check_convergence(locals())
        elif abs(e_tot - last_hf_e) < conv_tol and norm_gorb < conv_tol_grad:
            scf_conv = True

        if dump_chk:
            mf.dump_chk(locals())

        if callable(callback):
            callback(locals())

        if scf_conv:
            break

    if callable(callback):
        callback(locals())

    rotaiter.close()
    mo_energy, mo_coeff1 = mf._scf.canonicalize(mo_coeff, mo_occ, fock)
    if mf.canonicalization:
        log.info('Canonicalize SCF orbitals')
        mo_coeff = mo_coeff1
        if dump_chk:
            mf.dump_chk(locals())
    log.info('macro X = %d  E=%.15g  |g|= %g  total %d KF %d JK', imacro + 1,
             e_tot, norm_gorb, kftot + 1, jktot + 1)
    if (numpy.any(mo_occ == 0)
            and mo_energy[mo_occ > 0].max() > mo_energy[mo_occ == 0].min()):
        log.warn('H**O %s > LUMO %s was found in the canonicalized orbitals.',
                 mo_energy[mo_occ > 0].max(), mo_energy[mo_occ == 0].min())
    return scf_conv, e_tot, mo_energy, mo_coeff, mo_occ
Exemple #53
0
def get_pp_loc_part1(mydf, kpts=None):
    cell = mydf.cell
    if kpts is None:
        kpts_lst = numpy.zeros((1, 3))
    else:
        kpts_lst = numpy.reshape(kpts, (-1, 3))

    log = logger.Logger(mydf.stdout, mydf.verbose)
    t0 = t1 = (time.clock(), time.time())

    mesh = numpy.asarray(mydf.mesh)
    nkpts = len(kpts_lst)
    nao = cell.nao_nr()
    nao_pair = nao * (nao + 1) // 2
    charges = cell.atom_charges()

    kpt_allow = numpy.zeros(3)
    if mydf.eta == 0:
        if cell.dimension > 0:
            ke_guess = estimate_ke_cutoff(cell, cell.precision)
            mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess)
            if numpy.any(
                    mesh[:cell.dimension] < mesh_guess[:cell.dimension] * .8):
                logger.warn(
                    mydf, 'mesh %s is not enough for AFTDF.get_nuc function '
                    'to get integral accuracy %g.\nRecommended mesh is %s.',
                    mesh, cell.precision, mesh_guess)
        Gv, Gvbase, kws = cell.get_Gv_weights(mesh)

        vpplocG = pseudo.pp_int.get_gth_vlocG_part1(cell, Gv)
        vpplocG = -numpy.einsum('ij,ij->j', cell.get_SI(Gv), vpplocG)

        vpplocG *= kws
        vG = vpplocG
        vj = numpy.zeros((nkpts, nao_pair), dtype=numpy.complex128)

    else:
        if cell.dimension > 0:
            ke_guess = estimate_ke_cutoff_for_eta(cell, mydf.eta,
                                                  cell.precision)
            mesh_guess = tools.cutoff_to_mesh(cell.lattice_vectors(), ke_guess)
            if numpy.any(mesh < mesh_guess * .8):
                logger.warn(
                    mydf, 'mesh %s is not enough for AFTDF.get_nuc function '
                    'to get integral accuracy %g.\nRecommended mesh is %s.',
                    mesh, cell.precision, mesh_guess)
            mesh_min = numpy.min((mesh_guess, mesh), axis=0)
            if cell.dimension < 2 or cell.low_dim_ft_type == 'inf_vacuum':
                mesh[:cell.dimension] = mesh_min[:cell.dimension]
            else:
                mesh = mesh_min
        Gv, Gvbase, kws = cell.get_Gv_weights(mesh)

        nuccell = _compensate_nuccell(mydf)
        # PP-loc part1 is handled by fakenuc in _int_nuc_vloc
        vj = lib.asarray(mydf._int_nuc_vloc(nuccell, kpts_lst))
        t0 = t1 = log.timer_debug1('vnuc pass1: analytic int', *t0)

        coulG = tools.get_coulG(cell, kpt_allow, mesh=mesh, Gv=Gv) * kws
        aoaux = ft_ao.ft_ao(nuccell, Gv)
        vG = numpy.einsum('i,xi->x', -charges, aoaux) * coulG

    max_memory = max(2000, mydf.max_memory - lib.current_memory()[0])
    for aoaoks, p0, p1 in mydf.ft_loop(mesh,
                                       kpt_allow,
                                       kpts_lst,
                                       max_memory=max_memory,
                                       aosym='s2'):
        for k, aoao in enumerate(aoaoks):
            # rho_ij(G) nuc(-G) / G^2
            # = [Re(rho_ij(G)) + Im(rho_ij(G))*1j] [Re(nuc(G)) - Im(nuc(G))*1j] / G^2
            if gamma_point(kpts_lst[k]):
                vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].real, aoao.real)
                vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].imag, aoao.imag)
            else:
                vj[k] += numpy.einsum('k,kx->x', vG[p0:p1].conj(), aoao)
        t1 = log.timer_debug1('contracting Vnuc [%s:%s]' % (p0, p1), *t1)
    log.timer_debug1('contracting Vnuc', *t0)

    vj_kpts = []
    for k, kpt in enumerate(kpts_lst):
        if gamma_point(kpt):
            vj_kpts.append(lib.unpack_tril(vj[k].real.copy()))
        else:
            vj_kpts.append(lib.unpack_tril(vj[k]))

    if kpts is None or numpy.shape(kpts) == (3, ):
        vj_kpts = vj_kpts[0]
    return numpy.asarray(vj_kpts)
Exemple #54
0
def dip_moment(cell,
               dm,
               unit='Debye',
               verbose=logger.NOTE,
               grids=None,
               rho=None,
               kpt=np.zeros(3),
               origin=None):
    ''' Dipole moment in the unit cell (is it well defined)?

    Args:
         cell : an instance of :class:`Cell`

         dm (ndarray) : density matrix

    Return:
        A list: the dipole moment on x, y and z components
    '''
    from pyscf.pbc import gto
    from pyscf.pbc import tools
    from pyscf.pbc.dft import gen_grid
    from pyscf.pbc.dft import numint
    if cell.dimension != 3:
        # raise NotImplementedError
        logger.warn(
            cell, 'Dipole moment for low-dimension system is not supported.')
        return np.zeros(3)

    log = logger.new_logger(cell, verbose)
    a = cell.lattice_vectors()
    b = np.linalg.inv(a).T

    if grids is None:
        grids = gen_grid.UniformGrids(cell)
        #? FIXME: Less requirements on the density accuracy.
        #ke_cutoff = gto.estimate_ke_cutoff(cell, 1e-5)
        #grids.mesh = tools.cutoff_to_mesh(a, ke_cutoff)
    if rho is None:
        rho = numint.NumInt().get_rho(cell, dm, grids, kpt, cell.max_memory)

    if origin is None:
        origin = _search_dipole_gauge_origin(cell, grids, rho, log)

    # Move the unit cell to the position around the origin.
    def shift_grids(r):
        r_frac = lib.dot(r - origin, b.T)
        # Grids on the boundary (r_frac == +/-0.5) of the new cell may lead to
        # unbalanced contributions to the dipole moment. Exclude them from the
        # dipole and quadrupole
        r_frac[r_frac == 0.5] = 0
        r_frac[r_frac == -0.5] = 0
        r_frac[r_frac > 0.5] -= 1
        r_frac[r_frac < -0.5] += 1
        r = lib.dot(r_frac, a)
        return r

    r = shift_grids(grids.coords)
    e_dip = np.einsum('g,g,gx->x', rho, grids.weights, r)

    charges = cell.atom_charges()
    r = shift_grids(cell.atom_coords())
    nuc_dip = np.einsum('g,gx->x', charges, r)
    dip = nuc_dip - e_dip

    if unit.upper() == 'DEBYE':
        dip *= nist.AU2DEBYE
        log.note('Dipole moment(X, Y, Z, Debye): %8.5f, %8.5f, %8.5f', *dip)
    else:
        log.note('Dipole moment(X, Y, Z, A.U.): %8.5f, %8.5f, %8.5f', *dip)
    return dip
Exemple #55
0
def eaccsd_star_contract(eom,
                         eaccsd_evals,
                         eaccsd_evecs,
                         leaccsd_evecs,
                         imds=None):
    """
    Returns:
        e_star (list of float):
            The EA-CCSD* energy.

    Notes:
        See `ipccsd_star_contract` for description of arguments.

    Reference:
        Saeh, Stanton "...energy surfaces of radicals" JCP 111, 8275 (1999); DOI:10.1063/1.480171
    """
    assert eom.partition is None
    if imds is None:
        imds = eom.make_imds()
    t1, t2 = imds.t1, imds.t2
    eris = imds.eris
    assert isinstance(eris, gccsd._PhysicistsERIs)
    fock = eris.fock
    nocc, nvir = t1.shape
    nmo = nocc + nvir

    #fov = fock[:nocc, nocc:].diagonal()
    foo = fock[:nocc, :nocc].diagonal()
    fvv = fock[nocc:, nocc:].diagonal()

    vvvv = _cp(eris.vvvv)
    oovv = _cp(eris.oovv)
    ovvv = _cp(eris.ovvv)
    ovov = _cp(eris.ovov)
    #ovvo = -_cp(eris.ovov).transpose(0,1,3,2)
    ooov = _cp(eris.ooov)
    vooo = _cp(ooov).conj().transpose(3, 2, 1, 0)
    vvvo = _cp(ovvv).conj().transpose(3, 2, 1, 0)

    # Create denominator
    eabc = fvv[:, None, None] + fvv[None, :, None] + fvv[None, None, :]
    eij = foo[:, None] + foo[None, :]
    eijabc = eij[:, :, None, None, None] - eabc[None, None, :, :, :]

    # Permutation operators
    def pabc(tmp):
        '''P(abc)'''
        return tmp + tmp.transpose(0, 1, 3, 4, 2) + tmp.transpose(
            0, 1, 4, 2, 3)

    def pij(tmp):
        '''P(ij)'''
        return tmp - tmp.transpose(1, 0, 2, 3, 4)

    def pab(tmp):
        '''P(ab)'''
        return tmp - tmp.transpose(0, 1, 3, 2, 4)

    eaccsd_evecs = np.array(eaccsd_evecs)
    leaccsd_evecs = np.array(leaccsd_evecs)
    e_star = []
    eaccsd_evecs, leaccsd_evecs = [
        np.atleast_2d(x) for x in [eaccsd_evecs, leaccsd_evecs]
    ]
    eaccsd_evals = np.atleast_1d(eaccsd_evals)
    for ea_eval, ea_evec, ea_levec in zip(eaccsd_evals, eaccsd_evecs,
                                          leaccsd_evecs):
        # Enforcing <L|R> = 1
        l1, l2 = vector_to_amplitudes_ea(ea_levec, nmo, nocc)
        r1, r2 = vector_to_amplitudes_ea(ea_evec, nmo, nocc)
        ldotr = np.dot(l1, r1) + 0.5 * np.dot(l2.ravel(), r2.ravel())

        logger.info(eom, 'Left-right amplitude overlap : %14.8e', ldotr)
        if abs(ldotr) < 1e-7:
            logger.warn(
                eom, 'Small %s left-right amplitude overlap. Results '
                'may be inaccurate.', ldotr)

        l1 /= ldotr
        l2 /= ldotr

        # Denominator + eigenvalue(EA-CCSD)
        denom = eijabc + ea_eval
        denom = 1. / denom

        tmp = lib.einsum('c,ijab->ijabc', l1, oovv)
        lijabc = -pabc(tmp)
        tmp = lib.einsum('jima,mbc->ijabc', ooov, l2)
        lijabc += -pabc(tmp)
        tmp = lib.einsum('ieab,jce->ijabc', ovvv, l2)
        tmp = pabc(tmp)
        lijabc += -pij(tmp)

        tmp = lib.einsum('bcef,f->bce', vvvv, r1)
        tmp = lib.einsum('bce,ijae->ijabc', tmp, t2)
        rijabc = -pabc(tmp)
        tmp = lib.einsum('mcje,e->mcj', ovov, r1)
        tmp = lib.einsum('mcj,imab->ijabc', tmp, t2)
        tmp = pabc(tmp)
        rijabc += pij(tmp)
        tmp = lib.einsum('amij,mcb->ijabc', vooo, r2)
        rijabc += pabc(tmp)
        tmp = lib.einsum('baei,jce->ijabc', vvvo, r2)
        tmp = pabc(tmp)
        rijabc -= pij(tmp)

        deltaE = (1. / 12) * lib.einsum('ijabc,ijabc,ijabc', lijabc, rijabc,
                                        denom)
        deltaE = deltaE.real
        logger.info(eom, "Exc. energy, delta energy = %16.12f, %16.12f",
                    ea_eval + deltaE, deltaE)
        e_star.append(ea_eval + deltaE)

    return e_star
Exemple #56
0
    def build(self, j_only=None, with_j3c=True, kpts_band=None):
        if self.kpts_band is not None:
            self.kpts_band = numpy.reshape(self.kpts_band, (-1, 3))
        if kpts_band is not None:
            kpts_band = numpy.reshape(kpts_band, (-1, 3))
            if self.kpts_band is None:
                self.kpts_band = kpts_band
            else:
                self.kpts_band = unique(
                    numpy.vstack((self.kpts_band, kpts_band)))[0]

        self.check_sanity()
        self.dump_flags()

        self.auxcell = make_modrho_basis(self.cell, self.auxbasis,
                                         self.exp_to_discard)

        # Remove duplicated k-points. Duplicated kpts may lead to a buffer
        # located in incore.wrap_int3c larger than necessary. Integral code
        # only fills necessary part of the buffer, leaving some space in the
        # buffer unfilled.
        uniq_idx = unique(self.kpts)[1]
        kpts = numpy.asarray(self.kpts)[uniq_idx]
        if self.kpts_band is None:
            kband_uniq = numpy.zeros((0, 3))
        else:
            kband_uniq = [
                k for k in self.kpts_band if len(member(k, kpts)) == 0
            ]
        if j_only is None:
            j_only = self._j_only
        if j_only:
            kall = numpy.vstack([kpts, kband_uniq])
            kptij_lst = numpy.hstack((kall, kall)).reshape(-1, 2, 3)
        else:
            kptij_lst = [(ki, kpts[j]) for i, ki in enumerate(kpts)
                         for j in range(i + 1)]
            kptij_lst.extend([(ki, kj) for ki in kband_uniq for kj in kpts])
            kptij_lst.extend([(ki, ki) for ki in kband_uniq])
            kptij_lst = numpy.asarray(kptij_lst)

        if with_j3c:
            if isinstance(self._cderi_to_save, str):
                cderi = self._cderi_to_save
            else:
                cderi = self._cderi_to_save.name
            if isinstance(self._cderi, str):
                if self._cderi == cderi and os.path.isfile(cderi):
                    logger.warn(
                        self, 'DF integrals in %s (specified by '
                        '._cderi) is overwritten by GDF '
                        'initialization. ', cderi)
                else:
                    logger.warn(
                        self, 'Value of ._cderi is ignored. '
                        'DF integrals will be saved in file %s .', cderi)
            self._cderi = cderi
            t1 = (logger.process_clock(), logger.perf_counter())
            self._make_j3c(self.cell, self.auxcell, kptij_lst, cderi)
            t1 = logger.timer_debug1(self, 'j3c', *t1)
        return self
Exemple #57
0
 def build(self, mol=None):
     for irname in self.irrep_nelec:
         if irname not in self.mol.irrep_name:
             logger.warn(self, '!! No irrep %s', irname)
     return uhf.UHF.build(self, mol)
Exemple #58
0
def get_coulG(cell, k=np.zeros(3), exx=False, mf=None, mesh=None, Gv=None,
              wrap_around=True, omega=None, **kwargs):
    '''Calculate the Coulomb kernel for all G-vectors, handling G=0 and exchange.

    Args:
        k : (3,) ndarray
            k-point
        exx : bool or str
            Whether this is an exchange matrix element.
        mf : instance of :class:`SCF`

    Returns:
        coulG : (ngrids,) ndarray
            The Coulomb kernel.
        mesh : (3,) ndarray of ints (= nx,ny,nz)
            The number G-vectors along each direction.
        omega : float
            Enable Coulomb kernel erf(|omega|*r12)/r12 if omega > 0
            and erfc(|omega|*r12)/r12 if omega < 0.
            Note this parameter is slightly different to setting cell.omega
            for the treatment of exxdiv (at G0).  cell.omega affects Ewald
            probe charge at G0. It is used mostly with RSH functional for
            the long-range part of HF exchange. This parameter is used by
            real-space JK builder which requires Ewald probe charge to be
            computed with regular Coulomb interaction (1/r12) while the rest
            coulG is scaled as long-range Coulomb kernel.
    '''
    exxdiv = exx
    if isinstance(exx, str):
        exxdiv = exx
    elif exx and mf is not None:
        exxdiv = mf.exxdiv

    if mesh is None:
        mesh = cell.mesh
    if 'gs' in kwargs:
        warnings.warn('cell.gs is deprecated.  It is replaced by cell.mesh,'
                      'the number of PWs (=2*gs+1) along each direction.')
        mesh = [2*n+1 for n in kwargs['gs']]
    if Gv is None:
        Gv = cell.get_Gv(mesh)

    if abs(k).sum() > 1e-9:
        kG = k + Gv
    else:
        kG = Gv

    equal2boundary = np.zeros(Gv.shape[0], dtype=bool)
    if wrap_around and abs(k).sum() > 1e-9:
        # Here we 'wrap around' the high frequency k+G vectors into their lower
        # frequency counterparts.  Important if you want the gamma point and k-point
        # answers to agree
        b = cell.reciprocal_vectors()
        box_edge = np.einsum('i,ij->ij', np.asarray(mesh)//2+0.5, b)
        assert(all(np.linalg.solve(box_edge.T, k).round(9).astype(int)==0))
        reduced_coords = np.linalg.solve(box_edge.T, kG.T).T.round(9)
        on_edge = reduced_coords.astype(int)
        if cell.dimension >= 1:
            equal2boundary |= reduced_coords[:,0] == 1
            equal2boundary |= reduced_coords[:,0] ==-1
            kG[on_edge[:,0]== 1] -= 2 * box_edge[0]
            kG[on_edge[:,0]==-1] += 2 * box_edge[0]
        if cell.dimension >= 2:
            equal2boundary |= reduced_coords[:,1] == 1
            equal2boundary |= reduced_coords[:,1] ==-1
            kG[on_edge[:,1]== 1] -= 2 * box_edge[1]
            kG[on_edge[:,1]==-1] += 2 * box_edge[1]
        if cell.dimension == 3:
            equal2boundary |= reduced_coords[:,2] == 1
            equal2boundary |= reduced_coords[:,2] ==-1
            kG[on_edge[:,2]== 1] -= 2 * box_edge[2]
            kG[on_edge[:,2]==-1] += 2 * box_edge[2]

    absG2 = np.einsum('gi,gi->g', kG, kG)

    if getattr(mf, 'kpts', None) is not None:
        kpts = mf.kpts
    else:
        kpts = k.reshape(1,3)
    Nk = len(kpts)

    if exxdiv == 'vcut_sph':  # PRB 77 193110
        Rc = (3*Nk*cell.vol/(4*np.pi))**(1./3)
        with np.errstate(divide='ignore',invalid='ignore'):
            coulG = 4*np.pi/absG2*(1.0 - np.cos(np.sqrt(absG2)*Rc))
        coulG[absG2==0] = 4*np.pi*0.5*Rc**2

        if cell.dimension < 3:
            raise NotImplementedError

    elif exxdiv == 'vcut_ws':  # PRB 87, 165122
        assert(cell.dimension == 3)
        if not getattr(mf, '_ws_exx', None):
            mf._ws_exx = precompute_exx(cell, kpts)
        exx_alpha = mf._ws_exx['alpha']
        exx_kcell = mf._ws_exx['kcell']
        exx_q = mf._ws_exx['q']
        exx_vq = mf._ws_exx['vq']

        with np.errstate(divide='ignore',invalid='ignore'):
            coulG = 4*np.pi/absG2*(1.0 - np.exp(-absG2/(4*exx_alpha**2)))
        coulG[absG2==0] = np.pi / exx_alpha**2
        # Index k+Gv into the precomputed vq and add on
        gxyz = np.dot(kG, exx_kcell.lattice_vectors().T)/(2*np.pi)
        gxyz = gxyz.round(decimals=6).astype(int)
        mesh = np.asarray(exx_kcell.mesh)
        gxyz = (gxyz + mesh)%mesh
        qidx = (gxyz[:,0]*mesh[1] + gxyz[:,1])*mesh[2] + gxyz[:,2]
        #qidx = [np.linalg.norm(exx_q-kGi,axis=1).argmin() for kGi in kG]
        maxqv = abs(exx_q).max(axis=0)
        is_lt_maxqv = (abs(kG) <= maxqv).all(axis=1)
        coulG = coulG.astype(exx_vq.dtype)
        coulG[is_lt_maxqv] += exx_vq[qidx[is_lt_maxqv]]

        if cell.dimension < 3:
            raise NotImplementedError

    else:
        # Ewald probe charge method to get the leading term of the finite size
        # error in exchange integrals

        G0_idx = np.where(absG2==0)[0]
        if cell.dimension != 2 or cell.low_dim_ft_type == 'inf_vacuum':
            with np.errstate(divide='ignore'):
                coulG = 4*np.pi/absG2
                coulG[G0_idx] = 0

        elif cell.dimension == 2:
            # The following 2D analytical fourier transform is taken from:
            # R. Sundararaman and T. Arias PRB 87, 2013
            b = cell.reciprocal_vectors()
            Ld2 = np.pi/np.linalg.norm(b[2])
            Gz = kG[:,2]
            Gp = np.linalg.norm(kG[:,:2], axis=1)
            weights = 1. - np.cos(Gz*Ld2) * np.exp(-Gp*Ld2)
            with np.errstate(divide='ignore', invalid='ignore'):
                coulG = weights*4*np.pi/absG2
            if len(G0_idx) > 0:
                coulG[G0_idx] = -2*np.pi*Ld2**2 #-pi*L_z^2/2

        elif cell.dimension == 1:
            logger.warn(cell, 'No method for PBC dimension 1, dim-type %s.'
                        '  cell.low_dim_ft_type="inf_vacuum"  should be set.',
                        cell.low_dim_ft_type)
            raise NotImplementedError

            # Carlo A. Rozzi, PRB 73, 205119 (2006)
            a = cell.lattice_vectors()
            # Rc is the cylindrical radius
            Rc = np.sqrt(cell.vol / np.linalg.norm(a[0])) / 2
            Gx = abs(kG[:,0])
            Gp = np.linalg.norm(kG[:,1:], axis=1)
            with np.errstate(divide='ignore', invalid='ignore'):
                weights = 1 + Gp*Rc * scipy.special.j1(Gp*Rc) * scipy.special.k0(Gx*Rc)
                weights -= Gx*Rc * scipy.special.j0(Gp*Rc) * scipy.special.k1(Gx*Rc)
                coulG = 4*np.pi/absG2 * weights
                # TODO: numerical integation
                # coulG[Gx==0] = -4*np.pi * (dr * r * scipy.special.j0(Gp*r) * np.log(r)).sum()
            if len(G0_idx) > 0:
                coulG[G0_idx] = -np.pi*Rc**2 * (2*np.log(Rc) - 1)

        # The divergent part of periodic summation of (ii|ii) integrals in
        # Coulomb integrals were cancelled out by electron-nucleus
        # interaction. The periodic part of (ii|ii) in exchange cannot be
        # cancelled out by Coulomb integrals. Its leading term is calculated
        # using Ewald probe charge (the function madelung below)
        if cell.dimension > 0 and exxdiv == 'ewald' and len(G0_idx) > 0:
            coulG[G0_idx] += Nk*cell.vol*madelung(cell, kpts)

    coulG[equal2boundary] = 0

    # Scale the coulG kernel for attenuated Coulomb integrals.
    # * omega is used by RealSpaceJKBuilder which requires ewald probe charge
    # being evaluated with regular Coulomb interaction (1/r12).
    # * cell.omega, which affects the ewald probe charge, is often set by
    # DFT-RSH functionals to build long-range HF-exchange for erf(omega*r12)/r12
    if omega is not None:
        if omega > 0:
            coulG *= np.exp(-.25/omega**2 * absG2)
        else:
            coulG *= (1 - np.exp(-.25/omega**2 * absG2))
    elif cell.omega != 0:
        coulG *= np.exp(-.25/cell.omega**2 * absG2)

    return coulG
Exemple #59
0
def kernel(gw,
           mo_energy,
           mo_coeff,
           td_e,
           td_xy,
           eris=None,
           orbs=None,
           verbose=logger.NOTE):
    '''GW-corrected quasiparticle orbital energies

    Returns:
        A list :  converged, mo_energy, mo_coeff
    '''
    # mf must be DFT; for HF use xc = 'hf'
    mf = gw._scf
    assert (isinstance(mf, (dft.rks.RKS, dft.uks.UKS, dft.roks.ROKS,
                            dft.uks.UKS, dft.rks_symm.RKS, dft.uks_symm.UKS,
                            dft.rks_symm.ROKS, dft.uks_symm.UKS)))
    assert (gw.frozen == 0 or gw.frozen is None)

    if eris is None:
        eris = gw.ao2mo(mo_coeff)
    if orbs is None:
        orbs = range(gw.nmo)

    v_mf = mf.get_veff() - mf.get_j()
    v_mf = reduce(numpy.dot, (mo_coeff.T, v_mf, mo_coeff))

    nocc = gw.nocc
    nmo = gw.nmo
    nvir = nmo - nocc

    vk_oo = -np.einsum('piiq->pq', eris.oooo)
    vk_ov = -np.einsum('iqpi->pq', eris.ovoo)
    vk_vv = -np.einsum('ipqi->pq', eris.ovvo).conj()
    vk = np.array(np.bmat([[vk_oo, vk_ov], [vk_ov.T, vk_vv]]))

    nexc = len(td_e)
    # factor of 2 for normalization, see tdscf/rhf.py
    td_xy = 2 * np.asarray(td_xy)  # (nexc, 2, nocc, nvir)
    td_z = np.sum(td_xy, axis=1).reshape(nexc, nocc, nvir)
    tdm_oo = einsum('via,iapq->vpq', td_z, eris.ovoo)
    tdm_ov = einsum('via,iapq->vpq', td_z, eris.ovov)
    tdm_vv = einsum('via,iapq->vpq', td_z, eris.ovvv)
    tdm = []
    for oo, ov, vv in zip(tdm_oo, tdm_ov, tdm_vv):
        tdm.append(np.array(np.bmat([[oo, ov], [ov.T, vv]])))
    tdm = np.asarray(tdm)

    conv = True
    mo_energy = np.zeros_like(gw._scf.mo_energy)
    for p in orbs:
        tdm_p = tdm[:, :, p]
        if gw.linearized:
            ep = gw._scf.mo_energy[p]
            sigma = get_sigma_element(gw, ep, tdm_p, tdm_p, td_e).real
            dsigma_dw = get_sigma_deriv_element(gw, ep, tdm_p, tdm_p,
                                                td_e).real
            zn = 1.0 / (1 - dsigma_dw)
            mo_energy[p] = ep + zn * (sigma.real + vk[p, p] - v_mf[p, p])
        else:

            def quasiparticle(omega):
                sigma = get_sigma_element(gw, omega, tdm_p, tdm_p, td_e)
                return omega - gw._scf.mo_energy[p] - (sigma.real + vk[p, p] -
                                                       v_mf[p, p])

            try:
                mo_energy[p] = newton(quasiparticle,
                                      gw._scf.mo_energy[p],
                                      tol=1e-6,
                                      maxiter=100)
            except RuntimeError:
                conv = False
                mo_energy[p] = gw._scf.mo_energy[p]
                logger.warn(
                    gw, 'Root finding for GW eigenvalue %s did not converge. '
                    'Setting it equal to the reference MO energy.' % (p))
    mo_coeff = gw._scf.mo_coeff

    if gw.verbose >= logger.DEBUG:
        numpy.set_printoptions(threshold=nmo)
        logger.debug(gw, '  GW mo_energy =\n%s', mo_energy)
        numpy.set_printoptions(threshold=1000)

    return conv, mo_energy, mo_coeff
Exemple #60
0
def _make_eris(mp, mo_coeff=None, ao2mofn=None, verbose=None):
    log = logger.new_logger(mp, verbose)
    time0 = (time.clock(), time.time())
    eris = _ChemistsERIs()
    eris._common_init_(mp, mo_coeff)

    nocca, noccb = mp.get_nocc()
    nmoa, nmob = mp.get_nmo()
    nvira, nvirb = nmoa - nocca, nmob - noccb
    nao = eris.mo_coeff[0].shape[0]
    nmo_pair = nmoa * (nmoa + 1) // 2
    nao_pair = nao * (nao + 1) // 2
    mem_incore = (nao_pair**2 + nmo_pair**2) * 8 / 1e6
    mem_now = lib.current_memory()[0]
    max_memory = max(0, mp.max_memory - mem_now)

    moa = eris.mo_coeff[0]
    mob = eris.mo_coeff[1]
    orboa = moa[:, :nocca]
    orbob = mob[:, :noccb]
    orbva = moa[:, nocca:]
    orbvb = mob[:, noccb:]

    if (mp.mol.incore_anyway or
        (mp._scf._eri is not None and mem_incore + mem_now < mp.max_memory)):
        log.debug('transform (ia|jb) incore')
        if callable(ao2mofn):
            eris.ovov = ao2mofn(
                (orboa, orbva, orboa, orbva)).reshape(nocca * nvira,
                                                      nocca * nvira)
            eris.ovOV = ao2mofn(
                (orboa, orbva, orbob, orbvb)).reshape(nocca * nvira,
                                                      noccb * nvirb)
            eris.OVOV = ao2mofn(
                (orbob, orbvb, orbob, orbvb)).reshape(noccb * nvirb,
                                                      noccb * nvirb)
        else:
            eris.ovov = ao2mo.general(mp._scf._eri,
                                      (orboa, orbva, orboa, orbva))
            eris.ovOV = ao2mo.general(mp._scf._eri,
                                      (orboa, orbva, orbob, orbvb))
            eris.OVOV = ao2mo.general(mp._scf._eri,
                                      (orbob, orbvb, orbob, orbvb))

    elif getattr(mp._scf, 'with_df', None):
        logger.warn(
            mp, 'UMP2 detected DF being used in the HF object. '
            'MO integrals are computed based on the DF 3-index tensors.\n'
            'It\'s recommended to use DF-UMP2 module.')
        log.debug('transform (ia|jb) with_df')
        eris.ovov = mp._scf.with_df.ao2mo((orboa, orbva, orboa, orbva))
        eris.ovOV = mp._scf.with_df.ao2mo((orboa, orbva, orbob, orbvb))
        eris.OVOV = mp._scf.with_df.ao2mo((orbob, orbvb, orbob, orbvb))

    else:
        log.debug('transform (ia|jb) outcore')
        eris.feri = lib.H5TmpFile()
        _ao2mo_ovov(mp, (orboa, orbva, orbob, orbvb), eris.feri,
                    max(2000, max_memory), log)
        eris.ovov = eris.feri['ovov']
        eris.ovOV = eris.feri['ovOV']
        eris.OVOV = eris.feri['OVOV']

    time1 = log.timer('Integral transformation', *time0)
    return eris