def test_subset(self): sm = StructureMatcher( ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=False, allow_subset=True, ) l = Lattice.orthorhombic(10, 20, 30) s1 = Structure(l, ["Si", "Si", "Ag"], [[0, 0, 0.1], [0, 0, 0.2], [0.7, 0.4, 0.5]]) s2 = Structure(l, ["Si", "Ag"], [[0, 0.1, 0], [-0.7, 0.5, 0.4]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0, 0, 0.1])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.7, 0.4, 0.5])), 1) # test with fewer species in s2 s1 = Structure(l, ["Si", "Ag", "Si"], [[0, 0, 0.1], [0, 0, 0.2], [0.7, 0.4, 0.5]]) s2 = Structure(l, ["Si", "Si"], [[0, 0.1, 0], [-0.7, 0.5, 0.4]]) result = sm.get_s2_like_s1(s1, s2) mindists = np.min(s1.lattice.get_all_distances(s1.frac_coords, result.frac_coords), axis=0) self.assertLess(np.max(mindists), 1e-6) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0, 0, 0.1])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.7, 0.4, 0.5])), 1) # test with not enough sites in s1 # test with fewer species in s2 s1 = Structure(l, ["Si", "Ag", "Cl"], [[0, 0, 0.1], [0, 0, 0.2], [0.7, 0.4, 0.5]]) s2 = Structure(l, ["Si", "Si"], [[0, 0.1, 0], [-0.7, 0.5, 0.4]]) self.assertEqual(sm.get_s2_like_s1(s1, s2), None)
def test_find_in_coord_list_pbc(self): coords = [[0, 0, 0], [0.5, 0.5, 0.5]] test_coord = [0.1, 0.1, 0.1] self.assertFalse(find_in_coord_list_pbc(coords, test_coord)) self.assertEqual(find_in_coord_list_pbc(coords, test_coord, atol=0.15)[0], 0) test_coord = [0.99, 0.99, 0.99] self.assertEqual( find_in_coord_list_pbc(coords, test_coord, atol=0.02)[0], 0) test_coord = [-0.499, -0.499, -0.499] self.assertEqual( find_in_coord_list_pbc(coords, test_coord, atol=0.01)[0], 1)
def find_site_ce(structure, target_site): """ Returns mp_symbol of site environment of given site :param structure: (Structure) Structure containing target Site :param target_site: (Site) target Site :return: (String) mp_symbol of site coordination environment of given site """ # Find index of target_site target_isite = find_in_coord_list_pbc(structure.frac_coords, target_site.frac_coords)[0] # Set up LocalGeometryFinder s1_finder = polyfinder.LocalGeometryFinder() s1_finder.setup_structure(structure) s1_finder.setup_parameters(centering_type='standard', structure_refinement='none') # Find site environment from LocalGeometryFinder environments = s1_finder.compute_structure_environments_detailed_voronoi(only_indices=[target_isite], maximum_distance_factor=1.5) # Calculate actual site polyhedra using 'strategy' strategy = strategies.SimplestChemenvStrategy() strategy.set_structure_environments(environments) site_environment = strategy.get_site_coordination_environment(site=None, isite=target_isite) return site_environment[0]
def _get_neighbor_array(self, phonon_center_site, phonon_center_radius, mystruc, tol=1e-1): """ Get a neighbor-index array. Use program_keywords 'phonon_center_site' and 'phonon_center_radius' to limit the number of phonons calculated. Args: phonon_center_site <str>: phonon center site (coordinate) phonon_center_radius <float>: phonon center radius in Angstroms. If nonzero, all atoms in a radius around EACH site found in phonon_center_site will also be taken into account mystruc <Structure>: pymatgen Structure tol <float>: Tolerance for match-searching. """ if phonon_center_site == None: return None pcscoord = np.array(phonon_center_site.strip().split(), float) scalingsize = self.metafile.read_data("scaling_size") if not (scalingsize == None): pcscoord = np.dot(pcscoord, np.linalg.inv(self.scaleinput)) # scale = scalingsize.split('[')[1].split(']')[0] # try: # scaleinput = [int(scale.split(',')[0]),int(scale.split(',')[1]),int(scale.split(',')[2])] # input scaling size like [2,1,2] # pcscoord = pcscoord / np.array(scaleinput) # except ValueError: # input scaling matrix like [1 1 0,1 -1 0,0 0 1] # scaleinput = np.array([map(int, scale.split(',')[0].split()),map(int, scale.split(',')[1].split()),map(int, scale.split(',')[2].split())]) # pcscoord = np.dot(pcscoord, np.linalg.inv(scaleinput)) tol = float(tol) pcsarr = find_in_coord_list_pbc(mystruc.frac_coords, pcscoord, tol) uniqsites = np.unique(pcsarr) if len(uniqsites) == 0: raise MASTError( "pmgextend/structure_extensions", "No sites found for phonon centering for %s" % self.keywords["name"] ) if phonon_center_radius == None: return uniqsites nrad = float(phonon_center_radius) if nrad == 0: return uniqsites if nrad < 0: raise MASTError( "pmgextend/structure_extensions", "Phonon center radius should not be less than zero for %s!" % self.keywords["name"], ) nbtotarr = None for pcs in uniqsites: neighbors = mystruc.get_neighbors(mystruc[pcs], nrad, True) if nbtotarr == None: nbtotarr = neighbors else: np.concatenate([nbtotarr, neighbors]) nbsitelist = list() for nbr in nbtotarr: nbsitelist.append(nbr[-1]) nbsitelist = np.array(nbsitelist) alltotarr = np.concatenate([uniqsites, nbsitelist]) allsites = np.unique(alltotarr) return allsites
def test_get_s2_like_s1(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=True) l = Lattice.orthorhombic(1, 2, 3) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s1.make_supercell([2,1,1]) s2 = Structure(l, ['Si', 'Si', 'Ag'], [[0,0.1,0],[0,0.1,-0.95],[-.7,.5,.375]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.35,0.4,0.5])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.125])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.175])), 1)
def test_get_s2_like_s1(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=True) l = Lattice.orthorhombic(1, 2, 3) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s1.make_supercell([2,1,1]) s2 = Structure(l, ['Si', 'Si', 'Ag'], [[0,0.1,0],[0,0.1,-0.95],[-.7,.5,.375]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.35,0.4,0.5])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.125])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.175])), 1)
def test_subset(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=False, allow_subset=True) l = Lattice.orthorhombic(10, 20, 30) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]]) s2 = Structure(l, ['Si', 'Ag'], [[0, 0.1, 0], [-.7, .5, .4]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual( len(find_in_coord_list_pbc(result.frac_coords, [0, 0, 0.1])), 1) self.assertEqual( len(find_in_coord_list_pbc(result.frac_coords, [0.7, 0.4, 0.5])), 1) #test with fewer species in s2 s1 = Structure(l, ['Si', 'Ag', 'Si'], [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]]) s2 = Structure(l, ['Si', 'Si'], [[0, 0.1, 0], [-.7, .5, .4]]) result = sm.get_s2_like_s1(s1, s2) mindists = np.min(s1.lattice.get_all_distances(s1.frac_coords, result.frac_coords), axis=0) self.assertLess(np.max(mindists), 1e-6) self.assertEqual( len(find_in_coord_list_pbc(result.frac_coords, [0, 0, 0.1])), 1) self.assertEqual( len(find_in_coord_list_pbc(result.frac_coords, [0.7, 0.4, 0.5])), 1) #test with not enough sites in s1 #test with fewer species in s2 s1 = Structure(l, ['Si', 'Ag', 'Cl'], [[0, 0, 0.1], [0, 0, 0.2], [.7, .4, .5]]) s2 = Structure(l, ['Si', 'Si'], [[0, 0.1, 0], [-.7, .5, .4]]) self.assertEqual(sm.get_s2_like_s1(s1, s2), None)
def get_matching_coord(coord): keys = list(coord_to_species.keys()) coords = np.array(keys) for op in self.symmetry_operations: c = op.operate(coord) inds = find_in_coord_list_pbc(coords, c, atol=self._site_tolerance) # cant use if inds, because python is dumb and np.array([0]) evaluates # to False if len(inds): return keys[inds[0]] return False
def test_subset(self): sm = StructureMatcher(ltol=0.2, stol=0.3, angle_tol=5, primitive_cell=False, scale=True, attempt_supercell=False, allow_subset=True) l = Lattice.orthorhombic(10, 20, 30) s1 = Structure(l, ['Si', 'Si', 'Ag'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Ag'], [[0,0.1,0],[-.7,.5,.4]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.1])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.7,0.4,0.5])), 1) #test with fewer species in s2 s1 = Structure(l, ['Si', 'Ag', 'Si'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Si'], [[0,0.1,0],[-.7,.5,.4]]) result = sm.get_s2_like_s1(s1, s2) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0,0,0.1])), 1) self.assertEqual(len(find_in_coord_list_pbc(result.frac_coords, [0.7,0.4,0.5])), 1) #test with not enough sites in s1 #test with fewer species in s2 s1 = Structure(l, ['Si', 'Ag', 'Cl'], [[0,0,0.1],[0,0,0.2],[.7,.4,.5]]) s2 = Structure(l, ['Si', 'Si'], [[0,0.1,0],[-.7,.5,.4]]) self.assertEqual(sm.get_s2_like_s1(s1, s2), None)
def induce_defect(self, defect, coord_type, threshold): """Creates a defect, and returns the modified structure Args: defect <dict>: Defect subdictionary (single defect) of the form: {'symbol': 'cr', 'type': 'interstitial', 'coordinates': array([ 0. , 0.5, 0. ])}} coord_type <str>: cartesian or fractional threshold <float>: Threshold for finding the defect position in what may be a relaxed, imperfect structure. Returns: defected structure <Structure> """ struct_ed = self.keywords['struc_work1'].copy() symbol = defect['symbol'].title() #Cap first letter # If we have cartesian coordinates, then we convert them to fractional here. if ('cartesian' in coord_type): defect['coordinates'] = self._cart2frac( defect['coordinates'], self.keywords['struc_work1']) if (defect['type'] == 'vacancy'): self.logger.info('Creating a %s vacancy at %s' % (symbol, str(defect['coordinates']))) index = find_in_coord_list_pbc( self.keywords['struc_work1'].frac_coords, defect['coordinates'], atol=threshold) if len(index) > 1: raise MASTError( self.__class__.__name__, "Multiple indices %s found. Check structure and/or adjust threshold %s to finer tolerance for ingredient %s" % (index, threshold, self.keywords['name'])) if len(index) == 0: raise MASTError( self.__class__.__name__, "No indices found. Check structure and/or adjust threshold %s to lower tolerance for ingredient %s" % (threshold, self.keywords['name'])) struct_ed.remove_sites([index]) elif (defect['type'] == 'interstitial'): self.logger.info('Creating a %s interstitial at %s' % (symbol, str(defect['coordinates']))) struct_ed.append(symbol, defect['coordinates'], coords_are_cartesian=False, validate_proximity=True) elif (defect['type'] in ['antisite', 'substitution']): self.logger.info('Creating a %s antisite at %s' % (symbol, str(defect['coordinates']))) index = find_in_coord_list_pbc( self.keywords['struc_work1'].frac_coords, defect['coordinates'], atol=threshold) if len(index) > 1: raise MASTError( self.__class__.__name__, "Multiple indices %s found. Check structure and/or adjust threshold %s to finer tolerance for ingredient %s" % (index, threshold, self.keywords['name'])) if len(index) == 0: raise MASTError( self.__class__.__name__, "No indices found. Check structure and/or adjust threshold %s to lower tolerance for ingredient %s" % (threshold, self.keywords['name'])) struct_ed.replace(index, symbol) struct_ed = struct_ed.get_sorted_structure() else: raise RuntimeError('Defect type %s not supported' % defect['type']) return struct_ed
def _get_neighbor_array(self, phonon_center_site, phonon_center_radius, mystruc, tol=1e-1): """ Get a neighbor-index array. Use program_keywords 'phonon_center_site' and 'phonon_center_radius' to limit the number of phonons calculated. Args: phonon_center_site <str>: phonon center site (coordinate) phonon_center_radius <float>: phonon center radius in Angstroms. If nonzero, all atoms in a radius around EACH site found in phonon_center_site will also be taken into account mystruc <Structure>: pymatgen Structure tol <float>: Tolerance for match-searching. """ if phonon_center_site == None: return None pcscoord = np.array(phonon_center_site.strip().split(), float) scalingsize = self.metafile.read_data('scaling_size') if not (scalingsize == None): pcscoord = np.dot(pcscoord, np.linalg.inv(self.scaleinput)) #scale = scalingsize.split('[')[1].split(']')[0] #try: # scaleinput = [int(scale.split(',')[0]),int(scale.split(',')[1]),int(scale.split(',')[2])] # input scaling size like [2,1,2] # pcscoord = pcscoord / np.array(scaleinput) #except ValueError: # input scaling matrix like [1 1 0,1 -1 0,0 0 1] # scaleinput = np.array([map(int, scale.split(',')[0].split()),map(int, scale.split(',')[1].split()),map(int, scale.split(',')[2].split())]) # pcscoord = np.dot(pcscoord, np.linalg.inv(scaleinput)) tol = float(tol) pcsarr = find_in_coord_list_pbc(mystruc.frac_coords, pcscoord, tol) uniqsites = np.unique(pcsarr) if len(uniqsites) == 0: raise MASTError( "pmgextend/structure_extensions", "No sites found for phonon centering for %s" % self.keywords['name']) if phonon_center_radius == None: return uniqsites nrad = float(phonon_center_radius) if nrad == 0: return uniqsites if nrad < 0: raise MASTError( "pmgextend/structure_extensions", "Phonon center radius should not be less than zero for %s!" % self.keywords['name']) nbtotarr = None for pcs in uniqsites: neighbors = mystruc.get_neighbors(mystruc[pcs], nrad, True) if nbtotarr == None: nbtotarr = neighbors else: np.concatenate([nbtotarr, neighbors]) nbsitelist = list() for nbr in nbtotarr: nbsitelist.append(nbr[-1]) nbsitelist = np.array(nbsitelist) alltotarr = np.concatenate([uniqsites, nbsitelist]) allsites = np.unique(alltotarr) return allsites
def sort_structure_and_neb_lines(self, neblines, folderstr, images=0): """Sort the structure in an approved way: 1. Remove lines which closely match the neb moving lines in the NEB section. 2. Sort the structure by element and coordinate. 3. Prepend the NEB moving lines to their element sections. 4. Return the modified structure. Args: folderstr <str> : '00' = initial config, '0N+1' = final config, '0N' = corresponding image neblines <list> : list of NEB lines images <int> : number of images Returns: sorted structure <Structure> """ import MAST.data atol = 0.1 # Need fairly large tolerance to account for relaxation. sortedstruc = self.keywords['struc_work1'].get_sorted_structure() struct_ed = sortedstruc.copy() nebidx = list() elemstarts = self._get_element_indices(sortedstruc) for nebline in neblines: nebdict = self._parse_neb_line(nebline) temp_fin = sortedstruc.copy() temp_fin.append(nebdict['element'], nebdict['coord'][1]) temp_start = sortedstruc.copy() temp_start.append(nebdict['element'], nebdict['coord'][0]) strlist = temp_start.interpolate(temp_fin, images + 1) lastidx = strlist[0].num_sites - 1 if folderstr == '00': mycoord = nebdict['coord'][0] elif folderstr == str(images + 1).zfill(2): mycoord = nebdict['coord'][1] else: mystridx = int(folderstr) mycoord = strlist[mystridx].frac_coords[lastidx] scalingsize = self.metafile.read_data('scaling_size') if not (scalingsize == None): mycoord = np.dot(mycoord, np.linalg.inv(self.scaleinput)) #scale = scalingsize.split('[')[1].split(']')[0] #try: # scaleinput = [int(scale.split(',')[0]),int(scale.split(',')[1]),int(scale.split(',')[2])] # input scaling size like [2,1,2] # mycoord = mycoord / np.array(scaleinput) #except ValueError: # input scaling matrix like [1 1 0,1 -1 0,0 0 1] # scaleinput = np.array([map(int, scale.split(',')[0].split()),map(int, scale.split(',')[1].split()),map(int, scale.split(',')[2].split())]) # mycoord = np.dot(mycoord, np.linalg.inv(scaleinput)) indexraw = find_in_coord_list_pbc(sortedstruc.frac_coords, mycoord, atol) index = list() for indexentry in indexraw: if sortedstruc.species[indexentry] == temp_start.species[ lastidx]: index.append(indexentry) if len(index) == 0: raise MASTError( "pmgextend/structure_extensions", "No coordinate found matching %s for %s" % (mycoord, self.keywords['name'])) nebidx.append(index[0]) #only take first site? mysite = sortedstruc.sites[index[0]] myelem = MAST.data.atomic_number[mysite.species_string] struct_ed.remove_sites([index[0]]) struct_ed.insert(elemstarts[myelem], mysite.specie, mysite.frac_coords) sortedstruc = struct_ed.copy() #get new ordering if not len(nebidx) == len(neblines): raise MASTError( "pmgextend/structure_extensions", "Not all NEB lines found for %s" % self.keywords['name']) return struct_ed
def induce_defect(self, defect, coord_type, threshold): """Creates a defect, and returns the modified structure Args: defect <dict>: Defect subdictionary (single defect) of the form: {'symbol': 'cr', 'type': 'interstitial', 'coordinates': array([ 0. , 0.5, 0. ])}} coord_type <str>: cartesian or fractional threshold <float>: Threshold for finding the defect position in what may be a relaxed, imperfect structure. Returns: defected structure <Structure> """ struct_ed = self.keywords["struc_work1"].copy() symbol = defect["symbol"].title() # Cap first letter # If we have cartesian coordinates, then we convert them to fractional here. if "cartesian" in coord_type: defect["coordinates"] = self._cart2frac(defect["coordinates"], self.keywords["struc_work1"]) if defect["type"] == "vacancy": self.logger.info("Creating a %s vacancy at %s" % (symbol, str(defect["coordinates"]))) index = find_in_coord_list_pbc( self.keywords["struc_work1"].frac_coords, defect["coordinates"], atol=threshold ) if len(index) > 1: raise MASTError( self.__class__.__name__, "Multiple indices %s found. Check structure and/or adjust threshold %s to finer tolerance for ingredient %s" % (index, threshold, self.keywords["name"]), ) if len(index) == 0: raise MASTError( self.__class__.__name__, "No indices found. Check structure and/or adjust threshold %s to lower tolerance for ingredient %s" % (threshold, self.keywords["name"]), ) struct_ed.remove_sites([index]) elif defect["type"] == "interstitial": self.logger.info("Creating a %s interstitial at %s" % (symbol, str(defect["coordinates"]))) struct_ed.append(symbol, defect["coordinates"], coords_are_cartesian=False, validate_proximity=True) elif defect["type"] in ["antisite", "substitution"]: self.logger.info("Creating a %s antisite at %s" % (symbol, str(defect["coordinates"]))) index = find_in_coord_list_pbc( self.keywords["struc_work1"].frac_coords, defect["coordinates"], atol=threshold ) if len(index) > 1: raise MASTError( self.__class__.__name__, "Multiple indices %s found. Check structure and/or adjust threshold %s to finer tolerance for ingredient %s" % (index, threshold, self.keywords["name"]), ) if len(index) == 0: raise MASTError( self.__class__.__name__, "No indices found. Check structure and/or adjust threshold %s to lower tolerance for ingredient %s" % (threshold, self.keywords["name"]), ) struct_ed.replace(index, symbol) struct_ed = struct_ed.get_sorted_structure() else: raise RuntimeError("Defect type %s not supported" % defect["type"]) return struct_ed
def sort_structure_and_neb_lines(self, neblines, folderstr, images=0): """Sort the structure in an approved way: 1. Remove lines which closely match the neb moving lines in the NEB section. 2. Sort the structure by element and coordinate. 3. Prepend the NEB moving lines to their element sections. 4. Return the modified structure. Args: folderstr <str> : '00' = initial config, '0N+1' = final config, '0N' = corresponding image neblines <list> : list of NEB lines images <int> : number of images Returns: sorted structure <Structure> """ import MAST.data atol = 0.1 # Need fairly large tolerance to account for relaxation. sortedstruc = self.keywords["struc_work1"].get_sorted_structure() struct_ed = sortedstruc.copy() nebidx = list() elemstarts = self._get_element_indices(sortedstruc) for nebline in neblines: nebdict = self._parse_neb_line(nebline) temp_fin = sortedstruc.copy() temp_fin.append(nebdict["element"], nebdict["coord"][1]) temp_start = sortedstruc.copy() temp_start.append(nebdict["element"], nebdict["coord"][0]) strlist = temp_start.interpolate(temp_fin, images + 1) lastidx = strlist[0].num_sites - 1 if folderstr == "00": mycoord = nebdict["coord"][0] elif folderstr == str(images + 1).zfill(2): mycoord = nebdict["coord"][1] else: mystridx = int(folderstr) mycoord = strlist[mystridx].frac_coords[lastidx] scalingsize = self.metafile.read_data("scaling_size") if not (scalingsize == None): mycoord = np.dot(mycoord, np.linalg.inv(self.scaleinput)) # scale = scalingsize.split('[')[1].split(']')[0] # try: # scaleinput = [int(scale.split(',')[0]),int(scale.split(',')[1]),int(scale.split(',')[2])] # input scaling size like [2,1,2] # mycoord = mycoord / np.array(scaleinput) # except ValueError: # input scaling matrix like [1 1 0,1 -1 0,0 0 1] # scaleinput = np.array([map(int, scale.split(',')[0].split()),map(int, scale.split(',')[1].split()),map(int, scale.split(',')[2].split())]) # mycoord = np.dot(mycoord, np.linalg.inv(scaleinput)) indexraw = find_in_coord_list_pbc(sortedstruc.frac_coords, mycoord, atol) index = list() for indexentry in indexraw: if sortedstruc.species[indexentry] == temp_start.species[lastidx]: index.append(indexentry) if len(index) == 0: raise MASTError( "pmgextend/structure_extensions", "No coordinate found matching %s for %s" % (mycoord, self.keywords["name"]), ) nebidx.append(index[0]) # only take first site? mysite = sortedstruc.sites[index[0]] myelem = MAST.data.atomic_number[mysite.species_string] struct_ed.remove_sites([index[0]]) struct_ed.insert(elemstarts[myelem], mysite.specie, mysite.frac_coords) sortedstruc = struct_ed.copy() # get new ordering if not len(nebidx) == len(neblines): raise MASTError("pmgextend/structure_extensions", "Not all NEB lines found for %s" % self.keywords["name"]) return struct_ed
def get_connectivity_description_1(structure, radius=2.6, peripheral_species=None, central_species=None): """ Writes a verbal description of the connectivity between cations in a structure and does differentiate between species on different sites in the unit cell. Uses the Chemenv module in Pymatgen to calculate the coordination environment for specific sites. :param structure: (Structure) target Structure :param radius: (float) radius within which to determine whether a nearby atom is a peripheral ion :param peripheral_species: (List of Strings) list of species strings of what we consider the peripheral species of the polyhedra in the structure :param central_species: (List of Strings) list of species strings of what we consider the central species of the polyhedra in the structure :return: (dict) dictionary of strings containing verbal descriptions of connectivites between cations in the given structure; keys = cation tag (eg: Li1, Na2, where the letters represent the species and the number distinguishes the species from the other instances of that same species in the unit cell); dict values = String descriptions of connectivity """ if peripheral_species is None: peripheral_species = ['O2-', 'O', 'F-', 'F', 'Cl-', 'Cl', 'I-', 'I', 'Br-', 'Br', 'S2-', 'S', 'N', 'N3-'] if central_species is None: central_species = [] connectivity_matrix, all_polyhedra, supercell = \ get_connectivity_matrix(structure, True, radius, peripheral_species, central_species) lgf = polyfinder.LocalGeometryFinder() lgf.setup_parameters(centering_type='standard', structure_refinement='none') lgf.setup_structure(supercell) environments = lgf.compute_structure_environments_detailed_voronoi(maximum_distance_factor=1.5) light_se = se.LightStructureEnvironments(strategies.SimplestChemenvStrategy(), environments) path_to_jsons = os.path.dirname(cg_files.__file__) descriptions = {} for cation_1 in connectivity_matrix.keys(): descriptions[cation_1] = "" for cation_1 in connectivity_matrix.keys(): example_poly1 = get_ex_poly(all_polyhedra, cation_1) target_isite1 = find_in_coord_list_pbc(supercell.frac_coords, example_poly1.central_ion.frac_coords)[0] print supercell[target_isite1] print light_se._coordination_environments site_environment1 = light_se._coordination_environments[target_isite1]['ce_symbol'] with open(path_to_jsons+"/%s.json" % site_environment1) as json_file: data1 = json.load(json_file) cn1 = data1['name'] descriptions[cation_1] += cation_1 + " are " + cn1 + ". \n" for cation_2 in connectivity_matrix[cation_1].keys(): connected = False for connectivity_type in connectivity_matrix[cation_1][cation_2].keys(): if connectivity_matrix[cation_1][cation_2][connectivity_type] != 0: connected = True if connected: descriptions[cation_1] += "They are " first = True for connectivity_type in connectivity_matrix[cation_1][cation_2].keys(): if connectivity_matrix[cation_1][cation_2][connectivity_type] != 0: if first: descriptions[cation_1] += connectivity_type + "-connected " first = False else: descriptions[cation_1] += "and " + connectivity_type + "-connected " example_poly2 = get_ex_poly(all_polyhedra, cation_1) target_isite2 = find_in_coord_list_pbc(supercell.frac_coords, example_poly2.central_ion.frac_coords)[0] print supercell[target_isite2] print light_se._coordination_environments site_environment2 = light_se._coordination_environments[target_isite2]['ce_symbol'] with open(path_to_jsons+"/%s.json" % site_environment2) as json_file: data2 = json.load(json_file) cn2 = data2['name'] descriptions[cation_1] += "to " + cn2 + " " + cation_2 + ". " return descriptions