Example #1
0
def ase_neighborlist(atoms, cutoffs=None):
    """Make dict of neighboring atoms using ase function.

    This provides a wrapper for the ASE neighborlist generator. Currently
    default values are used.

    Parameters
    ----------
    atoms : object
        Target ase atoms object on which to get neighbor list.
    cutoffs : list
        A list of radii for each atom in atoms.
    rtol : float
        The tolerance factor to allow for small variation in the cutoff radii.

    Returns
    -------
    neighborlist : dict
        A dictionary containing the atom index and each neighbor index.
    """
    if cutoffs is None:
        cutoffs = [get_radius(a.number) for a in atoms]
    nl = NeighborList(
        cutoffs, skin=0., sorted=False, self_interaction=False,
        bothways=True)

    nl.update(atoms)

    neighborlist = {}
    for i, _ in enumerate(atoms):
        neighborlist[i] = sorted(list(map(int, nl.get_neighbors(i)[0])))

    return neighborlist
Example #2
0
 def setup_metal(self):
     """Get the atoms objects."""
     symbols = ['Ag', 'Au', 'Cu', 'Pt', 'Pd', 'Ir', 'Rh', 'Ni', 'Co']
     images = []
     for s in symbols:
         rs = get_radius(atomic_numbers[s])
         a = 2 * rs * 2**0.5
         atoms = bulk(s, crystalstructure='bcc', a=a)
         images.append(atoms)
     return images
Example #3
0
 def setup_atoms(self):
     """Get the atoms objects."""
     adsorbates = ['H', 'O', 'C', 'N', 'S', 'Cl', 'P', 'F']
     symbols = ['Ag', 'Au', 'Cu', 'Pt', 'Pd', 'Ir', 'Rh', 'Ni', 'Co']
     images = []
     for i, s in enumerate(symbols):
         rs = get_radius(atomic_numbers[s])
         a = 2 * rs * 2**0.5
         for ads in adsorbates:
             atoms = fcc111(s, (2, 2, 3), a=a)
             atoms.center(vacuum=6, axis=2)
             h = (default_catlearn_radius(atomic_numbers[ads]) +
                  rs) / 2**0.5
             add_adsorbate(atoms, ads, h, 'bridge')
             images.append(atoms)
     return images
Example #4
0
def auto_layers(atoms, miller=(0, 0, 1)):
    """Returns two arrays describing which layer each atom belongs
    to and the distance between the layers and origo.
    Assumes the tolerance corresponds to the average atomic radii of the slab.

    Parameters
    ----------
    atoms : object
        The atoms object must have the following keys in atoms.subsets:

        'slab_atoms' : list
            indices of atoms belonging to the slab
    """
    radii = [get_radius(z) for z in atoms.numbers[atoms.subsets['slab_atoms']]]
    radius = np.average(radii) / 2.
    lz, li = get_layers(atoms, miller=miller, tolerance=radius)
    return lz, li
Example #5
0
def layers2ads_index(atoms, formula):
    """ Returns the indexes of atoms in layers exceeding the number of layers
    stored in the key value pair 'layers'.

    Parameters
    ----------
    atoms : ase atoms object.
        atoms.info must be a dictionary containing the key 'key_value_pairs',
        which is expected to contain CatMAP standard adsorbate structure
        key value pairs. See the ase db to catmap module in catmap.
        the key value pair 'species' must be the
        chemical formula of the adsorbate and 'layers' must be an integer.
    """
    composition = string2symbols(formula)
    n_ads = len(composition)
    natoms = len(atoms)
    radii = [get_radius(s) for s in composition]
    lz, li = get_layers(atoms, (0, 0, 1), tolerance=np.average(radii))
    layers = int(atoms.info['key_value_pairs']['layers'])
    ads_atoms = [a.index for a in atoms if li[a.index] > layers - 1]
    ads_atoms = list(range(natoms - n_ads, natoms))
    if len(ads_atoms) != len(composition):
        raise AssertionError("ads atoms identification by layers failed.")
    return ads_atoms
Example #6
0
def catlearn_neighborlist(atoms, dx=None, max_neighbor=1, mic=True):
    """Make dict of neighboring atoms for discrete system.

    Possible to return neighbors from defined neighbor shell e.g. 1st, 2nd,
    3rd by changing the neighbor number.

    Parameters
    ----------
    atoms : object
        Target ase atoms object on which to get neighbor list.
    dx : dict
        Buffer to calculate nearest neighbor pairs in dict format:
        dx = {atomic_number: buffer}.
    max_neighbor : int or str
        Maximum neighbor shell. If int is passed this will define how many
        shells to consider. If 'full' is passed then all neighbor combinations
        will be included. This might get expensive for particularly large
        systems.

    Returns
    -------
    connection_matrix : array
        An array of the neighbor shell each atom index is located in.
    """
    atomic_numbers = atoms.get_atomic_numbers()

    # Set up buffer dict.
    if dx is None:
        dx = dict.fromkeys(set(atomic_numbers), 0)
        for i in dx:
            dx[i] = get_radius(i) / 5.

    dist = atoms.get_all_distances(mic=mic)

    r_list, b_list = [], []
    for an in atomic_numbers:
        r_list.append(get_radius(an))
        b_list.append(dx[an])

    radius_matrix = np.asarray(r_list) + np.reshape(r_list, (len(r_list), 1))
    buffer_matrix = np.asarray(b_list) + np.reshape(
        b_list, (len(b_list), 1)) / 2.

    connection_matrix = np.zeros((len(atoms), len(atoms)))
    if isinstance(max_neighbor, int):
        for n in range(max_neighbor):
            dist, connection_matrix, unconnected = _neighbor_iterator(
                dist, radius_matrix, buffer_matrix, n, connection_matrix)
    elif max_neighbor == 'full':
        n, unconnected = 0, 1
        while unconnected > 0:
            dist, connection_matrix, unconnected = _neighbor_iterator(
                dist, radius_matrix, buffer_matrix, n, connection_matrix)
            n += 1
    else:
        msg = 'max_neighbor parameter {} not recognized.'.format(max_neighbor)
        raise NotImplementedError(msg)

    np.fill_diagonal(connection_matrix, 0.)

    return connection_matrix
Example #7
0
def detect_termination(atoms):
    """ Returns three lists, the first containing indices of bulk atoms and
    the second containing indices of atoms in the second outermost layer, and
    the last denotes atoms in the outermost layer or termination or the slab.

    Parameters
    ----------
    atoms : ase atoms object.
        The atoms object must have the following keys in atoms.subsets:
            - 'ads_atoms' : list
                indices of atoms belonging to the adsorbate
            - 'slab_atoms' : list
                indices of atoms belonging to the slab
    """
    max_coord = 0
    try:
        cm = atoms.connectivity.copy()
        np.fill_diagonal(cm, 0)
        # List coordination numbers of slab atoms.
        coord = np.count_nonzero(cm[atoms.subsets['slab_atoms'], :], axis=1)
        coord -= 1
        bulk = []
        term = []
        max_coord = np.max(coord)
        for j, c in enumerate(coord):
            a_s = atoms.subsets['slab_atoms'][j]
            if (c < max_coord
                    and a_s not in atoms.constraints[0].get_indices()):
                term.append(a_s)
            else:
                bulk.append(a_s)
        subsurf = []
        for a_b in bulk:
            for a_t in term:
                if cm[a_t, a_b] > 0:
                    subsurf.append(a_b)
        subsurf = list(np.unique(subsurf))
        try:
            sx, sy = atoms.info['key_value_pairs']['supercell'].split('x')
            sx = int(''.join(i for i in sx if i.isdigit()))
            sy = int(''.join(i for i in sy if i.isdigit()))
            if int(sx) * int(sy) != len(term):
                msg = str(len(term)) + ' termination atoms identified.' + \
                    'size = ' + atoms.info['key_value_pairs']['supercell'] + \
                    ' id: ' + str(atoms.info['id'])
                warnings.warn(msg)
        except KeyError:
            pass
        if len(bulk) is 0 or len(term) is 0 or len(subsurf) is 0:
            # print(il, zl)
            # msg = 'dbid: ' + str(atoms.info['id'])
            raise AssertionError()
    except (AssertionError, IndexError):
        layers = int(atoms.info['key_value_pairs']['layers'])
        radii = [
            get_radius(z) for z in atoms.numbers[atoms.subsets['slab_atoms']]
        ]
        radius = np.average(radii)
        il, zl = get_layers(atoms, (0, 0, 1), tolerance=radius)
        if len(zl) < layers:
            # msg = 'dbid: ' + str(atoms.info['id'])
            raise AssertionError()
        # bulk atoms includes subsurface atoms.
        bulk = [a.index for a in atoms if il[a.index] <= layers - 2]
        subsurf = [a.index for a in atoms if il[a.index] == layers - 2]
        term = [
            a.index for a in atoms if il[a.index] >= layers -
            1 and a.index not in atoms.subsets['ads_atoms']
        ]
    if len(bulk) is 0 or len(term) is 0 or len(subsurf) is 0:
        print(bulk, term, subsurf)
        msg = 'Detect bulk/term.'
        if 'id' in atoms.info:
            msg += ' id: ' + str(atoms.info['id'])
        print(il, zl)
        raise AssertionError(msg)
    for a_s in atoms.subsets['site_atoms']:
        if a_s not in term:
            msg = 'site not in term.'
            if 'id' in atoms.info:
                msg += str(atoms.info['id'])
            warnings.warn(msg)
            break
    return bulk, term, subsurf