예제 #1
0
def aug_etb_for_dfbasis(mol, dfbasis=DFBASIS, beta=ETB_BETA,
                        start_at=FIRST_ETB_ELEMENT):
    '''augment weigend basis with even-tempered gaussian basis
    exps = alpha*beta^i for i = 1..N
    '''
    nuc_start = gto.charge(start_at)
    uniq_atoms = set([a[0] for a in mol._atom])

    newbasis = {}
    for symb in uniq_atoms:
        nuc_charge = gto.charge(symb)
        if nuc_charge < nuc_start:
            newbasis[symb] = dfbasis
        #?elif symb in mol._ecp:
        else:
            conf = elements.CONFIGURATION[nuc_charge]
            max_shells = 4 - conf.count(0)
            emin_by_l = [1e99] * 8
            emax_by_l = [0] * 8
            l_max = 0
            for b in mol._basis[symb]:
                l = b[0]
                l_max = max(l_max, l)
                if l >= max_shells+1:
                    continue

                if isinstance(b[1], int):
                    e_c = numpy.array(b[2:])
                else:
                    e_c = numpy.array(b[1:])
                es = e_c[:,0]
                cs = e_c[:,1:]
                es = es[abs(cs).max(axis=1) > 1e-3]
                emax_by_l[l] = max(es.max(), emax_by_l[l])
                emin_by_l[l] = min(es.min(), emin_by_l[l])

            l_max1 = l_max + 1
            emin_by_l = numpy.array(emin_by_l[:l_max1])
            emax_by_l = numpy.array(emax_by_l[:l_max1])

# Estimate the exponents ranges by geometric average
            emax = numpy.sqrt(numpy.einsum('i,j->ij', emax_by_l, emax_by_l))
            emin = numpy.sqrt(numpy.einsum('i,j->ij', emin_by_l, emin_by_l))
            liljsum = numpy.arange(l_max1)[:,None] + numpy.arange(l_max1)
            emax_by_l = [emax[liljsum==ll].max() for ll in range(l_max1*2-1)]
            emin_by_l = [emin[liljsum==ll].min() for ll in range(l_max1*2-1)]
            # Tune emin and emax
            emin_by_l = numpy.array(emin_by_l) * 2  # *2 for alpha+alpha on same center
            emax_by_l = numpy.array(emax_by_l) * 2  #/ (numpy.arange(l_max1*2-1)*.5+1)

            ns = numpy.log((emax_by_l+emin_by_l)/emin_by_l) / numpy.log(beta)
            etb = []
            for l, n in enumerate(numpy.ceil(ns).astype(int)):
                if n > 0:
                    etb.append((l, n, emin_by_l[l], beta))
            newbasis[symb] = gto.expand_etbs(etb)

    return newbasis
예제 #2
0
def get_atm_nrhf(mol):
    if mol.has_ecp():
        raise NotImplementedError('Atomic calculation with ECP is not implemented')

    atm_scf_result = {}
    for a, b in mol._basis.items():
        atm = gto.Mole()
        atm.stdout = mol.stdout
        atm.atom = atm._atom = [[a, (0, 0, 0)]]
        atm._basis = {a: b}
        atm.nelectron = gto.charge(a)
        atm.spin = atm.nelectron % 2
        atm._atm, atm._bas, atm._env = \
                atm.make_env(atm._atom, atm._basis, atm._env)
        atm._built = True
        if atm.nelectron == 0:  # GHOST
            nao = atm.nao_nr()
            mo_occ = mo_energy = numpy.zeros(nao)
            mo_coeff = numpy.zeros((nao,nao))
            atm_scf_result[a] = (0, mo_energy, mo_coeff, mo_occ)
        else:
            atm_hf = AtomSphericAverageRHF(atm)
            atm_hf.verbose = 0
            atm_scf_result[a] = atm_hf.scf()[1:]
            atm_hf._eri = None
    mol.stdout.flush()
    return atm_scf_result
예제 #3
0
    def print_geometry_header(self):
        ''' Atoms written in order of increasing ia
        '''
        #Write number of atom types, number of atoms
        self.out_file.write('\' * Geometry section\'\n')
        self.out_file.write('3\t\t\tndim\n')
        self.out_file.write('%d %d\t\t\tnctypes, ncent\n' %
                            (len(self.atoms), self.mol.natm))

        #For each atom, write the atom type
        ia2species = [
            self.atoms.index(self.mol.atom_symbol(ia)) + 1
            for ia in range(self.mol.natm)
        ]
        self.out_file.write(' '.join([str(species) for species in ia2species]))
        self.out_file.write('\t\t\t(iwctype(i), i= 1,ncent)\n')

        #For each atom type, write Z
        self.out_file.write(' '.join(
            [str(gto.charge(atom)) for atom in self.atoms]))
        self.out_file.write('\t\t\t(znuc(i), i=1, nctype)\n')

        #For each atom, write the coordinates/atom type
        for ia in range(self.mol.natm):
            self.out_file.write('%E\t%E\t%E\t%d\n' %
                                (tuple(self.mol.atom_coord(ia)) +
                                 (ia2species[ia], )))
        self.out_file.write('\n')
        return
예제 #4
0
파일: atom_hf.py 프로젝트: quansilong/pyscf
def get_atm_nrhf(mol, atomic_configuration=elements.NRSRHF_CONFIGURATION):
    atm_scf_result = {}
    for a, b in mol._basis.items():
        atm = gto.Mole()
        atm.stdout = mol.stdout
        atm.atom = atm._atom = [[a, (0, 0, 0)]]
        atm._basis = {a: b}
        atm.nelectron = gto.charge(a)
        atm.spin = atm.nelectron % 2
        atm._atm, atm._bas, atm._env = \
                atm.make_env(atm._atom, atm._basis, atm._env)
        if a in mol._ecp:
            atm._ecp[a] = mol._ecp[a]
            atm._atm, atm._ecpbas, atm._env = \
                    atm.make_ecp_env(atm._atm, atm._ecp, atm._env)
        atm._built = True
        if atm.nelectron == 0:  # GHOST
            nao = atm.nao_nr()
            mo_occ = mo_energy = numpy.zeros(nao)
            mo_coeff = numpy.zeros((nao, nao))
            atm_scf_result[a] = (0, mo_energy, mo_coeff, mo_occ)
        else:
            atm_hf = AtomSphericAverageRHF(atm)
            atm_hf.atomic_configuration = atomic_configuration
            atm_hf.verbose = 0
            atm_hf.run()
            atm_scf_result[a] = (atm_hf.e_tot, atm_hf.mo_energy,
                                 atm_hf.mo_coeff, atm_hf.mo_occ)
            atm_hf._eri = None
    mol.stdout.flush()
    return atm_scf_result
예제 #5
0
    def kernel(self):
        mol = self.mol
        basis_type = _get_basis_type(mol)
        if self.xc in FUNC_CODE:
            func, supported_versions = FUNC_CODE[self.xc]
            if func == 'b3lyp' and basis_type == '6-31gd':
                func, supported_versions = FUNC_CODE['B3LYP/631GD']
            elif func == 'hf' and basis_type == 'sv':
                func, supported_versions = FUNC_CODE['HF/SV']
        else:
            raise RuntimeError('Functional %s not found' % self.xc)
        assert (self.version in supported_versions)

        # dft-d3 has special treatment for def2-TZ basis
        tz = (basis_type == 'def2-TZ')

        coords = mol.atom_coords()
        nuc_types = [gto.charge(mol.atom_symbol(ia)) for ia in range(mol.natm)]
        nuc_types = numpy.asarray(nuc_types, dtype=numpy.int32)

        edisp = ctypes.c_double(0)
        grads = numpy.zeros((mol.natm, 3))

        drv = self.libdftd3.wrapper
        drv(ctypes.c_int(mol.natm), coords.ctypes.data_as(ctypes.c_void_p),
            nuc_types.ctypes.data_as(ctypes.c_void_p), ctypes.c_char_p(func),
            ctypes.c_int(self.version), ctypes.c_int(tz), ctypes.byref(edisp),
            grads.ctypes.data_as(ctypes.c_void_p))
        self.edisp = edisp.value
        self.grads = grads
        return edisp.value, grads
예제 #6
0
파일: cubegen.py 프로젝트: tmash/pyscf
    def write(self, field, fname, comment=None):
        """  Result: .cube file with the field in the file fname.  """
        assert (field.ndim == 3)
        assert (field.shape == (self.nx, self.ny, self.nz))
        if comment is None:
            comment = 'Generic field? Supply the optional argument "comment" to define this line'

        mol = self.mol
        coord = mol.atom_coords()
        with open(fname, 'w') as f:
            f.write(comment + '\n')
            f.write('PySCF Version: %s  Date: %s\n' %
                    (pyscf.__version__, time.ctime()))
            f.write('%5d' % mol.natm)
            f.write('%12.6f%12.6f%12.6f\n' % tuple(self.boxorig.tolist()))
            f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nx, self.xs[1], 0, 0))
            f.write('%5d%12.6f%12.6f%12.6f\n' % (self.ny, 0, self.ys[1], 0))
            f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nz, 0, 0, self.zs[1]))
            for ia in range(mol.natm):
                atmsymb = mol.atom_symbol(ia)
                f.write('%5d%12.6f' % (gto.charge(atmsymb), 0.))
                f.write('%12.6f%12.6f%12.6f\n' % tuple(coord[ia]))

            for ix in range(self.nx):
                for iy in range(self.ny):
                    for iz0, iz1 in lib.prange(0, self.nz, 6):
                        fmt = '%13.5E' * (iz1 - iz0) + '\n'
                        f.write(fmt % tuple(field[ix, iy, iz0:iz1].tolist()))
예제 #7
0
파일: atom_hf.py 프로젝트: chrinide/pyscf
def get_atm_nrhf(mol):
    if mol.has_ecp():
        raise NotImplementedError('Atomic calculation with ECP is not implemented')

    atm_scf_result = {}
    for a, b in mol._basis.items():
        atm = gto.Mole()
        atm.stdout = mol.stdout
        atm.atom = atm._atom = [[a, (0, 0, 0)]]
        atm._basis = {a: b}
        atm.nelectron = gto.charge(a)
        atm.spin = atm.nelectron % 2
        atm._atm, atm._bas, atm._env = \
                atm.make_env(atm._atom, atm._basis, atm._env)
        atm._built = True
        if atm.nelectron == 0:  # GHOST
            nao = atm.nao_nr()
            mo_occ = mo_energy = numpy.zeros(nao)
            mo_coeff = numpy.zeros((nao,nao))
            atm_scf_result[a] = (0, mo_energy, mo_coeff, mo_occ)
        else:
            atm_hf = AtomSphericAverageRHF(atm)
            atm_hf.verbose = 0
            atm_scf_result[a] = atm_hf.scf()[1:]
            atm_hf._eri = None
    mol.stdout.flush()
    return atm_scf_result
예제 #8
0
파일: cubegen.py 프로젝트: BoothGroup/pyscf
 def write_header(self, filename, dset_ids=None):
     """Write header of cube-file."""
     if self.nfields > 1 and dset_ids is None:
         dset_ids = range(1, self.nfields + 1)
     with open(filename, 'w') as f:
         f.write('%s\n' % self.title)
         f.write('%s\n' % self.comment)
         if self.nfields > 1:
             f.write('%5d' % -self.cell.natm)
         else:
             f.write('%5d' % self.cell.natm)
         f.write('%12.6f%12.6f%12.6f' % tuple(self.origin))
         if self.nfields > 1:
             f.write('%5d' % self.nfields)
         f.write('\n')
         # Lattice vectors
         f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nx, *(self.a[0] /
                                                         (self.nx - 1))))
         f.write('%5d%12.6f%12.6f%12.6f\n' % (self.ny, *(self.a[1] /
                                                         (self.ny - 1))))
         f.write('%5d%12.6f%12.6f%12.6f\n' % (self.nz, *(self.a[2] /
                                                         (self.nz - 1))))
         # Atoms
         for atm in range(self.cell.natm):
             sym = self.cell.atom_symbol(atm)
             f.write('%5d%12.6f' % (gto.charge(sym), 0.0))
             f.write('%12.6f%12.6f%12.6f\n' %
                     tuple(self.cell.atom_coords()[atm]))
         # Data set indices
         if self.nfields > 1:
             f.write('%5d' % self.nfields)
             for i in range(self.nfields):
                 f.write('%5d' % dset_ids[i])
             f.write('\n')
예제 #9
0
파일: gen_grid.py 프로젝트: wmizukami/pyscf
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
예제 #10
0
파일: gen_grid.py 프로젝트: chrinide/pyscf
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
예제 #11
0
def frac_occ(symb, l):
    nuc = gto.charge(symb)
    if l < 4 and elements.CONFIGURATION[nuc][l] > 0:
        ne = elements.CONFIGURATION[nuc][l]
        nd = (l * 2 + 1) * 2
        ndocc = ne.__floordiv__(nd)
        frac = (float(ne) / nd - ndocc) * 2
    else:
        ndocc = frac = 0
    return ndocc, frac
예제 #12
0
파일: atom_hf.py 프로젝트: chrinide/pyscf
def frac_occ(symb, l):
    nuc = gto.charge(symb)
    if l < 4 and elements.CONFIGURATION[nuc][l] > 0:
        ne = elements.CONFIGURATION[nuc][l]
        nd = (l * 2 + 1) * 2
        ndocc = ne.__floordiv__(nd)
        frac = (float(ne) / nd - ndocc) * 2
    else:
        ndocc = frac = 0
    return ndocc, frac
예제 #13
0
파일: atom_hf.py 프로젝트: zzy2014/pyscf
def frac_occ(symb, l, atomic_configuration=elements.NRSRHF_CONFIGURATION):
    nuc = gto.charge(symb)
    if l < 4 and atomic_configuration[nuc][l] > 0:
        ne = atomic_configuration[nuc][l]
        nd = (l * 2 + 1) * 2
        ndocc = ne.__floordiv__(nd)
        frac = (float(ne) / nd - ndocc) * 2
    else:
        ndocc = frac = 0
    return ndocc, frac
예제 #14
0
def plot_mesh_3d(mesh, weight=False, **kwargs):
    '''Plot atoms and grid points in a 3d plot.

    Args:
        mesh :
            Object of class :class:`Grids`.

    Kwargs:
        weight : bool or int
            Scale grid points by their weights when set to ``True``. Integers
            will scale grid points.
    '''
    # Initialize logger
    verbose = mesh.verbose
    log = logger.Logger(stdout, verbose)
    # Handle user inputs
    if not isinstance(mesh, Grids):
        log.error('The mesh parameter has to be a Grids object.')
    if not isinstance(weight, bool) and not isinstance(weight, int):
        log.error('The weight parameter has to be a boolean or an integer.')

    mol = mesh.mol
    coords = mesh.coords
    atoms = mol.atom_coords()
    if weight and isinstance(weight, bool):
        weights = abs(mesh.weights)
    elif weight and isinstance(weight, int):
        weights = weight
    else:
        weights = 2
    # Get the atom colors and radii (scale with 100 to make it look good)
    colors = []
    radii = []
    for ia in range(mol.natm):
        colors.append(cpk_colors.get(mol.atom_symbol(ia), 'magenta'))
        radii.append(BRAGG_RADII[charge(mol.atom_symbol(ia))] * 100)
    fig = plt.figure()
    ax = fig.add_subplot(111, projection=Axes3D.name)
    # Plot atoms
    ax.scatter(atoms[:, 0],
               atoms[:, 1],
               atoms[:, 2],
               s=radii,
               c=colors,
               edgecolors='k',
               depthshade=0)
    # Plot mesh points
    ax.scatter(coords[:, 0], coords[:, 1], coords[:, 2], s=weights, c='g')
    ax.set_xlabel('x-axis', fontsize=12)
    ax.set_ylabel('y-axis', fontsize=12)
    ax.set_zlabel('z-axis', fontsize=12)
    plt.tight_layout()
    plt.show()
    return
예제 #15
0
파일: ddcosmo.py 프로젝트: tmash/pyscf
def get_atomic_radii(pcmobj):
    mol = pcmobj.mol
    vdw_radii = pcmobj.radii_table
    atom_radii = pcmobj.atom_radii

    atom_symb = [mol.atom_symbol(i) for i in range(mol.natm)]
    r_vdw = [vdw_radii[gto.charge(x)] for x in atom_symb]
    if atom_radii is not None:
        for i in range(mol.natm):
            if atom_symb[i] in atom_radii:
                r_vdw[i] = atom_radii[atom_symb[i]]
    return numpy.asarray(r_vdw)
예제 #16
0
파일: newton_ah.py 프로젝트: chrinide/pyscf
def project_mol(mol, dual_basis={}):
    from pyscf import df
    uniq_atoms = set([a[0] for a in mol._atom])
    newbasis = {}
    for symb in uniq_atoms:
        if gto.charge(symb) <= 10:
            newbasis[symb] = '321g'
        elif gto.charge(symb) <= 12:
            newbasis[symb] = 'dzp'
        elif gto.charge(symb) <= 18:
            newbasis[symb] = 'dz'
        elif gto.charge(symb) <= 86:
            newbasis[symb] = 'dzp'
        else:
            newbasis[symb] = 'sto3g'
    if isinstance(dual_basis, (dict, tuple, list)):
        newbasis.update(dual_basis)
    elif isinstance(dual_basis, str):
        for k in newbasis:
            newbasis[k] = dual_basis
    return df.addons.make_auxmol(mol, newbasis)
예제 #17
0
파일: ddcosmo.py 프로젝트: chrinide/pyscf
def get_atomic_radii(pcmobj):
    mol = pcmobj.mol
    vdw_radii = pcmobj.radii_table
    atom_radii = pcmobj.atom_radii

    atom_symb = [mol.atom_symbol(i) for i in range(mol.natm)]
    r_vdw = [vdw_radii[gto.charge(x)] for x in atom_symb]
    if atom_radii is not None:
        for i in range(mol.natm):
            if atom_symb[i] in atom_radii:
                r_vdw[i] = atom_radii[atom_symb[i]]
    return numpy.asarray(r_vdw)
예제 #18
0
def project_mol(mol, dual_basis={}):
    from pyscf import df
    uniq_atoms = set([a[0] for a in mol._atom])
    newbasis = {}
    for symb in uniq_atoms:
        if gto.charge(symb) <= 10:
            newbasis[symb] = '321g'
        elif gto.charge(symb) <= 12:
            newbasis[symb] = 'dzp'
        elif gto.charge(symb) <= 18:
            newbasis[symb] = 'dz'
        elif gto.charge(symb) <= 86:
            newbasis[symb] = 'dzp'
        else:
            newbasis[symb] = 'sto3g'
    if isinstance(dual_basis, (dict, tuple, list)):
        newbasis.update(dual_basis)
    elif isinstance(dual_basis, str):
        for k in newbasis:
            newbasis[k] = dual_basis
    return df.addons.make_auxmol(mol, newbasis)
예제 #19
0
    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)
예제 #20
0
def get_ang(symb, level):
    '''Get angular grids.

    Args:
        symb : str
            Atom type identifier.

        level : int
            Grid level of atom type.

    Returns: int
        Amount of angular grids.
    '''
    try:
        return ang[symb][level]
    except (KeyError, TypeError):
        return dft.gen_grid._default_ang(gto.charge(symb), level)
예제 #21
0
파일: geom.py 프로젝트: chrinide/pyscf
def symm_identical_atoms(gpname, atoms):
    ''' Requires '''
    from pyscf import gto
    # Dooh Coov for linear molecule
    if gpname == 'Dooh':
        coords = numpy.array([a[1] for a in atoms], dtype=float)
        idx0 = argsort_coords(coords)
        coords0 = coords[idx0]
        opdic = symm_ops(gpname)
        newc = numpy.dot(coords, opdic['sz'])
        idx1 = argsort_coords(newc)
        dup_atom_ids = numpy.sort((idx0,idx1), axis=0).T
        uniq_idx = numpy.unique(dup_atom_ids[:,0], return_index=True)[1]
        eql_atom_ids = dup_atom_ids[uniq_idx]
        eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids]
        return eql_atom_ids
    elif gpname == 'Coov':
        eql_atom_ids = [[i] for i,a in enumerate(atoms)]
        return eql_atom_ids

    charges = numpy.array([gto.charge(a[0]) for a in atoms])
    coords = numpy.array([a[1] for a in atoms])
    center = numpy.einsum('z,zr->r', charges, coords)/charges.sum()

#    if not numpy.allclose(center, 0, atol=TOLERANCE):
#        sys.stderr.write('WARN: Molecular charge center %s is not on (0,0,0)\n'
#                        % center)
    opdic = symm_ops(gpname)
    ops = [opdic[op] for op in OPERATOR_TABLE[gpname]]
    idx = argsort_coords(coords)
    coords0 = coords[idx]

    dup_atom_ids = []
    for op in ops:
        newc = numpy.dot(coords, op)
        idx = argsort_coords(newc)
        if not numpy.allclose(coords0, newc[idx], atol=TOLERANCE):
            raise RuntimeError('Symmetry identical atoms not found')
        dup_atom_ids.append(idx)

    dup_atom_ids = numpy.sort(dup_atom_ids, axis=0).T
    uniq_idx = numpy.unique(dup_atom_ids[:,0], return_index=True)[1]
    eql_atom_ids = dup_atom_ids[uniq_idx]
    eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids]
    return eql_atom_ids
예제 #22
0
def symm_identical_atoms(gpname, atoms):
    ''' Requires '''
    from pyscf import gto
    # Dooh Coov for linear molecule
    if gpname == 'Dooh':
        coords = numpy.array([a[1] for a in atoms], dtype=float)
        idx0 = argsort_coords(coords)
        coords0 = coords[idx0]
        opdic = symm_ops(gpname)
        newc = numpy.dot(coords, opdic['sz'])
        idx1 = argsort_coords(newc)
        dup_atom_ids = numpy.sort((idx0, idx1), axis=0).T
        uniq_idx = numpy.unique(dup_atom_ids[:, 0], return_index=True)[1]
        eql_atom_ids = dup_atom_ids[uniq_idx]
        eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids]
        return eql_atom_ids
    elif gpname == 'Coov':
        eql_atom_ids = [[i] for i, a in enumerate(atoms)]
        return eql_atom_ids

    charges = numpy.array([gto.charge(a[0]) for a in atoms])
    coords = numpy.array([a[1] for a in atoms])
    center = numpy.einsum('z,zr->r', charges, coords) / charges.sum()

    #    if not numpy.allclose(center, 0, atol=TOLERANCE):
    #        sys.stderr.write('WARN: Molecular charge center %s is not on (0,0,0)\n'
    #                        % center)
    opdic = symm_ops(gpname)
    ops = [opdic[op] for op in OPERATOR_TABLE[gpname]]
    idx = argsort_coords(coords)
    coords0 = coords[idx]

    dup_atom_ids = []
    for op in ops:
        newc = numpy.dot(coords, op)
        idx = argsort_coords(newc)
        if not numpy.allclose(coords0, newc[idx], atol=TOLERANCE):
            raise RuntimeError('Symmetry identical atoms not found')
        dup_atom_ids.append(idx)

    dup_atom_ids = numpy.sort(dup_atom_ids, axis=0).T
    uniq_idx = numpy.unique(dup_atom_ids[:, 0], return_index=True)[1]
    eql_atom_ids = dup_atom_ids[uniq_idx]
    eql_atom_ids = [list(sorted(set(i))) for i in eql_atom_ids]
    return eql_atom_ids
예제 #23
0
def get_atomic_radii(pcmobj):
    '''
    get atomic radii for QM and MM
    '''
    mol = pcmobj.mol
    mm_mol = pcmobj.mm_mol
    vdw_radii = pcmobj.radii_table
    atom_radii = pcmobj.atom_radii
    atom_symb = [mol.atom_symbol(i) for i in range(mol.natm)]
    if mm_mol is not None:
        atom_symb += [mm_mol.atom_symbol(i) for i in range(mm_mol.natm)]

    r_vdw = [vdw_radii[gto.charge(x)] for x in atom_symb]
    if atom_radii is not None:
        for i in range(len(atom_symb)):
            if atom_symb[i] in atom_radii:
                r_vdw[i] = atom_radii[atom_symb[i]]

    return numpy.asarray(r_vdw)
예제 #24
0
    def write(self, field, fname, comment=None):
        """  Result: .cube file with the field in the file fname.  """
        assert (field.ndim == 3)
        assert (field.shape == (self.nx, self.ny, self.nz))
        if comment is None:
            comment = 'Generic field? Supply the optional argument "comment" to define this line'

        mol = self.mol
        coord = mol.atom_coords()
        with open(fname, 'w') as f:
            f.write(comment + '\n')
            f.write(
                f'PySCF Version: {pyscf.__version__}  Date: {time.ctime()}\n')
            f.write(f'{mol.natm:5d}')
            f.write('%12.6f%12.6f%12.6f\n' % tuple(self.boxorig.tolist()))
            dx = self.xs[-1] if len(self.xs) == 1 else self.xs[1]
            dy = self.ys[-1] if len(self.ys) == 1 else self.ys[1]
            dz = self.zs[-1] if len(self.zs) == 1 else self.zs[1]
            delta = (self.box.T * [dx, dy, dz]).T
            f.write(
                f'{self.nx:5d}{delta[0,0]:12.6f}{delta[0,1]:12.6f}{delta[0,2]:12.6f}\n'
            )
            f.write(
                f'{self.ny:5d}{delta[1,0]:12.6f}{delta[1,1]:12.6f}{delta[1,2]:12.6f}\n'
            )
            f.write(
                f'{self.nz:5d}{delta[2,0]:12.6f}{delta[2,1]:12.6f}{delta[2,2]:12.6f}\n'
            )
            for ia in range(mol.natm):
                atmsymb = mol.atom_symbol(ia)
                f.write('%5d%12.6f' % (gto.charge(atmsymb), 0.))
                f.write('%12.6f%12.6f%12.6f\n' % tuple(coord[ia]))

            for ix in range(self.nx):
                for iy in range(self.ny):
                    for iz0, iz1 in lib.prange(0, self.nz, 6):
                        fmt = '%13.5E' * (iz1 - iz0) + '\n'
                        f.write(fmt % tuple(field[ix, iy, iz0:iz1].tolist()))
예제 #25
0
파일: itrf.py 프로젝트: chrinide/pyscf
    def kernel(self):
        mol = self.mol
        basis_type = _get_basis_type(mol)
        if self.xc in FUNC_CODE:
            func, supported_versions = FUNC_CODE[self.xc]
            if func == 'b3lyp' and basis_type == '6-31gd':
                func, supported_versions = FUNC_CODE['B3LYP/631GD']
            elif func == 'hf' and basis_type == 'sv':
                func, supported_versions = FUNC_CODE['HF/SV']
        else:
            raise RuntimeError('Functional %s not found' % self.xc)
        assert(self.version in supported_versions)

        # dft-d3 has special treatment for def2-TZ basis
        tz = (basis_type == 'def2-TZ')

        coords = mol.atom_coords()
        nuc_types = [gto.charge(mol.atom_symbol(ia))
                     for ia in range(mol.natm)]
        nuc_types = numpy.asarray(nuc_types, dtype=numpy.int32)

        edisp = ctypes.c_double(0)
        grads = numpy.zeros((mol.natm,3))

        drv = self.libdftd3.wrapper
        drv(ctypes.c_int(mol.natm),
            coords.ctypes.data_as(ctypes.c_void_p),
            nuc_types.ctypes.data_as(ctypes.c_void_p),
            ctypes.c_char_p(func),
            ctypes.c_int(self.version),
            ctypes.c_int(tz),
            ctypes.byref(edisp),
            grads.ctypes.data_as(ctypes.c_void_p))
        self.edisp = edisp.value
        self.grads = grads
        return edisp.value, grads
예제 #26
0
파일: ddcosmo.py 프로젝트: chrinide/pyscf
    energy = energy
    gen_solver = as_solver = gen_ddcosmo_solver
    get_atomic_radii = get_atomic_radii

    def regularize_xt(self, t, eta, scale=1):
        # scale = eta*scale, is it correct?
        return regularize_xt(t, eta*scale)


if __name__ == '__main__':
    from pyscf import scf
    from pyscf import mcscf
    from pyscf import cc
    mol = gto.M(atom='H 0 0 0; H 0 1 1.2; H 1. .1 0; H .5 .5 1')
    natm = mol.natm
    r_vdw = [radii.VDW[gto.charge(mol.atom_symbol(i))]
             for i in range(natm)]
    r_vdw = numpy.asarray(r_vdw)
    pcmobj = DDCOSMO(mol)
    pcmobj.regularize_xt = lambda t, eta, scale: regularize_xt(t, eta)
    pcmobj.lebedev_order = 7
    pcmobj.lmax = 6
    pcmobj.eta = 0.1
    nlm = (pcmobj.lmax+1)**2
    coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order)
    fi = make_fi(pcmobj, r_vdw)
    ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True))
    L = make_L(pcmobj, r_vdw, ylm_1sph, fi)
    print(lib.finger(L) - 6.2823493771037473)

    mol = gto.Mole()
예제 #27
0
파일: ddcosmo.py 프로젝트: tmash/pyscf
    energy = energy
    gen_solver = as_solver = gen_ddcosmo_solver
    get_atomic_radii = get_atomic_radii

    def regularize_xt(self, t, eta, scale=1):
        # scale = eta*scale, is it correct?
        return regularize_xt(t, eta*scale)


if __name__ == '__main__':
    from pyscf import scf
    from pyscf import mcscf
    from pyscf import cc
    mol = gto.M(atom='H 0 0 0; H 0 1 1.2; H 1. .1 0; H .5 .5 1')
    natm = mol.natm
    r_vdw = [radii.VDW[gto.charge(mol.atom_symbol(i))]
             for i in range(natm)]
    r_vdw = numpy.asarray(r_vdw)
    pcmobj = DDCOSMO(mol)
    pcmobj.regularize_xt = lambda t, eta, scale: regularize_xt(t, eta)
    pcmobj.lebedev_order = 7
    pcmobj.lmax = 6
    pcmobj.eta = 0.1
    nlm = (pcmobj.lmax+1)**2
    coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order)
    fi = make_fi(pcmobj, r_vdw)
    ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True))
    L = make_L(pcmobj, r_vdw, ylm_1sph, fi)
    print(lib.finger(L) - 6.2823493771037473)

    mol = gto.Mole()
예제 #28
0
def plot_mesh_2d(mesh, weight=False, plane='xy'):
    '''Project atoms and grid points to a given plane in a 2d plot.

    Args:
        mesh :
            Object of class :class:`Grids`.

    Kwargs:
        weight : bool or int
            Scale grid points by their weights when set to ``True``. Integers
            will scale grid points.

        plane : str
            Contains the plane to project on to. Needs two elements of ``'x'``,
            ``'y'``, and ``'z'``.
    '''
    # Dictionary to map input axes to their coordinates
    ax = {'x': 0, 'y': 1, 'z': 2}

    # Initialize logger
    verbose = mesh.verbose
    log = logger.Logger(stdout, verbose)
    # Handle user inputs
    if not isinstance(mesh, Grids):
        log.error('The mesh parameter has to be a Grids object.')
    if not isinstance(weight, bool) and not isinstance(weight, int):
        log.error('The weight parameter has to be a boolean or an integer.')
    if not isinstance(plane, str):
        log.error('The plane parameter has to be a string.')
    if len(plane) != 2:
        log.error('The plane parameter has to be a string of length 2.')
    if not set(plane).issubset(ax.keys()):
        log.error('The plane parameter only accepts combinations of \'%s\'.',
                  '\', \''.join(ax.keys()))

    ax1, ax2 = list(plane.lower())
    mol = mesh.mol
    coords = mesh.coords
    atoms = mol.atom_coords()
    if weight and isinstance(weight, bool):
        weights = abs(mesh.weights)
    elif weight and isinstance(weight, int):
        weights = weight
    else:
        weights = 2
    # Get the atom colors and radii (scale with 100 to make it look good)
    colors = []
    radii = []
    for ia in range(mol.natm):
        colors.append(cpk_colors.get(mol.atom_symbol(ia), 'magenta'))
        radii.append(BRAGG_RADII[charge(mol.atom_symbol(ia))] * 100)
    # Project atoms
    plt.scatter(atoms[:, ax[ax1]],
                atoms[:, ax[ax2]],
                s=radii,
                c=colors,
                edgecolors='k')
    # Project mesh points
    plt.scatter(coords[:, ax[ax1]], coords[:, ax[ax2]], s=weights, c='g')
    plt.xlabel(ax1 + '-axis', fontsize=12)
    plt.ylabel(ax2 + '-axis', fontsize=12)
    plt.tight_layout()
    plt.show()
    return
예제 #29
0
    energy = energy
    gen_solver = as_solver = gen_ddcosmo_solver
    get_atomic_radii = get_atomic_radii

    def regularize_xt(self, t, eta, scale=1):
        # scale = eta*scale, is it correct?
        return regularize_xt(t, eta * scale)


if __name__ == '__main__':
    from pyscf import scf
    from pyscf import mcscf
    from pyscf import cc
    mol = gto.M(atom='H 0 0 0; H 0 1 1.2; H 1. .1 0; H .5 .5 1')
    natm = mol.natm
    r_vdw = [radii.VDW[gto.charge(mol.atom_symbol(i))] for i in range(natm)]
    r_vdw = numpy.asarray(r_vdw)
    pcmobj = DDCOSMO(mol)
    pcmobj.regularize_xt = lambda t, eta, scale: regularize_xt(t, eta)
    pcmobj.lebedev_order = 7
    pcmobj.lmax = 6
    pcmobj.eta = 0.1
    nlm = (pcmobj.lmax + 1)**2
    coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order)
    fi = make_fi(pcmobj, r_vdw)
    ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True))
    L = make_L(pcmobj, r_vdw, ylm_1sph, fi)
    print(lib.finger(L) - 6.2823493771037473)

    mol = gto.Mole()
    mol.atom = ''' O                  0.00000000    0.00000000   -0.11081188
예제 #30
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