def get_interstitials(self): evaluator = ValenceIonicRadiusEvaluator( self.structure) # computes site valence and ionic radii using bond valence analyser. # note this uses the sites, periodic table, bond valence, composition and local env packages! (as well as structure) radii = evaluator.radii valences = evaluator.valences #get the voronoi sites interstitial = Interstitial(self.structure, radii = radii, valences = valences, symmetry_flag = self.settings_obj.sym_dist) # this evaluates the structure and uses radii and valence to generate voronoi sites depending on whether vertex, # facecenter or edge center is selected. # note: not sure if hsould set oxi_state = False. By default it is true and it then uses ionic radii in the calculation, # shouldnt really change centres? Returns and interstitial object. ._defect_sites returns the coordinates and labels of # all intersittial sites which were found from the voronoi nodes/edges/faces/all depending on settings. # sym if False so we get all sites, including symmetry inequivalent sites! # structure the list of interstitial sites as a tuple with the voronoi radius in there interstitial_sites = [ ([site._fcoords[0], site._fcoords[1], site._fcoords[2]], site.properties.get('voronoi_radius', None)) for site in interstitial._defect_sites] # this creates a list of tuples: [ (array of site location # fractional coordinates, Voronoi radius') ] # shift vornoi sites up if they were previously shifted down interstitial_sites = [([i[0][0] * self.structure.lattice.a - self.downwards_shifts[0][0], i[0][1] * self.structure.lattice.b - self.downwards_shifts[1][1], i[0][2] * self.structure.lattice.c - self.downwards_shifts[2][2]], i[1]) for i in interstitial_sites] # shift it and convert to cart coords at the same time return interstitial_sites
def vac_intl(cellmax=2, mpid='', struct=None): """ Vacancy and interstitial generator Args: cellmax: maximum cell size struct: Structure object Returns: def_str: defect structures """ if struct == None: with MPRester() as mp: struct = mp.get_structure_by_material_id(mpid) if mpid == '': print("Provide structure") sg_mat = SpacegroupAnalyzer(struct) struct = sg_mat.get_conventional_standard_structure() def_str = [] count = 0 cell_arr = [cellmax, cellmax, cellmax] vac = Vacancy(struct, {}, {}) for el in list(struct.symbol_set): scs = vac.make_supercells_with_defects(cell_arr, el) for i in range(len(scs)): if i == 0: pos = Poscar(scs[i]) pos.comment = str('bulk') + str('.') + str('cellmax') + str( cellmax) if count == 0: def_str.append(pos) count = count + 1 else: pos = Poscar(scs[i]) pos.comment = str('vac') + str('cellmax') + str(cellmax) + str( '@') + str(vac.get_defectsite_multiplicity(i)) + str( 'Element') + str(el) if pos not in def_str: def_str.append(pos) struct_valrad_eval = ValenceIonicRadiusEvaluator(struct) val = struct_valrad_eval.valences rad = struct_valrad_eval.radii struct_val = val struct_rad = rad intl = Interstitial(struct, val, rad) for el in struct.composition.elements: scs = intl.make_supercells_with_defects(cell_arr, el) for i in range(1, len(scs)): pos = Poscar(scs[i]) pos.comment = str('intl') + str('cellmax') + str(cellmax) + str( '@') + str(intl.get_defectsite_coordination_number( i - 1)) + str('Element') + str(el) if pos not in def_str: def_str.append(pos) print(len(def_str)) return def_str
def featurize(self, s, cutoff=None, dr=0.05): """ Get ReDF of input structure. Args: s: input Structure object. cutoff: (float) distance up to which the ReDF is to be calculated (default: longest diagaonal in primitive cell). dr: (float) width of bins ("x"-axis) of ReDF (default: 0.05 A). Returns: (dict) a copy of the electronic radial distribution functions (ReDF) as a dictionary. The distance list ("x"-axis values of ReDF) can be accessed via key 'distances'; the ReDF itself is accessible via key 'redf'. """ if dr <= 0: raise ValueError("width of bins for ReDF must be >0") # Make structure primitive. struct = SpacegroupAnalyzer(s).find_primitive() or s # Add oxidation states. struct = ValenceIonicRadiusEvaluator(struct).structure if cutoff is None: # Set cutoff to longest diagonal. a = struct.lattice.matrix[0] b = struct.lattice.matrix[1] c = struct.lattice.matrix[2] cutoff = max([ np.linalg.norm(a + b + c), np.linalg.norm(-a + b + c), np.linalg.norm(a - b + c), np.linalg.norm(a + b - c) ]) nbins = int(cutoff / dr) + 1 redf_dict = { "distances": np.array([(i + 0.5) * dr for i in range(nbins)]), "redf": np.zeros(nbins, dtype=np.float) } for site in struct.sites: this_charge = float(site.specie.oxi_state) neighs_dists = struct.get_neighbors(site, cutoff) for neigh, dist in neighs_dists: neigh_charge = float(neigh.specie.oxi_state) bin_index = int(dist / dr) redf_dict["redf"][bin_index] += ( this_charge * neigh_charge) / (struct.num_sites * dist) return redf_dict
def featurize(self, s, cutoff=10.0): """ Get minimum relative distances of all sites of the input structure. Args: s: Pymatgen Structure object. Returns: min_rel_dists: (list of floats) list of all minimum relative distances (i.e., for all sites). """ vire = ValenceIonicRadiusEvaluator(s) min_rel_dists = [] for site in vire.structure: min_rel_dists.append(min([dist / ( vire.radii[site.species_string] + vire.radii[neigh.species_string]) for neigh, dist in \ vire.structure.get_neighbors(site, self.cutoff)])) return [min_rel_dists[:]]
def featurize(self, s, cutoff=10.0): """ Get minimum relative distances of all sites of the input structure. Args: s: Pymatgen Structure object. cutoff: (float) (absolute) distance up to which tentative closest neighbors (on the basis of relative distances) are to be determined. Returns: min_rel_dists: (list of floats) list of all minimum relative distances (i.e., for all sites). """ vire = ValenceIonicRadiusEvaluator(s) min_rel_dists = [] for site in vire.structure: min_rel_dists.append(min([dist / ( vire.radii[site.species_string] + vire.radii[neigh.species_string]) for neigh, dist in \ vire.structure.get_neighbors(site, cutoff)])) return min_rel_dists[:]
def apply_transformation(self, structure, return_ranked_list=False): """ :param structure: :param return_ranked_list (Logical or integer): Use big enough number to return all defect structures :return: scs: Supercells with one interstitial defect in each structure. """ if not return_ranked_list: raise ValueError("InterstitialTransformation has no single best " "structure output. Must use return_ranked_list.") try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if self.radii: inter = Interstitial(structure, self.valences, self.radii) else: s = structure.copy() valrad_eval = ValenceIonicRadiusEvaluator(s) s = valrad_eval.structure val = valrad_eval.valences rad = valrad_eval.radii inter = Interstitial(s, val, rad, oxi_state=True) scs = inter.make_supercells_with_defects(self.supercell_dim, self.inter_specie) #if num_to_return < len(scs)-1: # raise ValueError("InterstitialTransformation has no ordering " # "of best structures. Must increase return_ranked_list.") structures = [] num_to_return = min(num_to_return, len(scs) - 1) for sc in scs[1:num_to_return + 1]: structures.append({'structure': sc}) return structures
def vac_antisite_def_struct_gen(c_size=15, mpid='', struct=None): def_str = [] if struct == None: with MPRester() as mp: struct = mp.get_structure_by_material_id(mpid) if mpid == '': print("Provide structure") dim1 = int((float(c_size) / float(max(abs(struct.lattice.matrix[0]))))) + 1 dim2 = int(float(c_size) / float(max(abs(struct.lattice.matrix[1])))) + 1 dim3 = int(float(c_size) / float(max(abs(struct.lattice.matrix[2])))) + 1 cellmax = max(dim1, dim2, dim3) prim_struct_sites = len(struct.sites) struct = SpacegroupAnalyzer(struct).get_conventional_standard_structure() conv_struct_sites = len(struct.sites) conv_prim_rat = 1 + int(conv_struct_sites / prim_struct_sites) sc_scale = [dim1, dim2, dim3] print("sc_scale", sc_scale) struct_valrad_eval = ValenceIonicRadiusEvaluator(struct) val = struct_valrad_eval.valences rad = struct_valrad_eval.radii struct_val = val struct_rad = rad vac = Vacancy(struct, {}, {}) scs = vac.make_supercells_with_defects(sc_scale) #print ('scssssss',scs[0].make_supercell([1,1,1])) for i in range(len(scs)): sc = scs[i] mpvis = MPRelaxSet(sc) #VaspInputSet(struct) #print ('sccccc',sc,type(sc[0])) tmp = struct.copy() poscar = mpvis.poscar #kpoints = Kpoints.automatic_density(sc,kpoint_den) #incar = mpvis.get_incar(sc) #print ('big pos',poscar) interdir = mpid if not i: fin_dir = os.path.join(interdir, 'bulk') poscar.comment = str('bulk') + str('@') + str('cellmax') + str( cellmax) def_str.append(poscar) poscar.write_file('POSCAR-' + str('bulk') + str(".vasp")) else: blk_str_sites = set(scs[0].sites) vac_str_sites = set(sc.sites) vac_sites = blk_str_sites - vac_str_sites vac_site = list(vac_sites)[0] site_mult = int( vac.get_defectsite_multiplicity(i - 1) / conv_prim_rat) vac_site_specie = vac_site.specie vac_symbol = vac_site.specie.symbol vac_dir = 'vacancy_{}_mult-{}_sitespecie-{}'.format( str(i), site_mult, vac_symbol) fin_dir = os.path.join(interdir, vac_dir) try: poscar.comment = str(vac_dir) + str('@') + str( 'cellmax') + str(cellmax) except: pass pos = poscar def_str.append(pos) poscar.write_file('POSCAR-' + str(vac_dir) + str(".vasp")) struct_species = scs[0].types_of_specie for specie in set(struct_species) - set([vac_site_specie]): subspecie_symbol = specie.symbol anti_struct = sc.copy() anti_struct.append(specie, vac_site.frac_coords) mpvis = MPRelaxSet(anti_struct) #VaspInputSet(struct) print('anti_struct', anti_struct) poscar = mpvis.poscar as_dir = 'antisite_{}_mult-{}_sitespecie-{}_subspecie-{}'.format( str(i), site_mult, vac_symbol, subspecie_symbol) fin_dir = os.path.join(interdir, as_dir) poscar.comment = str(as_dir) + str('@') + str('cellmax') + str( cellmax) pos = poscar def_str.append(pos) poscar.write_file('POSCAR-' + str(as_dir) + str(".vasp")) return def_str
def vac_antisite_def_struct_gen(c_size=15, mpid='', struct=None, write_file=True): """ Vacancy, antisite generator Args: c_size: cell size struct: Structure object or mpid: materials project id Returns: def_str: defect structures in Poscar object format """ def_str = [] if struct == None: with MPRester() as mp: struct = mp.get_structure_by_material_id(mpid) if mpid == '': print("Provide structure") c_size = c_size dim1 = int((float(c_size) / float(max(abs(struct.lattice.matrix[0]))))) + 1 dim2 = int(float(c_size) / float(max(abs(struct.lattice.matrix[1])))) + 1 dim3 = int(float(c_size) / float(max(abs(struct.lattice.matrix[2])))) + 1 cellmax = max(dim1, dim2, dim3) prim_struct_sites = len(struct.sites) struct = SpacegroupAnalyzer(struct).get_conventional_standard_structure() conv_struct_sites = len(struct.sites) conv_prim_rat = int(conv_struct_sites / prim_struct_sites) sc_scale = [dim1, dim2, dim3] print("sc_scale", sc_scale) struct_valrad_eval = ValenceIonicRadiusEvaluator(struct) val = struct_valrad_eval.valences rad = struct_valrad_eval.radii struct_val = val struct_rad = rad vac = Vacancy(struct, {}, {}) scs = vac.make_supercells_with_defects(sc_scale) for i in range(len(scs)): sc = scs[i] poscar = Poscar(sc) #mpvis.get_poscar(sc) interdir = mpid if not i: fin_dir = os.path.join(interdir, 'bulk') poscar.comment = str('bulk') + str('@') + str('cellmax') + str( cellmax) def_str.append(poscar) if write_file == True: poscar.write_file('POSCAR-' + str('bulk') + str(".vasp")) else: blk_str_sites = set(scs[0].sites) vac_str_sites = set(sc.sites) vac_sites = blk_str_sites - vac_str_sites vac_site = list(vac_sites)[0] site_mult = int( vac.get_defectsite_multiplicity(i - 1) / conv_prim_rat) vac_site_specie = vac_site.specie vac_symbol = vac_site.specie.symbol vac_dir = 'vacancy_{}_mult-{}_sitespecie-{}'.format( str(i), site_mult, vac_symbol) fin_dir = os.path.join(interdir, vac_dir) try: poscar.comment = str(vac_dir) + str('@') + str( 'cellmax') + str(cellmax) except: pass pos = poscar def_str.append(pos) if write_file == True: poscar.write_file('POSCAR-' + str(vac_dir) + str(".vasp")) struct_species = scs[0].types_of_specie for specie in set(struct_species) - set([vac_site_specie]): subspecie_symbol = specie.symbol anti_struct = sc.copy() anti_struct.append(specie, vac_site.frac_coords) poscar = Poscar(anti_struct) as_dir = 'antisite_{}_mult-{}_sitespecie-{}_subspecie-{}'.format( str(i), site_mult, vac_symbol, subspecie_symbol) fin_dir = os.path.join(interdir, as_dir) poscar.comment = str(as_dir) + str('@') + str('cellmax') + str( cellmax) pos = poscar def_str.append(pos) if write_file == True: poscar.write_file('POSCAR-' + str(as_dir) + str(".vasp")) return def_str
def vac_antisite_def_struct_gen(c_size=15,mpid='',struct=None): """ Vacancy, antisite generator Args: c_size: cell size struct: Structure object or mpid: materials project id Returns: def_str: defect structures in Poscar object format """ def_str=[] if struct ==None: with MPRester() as mp: struct = mp.get_structure_by_material_id(mpid) if mpid == '': print ("Provide structure") c_size=c_size dim1=int((float(c_size)/float( max(abs(struct.lattice.matrix[0])))))+1 dim2=int(float(c_size)/float( max(abs(struct.lattice.matrix[1]))))+1 dim3=int(float(c_size)/float( max(abs(struct.lattice.matrix[2]))))+1 cellmax=max(dim1,dim2,dim3) #print ("in vac_def cellmax=",cell prim_struct_sites = len(struct.sites) struct = SpacegroupAnalyzer(struct).get_conventional_standard_structure() conv_struct_sites = len(struct.sites) conv_prim_rat = int(conv_struct_sites/prim_struct_sites) #sc_scale = get_sc_scale(struct,cellmax) sc_scale=[dim1,dim2,dim3] #sc_scale=[cellmax,cellmax,cellmax] print ("sc_scale",sc_scale) #mpvis = MITRelaxSet #MPGGAVaspInputSet() # Begin defaults: All default settings. #blk_vasp_incar_param = {'IBRION':-1,'EDIFF':1e-4,'EDIFFG':0.001,'NSW':0,} #def_vasp_incar_param = {'ISIF':2,'NELM':99,'IBRION':2,'EDIFF':1e-6, # 'EDIFFG':0.001,'NSW':40,} #kpoint_den = 6000 # End defaults #ptcr_flag = True #try: # potcar = mpvis.get_potcar(struct) #except: # print ("VASP POTCAR folder not detected.\n" \ # "Only INCAR, POSCAR, KPOINTS are generated.\n" \ # "If you have VASP installed on this system, \n" \ # "refer to pymatgen documentation for configuring the settings.") # ptcr_flag = False struct_valrad_eval = ValenceIonicRadiusEvaluator(struct) val = struct_valrad_eval.valences rad = struct_valrad_eval.radii struct_val = val struct_rad = rad vac = Vacancy(struct, {}, {}) scs = vac.make_supercells_with_defects(sc_scale) #site_no = scs[0].num_sites #if site_no > cellmax: # max_sc_dim = max(sc_scale) # i = sc_scale.index(max_sc_dim) # sc_scale[i] -= 1 # scs = vac.make_supercells_with_defects(sc_scale) #print ('struct',scs) for i in range(len(scs)): sc = scs[i] #print (type(sc)) poscar = Poscar(sc) #mpvis.get_poscar(sc) #kpoints = Kpoints.automatic_density(sc,kpoint_den) #incar = mpvis.get_incar(sc) #if ptcr_flag: # potcar = mpvis.get_potcar(sc) interdir = mpid if not i: fin_dir = os.path.join(interdir,'bulk') #try: # os.makedirs(fin_dir) #except: # pass #incar.update(blk_vasp_incar_param) #incar.write_file(os.path.join(fin_dir,'INCAR')) #poscar.write_file(os.path.join(fin_dir,'POSCAR')) poscar.comment=str('bulk')+str('@')+str('cellmax')+str(cellmax) def_str.append(poscar) poscar.write_file('POSCAR-'+str('bulk')+str(".vasp")) #if ptcr_flag: # potcar.write_file(os.path.join(fin_dir,'POTCAR')) #kpoints.write_file(os.path.join(fin_dir,'KPOINTS')) else: blk_str_sites = set(scs[0].sites) vac_str_sites = set(sc.sites) vac_sites = blk_str_sites - vac_str_sites vac_site = list(vac_sites)[0] site_mult = int(vac.get_defectsite_multiplicity(i-1)/conv_prim_rat) #try: # site_mult = int(vac.get_defectsite_multiplicity(i-1)/conv_prim_rat) #except: # site_mult=1 # pass vac_site_specie = vac_site.specie vac_symbol = vac_site.specie.symbol vac_dir ='vacancy_{}_mult-{}_sitespecie-{}'.format(str(i), site_mult, vac_symbol) fin_dir = os.path.join(interdir,vac_dir) #try: # os.makedirs(fin_dir) #except: # pass #incar.update(def_vasp_incar_param) try: poscar.comment=str(vac_dir)+str('@')+str('cellmax')+str(cellmax) except: pass pos=poscar #pos=poscar.structure def_str.append(pos) #poscar.write_file(os.path.join(fin_dir,'POSCAR')) poscar.write_file('POSCAR-'+str(vac_dir)+str(".vasp")) #incar.write_file(os.path.join(fin_dir,'INCAR')) #if ptcr_flag: # potcar.write_file(os.path.join(fin_dir,'POTCAR')) #kpoints.write_file(os.path.join(fin_dir,'KPOINTS')) # Antisite generation at all vacancy sites struct_species = scs[0].types_of_specie for specie in set(struct_species)-set([vac_site_specie]): subspecie_symbol = specie.symbol anti_struct = sc.copy() anti_struct.append(specie, vac_site.frac_coords) poscar = Poscar(anti_struct) #incar = mpvis.get_incar(anti_struct) #incar.update(def_vasp_incar_param) as_dir ='antisite_{}_mult-{}_sitespecie-{}_subspecie-{}'.format( str(i), site_mult, vac_symbol, subspecie_symbol) fin_dir = os.path.join(interdir,as_dir) #try: # os.makedirs(fin_dir) #except: # pass poscar.comment=str(as_dir)+str('@')+str('cellmax')+str(cellmax) pos=poscar #pos=poscar.structure def_str.append(pos) #poscar.write_file(os.path.join(fin_dir,'POSCAR')) poscar.write_file('POSCAR-'+str(as_dir)+str(".vasp")) #incar.write_file(os.path.join(fin_dir,'INCAR')) #if ptcr_flag: # potcar.write_file(os.path.join(fin_dir,'POTCAR')) #kpoints.write_file(os.path.join(fin_dir,'KPOINTS')) #try: # struct.make_supercell(sc_scale) # intl = Interstitial(struct, val, rad) # cell_arr=sc_scale # for el in struct.composition.elements: # scs = intl.make_supercells_with_defects(1,el) # #scs = intl.make_supercells_with_defects(cell_arr,el) # for i in range(1,len(scs)): # pos=Poscar(scs[i]) # pos.comment=str('intl_')+str('cellmax')+str(cellmax)+str('@')+str(intl.get_defectsite_coordination_number(i-1))+str('Element')+str(el) # def_str.append(pos) # pos.write_file('POSCAR-'+str('intl_')+str('cellmax')+str(cellmax)+str('@')+str(intl.get_defectsite_coordination_number(i-1))+str('Element')+str(el)) #except: # pass return def_str
def get_neighbors_of_site_with_index(struct, n, p=None): """ Determine the neighbors around the site that has index n in the input Structure object struct, given the approach defined by parameters p. All supported neighbor-finding approaches and listed and explained in the following. All approaches start by creating a tentative list of neighbors using a large cutoff radius defined in parameter dictionary p via key "cutoff". "min_dist": find nearest neighbor and its distance d_nn; consider all neighbors which are within a distance of d_nn * (1 + delta), where delta is an additional parameter provided in the dictionary p via key "delta". "scaled_VIRE": compute the radii, r_i, of all sites on the basis of the valence-ionic radius evaluator (VIRE); consider all neighbors for which the distance to the central site is less than the sum of the radii multiplied by an a priori chosen parameter, delta, (i.e., dist < delta * (r_central + r_neighbor)). "min_relative_VIRE": same approach as "min_dist", except that we use relative distances (i.e., distances divided by the sum of the atom radii from VIRE). "min_relative_OKeeffe": same approach as "min_relative_VIRE", except that we use the bond valence parameters from O'Keeffe's bond valence method (J. Am. Chem. Soc. 1991, 3226-3229) to calculate relative distances. Args: struct (Structure): input structure. n (int): index of site in Structure object for which neighbors are to be determined. p (dict): specification (via "approach" key; default is "min_dist") and parameters of neighbor-finding approach. Default cutoff radius is 6 Angstrom (key: "cutoff"). Other default parameters are as follows. min_dist: "delta": 0.15; min_relative_OKeeffe: "delta": 0.05; min_relative_VIRE: "delta": 0.05; scaled_VIRE: "delta": 2. Returns: ([site]) list of sites that are considered to be nearest neighbors to site with index n in Structure object struct. """ warnings.warn( 'This function will be removed as soon as the equivalent function in Pymatgen works with the new near neighbor-finding classes.') sites = [] if p is None: p = {"approach": "min_dist", "delta": 0.1, "cutoff": 6} if p["approach"] not in [ "min_relative_OKeeffe", "min_dist", "min_relative_VIRE", \ "scaled_VIRE"]: raise RuntimeError("Unsupported neighbor-finding approach" " (\"{}\")".format(p["approach"])) if p["approach"] == "min_relative_OKeeffe" or p["approach"] == "min_dist": neighs_dists = struct.get_neighbors(struct[n], p["cutoff"]) try: eln = struct[n].specie.element except: eln = struct[n].species_string elif p["approach"] == "scaled_VIRE" or p["approach"] == "min_relative_VIRE": vire = ValenceIonicRadiusEvaluator(struct) if np.linalg.norm(struct[n].coords - vire.structure[n].coords) > 1e-6: raise RuntimeError("Mismatch between input structure and VIRE structure.") neighs_dists = vire.structure.get_neighbors(vire.structure[n], p["cutoff"]) rn = vire.radii[vire.structure[n].species_string] reldists_neighs = [] for neigh, dist in neighs_dists: if p["approach"] == "scaled_VIRE": dscale = p["delta"] * (vire.radii[neigh.species_string] + rn) if dist < dscale: sites.append(neigh) elif p["approach"] == "min_relative_VIRE": reldists_neighs.append([dist / ( vire.radii[neigh.species_string] + rn), neigh]) elif p["approach"] == "min_relative_OKeeffe": try: el2 = neigh.specie.element except: el2 = neigh.species_string reldists_neighs.append([dist / get_okeeffe_distance_prediction( eln, el2), neigh]) elif p["approach"] == "min_dist": reldists_neighs.append([dist, neigh]) if p["approach"] == "min_relative_VIRE" or \ p["approach"] == "min_relative_OKeeffe" or \ p["approach"] == "min_dist": min_reldist = min([reldist for reldist, neigh in reldists_neighs]) for reldist, neigh in reldists_neighs: if reldist / min_reldist < 1.0 + p["delta"]: sites.append(neigh) return sites
def inject_ions(structure, ion, atomic_fraction): """ Adds ions to a percentage of interstitial sites into a structure that results in an at% less than or equal to the specified atomic_fraction. Starts by filling interstitial sites with the largest voronoi radius, and then works downward. Args: structure (Structure): Pymatgen Structure object to intercalate into. ion (str): name of atom to intercalate, e.g. 'Li', or 'Mg'. atomic_fraction (int): This fraction of the final intercalated structure will be intercalated atoms. Must be < 1.0. Returns: structure. Includes intercalated atoms. """ specie = Element(ion) # If the structure isn't big enough to accomodate such a small # atomic fraction, multiply it in the x direction. n_ions = 1. while not n_ions / structure.num_sites <= atomic_fraction: structure.make_supercell([2, 1, 1]) evaluator = ValenceIonicRadiusEvaluator(structure) interstitial = Interstitial(structure, radii=evaluator.radii, valences=evaluator.valences) interstitial_sites = [ (site._fcoords, site.properties.get('voronoi_radius', None)) for site in interstitial._defect_sites] # Sort the interstitial sites by their voronoi radii. interstitial_sites.sort(key=operator.itemgetter(1)) interstitial_sites.reverse() i = 0 while n_ions / (structure.num_sites + 1) <= atomic_fraction: try: structure.append(species=specie, coords=interstitial_sites[i][0], validate_proximity=True) n_ions += 1 i += 1 evaluator = ValenceIonicRadiusEvaluator(structure) interstitial = Interstitial(structure, radii=evaluator.radii, valences=evaluator.valences) interstitial_sites = [ (site._fcoords, site.properties.get('voronoi_radius', None)) for site in interstitial._defect_sites] # Sort the interstitial sites by their voronoi radii. interstitial_sites.sort(key=operator.itemgetter(1)) interstitial_sites.reverse() except ValueError: i += 1 except IndexError: raise ValueError('The atomic_fraction specified exceeds the ' 'number of available interstitial sites in this ' 'structure. Please choose a smaller ' 'atomic_fraction.') return structure
def __init__( self, settings_obj, ): self.settings_obj = settings_obj try: if self.settings_obj.poscar_path: self.structure = Structure.from_file( self.settings_obj.poscar_path) else: self.structure = Structure.from_file('POSCAR') except FileNotFoundError as e: print(e) print( 'The given filepath for the poscar did not find a poscar file, ensure POSCAR is at the end ' 'e.g. /POSCAR. if no filepath was given then no poscar was found in the current directory.' ) self.no_ions = int(self.settings_obj.int_dens * self.structure.num_sites) try: if self.settings_obj.locpot_path: self.vasp_pot, self.NGX, self.NGY, self.NGZ, self.lattice = md.read_vasp_density( self.settings_obj.locpot_path) else: self.vasp_pot, self.NGX, self.NGY, self.NGZ, self.lattice = md.read_vasp_density( 'LOCPOT') self.grid_pot, self.electrons = md.density_2_grid( self.vasp_pot, self.NGX, self.NGY, self.NGZ) # generate the grid of potentials except FileNotFoundError as e: print(e) print( 'The given filepath for the locpot did not find a locpot file, ensure LOCPOT is at the end ' 'e.g. /LOCPOT. if no filepath was given then no locpot was found in the current directory.' ) # then run as normal, once voronoi done and cells found, convert back and carry on if not self.check_orthog_lat(): print('exiting prog') sys.exit() self.find_vacuums( ) #this changes structure to one without vacuum. copies the old structure as self.orig_struct self.evaluator = ValenceIonicRadiusEvaluator( self.structure ) #computes site valence and ionic radii using bond valence analyser. # note this uses the sites, periodic table, bond valence, composition and local env packages! (as well as structure) self.radii = self.evaluator.radii self.valences = self.evaluator.valences self.interstitial = Interstitial( self.structure, radii=self.radii, valences=self.valences, symmetry_flag=self.settings_obj.sym_dist) # this evaluates the structure and uses radii and valence to generate voronoi sites depending on whether vertex, # facecenter or edge center is selected. # note: not sur eif hsould set oxi_state = False. By default it is true and it then uses ionic radii in the calculation, # shouldnt really change centres? Returns and interstitial object. ._defect_sites returns the coordinates and labels of # all intersittial sites which were found from the voronoi nodes/edges/faces/all depending on settings. # sym if False so we get all sites, including symmetry inequivalent sites! print('\n') self.interstitial_sites = [ ([site._fcoords[0], site._fcoords[1], site._fcoords[2]], site.properties.get('voronoi_radius', None)) for site in self.interstitial._defect_sites ] # this creates a list of tuples: [ (array of site location # fractional coordinates, Voronoi radius') ] # replaced with self.get_nearest_neighbour_dist(site) # shift vornoi up if shifted! self.interstitial_sites = [ ([ i[0][0] * self.structure.lattice.a - self.downwards_shifts[0][0], i[0][1] * self.structure.lattice.b - self.downwards_shifts[1][1], i[0][2] * self.structure.lattice.c - self.downwards_shifts[2][2] ], i[1]) for i in self.interstitial_sites ] #shift it and convert to cart coords at the same time # go back to the original, unshifted structure self.shifted_structure = self.structure.copy() self.structure = self.orig_struct.copy() self.interstitial_sites = [([ i[0][0] / self.structure.lattice.a, i[0][1] / self.structure.lattice.b, i[0][2] / self.structure.lattice.c ], i[1]) for i in self.interstitial_sites ] # convert it back to fractional coords