def symmetrically_inequivalent_sites(structure, specie=None, center=None, tolerance=1e-3, symprec=0.1): from method import error from method.atom import Atom from method.utilities import are_periodic_images from numpy import dot from numpy.linalg import norm if specie is None: raise error.RuntimeError("specie is None!") ops = get_symmetrical_operations(structure, symprec=symprec) temp = structure.copy() result = [] for i in range(len(temp)): equivalent_sites = [] if temp[i].type != specie: continue else: atom = Atom(temp[i].pos, type=temp[i].type, index=i) equivalent_sites.append(atom) for op in ops: rotation = op[:3] translation = op[3] transform = dot(rotation, temp[i].pos) + translation for j in range(i + 1, len(temp)): if temp[j].type != specie: continue if are_periodic_images(transform, temp[j].pos, cell=structure.cell, tolerance=tolerance): atom = Atom(temp[j].pos, type=temp[j].type, index=j) equivalent_sites.append(atom) temp[j].type = 'Used' result.append(equivalent_sites) indices = [] for equivalent in result: if center is None: indices.append(equivalent[0].index) else: center = dot(temp.cell, center) minimum = norm(equivalent[0].pos - center) index = equivalent[0].index for site in equivalent: if norm(site.pos - center) < minimum: minimum = norm(site.pos - center) index = site.index indices.append(index) return indices
def substitution(structure, types=None, subs=None, center=None, tolerance=0.01): """Yields point-defects in given structure. One-point substitution or vacancy is decided by type and subs parameters. The result loops over all symmetrically un-equivalent sites in structure. :param structure: 'pylada.crystal.Structure' Structure which is interested for doping. :param types: list of 'str' Atomic specie for which to make one-point defect in given structure. :param subs: list of 'str' Atomic specie to substitute atoms in structure. :param center: a 'list' as 1*3 matrix In practically doping, point-defect prefers to be made at the center of the host. Thus, it will choose the nearest position of center to make point-defect when center is *not* None. :param tolerance: 'float' To judge how close of two atoms equals to treat as equivalence. :note: If you want to substitute more than one atomic specie in structure, you can input e.g. type=['Si','Al']. If type=None, all different kinds of species in structure will be doped. If subs is None, it will create vacancy. Of course, subs can also more than one atomic specie, you need to input as a list. The parameter of center *should* be fractional coordinates, i.e. if you want to make a point defect\ at the center of host, that is center=[0.5, 0.5, 0.5] The smaller of tolerance makes symmetrical requires harder, and thus gives more *un-equivalent* sites \ when structure keeps unchanged. The smaller of 'symprec' will give less allowable symmetrical operations because of the more strict \ symmetrical requires. :return: 'pylada.crystal.Structure' A list of one-point substitution or vacancy structures. """ from method import error result = [] species = specieset(structure) if types is None: types = species else: types = [specie for specie in types if specie in species] if len(types) < 1: raise error.RuntimeError("Cannot find specie to substitute in structure!") view_structure = structure.copy() for specie in types: indices = symmetrically_inequivalent_indices(structure, center=center, species=specie, symprec=tolerance) for index in indices: if subs is None: doped_structure = structure.copy() del doped_structure[index] doped_structure.name = 'vacancy_of_{0}_in_site{1}'.format(specie, index+1) result.append(doped_structure) view_structure[index].type = 'Vac' else: for sub_specie in subs: doped_structure = structure.copy() doped_structure[index].type = sub_specie doped_structure.name = 'substitution_{0}_in_site{1}'.format(sub_specie, index+1) result.append(doped_structure) view_structure[index].type = 'Sub' return result, view_structure
def interstitial(structure, insert=None, center=None, position=None, tolerance=1e-3, symprec=0.1, vnrprec=1e-3, n_shell=4): """Yields interstitial structure when interstitial atom specie and position is known or to find candidate\ interstitial structure when interstitial sites is unknown. The method to find candidate interstitial is \ referred as *Computational Material Science 130(2017)1-9* :param structure: pylada.crystal.Structure Structure which is interested for doping. :param insert: str Specie of interstitial atom. :param center: a 'list' as 1*3 matrix In practically doping, point-defect prefers to be made at the center of the host. Thus, it will choose the nearest position of center to make point-defect when center is *not* None. :param position: a 'list' as 1*3 matrix If the position of interstitial atom is know, it will create this doped structure directly. :param tolerance: float To judge how close of two atoms equals to treat as equivalence. Needed in two place: 1. to find symmetrically inequivalent sites. 2. to remove equivalent sites in candidate interstitial sites. :param symprec: float The tolerance to give proper symmetrical operation matrix for structure. :param vnrprec: float The tolerance decides the number of neighbors for given symmetrical inequivalent sites. This will impact\ the shape of vonoroi cell. :param n_shell: int To decide how many shell of neighbors are considered for given symmetrical inequivalent sites. This will\ also impact the shape of vonoroi cell. :note: insert should be only one specie of atom, if you want to interstitial different atoms, loop this program. The parameter of center *should* be fractional coordinates, i.e. if you want to make a point defect\ at the center of host, that is center=[0.5, 0.5, 0.5] The smaller of tolerance makes symmetrical requires harder, and thus gives more *un-equivalent* sites\ when structure keeps unchanged. Meanwhile, the smaller tolerance will give more *un-equivalent* sites\ of candidate interstitial. Thus, if the result of candidate interstitial is too many, choose a bigger\ tolerance, e.g. tolerance=0.5, is a good choice. The smaller of 'symprec' will give less allowable symmetrical operations because of the more strict\ symmetrical requires. The smaller of 'vnrprec' will give fewer neighbors of each shell because of the more strict distance\ require. """ from method import error result = [] if insert is None: raise error.RuntimeError("Interstitial atom specie should be known!") if position is not None: doped_structure = structure.copy() doped_structure.add_atom(position, insert) doped_structure.name = 'interstitial_of_{0}_in_site0'.format(insert) result.append(doped_structure) view_structure = doped_structure else: positions = get_interstitial_positions(structure, center, tolerance, symprec, vnrprec, n_shell) view_structure = structure.copy() for i, position in enumerate(positions, start=1): doped_structure = structure.copy() doped_structure.add_atom(position, insert) doped_structure.name = 'interstitial_of_{0}_in_site{1}'.format( insert, i) result.append(doped_structure) view_structure.add_atom(position, insert) return result, view_structure