def read_compared_result_from_json(filename='structure compare.json'): import json import re from method.atom import Atom with open(filename, 'r+') as fp: result_json = json.load(fp) result = [] for element_json in result_json: element_json = json.loads(element_json) for key, value in element_json.items(): if re.match('type', key): continue elif re.match('su', key) or re.match('un', key): atom_list = [] for pair in value: tmp = [] for atom in pair: atom_json = json.loads(atom) tmp.append(Atom(atom_json['pos'], type=atom_json['type'], num=atom_json['num'])) atom_list.append(tmp) element_json[key] = atom_list else: atom_list = [] for atom in value: atom_json = json.loads(atom) atom_list.append(Atom(atom_json['pos'], type=atom_json['type'], num=atom_json['num'])) element_json[key] = atom_list result.append(element_json) 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)) structure.clear() structure.extend(temp) return structure
def get_species(structure): species = {} i = 0 for atom in structure: if species.get(atom.type): species[atom.type].append(Atom(atom.pos, atom.type, num=i)) else: species[atom.type] = [ Atom(atom.pos, atom.type, num=i), ] i = i + 1 return species
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
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 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
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
def insert(self, index, *args, **kwargs): """ Insert atoms in given position """ from method.atom import Atom if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], Atom): atom = args[0] else: atom = Atom(*args, **kwargs) self._atoms.insert(index, atom)
def extend(self, args): """ Adds atoms to structure """ from collections import Sequence from method.atom import Atom from method import error for arg in args: if isinstance(arg, Atom): self._atoms.append(arg) elif isinstance(arg, Sequence): self._atoms.append(Atom(*arg)) else: raise error.TypeError("Cannot convert argument to Atom")
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
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
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
def append(self, *args, **kwargs): from method.atom import Atom if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], Atom): self._atoms.append(args[0]) else: self._atoms.append(Atom(*args, **kwargs))
result_json = json.load(fp) result = [] for element in result_json: element = json.loads(element) for key, value in element.items(): if re.match('type', key): continue elif re.match('su', key) or re.match('un', key): atom_list = [] for pair in value: tmp = [] for atom in pair: atom_json = json.loads(atom) tmp.append( Atom(atom_json['pos'], type=atom_json['type'], num=atom_json['num'])) atom_list.append(tmp) element[key] = atom_list else: atom_list = [] for atom in value: atom_json = json.loads(atom) atom_list.append( Atom(atom_json['pos'], type=atom_json['type'], num=atom_json['num'])) element[key] = atom_list result.append(element) print(result)
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
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_mosaic_structure(cluster, shell): for atom in shell: cluster.append(Atom(atom.pos, atom.type, pseudo=-1)) return cluster