def strain(self, atoms=None): """Return a fingerprint with the espected strain of the site atoms and the termination atoms. Parameters ---------- atoms : object ASE Atoms object. Returns ---------- features : list If None was passed, the elements are strings, naming the feature. """ if atoms is None: return ['strain_site', 'strain_term'] else: if ('key_value_pairs' in atoms.info and 'term' in atoms.info['key_value_pairs']): term = atoms.info['key_value_pairs']['term'] term_numbers = [atomic_numbers[s] for s in string2symbols(term)] elif 'termination_atoms' in atoms.subsets: term = atoms.subsets['termination_atoms'] term_numbers = atoms.numbers[term] else: raise NotImplementedError("strain fingerprint.") if ('key_value_pairs' in atoms.info and 'bulk' in atoms.info['key_value_pairs']): bulk = atoms.info['key_value_pairs']['bulk'] bulk_numbers = [atomic_numbers[s] for s in string2symbols(bulk)] elif 'bulk_atoms' in atoms.subsets: bulk = atoms.subsets['bulk_atoms'] bulk_numbers = atoms.numbers[bulk] else: raise NotImplementedError("strain fingerprint.") site = atoms.subsets['site_atoms'] site_numbers = atoms.numbers[site] rbulk = [] rterm = [] rsite = [] for b in bulk_numbers: rbulk.append(get_radius(b)) for t in term_numbers: rterm.append(get_radius(t)) for z in site_numbers: rsite.append(get_radius(z)) av_term = np.average(rterm) av_bulk = np.average(rbulk) av_site = np.average(rsite) strain_site = (av_site - av_bulk) / av_bulk strain_term = (av_term - av_bulk) / av_bulk return [strain_site, strain_term]
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
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
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. li, lz = get_layers(atoms, miller=miller, tolerance=radius) return li, lz
def setup_metals(self, n=None): """Get the atoms objects.""" adsorbates = ['H', 'O', 'C', 'N', 'S', 'Cl', 'P', 'F'] symbols = ['Ag', 'Au', 'Cu', 'Pt', 'Pd', 'Ir', 'Rh', 'Ni', 'Co'] if n is not None: symbols = symbols[:n] adsorbates = adsorbates[:n] 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
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