Пример #1
0
    def from_bulk_and_miller(cls, structure, miller_index, min_slab_size=5.0,
                             min_vacuum_size=10.0, max_normal_search=None, 
                             center_slab = True, selective_dynamics=False,
                             undercoord_threshold = 0.09):
        """
        This method constructs the adsorbate site finder from a bulk 
        structure and a miller index, which allows the surface sites 
        to be determined from the difference in bulk and slab coordination, 
        as opposed to the height threshold.
        
        Args:
            structure (Structure): structure from which slab
                input to the ASF is constructed
            miller_index (3-tuple or list): miller index to be used
            min_slab_size (float): min slab size for slab generation
            min_vacuum_size (float): min vacuum size for slab generation
            max_normal_search (int): max normal search for slab generation
            center_slab (bool): whether to center slab in slab generation
            selective dynamics (bool): whether to assign surface sites
                to selective dynamics
            undercoord_threshold (float): threshold of "undercoordation"
                to use for the assignment of surface sites.  Default is
                0.1, for which surface sites will be designated if they
                are 10% less coordinated than their bulk counterpart
        """
        # TODO: for some reason this works poorly with primitive cells
        vcf_bulk = VoronoiCoordFinder(structure)
        bulk_coords = [len(vcf_bulk.get_coordinated_sites(n))
                       for n in range(len(structure))]
        struct = structure.copy(site_properties = {'bulk_coordinations':bulk_coords})
        slabs = generate_all_slabs(struct, max_index=max(miller_index), 
                                   min_slab_size=min_slab_size,
                                   min_vacuum_size=min_vacuum_size,
                                   max_normal_search = max_normal_search,
                                   center_slab = center_slab)

        slab_dict = {slab.miller_index:slab for slab in slabs}
        
        if miller_index not in slab_dict:
            raise ValueError("Miller index not in slab dict")

        this_slab = slab_dict[miller_index]

        vcf_surface = VoronoiCoordFinder(this_slab, allow_pathological=True)
        surf_props = []
        this_mi_vec = get_mi_vec(this_slab.miller_index)
        mi_mags = [np.dot(this_mi_vec, site.coords) for site in this_slab]
        average_mi_mag = np.average(mi_mags)
        for n, site in enumerate(this_slab):
            bulk_coord = this_slab.site_properties['bulk_coordinations'][n]
            slab_coord = len(vcf_surface.get_coordinated_sites(n))
            mi_mag = np.dot(this_mi_vec, site.coords)
            undercoord = (bulk_coord - slab_coord)/bulk_coord
            if undercoord > undercoord_threshold and mi_mag > average_mi_mag:
                surf_props += ['surface']
            else:
                surf_props += ['subsurface']
        new_site_properties = {'surface_properties':surf_props}
        new_slab = this_slab.copy(site_properties=new_site_properties)
        return cls(new_slab, selective_dynamics)
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
 def get_voronoi(self, poscars, diff_sp):
     """
     Known bug, solid_angle_tol = 0.5 works for Mn2O4 spinels. Needs to be checked for others.
     solid_angle_tol is the tolerance on the solid angle, bigger the angle- closer the atoms.
     """
     solid_angle_tol = 0.5
     sites = []
     n = int(diff_sp.values()[0][0])-1
     for i in range(0, len(poscars)):
         voronoi = VoronoiCoordFinder(poscars[i].structure)
         sites.append(voronoi.get_coordinated_sites(n, solid_angle_tol))
     return sites
Пример #7
0
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)
Пример #8
0
 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)
Пример #9
0
 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)
Пример #10
0
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)
Пример #11
0
    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
Пример #12
0
    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
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
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)
Пример #16
0
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)
print("percent_bond_distance_change:", bond_dist)
Пример #17
0
    def from_bulk_and_miller(cls,
                             structure,
                             miller_index,
                             min_slab_size=8.0,
                             min_vacuum_size=10.0,
                             max_normal_search=None,
                             center_slab=True,
                             selective_dynamics=False,
                             undercoord_threshold=0.09):
        """
        This method constructs the adsorbate site finder from a bulk 
        structure and a miller index, which allows the surface sites 
        to be determined from the difference in bulk and slab coordination, 
        as opposed to the height threshold.
        
        Args:
            structure (Structure): structure from which slab
                input to the ASF is constructed
            miller_index (3-tuple or list): miller index to be used
            min_slab_size (float): min slab size for slab generation
            min_vacuum_size (float): min vacuum size for slab generation
            max_normal_search (int): max normal search for slab generation
            center_slab (bool): whether to center slab in slab generation
            selective dynamics (bool): whether to assign surface sites
                to selective dynamics
            undercoord_threshold (float): threshold of "undercoordation"
                to use for the assignment of surface sites.  Default is
                0.1, for which surface sites will be designated if they
                are 10% less coordinated than their bulk counterpart
        """
        # TODO: for some reason this works poorly with primitive cells
        #       may want to switch the coordination algorithm eventually
        vcf_bulk = VoronoiCoordFinder(structure)
        bulk_coords = [
            len(vcf_bulk.get_coordinated_sites(n, tol=0.05))
            for n in range(len(structure))
        ]
        struct = structure.copy(
            site_properties={'bulk_coordinations': bulk_coords})
        slabs = generate_all_slabs(struct,
                                   max_index=max(miller_index),
                                   min_slab_size=min_slab_size,
                                   min_vacuum_size=min_vacuum_size,
                                   max_normal_search=max_normal_search,
                                   center_slab=center_slab)

        slab_dict = {slab.miller_index: slab for slab in slabs}

        if miller_index not in slab_dict:
            raise ValueError("Miller index not in slab dict")

        this_slab = slab_dict[miller_index]

        vcf_surface = VoronoiCoordFinder(this_slab, allow_pathological=True)

        surf_props, undercoords = [], []
        this_mi_vec = get_mi_vec(this_slab)
        mi_mags = [np.dot(this_mi_vec, site.coords) for site in this_slab]
        average_mi_mag = np.average(mi_mags)
        for n, site in enumerate(this_slab):
            bulk_coord = this_slab.site_properties['bulk_coordinations'][n]
            slab_coord = len(vcf_surface.get_coordinated_sites(n, tol=0.05))
            mi_mag = np.dot(this_mi_vec, site.coords)
            undercoord = (bulk_coord - slab_coord) / bulk_coord
            undercoords += [undercoord]
            if undercoord > undercoord_threshold and mi_mag > average_mi_mag:
                surf_props += ['surface']
            else:
                surf_props += ['subsurface']
        new_site_properties = {
            'surface_properties': surf_props,
            'undercoords': undercoords
        }
        new_slab = this_slab.copy(site_properties=new_site_properties)
        return cls(new_slab, selective_dynamics)