def extend_structure(structure, shell_r, pure_substrate=True, remove_dict=None):
    if pure_substrate is False:
        if remove_dict is None:
            print('ERROR: remove_list can not be None when substrate includes doped atoms.\n')
            exit(1)
        structure = remove_doped_atoms(structure, remove_dict)
    cell = structure.cell.T
    volume = structure.volume
    hz = volume/np.linalg.norm(np.cross(cell[0], cell[1]))
    hx = volume/np.linalg.norm(np.cross(cell[1], cell[2]))
    hy = volume/np.linalg.norm(np.cross(cell[2], cell[0]))
    if min(hx, hy, hz)/2 >= shell_r:
        return structure
    nz = int(np.ceil(shell_r/hz - 0.5))
    nx = int(np.ceil(shell_r/hx - 0.5))
    ny = int(np.ceil(shell_r/hy - 0.5))
    temp = []
    for i in range(-nx, nx+1):
        for j in range(-ny, ny+1):
            for k in range(-nz, nz+1):
                for atom in structure:
                    position = atom.pos + i*cell[0] + j*cell[1] + k*cell[2]
                    temp.append(Atom(position, atom.type))
    supercell = Structure(structure.cell, scale=structure.scale)
    supercell.extend(temp)
    return supercell
예제 #2
0
def supercell(structure, transform):
    from method.structure import Structure
    import numpy as np
    from numpy import dot

    r = []
    for j in range(3):
        minimum = 0
        maximum = 0
        for i in range(3):
            if transform[i][j] <= 0:
                minimum += transform[i][j]
            else:
                maximum += transform[i][j]
        r.append([minimum, maximum])
    result = Structure(dot(structure.cell, transform.T), scale=structure.scale)
    inverse = np.linalg.inv(transform)
    inv_cell = np.linalg.inv(structure.cell)
    for i in range(len(structure)):
        fractional = dot(inv_cell, structure[i].pos)
        for a0 in range(r[0][0]-1, r[0][1]+1):
            for a1 in range(r[1][0]-1, r[1][1]+1):
                for a2 in range(r[2][0]-1, r[2][1]+1):
                    translation = np.array([a0, a1, a2])
                    temp = dot((translation + fractional), inverse)
                    if is_in_cell(temp):
                        result.add_atom(dot(result.cell, temp), structure[i].type)
    return result
def remove_doped_atoms(structure, remove_dict):
    temp = []
    for atom in structure:
        if atom.type in remove_dict.keys():
            value = remove_dict[atom.type]
            if value != '':
                temp.append(Atom(atom.pos, value))
        else:
            temp.append(Atom(atom.pos, atom.type))
    new_structure = Structure(structure.cell, scale=structure.scale)
    new_structure.extend(temp)
    return new_structure
예제 #4
0
def build_shell(structure,
                pure_substrate=False,
                doped_atom=None,
                remove_dict=None,
                cluster_r=5,
                shell_r=30):
    """

    :param structure: Pylada.crystal.Structure
    :param pure_substrate: Bool type
    :param doped_atom: Pylada.crystal.Atom
    :param remove_dict: dict
    :param cluster_r: float
    :param shell_r: float
    :return:
    """
    if pure_substrate is True:
        pass
    else:
        if doped_atom is None:
            species = structure_species(structure)
            doped_name = species[0][0]
            num = species[0][1]
            if num != 1:
                print(
                    'WARNING: The number of doped atom is not exclusive, please give doped atom name and position.\n'
                )
            for atom in structure:
                if atom.type == doped_name:
                    doped_atom = Atom(atom.pos, atom.type)
                    break
    if pure_substrate is False:
        if remove_dict is None:
            print(
                'ERROR: remove_list can not be None when substrate includes doped atoms.\n'
            )
            exit(1)
        structure = remove_doped_atoms(structure, remove_dict)
    supercell = extend_structure(structure, shell_r)
    shell = Structure(structure.cell, scale=structure.scale)
    doped_center = doped_atom.pos
    temp = []
    for atom in supercell:
        position = atom.pos
        d = np.linalg.norm(position - doped_center)
        if cluster_r < d <= shell_r:
            temp.append(Atom(position - doped_center, atom.type))
    shell.extend(temp)
    return shell
예제 #5
0
def extend_structure(structure, shell_r=30):
    cell = structure.cell.T
    volume = structure.volume
    hz = volume / np.linalg.norm(np.cross(cell[0], cell[1]))
    hx = volume / np.linalg.norm(np.cross(cell[1], cell[2]))
    hy = volume / np.linalg.norm(np.cross(cell[2], cell[0]))
    if min(hx, hy, hz) >= shell_r:
        return structure
    nz = int(np.ceil(shell_r / hz - 0.5))
    nx = int(np.ceil(shell_r / hx - 0.5))
    ny = int(np.ceil(shell_r / hy - 0.5))
    temp = []
    for i in range(-nx, nx + 1):
        for j in range(-ny, ny + 1):
            for k in range(-nz, nz + 1):
                for atom in structure:
                    position = atom.pos + i * cell[0] + j * cell[1] + k * cell[
                        2]
                    temp.append(Atom(position, atom.type))
    supercell = Structure(structure.cell, scale=structure.scale)
    supercell.extend(temp)
    return supercell
예제 #6
0
def build_shell(structure,
                center,
                cluster_r,
                shell_r,
                pure_substrate=False,
                remove_dict=None):

    if pure_substrate is False:
        if remove_dict is None:
            print(
                'ERROR: remove_list can not be None when substrate includes doped atoms.\n'
            )
            exit(1)
        structure = remove_doped_atoms(structure, remove_dict)
    supercell = extend_structure(structure, shell_r)
    shell = Structure(structure.cell, scale=structure.scale)
    temp = []
    for atom in supercell:
        position = atom.pos
        d = np.linalg.norm(position - center)
        if cluster_r < d <= shell_r:
            temp.append(Atom(position - center, atom.type))
    shell.extend(temp)
    return shell
예제 #7
0
def supercell(structure, transform):
    from method.structure import Structure
    from method.atom import Atom
    import numpy as np
    from numpy import dot
    epsilon = 1e-3

    r = []
    surface = []
    for j in range(3):
        minimum = 0
        maximum = 0
        for i in range(3):
            if transform[i][j] <= 0:
                minimum += transform[i][j]
            else:
                maximum += transform[i][j]
        r.append([minimum, maximum])
    result = Structure(dot(structure.cell, transform.T), scale=structure.scale)
    inverse = np.linalg.inv(transform)
    inv_cell = np.linalg.inv(structure.cell)
    for i in range(len(structure)):
        fractional = dot(inv_cell, structure[i].pos)
        for a0 in range(r[0][0] - 1, r[0][1] + 1):
            for a1 in range(r[1][0] - 1, r[1][1] + 1):
                for a2 in range(r[2][0] - 1, r[2][1] + 1):
                    translation = np.array([a0, a1, a2])
                    temp = dot((translation + fractional), inverse)
                    if is_in_cell(temp, epsilon):
                        result.add_atom(dot(result.cell, temp),
                                        structure[i].type)
                    elif is_in_surface(temp, epsilon):
                        surface.append(
                            Atom(dot(result.cell, temp),
                                 structure[i].type,
                                 flag=0))
    surface = remove_reduplicate(surface, dot(structure.cell, transform.T),
                                 epsilon)
    result.extend(surface)
    return result
예제 #8
0
def poscar(path="POSCAR", types=None):
    """ Tries to read a VASP POSCAR file.

         :param path: Path to the POSCAR file. Can also be an object with
           file-like behavior.
         :type path: str or file object
         :param types: Species in the POSCAR.
         :type types: None or sequence of str

        :return: `pylada.crystal.Structure` instance.
    """
    import re
    from os.path import join, exists, isdir
    from copy import deepcopy
    from numpy import array, dot, transpose
    from numpy.linalg import det
    from quantities import angstrom
    from method.structure import Structure
    from method import error

    # if types is not none, converts to a list of strings.
    if types is not None:
        if isinstance(types, str):
            types = [types]  # can't see another way of doing this...
        elif not hasattr(types, "__iter__"):
            types = [str(types)]  # single lone vasp.specie.Specie
        else:
            types = [str(s) for s in types]

    if path is None:
        path = "POSCAR"
    if not hasattr(path, 'read'):
        assert exists(path), IOError("Could not find path %s." % (path))
        if isdir(path):
            assert exists(join(path, "POSCAR")), IOError("Could not find POSCAR in %s." % (path))
            path = join(path, "POSCAR")
    result = Structure()
    poscar = path if hasattr(path, "read") else open(path, 'r')

    try:
        # gets name of structure
        result.name = poscar.readline().strip()
        if len(result.name) > 0 and result.name[0] == "#":
            result.name = result.name[1:].strip()
        # reads scale
        scale = float(poscar.readline().split()[0])
        # gets cell vectors.
        cell = []
        for i in range(3):
            line = poscar.readline()
            assert len(line.split()) >= 3,\
                RuntimeError("Could not read column vector from poscar: %s." % (line))
            cell.append([float(f) for f in line.split()[:3]])
        result.cell = transpose(array(cell))
        vol = det(cell)
        if scale < 1.E-8:
            scale = abs(scale / vol) ** (1.0 / 3)
        result.scale = scale * angstrom
        # checks for vasp 5 input.
        is_vasp_5 = True
        line = poscar.readline().split()
        for i in line:
            if not re.match(r"[A-Z][a-z]?", i):
                is_vasp_5 = False
                break
        if is_vasp_5:
            text_types = deepcopy(line)
            if types is not None and not set(text_types).issubset(set(types)):
                raise error.ValueError("Unknown species in poscar: {0} not in {1}."
                                       .format(text_types, types))
            types = text_types
            line = poscar.readline().split()
        if types is None:
            raise RuntimeError("No atomic species given in POSCAR or input.")
        #  checks/reads for number of each specie
        if len(types) < len(line):
            raise RuntimeError("Too many atomic species in POSCAR.")
        nb_atoms = [int(u) for u in line]
        # Check whether selective dynamics, cartesian, or direct.
        first_char = poscar.readline().strip().lower()[0]
        selective_dynamics = False
        if first_char == 's':
            selective_dynamics = True
            first_char = poscar.readline().strip().lower()[0]
        # Checks whether cartesian or direct.
        is_direct = first_char not in ['c', 'k']
        # reads atoms.
        for n, specie in zip(nb_atoms, types):
            for i in range(n):
                line = poscar.readline().split()
                pos = array([float(u) for u in line[:3]], dtype="float64")
                if is_direct:
                    pos = dot(result.cell, pos)
                result.add_atom(pos=pos, type=specie)
                if selective_dynamics:
                    for which, freeze in zip(line[3:], ['x', 'y', 'z']):
                        if which.lower()[0] == 't':
                            result[-1].freeze = getattr(result[-1], 'freeze', '') + freeze
    finally:
        poscar.close()

    return result
예제 #9
0
def build_cluster(structure,
                  doped_atom=None,
                  cluster_r=5,
                  core_r=None,
                  tolerance=0.2):
    from coordination_shells import coordination_shells
    """

    :param structure: Pylada.crystal.Structure
    :param doped_atom: Pylada.crystal.Atom
    :param cluster_r: float
    :param core_r: float
    :return: cluster, Pylada.crystal.Structure
    """

    if doped_atom is None:
        species = structure_species(structure)
        doped_name = species[0][0]
        num = species[0][1]
        if num != 1:
            print(
                'WARNING: The number of doped atom is not exclusive, please give doped atom name and position.\n'
            )
        for atom in structure:
            if atom.type == doped_name:
                doped_atom = Atom(atom.pos, atom.type)
                break
    cluster = Structure(structure.cell, scale=structure.scale)
    doped_center = doped_atom.pos
    if core_r is not None:
        for atom in structure:
            position = atom.pos
            d = np.linalg.norm(doped_center - position)
            if d <= core_r:
                cluster.append(
                    Atom(atom.pos - doped_center, atom.type, pseudo=0))
            elif d <= cluster_r:
                cluster.append(
                    Atom(atom.pos - doped_center, atom.type, pseudo=-1))
    else:
        # try to find the nearest neighbors of doped atom
        neighbors = coordination_shells(structure,
                                        nshells=4,
                                        center=doped_center,
                                        tolerance=tolerance)
        nearest_neighbors = []
        flag = 0
        for item in neighbors[0]:
            atom = item[0]
            nearest_neighbors.append(atom)
            atom.pseudo = 0
        if len(sorted({a.type for a in nearest_neighbors})) > 1:
            print(
                'WARNING: The species of nearest neighbor atoms are more than one.\n'
            )
        atom = neighbors[0][0][0]
        nearest_name = atom.type
        for i in range(1, 4):
            if flag != 0:
                break
            temp = [item[0] for item in neighbors[i]]
            if len(sorted({a.type for a in temp})) > 1:
                print('WARNING: The species of next nearest neighbor atoms:\n')
                print(sorted({a.type for a in temp}))
                print(
                    '\nwhich means the tolerance parameter might be too big to distinguish different shell of '
                    'neighbors\n')
                # when this situation happened, we discard this shell.
                break
            for item in neighbors[i]:
                atom = item[0]
                if nearest_name == atom.type:
                    nearest_neighbors.append(atom)
                    atom.pseudo = 0
                else:
                    flag = 1
        for atom in structure:
            position = atom.pos
            d = np.linalg.norm(doped_center - position)
            if d <= cluster_r:
                if hasattr(atom, 'pseudo'):
                    cluster.append(
                        Atom(atom.pos - doped_center, atom.type, pseudo=0))
                elif atom.type == doped_atom.type and d < 0.01:
                    cluster.append(
                        Atom(atom.pos - doped_center, atom.type, pseudo=0))
                else:
                    cluster.append(
                        Atom(atom.pos - doped_center, atom.type, pseudo=-1))
    return cluster
def build_cluster(structure,
                  cluster_r,
                  doped_atom_type=None,
                  center=None,
                  core_r=None,
                  tolerance=0.2):
    from method.coordination_shells import coordination_shells

    position = np.array([0.0, 0.0, 0.0])
    species = structure_species(structure)
    if doped_atom_type is None:
        doped_atom_type = species[0][0]
        print('\nTry to use *{0}* atoms as doped atoms\n'.format(
            doped_atom_type))
    if center is None:
        num = 0
        for atom in structure:
            if atom.type == doped_atom_type:
                position += atom.pos
                num += 1
        center = position / num
    if cluster_r > min(distance_of_center_and_surface(center,
                                                      structure.cell.T)):
        print(
            '\nERROR: the cluster is out range of the CONTCAR supercell structure. '
            'Please use a bigger supercell or a smaller cluster_r parameter\n')
        exit(1)

    cluster = Structure(structure.cell, scale=structure.scale)
    if core_r is None:
        print(
            '\nTry to use the nearest neighbor of doped atoms to build core structure.\n'
        )
        nearest_neighbors = []
        for atom in structure:
            if atom.type == doped_atom_type:
                neighbors = coordination_shells(structure,
                                                nshells=5,
                                                center=atom.pos,
                                                tolerance=tolerance)
                nearest_neighbors.append(atom)
                atom.pseudo = 0
                for item in neighbors[0]:
                    atom = item[0]
                    nearest_neighbors.append(atom)
                    atom.pseudo = 0
                atom = neighbors[0][0][0]
                nearest_name = atom.type
                print('\nSet *{0}* atoms as nearest neighbor.\n'.format(
                    nearest_name))
                flag = 0
                for i in range(1, 5):
                    temp = []
                    if flag != 0:
                        break
                    for item in neighbors[i]:
                        atom = item[0]
                        if nearest_name == atom.type:
                            if not hasattr(atom, 'pseudo'):
                                temp.append(atom)
                                atom.pseudo = 0
                        else:
                            flag = 1
                    nearest_neighbors.extend(temp)
        # nearest neighbor might be outside of CONTCAR
        with open('core structure.txt', 'w+') as fp:
            for atom in nearest_neighbors:
                fp.writelines(atom.type + '   ' + str(atom.pos) + '\n')
        for atom in structure:
            position = atom.pos
            d = np.linalg.norm(center - position)
            if d <= cluster_r:
                if hasattr(atom, 'pseudo'):
                    cluster.append(Atom(atom.pos - center, atom.type,
                                        pseudo=0))
                else:
                    cluster.append(
                        Atom(atom.pos - center, atom.type, pseudo=-1))
    else:
        for atom in structure:
            d = np.linalg.norm(center - atom.pos)
            if d <= core_r:
                cluster.append(Atom(atom.pos - center, atom.type, pseudo=0))
            elif d <= cluster_r:
                cluster.append(Atom(atom.pos - center, atom.type, pseudo=-1))
    return cluster, center