def _get_ionic_radii(self): """ Computes ionic radii of elements for all sites in the structure. If valence is zero, atomic radius is used. """ radii = [] coord_finder = VoronoiCoordFinder(self._structure) def nearest_key(sorted_vals, key): i = bisect_left(sorted_vals, key) if i == len(sorted_vals): i = -1 return sorted_vals[i] for i in range(len(self._structure.sites)): site = self._structure.sites[i] el = site.specie.symbol oxi_state = int(round(site.specie.oxi_state)) coord_no = int(round(coord_finder.get_coordination_number(i))) try: tab_oxi_states = map(int, _ion_radii[el].keys()) tab_oxi_states.sort() oxi_state = nearest_key(tab_oxi_states, oxi_state) radius = _ion_radii[el][str(oxi_state)][str(coord_no)] except KeyError: if coord_finder.get_coordination_number(i)-coord_no > 0: new_coord_no = coord_no + 1 else: new_coord_no = coord_no - 1 try: radius = _ion_radii[el][str(oxi_state)][str(new_coord_no)] coord_no = new_coord_no except: tab_coords = map(int, _ion_radii[el][str(oxi_state)].keys()) tab_coords.sort() new_coord_no = nearest_key(tab_coords, coord_no) i = 0 for val in tab_coords: if val > coord_no: break i = i + 1 if i == len(tab_coords): key = str(tab_coords[-1]) radius = _ion_radii[el][str(oxi_state)][key] elif i == 0: key = str(tab_coords[0]) radius = _ion_radii[el][str(oxi_state)][key] else: key = str(tab_coords[i-1]) radius1 = _ion_radii[el][str(oxi_state)][key] key = str(tab_coords[i]) radius2 = _ion_radii[el][str(oxi_state)][key] radius = (radius1+radius2)/2 #implement complex checks later radii.append(radius) return radii
def _get_coord_no_sites_chrg(self, site): """ Compute the coordination number and coordination charge Args: site: pymatgen.core.sites.Site """ struct = self._structure.copy() struct.append(site.specie.symbol, site.frac_coords) coord_finder = VoronoiCoordFinder(struct) coord_no = coord_finder.get_coordination_number(-1) coord_sites = coord_finder.get_coordinated_sites(-1) # In some cases coordination sites to interstitials include # interstitials also. Filtering them. def no_inter(site): return not site.specie.symbol == 'X' coord_sites = filter(no_inter, coord_sites) coord_chrg = 0 for site, weight in coord_finder.get_voronoi_polyhedra(-1).items(): if not site.specie.symbol == 'X': coord_chrg += weight * self._valence_dict[site.species_string] return coord_no, coord_sites, coord_chrg
def _get_coord_no_sites_chrg(self, site): """ Compute the coordination number and coordination charge Args: site: pymatgen.core.sites.Site """ struct = self._structure.copy() struct.append(site.species_string, site.frac_coords) coord_finder = VoronoiCoordFinder(struct) coord_no = coord_finder.get_coordination_number(-1) coord_sites = coord_finder.get_coordinated_sites(-1) # In some cases coordination sites to interstitials include # interstitials also. sites_to_be_deleted = [] for i in range(len(coord_sites)): if coord_sites[i].species_string == 'X': sites_to_be_deleted.append(i) sites_to_be_deleted.reverse() # So index won't change in between for ind in sites_to_be_deleted: del coord_sites[ind] coord_chrg = 0 for site, weight in coord_finder.get_voronoi_polyhedra(-1).items(): if not site.species_string == 'X': coord_chrg += weight * self._valence_dict[site.species_string] return coord_no, coord_sites, coord_chrg
def _get_coord_no_sites_chrg(self, site): """ Compute the coordination number and coordination charge Args: site: pymatgen.core.sites.Site """ struct = self._structure.copy() struct.append(site.specie.symbol, site.frac_coords) coord_finder = VoronoiCoordFinder(struct) coord_no = coord_finder.get_coordination_number(-1) coord_sites = coord_finder.get_coordinated_sites(-1) # In some cases coordination sites to interstitials include # interstitials also. Filtering them. def no_inter(site): return not site.specie.symbol == 'X' coord_sites = filter(no_inter, coord_sites) coord_chrg = 0 for site, weight in coord_finder.get_voronoi_polyhedra(-1).items(): if not site.specie.symbol == 'X': coord_chrg += weight * self._valence_dict[site.species_string] return coord_no, coord_sites, coord_chrg
def _get_coord_no_sites_chrg(self, site): """ Compute the coordination number and coordination charge Args: site: pymatgen.core.sites.Site """ struct = self._structure.copy() struct.append(site.species_string, site.frac_coords) coord_finder = VoronoiCoordFinder(struct) coord_no = coord_finder.get_coordination_number(-1) coord_sites = coord_finder.get_coordinated_sites(-1) # In some cases coordination sites to interstitials include # interstitials also. sites_to_be_deleted = [] for i in range(len(coord_sites)): if coord_sites[i].species_string == 'X': sites_to_be_deleted.append(i) sites_to_be_deleted.reverse() # So index won't change in between for ind in sites_to_be_deleted: del coord_sites[ind] coord_chrg = 0 for site, weight in coord_finder.get_voronoi_polyhedra(-1).items(): if not site.species_string == 'X': coord_chrg += weight * self._valence_dict[site.species_string] return coord_no, coord_sites, coord_chrg
class VoronoiCoordFinderTest(unittest.TestCase): def setUp(self): filepath = os.path.join(test_dir, 'vasprun.xml') reader = Vasprun(filepath) s = reader.final_structure self.finder = VoronoiCoordFinder(s,[Element("O")]) def test_get_voronoi_polyhedra(self): self.assertEqual(len(self.finder.get_voronoi_polyhedra(0).items()),10, "Incorrect number of results returned for get_voronoi_polyhedra") def test_get_coordination_number(self): print self.finder.get_coordination_number(0) self.assertAlmostEqual(self.finder.get_coordination_number(0), 5.60588600732, 7, "Incorrect coordination number returned!") def test_get_coordinated_sites(self): self.assertEqual(len(self.finder.get_coordinated_sites(0)), 10)
def get_cn(self, poscars, diff_sp): """ A function to compute the coordinations numbers not rounded Output: cn """ n = int(diff_sp.values()[0][0])-1 cn=[] for i in range(0,len(poscars)): coord_no = VoronoiCoordFinder(poscars[i].structure) cn.append(coord_no.get_coordination_number(n)) return cn
def _coord_find(self): """ calls VoronoiCoordFinder to compute the coordination number, coordination charge """ for i in range(self.defect_count()): struct = self._structs[i].copy() coord_finder = VoronoiCoordFinder(struct) self._coord_no.append(coord_finder.get_coordination_number(-1)) self._coord_sites.append(coord_finder.get_coordinated_sites(-1)) coord_chrg = 0 for site, weight in coord_finder.get_voronoi_polyhedra(-1).items(): coord_chrg += weight * self._valence_dict[site.species_string] self._coord_charge_no.append(coord_chrg)
class VoronoiCoordFinderTest(PymatgenTest): def setUp(self): s = self.get_structure('LiFePO4') self.finder = VoronoiCoordFinder(s, [Element("O")]) def test_get_voronoi_polyhedra(self): self.assertEqual(len(self.finder.get_voronoi_polyhedra(0).items()), 8) def test_get_coordination_number(self): self.assertAlmostEqual(self.finder.get_coordination_number(0), 5.809265748999465, 7) def test_get_coordinated_sites(self): self.assertEqual(len(self.finder.get_coordinated_sites(0)), 8)
class VoronoiCoordFinderTest(PymatgenTest): def setUp(self): s = self.get_structure('LiFePO4') self.finder = VoronoiCoordFinder(s, [Element("O")]) def test_get_voronoi_polyhedra(self): self.assertEqual(len(self.finder.get_voronoi_polyhedra(0).items()), 8) def test_get_coordination_number(self): self.assertAlmostEqual(self.finder.get_coordination_number(0), 5.809265748999465, 7) def test_get_coordinated_sites(self): self.assertEqual(len(self.finder.get_coordinated_sites(0)), 8)
def _coord_find(self): """ calls VoronoiCoordFinder to compute the coordination number, coordination charge """ for i in range(self.defect_count()): struct = self._structs[i].copy() coord_finder = VoronoiCoordFinder(struct) self._coord_no.append(coord_finder.get_coordination_number(-1)) self._coord_sites.append(coord_finder.get_coordinated_sites(-1)) coord_chrg = 0 for site, weight in coord_finder.get_voronoi_polyhedra(-1).items(): coord_chrg += weight * self._valence_dict[site.species_string] self._coord_charge_no.append(coord_chrg)
def __init__(self, structure, valences, radii): """ Args: structure: pymatgen.core.structure.Structure valences: valences of elements as a dictionary radii: Radii of elements as a dictionary """ self._structure = structure self._valence_dict = valences self._rad_dict = radii # Store symmetrically distinct sites, their coordination numbers # coordinated_sites, effective charge symm_finder = SymmetryFinder(self._structure) symm_structure = symm_finder.get_symmetrized_structure() equiv_site_seq = symm_structure.equivalent_sites self._defect_sites = [] for equiv_sites in equiv_site_seq: self._defect_sites.append(equiv_sites[0]) self._vac_site_indices = [] for site in self._defect_sites: for i in range(len(self._structure.sites)): if site == self._structure[i]: self._vac_site_indices.append(i) coord_finder = VoronoiCoordFinder(self._structure) self._defectsite_coord_no = [] self._defect_coord_sites = [] for i in self._vac_site_indices: self._defectsite_coord_no.append( coord_finder.get_coordination_number(i) ) self._defect_coord_sites.append( coord_finder.get_coordinated_sites(i) ) # Store the ionic radii for the elements in the structure # (Used to computing the surface are and volume) # Computed based on valence of each element self._vac_eff_charges = None self._vol = None self._sa = None
def __init__(self, structure, valences, radii): """ Args: structure: pymatgen.core.structure.Structure valences: valences of elements as a dictionary radii: Radii of elements as a dictionary """ self._structure = structure self._valence_dict = valences self._rad_dict = radii # Store symmetrically distinct sites, their coordination numbers # coordinated_sites, effective charge symm_finder = SymmetryFinder(self._structure) symm_structure = symm_finder.get_symmetrized_structure() equiv_site_seq = symm_structure.equivalent_sites self._defect_sites = [] for equiv_sites in equiv_site_seq: self._defect_sites.append(equiv_sites[0]) self._vac_site_indices = [] for site in self._defect_sites: for i in range(len(self._structure.sites)): if site == self._structure[i]: self._vac_site_indices.append(i) coord_finder = VoronoiCoordFinder(self._structure) self._defectsite_coord_no = [] self._defect_coord_sites = [] for i in self._vac_site_indices: self._defectsite_coord_no.append( coord_finder.get_coordination_number(i)) self._defect_coord_sites.append( coord_finder.get_coordinated_sites(i)) # Store the ionic radii for the elements in the structure # (Used to computing the surface are and volume) # Computed based on valence of each element self._vac_eff_charges = None self._vol = None self._sa = None
class VoronoiCoordFinderTest(unittest.TestCase): def setUp(self): filepath = os.path.join(test_dir, 'LiFePO4.cif') parser = CifParser(filepath) s = parser.get_structures()[0] self.finder = VoronoiCoordFinder(s, [Element("O")]) def test_get_voronoi_polyhedra(self): self.assertEqual(len(self.finder.get_voronoi_polyhedra(0).items()), 8, "Incorrect number of results returned for " + "get_voronoi_polyhedra") def test_get_coordination_number(self): self.assertAlmostEqual(self.finder.get_coordination_number(0), 5.809265748999465, 7) def test_get_coordinated_sites(self): self.assertEqual(len(self.finder.get_coordinated_sites(0)), 8)
class VoronoiCoordFinderTest(unittest.TestCase): def setUp(self): filepath = os.path.join(test_dir, 'LiFePO4.cif') parser = CifParser(filepath) s = parser.get_structures()[0] self.finder = VoronoiCoordFinder(s, [Element("O")]) def test_get_voronoi_polyhedra(self): self.assertEqual( len(self.finder.get_voronoi_polyhedra(0).items()), 8, "Incorrect number of results returned for " + "get_voronoi_polyhedra") def test_get_coordination_number(self): self.assertAlmostEqual(self.finder.get_coordination_number(0), 5.809265748999465, 7) def test_get_coordinated_sites(self): self.assertEqual(len(self.finder.get_coordinated_sites(0)), 8)
def get_coordination_numbers(d): """ Helper method to get the coordination number of all sites in the final structure from a run. Args: d: Run dict generated by VaspToDbTaskDrone. Returns: Coordination numbers as a list of dict of [{"site": site_dict, "coordination": number}, ...]. """ structure = Structure.from_dict(d["output"]["crystal"]) f = VoronoiCoordFinder(structure) cn = [] for i, s in enumerate(structure.sites): try: n = f.get_coordination_number(i) number = int(round(n)) cn.append({"site": s.to_dict, "coordination": number}) except Exception: logger.error("Unable to parse coordination errors") return cn
def get_coordination_numbers(d): """ Helper method to get the coordination number of all sites in the final structure from a run. Args: d: Run dict generated by VaspToDbTaskDrone. Returns: Coordination numbers as a list of dict of [{"site": site_dict, "coordination": number}, ...]. """ structure = Structure.from_dict(d["output"]["crystal"]) f = VoronoiCoordFinder(structure) cn = [] for i, s in enumerate(structure.sites): try: n = f.get_coordination_number(i) number = int(round(n)) cn.append({"site": s.as_dict(), "coordination": number}) except Exception: logger.error("Unable to parse coordination errors") return cn
spacegroup2 = SpacegroupAnalyzer(s2) print('space group symbol of structure1:', spacegroup1.get_space_group_symbol()) print('space group number of structure1:', spacegroup1.get_space_group_number()) print('space group symbol of structure2:', spacegroup2.get_space_group_symbol()) print('space group number of structure2:', spacegroup2.get_space_group_number()) Voronoi = VoronoiCoordFinder(s2, target=None) site = s2.num_sites #print("s2[0]:",s2.sites) print("s2_cart_coords[0]", s2.cart_coords[0]) #print("s2_distance_(0,1)",s2.get_distance(0,1)) polyhedra = Voronoi.get_voronoi_polyhedra(1) coordinate = Voronoi.get_coordination_number(1) coordinate_sites = Voronoi.get_coordinated_sites(1) Voronoi_Analyzer = VoronoiAnalyzer() anay = Voronoi_Analyzer.analyze(s1, n=0) strucs = [s1, s2] anays = Voronoi_Analyzer.analyze_structures(strucs) print("Voronoi_Analyzer.analyze(s1,n=0):", anay) #plt = Voronoi_Analyzer.plot_vor_analysis(anays) relax = RelaxationAnalyzer(s1, s2) volume_change = relax.get_percentage_volume_change() lattice_parameter_changes = relax.get_percentage_lattice_parameter_changes() print('initial volume:', s1.volume) print('final volume:', s2.volume) print("percent_volume_change:", volume_change) print("percent_lattice_change:", lattice_parameter_changes) bond_dist = relax.get_percentage_bond_dist_changes(max_radius=6)
def run_task(self, fw_spec): MyDB.db_access().connect() collection = MyDB.db_access().collection(fw_spec['collection']) with open('vasp.out', 'r') as output: content = output.readlines() examine = content[-2].strip() if examine[0:3] == '1 F': chgcar = Chgcar.from_file('CHGCAR') s1 = self['struct_s1'] s2 = self['struct_s2'] relax_sites = [] for site_i, site in enumerate(s1.sites): if site.specie == fw_spec['moving_cation']: relax_sites.append(site_i) pf = NEBPathfinder(s1, s2, relax_sites=relax_sites, v=ChgcarPotential(chgcar).get_v(), n_images=8) images = pf.images doc = collection.find_one({ 'mp-id': fw_spec["mp-id"], 'pair_index': fw_spec["pair_index"] }) path = [] coordination_number = [] for image in images: struct = Structure.from_dict(doc["gamma_structure"]) site_index = image.species.index(fw_spec['moving_cation']) cation_site = image[site_index] struct.insert(0, cation_site.specie, cation_site.frac_coords, properties=cation_site.properties) path.append(image[site_index].as_dict()) voro_cn = VoronoiCoordFinder(struct) cn = voro_cn.get_coordination_number(0) coordination_number.append(cn) collection.update( { "mp-id": fw_spec["mp-id"], "pair_index": fw_spec["pair_index"] }, { "$set": { "status": "success", "CN_path": coordination_number, "path": path } }) else: collection.update( { "mp-id": fw_spec["mp-id"], "pair_index": fw_spec["pair_index"] }, {"$set": { "status": "error" }}) MyDB.db_access().close() return FWAction()
def _get_ionic_radii(self): """ Computes ionic radii of elements for all sites in the structure. If valence is zero, atomic radius is used. """ radii = [] coord_finder = VoronoiCoordFinder(self._structure) def nearest_key(sorted_vals, key): i = bisect_left(sorted_vals, key) if i == len(sorted_vals): return sorted_vals[-1] if i == 0: return sorted_vals[0] before = sorted_vals[i - 1] after = sorted_vals[i] if after - key < key - before: return after else: return before for i in range(len(self._structure.sites)): site = self._structure.sites[i] if isinstance(site.specie, Element): radius = site.specie.atomic_radius radii.append(radius) continue el = site.specie.symbol oxi_state = int(round(site.specie.oxi_state)) coord_no = int(round(coord_finder.get_coordination_number(i))) try: tab_oxi_states = map(int, _ion_radii[el].keys()) tab_oxi_states.sort() oxi_state = nearest_key(tab_oxi_states, oxi_state) radius = _ion_radii[el][str(oxi_state)][str(coord_no)] except KeyError: if coord_finder.get_coordination_number(i) - coord_no > 0: new_coord_no = coord_no + 1 else: new_coord_no = coord_no - 1 try: radius = _ion_radii[el][str(oxi_state)][str(new_coord_no)] coord_no = new_coord_no except: tab_coords = map(int, _ion_radii[el][str(oxi_state)].keys()) tab_coords.sort() new_coord_no = nearest_key(tab_coords, coord_no) i = 0 for val in tab_coords: if val > coord_no: break i = i + 1 if i == len(tab_coords): key = str(tab_coords[-1]) radius = _ion_radii[el][str(oxi_state)][key] elif i == 0: key = str(tab_coords[0]) radius = _ion_radii[el][str(oxi_state)][key] else: key = str(tab_coords[i - 1]) radius1 = _ion_radii[el][str(oxi_state)][key] key = str(tab_coords[i]) radius2 = _ion_radii[el][str(oxi_state)][key] radius = (radius1 + radius2) / 2 #implement complex checks later radii.append(radius) return radii
def get_surface_sites(self, tag=False): """ Returns the surface sites and their site indices in a dictionary. The oriented unit cell of the slab will determine the coordination number of a typical site. We use VoronoiCoordFinder to determine the coordination number of bulk sites and slab sites. Due to the pathological error resulting from some surface sites in the VoronoiCoordFinder, we assume any site that has this error is a surface site as well. This will work for elemental systems only for now. Useful for analysis involving broken bonds and for finding adsorption sites. Args: tag (bool): Option to adds site attribute "is_surfsite" (bool) to all sites of slab. Defaults to False Returns: A dictionary grouping sites on top and bottom of the slab together. {"top": [sites with indices], "bottom": [sites with indices} TODO: Is there a way to determine site equivalence between sites in a slab and sites in a bulk system? This would allow us get the coordination number of a specific site for multi-elemental systems or systems with more than one unequivalent sites This will allow us to use this for compound systems. """ from pymatgen.analysis.structure_analyzer import VoronoiCoordFinder # Get a dictionary of coordination numbers for each distinct site in the structure a = SpacegroupAnalyzer(self.oriented_unit_cell) ucell = a.get_symmetrized_structure() cn_dict = {} v = VoronoiCoordFinder(ucell) unique_indices = [equ[0] for equ in ucell.equivalent_indices] for i in unique_indices: el = ucell[i].species_string if el not in cn_dict.keys(): cn_dict[el] = [] # Since this will get the cn as a result of the weighted polyhedra, the # slightest difference in cn will indicate a different environment for a # species, eg. bond distance of each neighbor or neighbor species. The # decimal place to get some cn to be equal. cn = v.get_coordination_number(i) cn = float('%.5f' %(round(cn, 5))) if cn not in cn_dict[el]: cn_dict[el].append(cn) v = VoronoiCoordFinder(self) surf_sites_dict, properties = {"top": [], "bottom": []}, [] for i, site in enumerate(self): # Determine if site is closer to the top or bottom of the slab top = True if site.frac_coords[2] > self.center_of_mass[2] else False try: # A site is a surface site, if its environment does # not fit the environment of other sites cn = float('%.5f' %(round(v.get_coordination_number(i), 5))) if cn < min(cn_dict[site.species_string]): properties.append(True) key = "top" if top else "bottom" surf_sites_dict[key].append([site, i]) else: properties.append(False) except RuntimeError: # or if pathological error is returned, indicating a surface site properties.append(True) key = "top" if top else "bottom" surf_sites_dict[key].append([site, i]) if tag: self.add_site_property("is_surf_site", properties) return surf_sites_dict