def getInterstitials(ase_in,inter,spinpol): pmg_init = AseAtomsAdaptor.get_structure(ase_in) pmg_init2 = SpacegroupAnalyzer(pmg_init).get_conventional_standard_structure() interstitial = Interstitial(pmg_init2,None,covalent_radii) #accuracy=high breaks... os.system('cls' if os.name == 'nt' else 'clear') output = [] for i,site in enumerate(interstitial.enumerate_defectsites()): coordination = int(round(interstitial.get_defectsite_coordination_number(i))) mult = 0 # interstitial.get_defectsite_multiplicity(i) -- broken ??? insert = InsertSitesTransformation([inter],[site.coords],coords_are_cartesian=True) try: pmg_new = insert.apply_transformation(pmg_init2.copy()) ase_new = AseAtomsAdaptor.get_atoms(pmg_new) if coordination == 4: siteName='T' elif coordination == 6: siteName='O' else: siteName = '%d-fold'%coordination strname = '_%s-%s'%(inter,siteName) if spinpol: new_magmoms = [3 if e in misc.magElems else 0 for e in ase_new.get_chemical_symbols()] ase_new.set_initial_magnetic_moments(new_magmoms) output.append((ase_new,strname)) except ValueError: pass #ValueError: New site is too close to an existing site! return output
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 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 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 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 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 main(): jIDs = [x[0] for x in plotQuery(['jobid'], CONSTRAINTS)] question = "Going to add an %s interstitial to %d bulk objects.\n(y/n)--> " % ( inter, len(jIDs)) if raw_input(question).lower() in ['y', 'yes']: for j in jIDs: aseinitID = query1('aseid', 'jobid', j) aseinit = asedb.get_atoms(id=aseinitID) # Access information about previous Job / Atoms object jobinit = db2object(j) xc, pw, kptden = jobinit.xc, jobinit.pw, jobinit.kptden psp, xtol, strain = jobinit.psp, jobinit.xtol, jobinit.strain precalc, dftcode = jobinit.precalc, jobinit.dftcode nameinit = jobinit.name() structure = jobinit.structure() vacancies = jobinit.vacancies() # Create conventional PyMatGen Object pmg_init = AseAtomsAdaptor.get_structure(aseinit) pmg_init2 = SpacegroupAnalyzer( pmg_init).get_conventional_standard_structure() interstitial = Interstitial( pmg_init2, None, covalent_radii) #accuracy=high breaks... os.system('cls' if os.name == 'nt' else 'clear') for i, site in enumerate(interstitial.enumerate_defectsites()): coordination = int( round(interstitial.get_defectsite_coordination_number(i))) mult = 0 # interstitial.get_defectsite_multiplicity(i) -- broken ??? insert = InsertSitesTransformation([inter], [site.coords], coords_are_cartesian=True) pmg_new = insert.apply_transformation(pmg_init2.copy()) ase_new = AseAtomsAdaptor.get_atoms(pmg_new) ase_new.set_calculator(EMT()) emt = ase_new.get_potential_energy() if coordination == 4: siteName = 'T' elif coordination == 6: siteName = 'O' else: siteName = '%d-fold' % coordination question = ('site: %s\ncoordination: %s\nmultiplicity: %s' % (site.coords, coordination, mult) + '\ninitial ase id: %d \nxc: %s \npw: %d ' % (aseinitID, xc, pw) + '\nkptden: %f \npsp: %s\nxtol: %f\nstrain: %f' % (kptden, psp, xtol, strain) + '\nprecalc: %s \ndftcode: %s' % (precalc, dftcode) + '\n\nDoes this structure look good?\n(y/n)--> ') view(ase_new) if raw_input(question).lower() in ['y', 'yes']: if checkForDuplicates(ase_new, structure, emt): newquestion = 'What structure does this have?\n(leave blank for general triclinic case)\n--> ' structure = raw_input(newquestion) if structure is '': structure = 'triclinic' info = { 'name': nameinit + '_%s-%s' % (inter, siteName), 'emt': emt # EMT for relaxed structures useless, only relevant for deciding when to relax something , 'relaxed': False # Could always doing this be a problem? , 'comments': 'Generated from initializeHydride.py', 'parent': aseinitID, 'kind': 'bulk', 'structure': structure, 'interstitial': siteName } if vacancies is not None: info['vacancies'] = vacancies newaseid = asedb.write(ase_new, key_value_pairs=info) newjob = Job(None, 'bulkrelax', newaseid, None, None, xc, pw, kptden, psp, xtol, strain, 2 if xc == 'mBEEF' else 1, precalc, dftcode, None, None, 'initialized') insertObject(newjob)
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