예제 #1
0
    def test_project_mo_nr2nr(self):
        nao = mol.nao_nr()
        c = numpy.random.random((nao, nao))
        c1 = addons.project_mo_nr2nr(mol, c, mol)
        self.assertAlmostEqual(abs(c - c1).max(), 0, 12)

        numpy.random.seed(15)
        nao = mol.nao_nr()
        mo1 = numpy.random.random((nao, nao))
        mo2 = addons.project_mo_nr2nr(mol, [mo1, mo1], mol_dz)
        self.assertAlmostEqual(abs(mo2[0]).sum(), 83.436359425591888, 11)
        self.assertAlmostEqual(abs(mo2[1]).sum(), 83.436359425591888, 11)
예제 #2
0
    def test_project_mo_nr2nr(self):
        nao = mol.nao_nr()
        c = numpy.random.random((nao,nao))
        c1 = addons.project_mo_nr2nr(mol, c, mol)
        self.assertAlmostEqual(abs(c-c1).max(), 0, 12)

        numpy.random.seed(15)
        nao = mol.nao_nr()
        mo1 = numpy.random.random((nao,nao))
        mo2 = addons.project_mo_nr2nr(mol, [mo1,mo1], mol_dz)
        self.assertAlmostEqual(abs(mo2[0]).sum(), 83.436359425591888, 11)
        self.assertAlmostEqual(abs(mo2[1]).sum(), 83.436359425591888, 11)
예제 #3
0
파일: hf.py 프로젝트: BB-Goldstein/pyscf
def init_guess_by_minao(mol):
    '''Generate initial guess density matrix based on ANO basis, then project
    the density matrix to the basis set defined by ``mol``

    Returns:
        Density matrix, 2D ndarray

    Examples:

    >>> from pyscf import gto, scf
    >>> mol = gto.M(atom='H 0 0 0; H 0 0 1.1')
    >>> scf.hf.init_guess_by_minao(mol)
    array([[ 0.94758917,  0.09227308],
           [ 0.09227308,  0.94758917]])
    '''
    from pyscf.scf import atom_hf
    from pyscf.scf import addons

    def minao_basis(symb):
        basis_add = pyscf.gto.basis.load('ano', symb)
        occ = []
        basis_new = []
        for l in range(4):
            ndocc, nfrac = atom_hf.frac_occ(symb, l)
            if ndocc > 0:
                occ.extend([2]*ndocc*(2*l+1))
            if nfrac > 1e-15:
                occ.extend([nfrac]*(2*l+1))
                ndocc += 1
            if ndocc > 0:
                basis_new.append([l] + [b[:ndocc+1] for b in basis_add[l][1:]])
        return occ, basis_new

    atmlst = set([pyscf.gto.mole._rm_digit(pyscf.gto.mole._symbol(k))
                  for k in mol._basis.keys()])
    basis = {}
    occdic = {}
    for symb in atmlst:
        if symb != 'GHOST':
            occ_add, basis_add = minao_basis(symb)
            occdic[symb] = occ_add
            basis[symb] = basis_add
    occ = []
    new_atom = []
    for ia in range(mol.natm):
        symb = mol.atom_pure_symbol(ia)
        if symb != 'GHOST':
            occ.append(occdic[symb])
            new_atom.append(mol._atom[ia])
    occ = numpy.hstack(occ)

    pmol = pyscf.gto.Mole()
    pmol._atm, pmol._bas, pmol._env = pmol.make_env(new_atom, basis, [])
    c = addons.project_mo_nr2nr(pmol, 1, mol)

    dm = numpy.dot(c*occ, c.T)
# normalize eletron number
#    s = mol.intor_symmetric('cint1e_ovlp_sph')
#    dm *= mol.nelectron / (dm*s).sum()
    return dm
예제 #4
0
파일: hf.py 프로젝트: pulkin/pyscf
def init_guess_by_atom(mol):
    '''Generate initial guess density matrix from superposition of atomic HF
    density matrix.  The atomic HF is occupancy averaged RHF

    Returns:
        Density matrix, 2D ndarray
    '''
    import copy
    from pyscf.scf import atom_hf
    from pyscf.scf import addons
    atm_scf = atom_hf.get_atm_nrhf(mol)
    mo = []
    mo_occ = []
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb != 'GHOST':
            if symb in atm_scf:
                e_hf, e, c, occ = atm_scf[symb]
            else:
                symb = mol.atom_pure_symbol(ia)
                e_hf, e, c, occ = atm_scf[symb]
            mo.append(c)
            mo_occ.append(occ)
    mo = scipy.linalg.block_diag(*mo)
    mo_occ = numpy.hstack(mo_occ)

    pmol = copy.copy(mol)
    pmol.cart = False
    c = addons.project_mo_nr2nr(pmol, mo, mol)
    dm = numpy.dot(c * mo_occ, c.T)

    for k, v in atm_scf.items():
        logger.debug1(mol, 'Atom %s, E = %.12g', k, v[0])
    return dm
예제 #5
0
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None):
    mol = mf.mol
    occidx = numpy.where(mo_occ == 2)[0]
    viridx = numpy.where(mo_occ == 0)[0]
    nocc = len(occidx)
    nvir = len(viridx)

    if fock_ao is None:
        if h1e is None: h1e = mf.get_hcore()
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = h1e + mf.get_veff(mol, dm0)
    fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff))

    g = fock[viridx[:, None], occidx] * 2

    foo = fock[occidx[:, None], occidx]
    fvv = fock[viridx[:, None], viridx]

    h_diag = (fvv.diagonal().reshape(-1, 1) - foo.diagonal()) * 2

    # To project Hessians from another basis if different basis sets are used
    # in newton solver and underlying mean-filed solver.
    if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol):
        mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol)

    if hasattr(mf, 'xc') and hasattr(mf, '_numint'):
        if mf.grids.coords is None:
            mf.grids.build()
        hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin > 0) + 1)
        rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc,
                                                    mo_coeff, mo_occ, 0)
        dm0 = None  #mf.make_rdm1(mo_coeff, mo_occ)
    else:
        hyb = None

    def h_op(x):
        x = x.reshape(nvir, nocc)
        x2 = numpy.einsum('sp,sq->pq', fvv, x) * 2
        x2 -= numpy.einsum('sp,rp->rs', foo, x) * 2

        d1 = reduce(numpy.dot, (mo_coeff[:, viridx], x, mo_coeff[:, occidx].T))
        dm1 = d1 + d1.T
        if hyb is None:
            vj, vk = mf.get_jk(mol, dm1)
            v1 = vj - vk * .5
        else:
            v1 = mf._numint.nr_rks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, 1,
                                       rho0, vxc, fxc)
            if abs(hyb) < 1e-10:
                v1 += mf.get_j(mol, dm1)
            else:
                vj, vk = mf.get_jk(mol, dm1)
                v1 += vj - vk * (hyb * .5)
        x2 += reduce(numpy.dot,
                     (mo_coeff[:, viridx].T, v1, mo_coeff[:, occidx])) * 4
        return x2.reshape(-1)

    return g.reshape(-1), h_op, h_diag.reshape(-1)
예제 #6
0
파일: newton_ah.py 프로젝트: eronca/pyscf
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None):
    mol = mf.mol
    occidx = numpy.where(mo_occ==2)[0]
    viridx = numpy.where(mo_occ==0)[0]
    nocc = len(occidx)
    nvir = len(viridx)

    if fock_ao is None:
        if h1e is None: h1e = mf.get_hcore()
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = h1e + mf.get_veff(mol, dm0)
    fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff))

    g = fock[viridx[:,None],occidx] * 2

    foo = fock[occidx[:,None],occidx]
    fvv = fock[viridx[:,None],viridx]

    h_diag = (fvv.diagonal().reshape(-1,1)-foo.diagonal()) * 2

    # To project Hessians from another basis if different basis sets are used
    # in newton solver and underlying mean-filed solver.
    if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol):
        mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol)

    if hasattr(mf, 'xc') and hasattr(mf, '_numint'):
        if mf.grids.coords is None:
            mf.grids.build()
        hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin>0)+1)
        rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc,
                                                    mo_coeff, mo_occ, 0)
        dm0 = None #mf.make_rdm1(mo_coeff, mo_occ)
    else:
        hyb = None

    def h_op(x):
        x = x.reshape(nvir,nocc)
        x2 = numpy.einsum('sp,sq->pq', fvv, x) * 2
        x2-= numpy.einsum('sp,rp->rs', foo, x) * 2

        d1 = reduce(numpy.dot, (mo_coeff[:,viridx], x, mo_coeff[:,occidx].T))
        dm1 = d1 + d1.T
        if hyb is None:
            v1 = mf.get_veff(mol, dm1)
        else:
            v1 = mf._numint.nr_rks_fxc(mol, mf.grids, mf.xc, dm0, dm1,
                                       0, 1, rho0, vxc, fxc)
            if abs(hyb) < 1e-10:
                v1 += mf.get_j(mol, dm1)
            else:
                vj, vk = mf.get_jk(mol, dm1)
                v1 += vj - vk * hyb * .5
        x2 += reduce(numpy.dot, (mo_coeff[:,viridx].T, v1,
                                 mo_coeff[:,occidx])) * 4
        return x2.reshape(-1)

    return g.reshape(-1), h_op, h_diag.reshape(-1)
예제 #7
0
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None,
                  with_symmetry=True):
    mol = mf.mol
    occidx = numpy.where(mo_occ==2)[0]
    viridx = numpy.where(mo_occ==0)[0]
    nocc = len(occidx)
    nvir = len(viridx)
    orbo = mo_coeff[:,occidx]
    orbv = mo_coeff[:,viridx]
    if with_symmetry and mol.symmetry:
        orbsym = hf_symm.get_orbsym(mol, mo_coeff)
        sym_forbid = orbsym[viridx].reshape(-1,1) != orbsym[occidx]

    if fock_ao is None:
        if h1e is None: h1e = mf.get_hcore()
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = h1e + mf.get_veff(mol, dm0)
    fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff))

    g = fock[viridx[:,None],occidx] * 2

    foo = fock[occidx[:,None],occidx]
    fvv = fock[viridx[:,None],viridx]

    h_diag = (fvv.diagonal().reshape(-1,1)-foo.diagonal()) * 2

    if with_symmetry and mol.symmetry:
        g[sym_forbid] = 0
        h_diag[sym_forbid] = 0

    # To project Hessians from another basis if different basis sets are used
    # in newton solver and underlying mean-filed solver.
    if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol):
        mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol)

    vind = _gen_rhf_response(mf, mo_coeff, mo_occ, singlet=None, hermi=1)

    def h_op(x):
        x = x.reshape(nvir,nocc)
        if with_symmetry and mol.symmetry:
            x = x.copy()
            x[sym_forbid] = 0
        x2 = numpy.einsum('ps,sq->pq', fvv, x)
        #x2-= .5*numpy.einsum('ps,rp->rs', foo, x)
        #x2-= .5*numpy.einsum('sp,rp->rs', foo, x)
        x2-= numpy.einsum('ps,rp->rs', foo, x)

        # *2 for double occupancy
        d1 = reduce(numpy.dot, (orbv, x*2, orbo.T.conj()))
        dm1 = d1 + d1.T.conj()
        v1 = vind(dm1)
        x2 += reduce(numpy.dot, (orbv.T.conj(), v1, orbo))
        if with_symmetry and mol.symmetry:
            x2[sym_forbid] = 0
        return x2.reshape(-1) * 2

    return g.reshape(-1), h_op, h_diag.reshape(-1)
예제 #8
0
    def test_project_dm_nr2nr(self):
        nao = mol.nao_nr()
        dm = numpy.random.random((nao, nao))
        dm = dm + dm.T
        x1 = addons.project_dm_nr2nr(mol, dm, mol)
        self.assertAlmostEqual(abs(dm - x1).max(), 0, 12)

        numpy.random.seed(15)
        mo = numpy.random.random((nao, 10))
        mo1 = addons.project_mo_nr2nr(mol, mo, mol_dz)
        dm = numpy.dot(mo, mo.T)
        dmref = numpy.dot(mo1, mo1.T)
        dm1 = addons.project_dm_nr2nr(mol, [dm, dm], mol_dz)

        self.assertAlmostEqual(abs(dmref - dm1[0]).max(), 0, 11)
        self.assertAlmostEqual(abs(dmref - dm1[1]).max(), 0, 11)
        self.assertAlmostEqual(lib.finger(dm1[0]), 73.603267455214876, 11)
예제 #9
0
    def test_project_dm_nr2nr(self):
        nao = mol.nao_nr()
        dm = numpy.random.random((nao,nao))
        dm = dm + dm.T
        x1 = addons.project_dm_nr2nr(mol, dm, mol)
        self.assertAlmostEqual(abs(dm-x1).max(), 0, 12)

        numpy.random.seed(15)
        mo = numpy.random.random((nao,10))
        mo1 = addons.project_mo_nr2nr(mol, mo, mol_dz)
        dm = numpy.dot(mo, mo.T)
        dmref = numpy.dot(mo1, mo1.T)
        dm1 = addons.project_dm_nr2nr(mol, [dm,dm], mol_dz)

        self.assertAlmostEqual(abs(dmref-dm1[0]).max(), 0, 11)
        self.assertAlmostEqual(abs(dmref-dm1[1]).max(), 0, 11)
        self.assertAlmostEqual(lib.finger(dm1[0]), 73.603267455214876, 11)
예제 #10
0
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None):
    mol = mf.mol
    occidxa = numpy.where(mo_occ[0] > 0)[0]
    occidxb = numpy.where(mo_occ[1] > 0)[0]
    viridxa = numpy.where(mo_occ[0] == 0)[0]
    viridxb = numpy.where(mo_occ[1] == 0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)

    if fock_ao is None:
        if h1e is None: h1e = mf.get_hcore()
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = h1e + mf.get_veff(mol, dm0)
    focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0]))
    fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1]))

    g = numpy.hstack((focka[viridxa[:, None],
                            occidxa].reshape(-1), fockb[viridxb[:, None],
                                                        occidxb].reshape(-1)))

    h_diaga = (focka[viridxa, viridxa].reshape(-1, 1) -
               focka[occidxa, occidxa])
    h_diagb = (fockb[viridxb, viridxb].reshape(-1, 1) -
               fockb[occidxb, occidxb])
    h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1)))

    if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol):
        mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol),
                    addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol))

    if hasattr(mf, 'xc') and hasattr(mf, '_numint'):
        if mf.grids.coords is None:
            mf.grids.build()
        hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin > 0) + 1)
        rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc,
                                                    mo_coeff, mo_occ, 1)
        #dm0 =(numpy.dot(mo_coeff[0]*mo_occ[0], mo_coeff[0].T),
        #      numpy.dot(mo_coeff[1]*mo_occ[1], mo_coeff[1].T))
        dm0 = None
    else:
        hyb = None

    def h_op(x):
        x1a = x[:nvira * nocca].reshape(nvira, nocca)
        x1b = x[nvira * nocca:].reshape(nvirb, noccb)
        x2a = numpy.einsum('rp,rq->pq', focka[viridxa[:, None], viridxa], x1a)
        x2a -= numpy.einsum('sq,ps->pq', focka[occidxa[:, None], occidxa], x1a)
        x2b = numpy.einsum('rp,rq->pq', fockb[viridxb[:, None], viridxb], x1b)
        x2b -= numpy.einsum('sq,ps->pq', fockb[occidxb[:, None], occidxb], x1b)

        d1a = reduce(numpy.dot,
                     (mo_coeff[0][:, viridxa], x1a, mo_coeff[0][:, occidxa].T))
        d1b = reduce(numpy.dot,
                     (mo_coeff[1][:, viridxb], x1b, mo_coeff[1][:, occidxb].T))
        dm1 = numpy.array((d1a + d1a.T, d1b + d1b.T))
        if hyb is None:
            vj, vk = mf.get_jk(mol, dm1)
            v1 = vj[0] + vj[1] - vk
        else:
            v1 = mf._numint.nr_uks_fxc(mol, mf.grids, mf.xc, dm0, dm1, 0, 1,
                                       rho0, vxc, fxc)
            if abs(hyb) < 1e-10:
                vj = mf.get_j(mol, dm1)
                v1 += vj[0] + vj[1]
            else:
                vj, vk = mf.get_jk(mol, dm1)
                v1 += vj[0] + vj[1] - vk * hyb
        x2a += reduce(
            numpy.dot,
            (mo_coeff[0][:, viridxa].T, v1[0], mo_coeff[0][:, occidxa]))
        x2b += reduce(
            numpy.dot,
            (mo_coeff[1][:, viridxb].T, v1[1], mo_coeff[1][:, occidxb]))
        return numpy.hstack((x2a.ravel(), x2b.ravel()))

    return g, h_op, h_diag
예제 #11
0
파일: uhf.py 프로젝트: armunoz/pyscf
 def fproj(mo):
     if project:
         return addons.project_mo_nr2nr(chk_mol, mo, mol)
     else:
         return mo
예제 #12
0
파일: hf.py 프로젝트: molguin-qc/pyscf
def init_guess_by_minao(mol):
    '''Generate initial guess density matrix based on ANO basis, then project
    the density matrix to the basis set defined by ``mol``

    Returns:
        Density matrix, 2D ndarray

    Examples:

    >>> from pyscf import gto, scf
    >>> mol = gto.M(atom='H 0 0 0; H 0 0 1.1')
    >>> scf.hf.init_guess_by_minao(mol)
    array([[ 0.94758917,  0.09227308],
           [ 0.09227308,  0.94758917]])
    '''
    from pyscf.scf import atom_hf
    from pyscf.scf import addons

    def minao_basis(symb, nelec_ecp):
        basis_add = pyscf.gto.basis.load('ano', symb)
        occ = []
        basis_new = []
# coreshl defines the core shells to be removed in the initial guess
        coreshl = pyscf.gto.ecp.core_configuration(nelec_ecp)
        #coreshl = (0,0,0,0)  # it keeps all core electrons in the initial guess
        for l in range(4):
            ndocc, nfrac = atom_hf.frac_occ(symb, l)
            if coreshl[l] > 0:
                occ.extend([0]*coreshl[l]*(2*l+1))
            if ndocc > coreshl[l]:
                occ.extend([2]*(ndocc-coreshl[l])*(2*l+1))
            if nfrac > 1e-15:
                occ.extend([nfrac]*(2*l+1))
                ndocc += 1
            if ndocc > 0:
                basis_new.append([l] + [b[:ndocc+1] for b in basis_add[l][1:]])
        return occ, basis_new

    atmlst = set([mol.atom_symbol(ia) for ia in range(mol.natm)])

    nelec_ecp_dic = {}
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb not in nelec_ecp_dic:
            nelec_ecp_dic[symb] = mol.atom_nelec_core(ia)

    basis = {}
    occdic = {}
    for symb in atmlst:
        if symb != 'GHOST':
            nelec_ecp = nelec_ecp_dic[symb]
            stdsymb = pyscf.gto.mole._std_symbol(symb)
            occ_add, basis_add = minao_basis(stdsymb, nelec_ecp)
            occdic[symb] = occ_add
            basis[symb] = basis_add
    occ = []
    new_atom = []
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb != 'GHOST':
            occ.append(occdic[symb])
            new_atom.append(mol._atom[ia])
    occ = numpy.hstack(occ)

    pmol = pyscf.gto.Mole()
    pmol._atm, pmol._bas, pmol._env = pmol.make_env(new_atom, basis, [])
    c = addons.project_mo_nr2nr(pmol, 1, mol)

    dm = numpy.dot(c*occ, c.T)
# normalize eletron number
#    s = mol.intor_symmetric('cint1e_ovlp_sph')
#    dm *= mol.nelectron / (dm*s).sum()
    return dm
예제 #13
0
파일: newton_ah.py 프로젝트: chrinide/pyscf
def gen_g_hop_rhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None,
                  with_symmetry=True):
    mo_coeff0 = mo_coeff
    mol = mf.mol
    if getattr(mf, '_scf', None) and mf._scf.mol != mol:
        #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497)
        # To project Hessians from another basis if different basis sets are used
        # in newton solver and underlying mean-filed solver.
        mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol)

    occidx = numpy.where(mo_occ==2)[0]
    viridx = numpy.where(mo_occ==0)[0]
    nocc = len(occidx)
    nvir = len(viridx)
    orbo = mo_coeff[:,occidx]
    orbv = mo_coeff[:,viridx]
    if with_symmetry and mol.symmetry:
        orbsym = hf_symm.get_orbsym(mol, mo_coeff)
        sym_forbid = orbsym[viridx,None] != orbsym[occidx]

    if fock_ao is None:
        # dm0 is the density matrix in projected basis. Computing fock in
        # projected basis.
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = mf.get_fock(h1e, dm=dm0)
        fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff))
    else:
        # If fock is given, it corresponds to main basis. It needs to be
        # diagonalized with the mo_coeff of the main basis.
        fock = reduce(numpy.dot, (mo_coeff0.conj().T, fock_ao, mo_coeff0))

    g = fock[viridx[:,None],occidx] * 2

    foo = fock[occidx[:,None],occidx]
    fvv = fock[viridx[:,None],viridx]

    h_diag = (fvv.diagonal().real[:,None] - foo.diagonal().real) * 2

    if with_symmetry and mol.symmetry:
        g[sym_forbid] = 0
        h_diag[sym_forbid] = 0
    vind = _gen_rhf_response(mf, mo_coeff, mo_occ, singlet=None, hermi=1)

    def h_op(x):
        x = x.reshape(nvir,nocc)
        if with_symmetry and mol.symmetry:
            x = x.copy()
            x[sym_forbid] = 0
        x2 = numpy.einsum('ps,sq->pq', fvv, x)
        #x2-= .5*numpy.einsum('ps,rp->rs', foo, x)
        #x2-= .5*numpy.einsum('sp,rp->rs', foo, x)
        x2-= numpy.einsum('ps,rp->rs', foo, x)

        # *2 for double occupancy
        d1 = reduce(numpy.dot, (orbv, x*2, orbo.conj().T))
        dm1 = d1 + d1.conj().T
        v1 = vind(dm1)
        x2 += reduce(numpy.dot, (orbv.conj().T, v1, orbo))
        if with_symmetry and mol.symmetry:
            x2[sym_forbid] = 0
        return x2.ravel() * 2

    return g.reshape(-1), h_op, h_diag.reshape(-1)
예제 #14
0
파일: uhf.py 프로젝트: sunqm/pyscf
 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
예제 #15
0
파일: orth.py 프로젝트: yfyh2013/pyscf
def project_to_atomic_orbitals(mol, basname):
    '''projected AO = |bas><bas|ANO>
    '''
    from pyscf.scf.addons import project_mo_nr2nr
    from pyscf.scf import atom_hf
    from pyscf.gto.ecp import core_configuration

    def search_atm_l(atm, l):
        bas_ang = atm._bas[:, gto.ANG_OF]
        ao_loc = atm.ao_loc_nr()
        idx = []
        for ib in numpy.where(bas_ang == l)[0]:
            idx.extend(range(ao_loc[ib], ao_loc[ib + 1]))
        return idx

    # Overlap of ANO and ECP basis
    def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore):
        ecp_ao_loc = atm_ecp.ao_loc_nr()
        ano_ao_loc = atm_ano.ao_loc_nr()
        ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1]
        ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1]
        ecp_bas_l = [[atm_ecp.bas_angular(i)] * d
                     for i, d in enumerate(ecp_ao_dim)]
        ano_bas_l = [[atm_ano.bas_angular(i)] * d
                     for i, d in enumerate(ano_ao_dim)]
        ecp_bas_l = numpy.hstack(ecp_bas_l)
        ano_bas_l = numpy.hstack(ano_bas_l)

        ecp_idx = []
        ano_idx = []
        for l in range(4):
            nocc, nfrac = atom_hf.frac_occ(stdsymb, l)
            if nfrac > 1e-15:
                nocc += 1
            if nocc == 0:
                break
            i0 = ecpcore[l] * (2 * l + 1)
            i1 = nocc * (2 * l + 1)
            ecp_idx.append(numpy.where(ecp_bas_l == l)[0][:i1 - i0])
            ano_idx.append(numpy.where(ano_bas_l == l)[0][i0:i1])
        ecp_idx = numpy.hstack(ecp_idx)
        ano_idx = numpy.hstack(ano_idx)
        s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:,
                                                                       ano_idx]
        return numpy.linalg.det(s12)

    nelec_ecp_dic = {}
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb not in nelec_ecp_dic:
            nelec_ecp_dic[symb] = mol.atom_nelec_core(ia)

    aos = {}
    atm = gto.Mole()
    atmp = gto.Mole()
    for symb in mol._basis.keys():
        stdsymb = gto.mole._std_symbol(symb)
        atm._atm, atm._bas, atm._env = \
                atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, [])
        atm.cart = mol.cart
        s0 = atm.intor_symmetric('int1e_ovlp')

        if 'GHOST' in symb.upper():
            aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal()))
            continue

        basis_add = gto.basis.load(basname, stdsymb)
        atmp._atm, atmp._bas, atmp._env = \
                atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, [])
        atmp.cart = mol.cart

        nelec_ecp = nelec_ecp_dic[symb]
        if nelec_ecp > 0:
            ecpcore = core_configuration(nelec_ecp)
            # Comparing to ANO valence basis, to check whether the ECP basis set has
            # reasonable AO-character contraction.  The ANO valence AO should have
            # significant overlap to ECP basis if the ECP basis has AO-character.
            if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1:
                aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal()))
                continue
        else:
            ecpcore = [0] * 4

        ano = project_mo_nr2nr(atmp, 1, atm)
        rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0))
        c = rm_ano.copy()
        for l in range(param.L_MAX):
            idx = numpy.asarray(search_atm_l(atm, l))
            nbf_atm_l = len(idx)
            if nbf_atm_l == 0:
                break

            idxp = numpy.asarray(search_atm_l(atmp, l))
            if l < 4:
                idxp = idxp[ecpcore[l]:]
            nbf_ano_l = len(idxp)

            if mol.cart:
                degen = (l + 1) * (l + 2) // 2
            else:
                degen = l * 2 + 1

            if nbf_atm_l > nbf_ano_l > 0:
                # For angular l, first place the projected ANO, then the rest AOs.
                sdiag = reduce(
                    numpy.dot,
                    (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal()
                nleft = (nbf_atm_l - nbf_ano_l) // degen
                shell_average = numpy.einsum('ij->i', sdiag.reshape(-1, degen))
                shell_rest = numpy.argsort(-shell_average)[:nleft]
                idx_rest = []
                for k in shell_rest:
                    idx_rest.extend(idx[k * degen:(k + 1) * degen])
                c[:, idx[:nbf_ano_l]] = ano[:, idxp]
                c[:, idx[nbf_ano_l:]] = rm_ano[:, idx_rest]
            elif nbf_ano_l >= nbf_atm_l > 0:  # More ANOs than the mol basis functions
                c[:, idx] = ano[:, idxp[:nbf_atm_l]]
        sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c)
        c *= 1. / numpy.sqrt(sdiag)
        aos[symb] = c

    nao = mol.nao_nr()
    c = numpy.zeros((nao, nao))
    p1 = 0
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb in mol._basis:
            ano = aos[symb]
        else:
            ano = aos[mol.atom_pure_symbol(ia)]
        p0, p1 = p1, p1 + ano.shape[1]
        c[p0:p1, p0:p1] = ano
    return c
예제 #16
0
파일: newton_ah.py 프로젝트: chrinide/pyscf
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None,
                  with_symmetry=True):
    mol = mf.mol
    mo_coeff0 = mo_coeff
    if getattr(mf, '_scf', None) and mf._scf.mol != mol:
        #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497)
        mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol),
                    addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol))

    occidxa = numpy.where(mo_occ[0]>0)[0]
    occidxb = numpy.where(mo_occ[1]>0)[0]
    viridxa = numpy.where(mo_occ[0]==0)[0]
    viridxb = numpy.where(mo_occ[1]==0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:,occidxa]
    orbob = mo_coeff[1][:,occidxb]
    orbva = mo_coeff[0][:,viridxa]
    orbvb = mo_coeff[1][:,viridxb]
    if with_symmetry and mol.symmetry:
        orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff)
        sym_forbida = orbsyma[viridxa,None] != orbsyma[occidxa]
        sym_forbidb = orbsymb[viridxb,None] != orbsymb[occidxb]
        sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel()))

    if fock_ao is None:
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = mf.get_fock(h1e, dm=dm0)
        focka = reduce(numpy.dot, (mo_coeff[0].conj().T, fock_ao[0], mo_coeff[0]))
        fockb = reduce(numpy.dot, (mo_coeff[1].conj().T, fock_ao[1], mo_coeff[1]))
    else:
        focka = reduce(numpy.dot, (mo_coeff0[0].conj().T, fock_ao[0], mo_coeff0[0]))
        fockb = reduce(numpy.dot, (mo_coeff0[1].conj().T, fock_ao[1], mo_coeff0[1]))
    fooa = focka[occidxa[:,None],occidxa]
    fvva = focka[viridxa[:,None],viridxa]
    foob = fockb[occidxb[:,None],occidxb]
    fvvb = fockb[viridxb[:,None],viridxb]

    g = numpy.hstack((focka[viridxa[:,None],occidxa].ravel(),
                      fockb[viridxb[:,None],occidxb].ravel()))

    h_diaga = fvva.diagonal().real[:,None] - fooa.diagonal().real
    h_diagb = fvvb.diagonal().real[:,None] - foob.diagonal().real
    h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1)))

    if with_symmetry and mol.symmetry:
        g[sym_forbid] = 0
        h_diag[sym_forbid] = 0

    vind = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1)

    def h_op(x):
        if with_symmetry and mol.symmetry:
            x = x.copy()
            x[sym_forbid] = 0
        x1a = x[:nvira*nocca].reshape(nvira,nocca)
        x1b = x[nvira*nocca:].reshape(nvirb,noccb)
        x2a = numpy.einsum('pr,rq->pq', fvva, x1a)
        x2a-= numpy.einsum('sq,ps->pq', fooa, x1a)
        x2b = numpy.einsum('pr,rq->pq', fvvb, x1b)
        x2b-= numpy.einsum('sq,ps->pq', foob, x1b)

        d1a = reduce(numpy.dot, (orbva, x1a, orboa.conj().T))
        d1b = reduce(numpy.dot, (orbvb, x1b, orbob.conj().T))
        dm1 = numpy.array((d1a+d1a.conj().T,d1b+d1b.conj().T))
        v1 = vind(dm1)
        x2a += reduce(numpy.dot, (orbva.conj().T, v1[0], orboa))
        x2b += reduce(numpy.dot, (orbvb.conj().T, v1[1], orbob))

        x2 = numpy.hstack((x2a.ravel(), x2b.ravel()))
        if with_symmetry and mol.symmetry:
            x2[sym_forbid] = 0
        return x2

    return g, h_op, h_diag
예제 #17
0
파일: rohf.py 프로젝트: berquist/pyscf
 def fproj(mo):
     if project:
         return addons.project_mo_nr2nr(chk_mol, mo, mol)
     else:
         return mo
예제 #18
0
def gen_g_hop_uhf(mf,
                  mo_coeff,
                  mo_occ,
                  fock_ao=None,
                  h1e=None,
                  with_symmetry=True):
    mol = mf.mol
    mo_coeff0 = mo_coeff
    if getattr(mf, '_scf', None) and mf._scf.mol != mol:
        #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497)
        mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol),
                    addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol))

    occidxa = numpy.where(mo_occ[0] > 0)[0]
    occidxb = numpy.where(mo_occ[1] > 0)[0]
    viridxa = numpy.where(mo_occ[0] == 0)[0]
    viridxb = numpy.where(mo_occ[1] == 0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:, occidxa]
    orbob = mo_coeff[1][:, occidxb]
    orbva = mo_coeff[0][:, viridxa]
    orbvb = mo_coeff[1][:, viridxb]
    if with_symmetry and mol.symmetry:
        orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff)
        sym_forbida = orbsyma[viridxa, None] != orbsyma[occidxa]
        sym_forbidb = orbsymb[viridxb, None] != orbsymb[occidxb]
        sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel()))

    if fock_ao is None:
        if getattr(mf, '_scf', None) and mf._scf.mol != mol:
            h1e = mf.get_hcore(mol)
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = mf.get_fock(h1e, dm=dm0)
        focka = reduce(numpy.dot,
                       (mo_coeff[0].conj().T, fock_ao[0], mo_coeff[0]))
        fockb = reduce(numpy.dot,
                       (mo_coeff[1].conj().T, fock_ao[1], mo_coeff[1]))
    else:
        focka = reduce(numpy.dot,
                       (mo_coeff0[0].conj().T, fock_ao[0], mo_coeff0[0]))
        fockb = reduce(numpy.dot,
                       (mo_coeff0[1].conj().T, fock_ao[1], mo_coeff0[1]))
    fooa = focka[occidxa[:, None], occidxa]
    fvva = focka[viridxa[:, None], viridxa]
    foob = fockb[occidxb[:, None], occidxb]
    fvvb = fockb[viridxb[:, None], viridxb]

    g = numpy.hstack((focka[viridxa[:, None],
                            occidxa].ravel(), fockb[viridxb[:, None],
                                                    occidxb].ravel()))

    h_diaga = fvva.diagonal().real[:, None] - fooa.diagonal().real
    h_diagb = fvvb.diagonal().real[:, None] - foob.diagonal().real
    h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1)))

    if with_symmetry and mol.symmetry:
        g[sym_forbid] = 0
        h_diag[sym_forbid] = 0

    vind = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1)

    def h_op(x):
        if with_symmetry and mol.symmetry:
            x = x.copy()
            x[sym_forbid] = 0
        x1a = x[:nvira * nocca].reshape(nvira, nocca)
        x1b = x[nvira * nocca:].reshape(nvirb, noccb)
        x2a = numpy.einsum('pr,rq->pq', fvva, x1a)
        x2a -= numpy.einsum('sq,ps->pq', fooa, x1a)
        x2b = numpy.einsum('pr,rq->pq', fvvb, x1b)
        x2b -= numpy.einsum('sq,ps->pq', foob, x1b)

        d1a = reduce(numpy.dot, (orbva, x1a, orboa.conj().T))
        d1b = reduce(numpy.dot, (orbvb, x1b, orbob.conj().T))
        dm1 = numpy.array((d1a + d1a.conj().T, d1b + d1b.conj().T))
        v1 = vind(dm1)
        x2a += reduce(numpy.dot, (orbva.conj().T, v1[0], orboa))
        x2b += reduce(numpy.dot, (orbvb.conj().T, v1[1], orbob))

        x2 = numpy.hstack((x2a.ravel(), x2b.ravel()))
        if with_symmetry and mol.symmetry:
            x2[sym_forbid] = 0
        return x2

    return g, h_op, h_diag
예제 #19
0
파일: newton_ah.py 프로젝트: eronca/pyscf
def gen_g_hop_uhf(mf, mo_coeff, mo_occ, fock_ao=None, h1e=None):
    mol = mf.mol
    occidxa = numpy.where(mo_occ[0]>0)[0]
    occidxb = numpy.where(mo_occ[1]>0)[0]
    viridxa = numpy.where(mo_occ[0]==0)[0]
    viridxb = numpy.where(mo_occ[1]==0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)

    if fock_ao is None:
        if h1e is None: h1e = mf.get_hcore()
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = h1e + mf.get_veff(mol, dm0)
    focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0]))
    fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1]))

    g = numpy.hstack((focka[viridxa[:,None],occidxa].reshape(-1),
                      fockb[viridxb[:,None],occidxb].reshape(-1)))

    h_diaga =(focka[viridxa,viridxa].reshape(-1,1) - focka[occidxa,occidxa])
    h_diagb =(fockb[viridxb,viridxb].reshape(-1,1) - fockb[occidxb,occidxb])
    h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1)))

    if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol):
        mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol),
                    addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol))

    if hasattr(mf, 'xc') and hasattr(mf, '_numint'):
        if mf.grids.coords is None:
            mf.grids.build()
        hyb = mf._numint.hybrid_coeff(mf.xc, spin=(mol.spin>0)+1)
        rho0, vxc, fxc = mf._numint.cache_xc_kernel(mol, mf.grids, mf.xc,
                                                    mo_coeff, mo_occ, 1)
        #dm0 =(numpy.dot(mo_coeff[0]*mo_occ[0], mo_coeff[0].T),
        #      numpy.dot(mo_coeff[1]*mo_occ[1], mo_coeff[1].T))
        dm0 = None
    else:
        hyb = None

    def h_op(x):
        x1a = x[:nvira*nocca].reshape(nvira,nocca)
        x1b = x[nvira*nocca:].reshape(nvirb,noccb)
        x2a  = numpy.einsum('rp,rq->pq', focka[viridxa[:,None],viridxa], x1a)
        x2a -= numpy.einsum('sq,ps->pq', focka[occidxa[:,None],occidxa], x1a)
        x2b  = numpy.einsum('rp,rq->pq', fockb[viridxb[:,None],viridxb], x1b)
        x2b -= numpy.einsum('sq,ps->pq', fockb[occidxb[:,None],occidxb], x1b)

        d1a = reduce(numpy.dot, (mo_coeff[0][:,viridxa], x1a,
                                 mo_coeff[0][:,occidxa].T))
        d1b = reduce(numpy.dot, (mo_coeff[1][:,viridxb], x1b,
                                 mo_coeff[1][:,occidxb].T))
        dm1 = numpy.array((d1a+d1a.T,d1b+d1b.T))
        if hyb is None:
            v1 = mf.get_veff(mol, dm1)
        else:
            v1 = mf._numint.nr_uks_fxc(mol, mf.grids, mf.xc, dm0, dm1,
                                       0, 1, rho0, vxc, fxc)
            if abs(hyb) < 1e-10:
                vj = mf.get_j(mol, dm1)
                v1 += vj[0] + vj[1]
            else:
                vj, vk = mf.get_jk(mol, dm1)
                v1 += vj[0]+vj[1] - vk * hyb * .5
        x2a += reduce(numpy.dot, (mo_coeff[0][:,viridxa].T, v1[0],
                                  mo_coeff[0][:,occidxa]))
        x2b += reduce(numpy.dot, (mo_coeff[1][:,viridxb].T, v1[1],
                                  mo_coeff[1][:,occidxb]))
        return numpy.hstack((x2a.ravel(), x2b.ravel()))

    return g, h_op, h_diag
예제 #20
0
def gen_g_hop_uhf(mf,
                  mo_coeff,
                  mo_occ,
                  fock_ao=None,
                  h1e=None,
                  with_symmetry=True):
    mol = mf.mol
    if hasattr(mf, '_scf') and id(mf._scf.mol) != id(mol):
        mo_coeff = (addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[0], mol),
                    addons.project_mo_nr2nr(mf._scf.mol, mo_coeff[1], mol))

    occidxa = numpy.where(mo_occ[0] > 0)[0]
    occidxb = numpy.where(mo_occ[1] > 0)[0]
    viridxa = numpy.where(mo_occ[0] == 0)[0]
    viridxb = numpy.where(mo_occ[1] == 0)[0]
    nocca = len(occidxa)
    noccb = len(occidxb)
    nvira = len(viridxa)
    nvirb = len(viridxb)
    orboa = mo_coeff[0][:, occidxa]
    orbob = mo_coeff[1][:, occidxb]
    orbva = mo_coeff[0][:, viridxa]
    orbvb = mo_coeff[1][:, viridxb]
    if with_symmetry and mol.symmetry:
        orbsyma, orbsymb = uhf_symm.get_orbsym(mol, mo_coeff)
        sym_forbida = orbsyma[viridxa].reshape(-1, 1) != orbsyma[occidxa]
        sym_forbidb = orbsymb[viridxb].reshape(-1, 1) != orbsymb[occidxb]
        sym_forbid = numpy.hstack((sym_forbida.ravel(), sym_forbidb.ravel()))

    if fock_ao is None:
        if h1e is None: h1e = mf.get_hcore()
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = h1e + mf.get_veff(mol, dm0)
    focka = reduce(numpy.dot, (mo_coeff[0].T, fock_ao[0], mo_coeff[0]))
    fockb = reduce(numpy.dot, (mo_coeff[1].T, fock_ao[1], mo_coeff[1]))
    fooa = focka[occidxa[:, None], occidxa]
    fvva = focka[viridxa[:, None], viridxa]
    foob = fockb[occidxb[:, None], occidxb]
    fvvb = fockb[viridxb[:, None], viridxb]

    g = numpy.hstack((focka[occidxa[:, None],
                            viridxa].T.ravel(), fockb[occidxb[:, None],
                                                      viridxb].T.ravel()))

    h_diaga = focka[viridxa, viridxa].reshape(-1, 1) - focka[occidxa, occidxa]
    h_diagb = fockb[viridxb, viridxb].reshape(-1, 1) - fockb[occidxb, occidxb]
    h_diag = numpy.hstack((h_diaga.reshape(-1), h_diagb.reshape(-1)))

    if with_symmetry and mol.symmetry:
        g[sym_forbid] = 0
        h_diag[sym_forbid] = 0

    vind = _gen_uhf_response(mf, mo_coeff, mo_occ, hermi=1)

    def h_op(x):
        if with_symmetry and mol.symmetry:
            x = x.copy()
            x[sym_forbid] = 0
        x1a = x[:nvira * nocca].reshape(nvira, nocca)
        x1b = x[nvira * nocca:].reshape(nvirb, noccb)
        x2a = numpy.einsum('pr,rq->pq', fvva, x1a)
        x2a -= numpy.einsum('sq,ps->pq', fooa, x1a)
        x2b = numpy.einsum('pr,rq->pq', fvvb, x1b)
        x2b -= numpy.einsum('sq,ps->pq', foob, x1b)

        d1a = reduce(numpy.dot, (orbva, x1a, orboa.T.conj()))
        d1b = reduce(numpy.dot, (orbvb, x1b, orbob.T.conj()))
        dm1 = numpy.array((d1a + d1a.T.conj(), d1b + d1b.T.conj()))
        v1 = vind(dm1)
        x2a += reduce(numpy.dot, (orbva.T.conj(), v1[0], orboa))
        x2b += reduce(numpy.dot, (orbvb.T.conj(), v1[1], orbob))
        x2 = numpy.hstack((x2a.ravel(), x2b.ravel()))
        if with_symmetry and mol.symmetry:
            x2[sym_forbid] = 0
        return x2

    return g, h_op, h_diag
예제 #21
0
파일: hf.py 프로젝트: pulkin/pyscf
def init_guess_by_minao(mol):
    '''Generate initial guess density matrix based on ANO basis, then project
    the density matrix to the basis set defined by ``mol``

    Returns:
        Density matrix, 2D ndarray

    Examples:

    >>> from pyscf import gto, scf
    >>> mol = gto.M(atom='H 0 0 0; H 0 0 1.1')
    >>> scf.hf.init_guess_by_minao(mol)
    array([[ 0.94758917,  0.09227308],
           [ 0.09227308,  0.94758917]])
    '''
    from pyscf.scf import atom_hf
    from pyscf.scf import addons

    def minao_basis(symb, nelec_ecp):
        basis_add = gto.basis.load('ano', symb)
        occ = []
        basis_new = []
        # coreshl defines the core shells to be removed in the initial guess
        coreshl = gto.ecp.core_configuration(nelec_ecp)
        #coreshl = (0,0,0,0)  # it keeps all core electrons in the initial guess
        for l in range(4):
            ndocc, nfrac = atom_hf.frac_occ(symb, l)
            if coreshl[l] > 0:
                occ.extend([0] * coreshl[l] * (2 * l + 1))
            if ndocc > coreshl[l]:
                occ.extend([2] * (ndocc - coreshl[l]) * (2 * l + 1))
            if nfrac > 1e-15:
                occ.extend([nfrac] * (2 * l + 1))
                ndocc += 1
            if ndocc > 0:
                basis_new.append([l] +
                                 [b[:ndocc + 1] for b in basis_add[l][1:]])
        return occ, basis_new

    atmlst = set([mol.atom_symbol(ia) for ia in range(mol.natm)])

    nelec_ecp_dic = {}
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb not in nelec_ecp_dic:
            nelec_ecp_dic[symb] = mol.atom_nelec_core(ia)

    basis = {}
    occdic = {}
    for symb in atmlst:
        if symb != 'GHOST':
            nelec_ecp = nelec_ecp_dic[symb]
            stdsymb = gto.mole._std_symbol(symb)
            occ_add, basis_add = minao_basis(stdsymb, nelec_ecp)
            occdic[symb] = occ_add
            basis[symb] = basis_add
    occ = []
    new_atom = []
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb != 'GHOST':
            occ.append(occdic[symb])
            new_atom.append(mol._atom[ia])
    occ = numpy.hstack(occ)

    pmol = gto.Mole()
    pmol._atm, pmol._bas, pmol._env = pmol.make_env(new_atom, basis, [])
    c = addons.project_mo_nr2nr(pmol, 1, mol)

    dm = numpy.dot(c * occ, c.T)
    # normalize eletron number
    #    s = mol.intor_symmetric('int1e_ovlp')
    #    dm *= mol.nelectron / (dm*s).sum()
    return dm
예제 #22
0
파일: orth.py 프로젝트: eronca/pyscf
def project_to_atomic_orbitals(mol, basname):
    '''projected AO = |bas><bas|ANO>
    '''
    from pyscf.scf.addons import project_mo_nr2nr
    from pyscf.gto.ecp import core_configuration
    def search_atm_l(atm, l):
        idx = []
        p0 = 0
        for ib, b in enumerate(atm._bas):
            l0 = atm.bas_angular(ib)
            nctr = atm.bas_nctr(ib)
            if l0 == l:
                idx.extend(range(p0,p0+(2*l+1)*nctr))
            p0 += (2*l0+1) * nctr
        return idx

    aos = {}
    atm = gto.Mole()
    atmp = gto.Mole()
    for symb in mol._basis.keys():
        stdsymb = gto.mole._std_symbol(symb)
        atm._atm, atm._bas, atm._env = \
                atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, [])

        if 'GHOST' in symb.upper():
            aos[symb] = numpy.eye(atm.nao_nr())
            continue

        s0 = atm.intor_symmetric('cint1e_ovlp_sph')

        basis_add = gto.basis.load(basname, stdsymb)
        atmp._atm, atmp._bas, atmp._env = \
                atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, [])
        ano = project_mo_nr2nr(atmp, 1, atm)
        rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0))
        nelec_ecp = 0
        if mol._ecp:
            if symb in mol._ecp:
                nelec_ecp = mol._ecp[symb][0]
            elif stdsymb in mol._ecp:
                nelec_ecp = mol._ecp[stdsymb][0]
        ecpcore = core_configuration(nelec_ecp)
        c = rm_ano.copy()
        for l in range(param.L_MAX):
            idx  = numpy.asarray(search_atm_l(atm, l))
            if len(idx) == 0:
                break

            idxp = numpy.asarray(search_atm_l(atmp, l))
            if l < 4:
                idxp = idxp[ecpcore[l]:]
            if len(idx) > len(idxp) > 0:
# For angular l, first place the projected ANO, then the rest AOs.
                sdiag = reduce(numpy.dot, (rm_ano[:,idx].T, s0, rm_ano[:,idx])).diagonal()
                nleft = (len(idx) - len(idxp)) // (2*l+1)
                shell_average = numpy.einsum('ij->i', sdiag.reshape(-1,l*2+1))
                shell_rest = numpy.argsort(-shell_average)[:nleft]
                idx_rest = []
                for k in shell_rest:
                    idx_rest.extend(idx[k*(2*l+1):(k+1)*(2*l+1)])
                c[:,idx[:len(idxp)]] = ano[:,idxp]
                c[:,idx[len(idxp):]] = rm_ano[:,idx_rest]
            elif len(idxp) >= len(idx) > 0:  # More ANOs than the mol basis functions
                c[:,idx] = ano[:,idxp[:len(idx)]]
        aos[symb] = c

    nao = mol.nao_nr()
    c = numpy.zeros((nao,nao))
    p0 = 0
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb in mol._basis:
            ano = aos[symb]
        else:
            symb = mol.atom_pure_symbol(ia)
            ano = aos[symb]
        p1 = p0 + ano.shape[1]
        c[p0:p1,p0:p1] = ano
        p0 = p1
    return c
예제 #23
0
파일: orth.py 프로젝트: chrinide/pyscf
def project_to_atomic_orbitals(mol, basname):
    '''projected AO = |bas><bas|ANO>
    '''
    from pyscf.scf.addons import project_mo_nr2nr
    from pyscf.scf import atom_hf
    from pyscf.gto.ecp import core_configuration
    def search_atm_l(atm, l):
        bas_ang = atm._bas[:,gto.ANG_OF]
        ao_loc = atm.ao_loc_nr()
        idx = []
        for ib in numpy.where(bas_ang == l)[0]:
            idx.extend(range(ao_loc[ib], ao_loc[ib+1]))
        return idx

    # Overlap of ANO and ECP basis
    def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore):
        ecp_ao_loc = atm_ecp.ao_loc_nr()
        ano_ao_loc = atm_ano.ao_loc_nr()
        ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1]
        ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1]
        ecp_bas_l = [[atm_ecp.bas_angular(i)]*d for i,d in enumerate(ecp_ao_dim)]
        ano_bas_l = [[atm_ano.bas_angular(i)]*d for i,d in enumerate(ano_ao_dim)]
        ecp_bas_l = numpy.hstack(ecp_bas_l)
        ano_bas_l = numpy.hstack(ano_bas_l)

        nelec_core = 0
        ecp_occ_tmp = []
        ecp_idx = []
        ano_idx = []
        for l in range(4):
            nocc, frac = atom_hf.frac_occ(stdsymb, l)
            l_occ = [2] * ((nocc-ecpcore[l])*(2*l+1))
            if frac > 1e-15:
                l_occ.extend([frac] * (2*l+1))
                nocc += 1
            if nocc == 0:
                break
            nelec_core += 2 * ecpcore[l] * (2*l+1)
            i0 = ecpcore[l] * (2*l+1)
            i1 = nocc * (2*l+1)
            ecp_idx.append(numpy.where(ecp_bas_l==l)[0][:i1-i0])
            ano_idx.append(numpy.where(ano_bas_l==l)[0][i0:i1])
            ecp_occ_tmp.append(l_occ[:i1-i0])
        ecp_idx = numpy.hstack(ecp_idx)
        ano_idx = numpy.hstack(ano_idx)
        ecp_occ = numpy.zeros(atm_ecp.nao_nr())
        ecp_occ[ecp_idx] = numpy.hstack(ecp_occ_tmp)
        nelec_valence_left = int(gto.mole.charge(stdsymb) - nelec_core
                                 - sum(ecp_occ[ecp_idx]))
        if nelec_valence_left > 0:
            logger.warn(mol, 'Characters of %d valence electrons are not identified.\n'
                        'It can affect the "meta-lowdin" localization method '
                        'and the population analysis of SCF method.\n'
                        'Adjustment to the core/valence partition may be needed '
                        '(see function lo.nao.set_atom_conf)\nto get reasonable '
                        'local orbitals or Mulliken population.\n',
                        nelec_valence_left)
            # Return 0 to force the projection to ANO basis
            return 0
        else:
            s12 = gto.intor_cross('int1e_ovlp', atm_ecp, atm_ano)[ecp_idx][:,ano_idx]
            return numpy.linalg.det(s12)

    nelec_ecp_dic = {}
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb not in nelec_ecp_dic:
            nelec_ecp_dic[symb] = mol.atom_nelec_core(ia)

    aos = {}
    atm = gto.Mole()
    atmp = gto.Mole()
    for symb in mol._basis.keys():
        stdsymb = gto.mole._std_symbol(symb)
        atm._atm, atm._bas, atm._env = \
                atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, [])
        atm.cart = mol.cart
        atm._built = True
        s0 = atm.intor_symmetric('int1e_ovlp')

        if gto.is_ghost_atom(symb):
            aos[symb] = numpy.diag(1./numpy.sqrt(s0.diagonal()))
            continue

        basis_add = gto.basis.load(basname, stdsymb)
        atmp._atm, atmp._bas, atmp._env = \
                atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, [])
        atmp.cart = mol.cart
        atmp._built = True

        if symb in nelec_ecp_dic and nelec_ecp_dic[symb] > 0:
            if not PROJECT_ECP_BASIS:
# If ECP basis has good atomic character, ECP basis can be used in the
# localization/population analysis directly. Otherwise project ECP basis to
# ANO basis.
                continue

            ecpcore = core_configuration(nelec_ecp_dic[symb])
# Comparing to ANO valence basis, to check whether the ECP basis set has
# reasonable AO-character contraction.  The ANO valence AO should have
# significant overlap to ECP basis if the ECP basis has AO-character.
            if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1:
                aos[symb] = numpy.diag(1./numpy.sqrt(s0.diagonal()))
                continue
        else:
            ecpcore = [0] * 4

        ano = project_mo_nr2nr(atmp, numpy.eye(atmp.nao_nr()), atm)
        rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0))
        c = rm_ano.copy()
        for l in range(param.L_MAX):
            idx = numpy.asarray(search_atm_l(atm, l))
            nbf_atm_l = len(idx)
            if nbf_atm_l == 0:
                break

            idxp = numpy.asarray(search_atm_l(atmp, l))
            if l < 4:
                idxp = idxp[ecpcore[l]:]
            nbf_ano_l = len(idxp)

            if mol.cart:
                degen = (l + 1) * (l + 2) // 2
            else:
                degen = l * 2 + 1

            if nbf_atm_l > nbf_ano_l > 0:
# For angular l, first place the projected ANO, then the rest AOs.
                sdiag = reduce(numpy.dot, (rm_ano[:,idx].T, s0, rm_ano[:,idx])).diagonal()
                nleft = (nbf_atm_l - nbf_ano_l) // degen
                shell_average = numpy.einsum('ij->i', sdiag.reshape(-1,degen))
                shell_rest = numpy.argsort(-shell_average)[:nleft]
                idx_rest = []
                for k in shell_rest:
                    idx_rest.extend(idx[k*degen:(k+1)*degen])
                c[:,idx[:nbf_ano_l]] = ano[:,idxp]
                c[:,idx[nbf_ano_l:]] = rm_ano[:,idx_rest]
            elif nbf_ano_l >= nbf_atm_l > 0:  # More ANOs than the mol basis functions
                c[:,idx] = ano[:,idxp[:nbf_atm_l]]
        sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c)
        c *= 1./numpy.sqrt(sdiag)
        aos[symb] = c

    nao = mol.nao_nr()
    c = numpy.zeros((nao,nao))
    p1 = 0
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb in mol._basis:
            ano = aos[symb]
        else:
            ano = aos[mol.atom_pure_symbol(ia)]
        p0, p1 = p1, p1 + ano.shape[1]
        c[p0:p1,p0:p1] = ano
    return c
예제 #24
0
def gen_g_hop_rhf(mf,
                  mo_coeff,
                  mo_occ,
                  fock_ao=None,
                  h1e=None,
                  with_symmetry=True):
    mo_coeff0 = mo_coeff
    mol = mf.mol
    if getattr(mf, '_scf', None) and mf._scf.mol != mol:
        #TODO: construct vind with dual-basis treatment, (see also JCP, 118, 9497)
        # To project Hessians from another basis if different basis sets are used
        # in newton solver and underlying mean-filed solver.
        mo_coeff = addons.project_mo_nr2nr(mf._scf.mol, mo_coeff, mol)

    occidx = numpy.where(mo_occ == 2)[0]
    viridx = numpy.where(mo_occ == 0)[0]
    nocc = len(occidx)
    nvir = len(viridx)
    orbo = mo_coeff[:, occidx]
    orbv = mo_coeff[:, viridx]
    if with_symmetry and mol.symmetry:
        orbsym = hf_symm.get_orbsym(mol, mo_coeff)
        sym_forbid = orbsym[viridx, None] != orbsym[occidx]

    if fock_ao is None:
        # dm0 is the density matrix in projected basis. Computing fock in
        # projected basis.
        if getattr(mf, '_scf', None) and mf._scf.mol != mol:
            h1e = mf.get_hcore(mol)
        dm0 = mf.make_rdm1(mo_coeff, mo_occ)
        fock_ao = mf.get_fock(h1e, dm=dm0)
        fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff))
    else:
        # If fock is given, it corresponds to main basis. It needs to be
        # diagonalized with the mo_coeff of the main basis.
        fock = reduce(numpy.dot, (mo_coeff0.conj().T, fock_ao, mo_coeff0))

    g = fock[viridx[:, None], occidx] * 2

    foo = fock[occidx[:, None], occidx]
    fvv = fock[viridx[:, None], viridx]

    h_diag = (fvv.diagonal().real[:, None] - foo.diagonal().real) * 2

    if with_symmetry and mol.symmetry:
        g[sym_forbid] = 0
        h_diag[sym_forbid] = 0
    vind = _gen_rhf_response(mf, mo_coeff, mo_occ, singlet=None, hermi=1)

    def h_op(x):
        x = x.reshape(nvir, nocc)
        if with_symmetry and mol.symmetry:
            x = x.copy()
            x[sym_forbid] = 0
        x2 = numpy.einsum('ps,sq->pq', fvv, x)
        #x2-= .5*numpy.einsum('ps,rp->rs', foo, x)
        #x2-= .5*numpy.einsum('sp,rp->rs', foo, x)
        x2 -= numpy.einsum('ps,rp->rs', foo, x)

        # *2 for double occupancy
        d1 = reduce(numpy.dot, (orbv, x * 2, orbo.conj().T))
        dm1 = d1 + d1.conj().T
        v1 = vind(dm1)
        x2 += reduce(numpy.dot, (orbv.conj().T, v1, orbo))
        if with_symmetry and mol.symmetry:
            x2[sym_forbid] = 0
        return x2.ravel() * 2

    return g.reshape(-1), h_op, h_diag.reshape(-1)
예제 #25
0
def project_to_atomic_orbitals(mol, basname):
    '''projected AO = |bas><bas|ANO>
    '''
    from pyscf.scf.addons import project_mo_nr2nr
    from pyscf.scf import atom_hf
    from pyscf.gto.ecp import core_configuration

    def search_atm_l(atm, l):
        bas_ang = atm._bas[:, gto.ANG_OF]
        ao_loc = atm.ao_loc_nr()
        idx = []
        for ib in numpy.where(bas_ang == l)[0]:
            idx.extend(range(ao_loc[ib], ao_loc[ib + 1]))
        return idx

    # Overlap of ANO and ECP basis
    def ecp_ano_det_ovlp(atm_ecp, atm_ano, ecpcore):
        ecp_ao_loc = atm_ecp.ao_loc_nr()
        ano_ao_loc = atm_ano.ao_loc_nr()
        ecp_ao_dim = ecp_ao_loc[1:] - ecp_ao_loc[:-1]
        ano_ao_dim = ano_ao_loc[1:] - ano_ao_loc[:-1]
        ecp_bas_l = [[atm_ecp.bas_angular(i)] * d
                     for i, d in enumerate(ecp_ao_dim)]
        ano_bas_l = [[atm_ano.bas_angular(i)] * d
                     for i, d in enumerate(ano_ao_dim)]
        ecp_bas_l = numpy.hstack(ecp_bas_l)
        ano_bas_l = numpy.hstack(ano_bas_l)

        nelec_core = 0
        ecp_occ_tmp = []
        ecp_idx = []
        ano_idx = []
        for l in range(4):
            nocc, frac = atom_hf.frac_occ(stdsymb, l)
            l_occ = [2] * ((nocc - ecpcore[l]) * (2 * l + 1))
            if frac > 1e-15:
                l_occ.extend([frac] * (2 * l + 1))
                nocc += 1
            if nocc == 0:
                break
            nelec_core += 2 * ecpcore[l] * (2 * l + 1)
            i0 = ecpcore[l] * (2 * l + 1)
            i1 = nocc * (2 * l + 1)
            ecp_idx.append(numpy.where(ecp_bas_l == l)[0][:i1 - i0])
            ano_idx.append(numpy.where(ano_bas_l == l)[0][i0:i1])
            ecp_occ_tmp.append(l_occ[:i1 - i0])
        ecp_idx = numpy.hstack(ecp_idx)
        ano_idx = numpy.hstack(ano_idx)
        ecp_occ = numpy.zeros(atm_ecp.nao_nr())
        ecp_occ[ecp_idx] = numpy.hstack(ecp_occ_tmp)
        nelec_valence_left = int(
            gto.charge(stdsymb) - nelec_core - sum(ecp_occ[ecp_idx]))
        if nelec_valence_left > 0:
            logger.warn(
                mol, 'Characters of %d valence electrons are not identified.\n'
                'It can affect the "meta-lowdin" localization method '
                'and the population analysis of SCF method.\n'
                'Adjustment to the core/valence partition may be needed '
                '(see function lo.nao.set_atom_conf)\nto get reasonable '
                'local orbitals or Mulliken population.\n', nelec_valence_left)
            # Return 0 to force the projection to ANO basis
            return 0
        else:
            s12 = gto.intor_cross('int1e_ovlp', atm_ecp,
                                  atm_ano)[ecp_idx][:, ano_idx]
            return numpy.linalg.det(s12)

    nelec_ecp_dic = {}
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb not in nelec_ecp_dic:
            nelec_ecp_dic[symb] = mol.atom_nelec_core(ia)

    aos = {}
    atm = gto.Mole()
    atmp = gto.Mole()
    for symb in mol._basis.keys():
        stdsymb = gto.mole._std_symbol(symb)
        atm._atm, atm._bas, atm._env = \
                atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, [])
        atm.cart = mol.cart
        atm._built = True
        s0 = atm.intor_symmetric('int1e_ovlp')

        if gto.is_ghost_atom(symb):
            aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal()))
            continue

        basis_add = gto.basis.load(basname, stdsymb)
        atmp._atm, atmp._bas, atmp._env = \
                atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, [])
        atmp.cart = mol.cart
        atmp._built = True

        if symb in nelec_ecp_dic and nelec_ecp_dic[symb] > 0:
            # If ECP basis has good atomic character, ECP basis can be used in the
            # localization/population analysis directly. Otherwise project ECP
            # basis to ANO basis.
            if not PROJECT_ECP_BASIS:
                continue

            ecpcore = core_configuration(nelec_ecp_dic[symb])
            # Comparing to ANO valence basis, to check whether the ECP basis set has
            # reasonable AO-character contraction.  The ANO valence AO should have
            # significant overlap to ECP basis if the ECP basis has AO-character.
            if abs(ecp_ano_det_ovlp(atm, atmp, ecpcore)) > .1:
                aos[symb] = numpy.diag(1. / numpy.sqrt(s0.diagonal()))
                continue
        else:
            ecpcore = [0] * 4

        # MINAO for heavier elements needs to be used with pseudo potential
        if (basname.upper() == 'MINAO' and gto.charge(stdsymb) > 36
                and symb not in nelec_ecp_dic):
            raise RuntimeError(
                'Basis MINAO has to be used with ecp for heavy elements')

        ano = project_mo_nr2nr(atmp, numpy.eye(atmp.nao_nr()), atm)
        rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0))
        c = rm_ano.copy()
        for l in range(param.L_MAX):
            idx = numpy.asarray(search_atm_l(atm, l))
            nbf_atm_l = len(idx)
            if nbf_atm_l == 0:
                break

            idxp = numpy.asarray(search_atm_l(atmp, l))
            if l < 4:
                idxp = idxp[ecpcore[l]:]
            nbf_ano_l = len(idxp)

            if mol.cart:
                degen = (l + 1) * (l + 2) // 2
            else:
                degen = l * 2 + 1

            if nbf_atm_l > nbf_ano_l > 0:
                # For angular l, first place the projected ANO, then the rest AOs.
                sdiag = reduce(
                    numpy.dot,
                    (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal()
                nleft = (nbf_atm_l - nbf_ano_l) // degen
                shell_average = numpy.einsum('ij->i', sdiag.reshape(-1, degen))
                shell_rest = numpy.argsort(-shell_average)[:nleft]
                idx_rest = []
                for k in shell_rest:
                    idx_rest.extend(idx[k * degen:(k + 1) * degen])
                c[:, idx[:nbf_ano_l]] = ano[:, idxp]
                c[:, idx[nbf_ano_l:]] = rm_ano[:, idx_rest]
            elif nbf_ano_l >= nbf_atm_l > 0:  # More ANOs than the mol basis functions
                c[:, idx] = ano[:, idxp[:nbf_atm_l]]
        sdiag = numpy.einsum('pi,pq,qi->i', c, s0, c)
        c *= 1. / numpy.sqrt(sdiag)
        aos[symb] = c

    nao = mol.nao_nr()
    c = numpy.zeros((nao, nao))
    p1 = 0
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb in mol._basis:
            ano = aos[symb]
        else:
            ano = aos[mol.atom_pure_symbol(ia)]
        p0, p1 = p1, p1 + ano.shape[1]
        c[p0:p1, p0:p1] = ano
    return c
예제 #26
0
 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
예제 #27
0
파일: orth.py 프로젝트: v3op01/pyscf
def project_to_atomic_orbitals(mol, basname):
    '''projected AO = |bas><bas|ANO>
    '''
    from pyscf.scf.addons import project_mo_nr2nr
    from pyscf.gto.ecp import core_configuration

    def search_atm_l(atm, l):
        idx = []
        p0 = 0
        for ib, b in enumerate(atm._bas):
            l0 = atm.bas_angular(ib)
            nctr = atm.bas_nctr(ib)
            if l0 == l:
                idx.extend(range(p0, p0 + (2 * l + 1) * nctr))
            p0 += (2 * l0 + 1) * nctr
        return idx

    aos = {}
    atm = gto.Mole()
    atmp = gto.Mole()
    for symb in mol._basis.keys():
        stdsymb = gto.mole._std_symbol(symb)
        atm._atm, atm._bas, atm._env = \
                atm.make_env([[stdsymb,(0,0,0)]], {stdsymb:mol._basis[symb]}, [])

        if 'GHOST' in symb.upper():
            aos[symb] = numpy.eye(atm.nao_nr())
            continue

        s0 = atm.intor_symmetric('cint1e_ovlp_sph')

        basis_add = gto.basis.load(basname, stdsymb)
        atmp._atm, atmp._bas, atmp._env = \
                atmp.make_env([[stdsymb,(0,0,0)]], {stdsymb:basis_add}, [])
        ano = project_mo_nr2nr(atmp, 1, atm)
        rm_ano = numpy.eye(ano.shape[0]) - reduce(numpy.dot, (ano, ano.T, s0))
        nelec_ecp = 0
        if mol._ecp:
            if symb in mol._ecp:
                nelec_ecp = mol._ecp[symb][0]
            elif stdsymb in mol._ecp:
                nelec_ecp = mol._ecp[stdsymb][0]
        ecpcore = core_configuration(nelec_ecp)
        c = rm_ano.copy()
        for l in range(param.L_MAX):
            idx = numpy.asarray(search_atm_l(atm, l))
            if len(idx) == 0:
                break

            idxp = numpy.asarray(search_atm_l(atmp, l))
            if l < 4:
                idxp = idxp[ecpcore[l]:]
            if len(idx) > len(idxp) > 0:
                # For angular l, first place the projected ANO, then the rest AOs.
                sdiag = reduce(
                    numpy.dot,
                    (rm_ano[:, idx].T, s0, rm_ano[:, idx])).diagonal()
                nleft = (len(idx) - len(idxp)) // (2 * l + 1)
                shell_average = numpy.einsum('ij->i',
                                             sdiag.reshape(-1, l * 2 + 1))
                shell_rest = numpy.argsort(-shell_average)[:nleft]
                idx_rest = []
                for k in shell_rest:
                    idx_rest.extend(idx[k * (2 * l + 1):(k + 1) * (2 * l + 1)])
                c[:, idx[:len(idxp)]] = ano[:, idxp]
                c[:, idx[len(idxp):]] = rm_ano[:, idx_rest]
            elif len(idxp) >= len(
                    idx) > 0:  # More ANOs than the mol basis functions
                c[:, idx] = ano[:, idxp[:len(idx)]]
        aos[symb] = c

    nao = mol.nao_nr()
    c = numpy.zeros((nao, nao))
    p0 = 0
    for ia in range(mol.natm):
        symb = mol.atom_symbol(ia)
        if symb in mol._basis:
            ano = aos[symb]
        else:
            symb = mol.atom_pure_symbol(ia)
            ano = aos[symb]
        p1 = p0 + ano.shape[1]
        c[p0:p1, p0:p1] = ano
        p0 = p1
    return c