Esempio n. 1
0
def double_unit_cell(struc):
	"""
	doubling the size of the unit cell

	use case: given a perovskite structure, return the corresponding double perovskite structure

	Args: 
		struc: the input structure

	Returns:
	 	the doubled new structure
	"""
	lattice = struc.lattice.matrix
	vector_a = lattice[0] + lattice[1]
	vector_b = lattice[1] + lattice[2]
	vector_c = lattice[0] + lattice[2]
	new_lattice = Lattice([vector_a, vector_b, vector_c])
	
	#the atoms
	new_sites = []
	for site in struc.sites:
		new_sites.append(PeriodicSite(site.species_and_occu, site.coords, new_lattice, coords_are_cartesian=True))
		new_sites.append(PeriodicSite(site.species_and_occu, site.coords+lattice[0], new_lattice, coords_are_cartesian=True))

	species = []
	coords = []
	for site in new_sites:
		species.append(site.specie)
		coords.append(site.coords)

	new_struc = Structure(new_lattice, species, coords, to_unit_cell=True, coords_are_cartesian=True)
	return new_struc
Esempio n. 2
0
    def test_substitution(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]

        sub_site = PeriodicSite("Sr", struc[V_index].coords, struc.lattice, coords_are_cartesian=True)
        substitution = Substitution(struc, sub_site)

        # test generation and super cell
        sub_struc = substitution.generate_defect_structure(1)
        self.assertEqual(sub_struc.composition.as_dict(), {"V": 1, "Sr": 1, "O": 4})

        sub_struc = substitution.generate_defect_structure(2)
        self.assertEqual(sub_struc.composition.as_dict(), {"V": 15, "Sr": 1, "O": 32})

        sub_struc = substitution.generate_defect_structure(3)
        self.assertEqual(sub_struc.composition.as_dict(), {"V": 53, "Sr": 1, "O": 108})

        sub_struc = substitution.generate_defect_structure([[2., 0, 0], [0, 0, -3.], [0, 2., 0]])
        self.assertEqual(sub_struc.composition.as_dict(), {"V": 23, "O": 48, "Sr": 1})

        # test charge
        substitution = Substitution(struc, sub_site)
        sub_struc = substitution.generate_defect_structure(1)
        self.assertEqual(sub_struc.charge, 0.0)

        substitution = Substitution(struc, sub_site, charge=1.0)
        sub_struc = substitution.generate_defect_structure(1)
        self.assertEqual(sub_struc.charge, 1.0)

        substitution = Substitution(struc, sub_site, charge=-1.0)
        sub_struc = substitution.generate_defect_structure(1)
        self.assertEqual(sub_struc.charge, -1.0)

        # test multiplicity
        substitution = Substitution(struc, sub_site)
        self.assertEqual(substitution.multiplicity, 2.0)

        O_index = struc.indices_from_symbol("O")[0]
        sub_site = PeriodicSite("Sr", struc[O_index].coords, struc.lattice, coords_are_cartesian=True)
        substitution = Substitution(struc, sub_site)
        self.assertEqual(substitution.multiplicity, 4)

        # Test composition
        self.assertEqual(dict(substitution.defect_composition.as_dict()), {"V": 2, "Sr": 1, "O": 3})

        # test that structure generation doesn't break if velocities existed previously
        # (previously caused failures for structure printing)
        vel_struc = Structure( struc.lattice, struc.species, struc.frac_coords,
                               site_properties= {'velocities': [[0., 0., 0.]]*len(struc) } )
        substitution = Substitution(vel_struc, sub_site)
        sub_struc = substitution.generate_defect_structure(1)

        self.assertTrue( 'velocities' not in sub_struc.site_properties)

        # test value error raised for site not in the structure
        non_site = PeriodicSite( "Sr", struc[V_index].frac_coords - [0., 0., .1], struc.lattice)
        self.assertRaises( ValueError, Substitution, struc, non_site)
Esempio n. 3
0
 def get_period_dis(self, p1, p2):
     """
     在考虑周期性的情况下,计算两点之间的距离
     :param p1: 分数坐标,例如[0.5,0.5,0.5]
     :param p2: 分数坐标
     :return:  两点之间的距离,考虑周期性
     """
     temp_site1 = PeriodicSite('Ar', p1, self.__struc.lattice)
     temp_site2 = PeriodicSite('Ar', p2, self.__struc.lattice)
     dis = temp_site1.distance(temp_site2)
     return dis
Esempio n. 4
0
    def test_to_unit_cell(self):
        site = PeriodicSite("Fe", np.array([1.25, 2.35, 4.46]), self.lattice)
        site.to_unit_cell(in_place=True)
        val = [0.25, 0.35, 0.46]
        self.assertArrayAlmostEqual(site.frac_coords, val)

        lattice_pbc = Lattice(self.lattice.matrix, pbc=(True, True, False))
        site = PeriodicSite("Fe", np.array([1.25, 2.35, 4.46]), lattice_pbc)
        site.to_unit_cell(in_place=True)
        val = [0.25, 0.35, 4.46]
        self.assertArrayAlmostEqual(site.frac_coords, val)
Esempio n. 5
0
 def test_is_periodic_image(self):
     other = PeriodicSite("Fe", np.array([1.25, 2.35, 4.45]), self.lattice)
     self.assertTrue(self.site.is_periodic_image(other),
                     "This other site should be a periodic image.")
     other = PeriodicSite("Fe", np.array([1.25, 2.35, 4.46]), self.lattice)
     self.assertFalse(self.site.is_periodic_image(other),
                      "This other site should not be a periodic image.")
     other = PeriodicSite("Fe", np.array([1.25, 2.35, 4.45]),
                          Lattice.rhombohedral(2, 60))
     self.assertFalse(self.site.is_periodic_image(other),
                      "Different lattices should not be periodic images.")
Esempio n. 6
0
def rediscovery(migrate,vorosites,stru):
    labels = []
    recover_labels = []
    recover_state = {}
    true_recover_dis = {}
    #点类型,分别表示间隙、瓶颈、面心
    points_type = ["It","Bn","Fc"]


    for k in range(len(stru.sites)):
        site = stru.sites[k]
        label = site._atom_site_label
        if migrate not in label:
            continue
        #labels记录所有的label
        if label not in labels:
            labels.append(label)
        #recover_labels记录已恢复的label
        if label in recover_labels:
            continue

        for pts_idx, pts in enumerate (vorosites):
            cp_tag = np.ones((len(pts), ), dtype=int)
            for pt_idx, pt in enumerate (pts):
                if cp_tag[pt_idx] != -1:
                    print("mobile:",site,"label",label)
                    print("void:",pt)
                    #以Ar作为临时当前空隙的表示符号
                    tmp_site = PeriodicSite("Ar",pt,stru.lattice)
                    print(site.distance(tmp_site))

                    if site.distance(tmp_site) < 0.5:
                        #当某空隙位已与结构中的晶格位配对时,将该空隙位以及与该空隙位0.25A半径范围内的所有空隙位移除,后续不再判断。
                        recover_labels.append(label)

                        true_recover_dis[str(label)] = (points_type[pts_idx]+str(pt_idx),site.distance(tmp_site))
                        cp_tag[pt_idx] = -1
                        
                        for pt_idx2, pt2 in enumerate (pts):
                            tmp_site2 = PeriodicSite("Ar",list(pt2),stru.lattice)
                            if tmp_site.distance(tmp_site2) < 0.25:
                                cp_tag[pt_idx2] = -1
                        break

    #统计当前结构的恢复率
    recover_rate = len(recover_labels)/len(labels)
    for la in labels:
        if la in recover_labels:
            recover_state[str(la)] = True
        else:
            recover_state[str(la)] = False

    return recover_rate, recover_state, true_recover_dis
Esempio n. 7
0
 def test_distance_and_image(self):
     other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice)
     (distance, image) = self.site.distance_and_image(other_site)
     self.assertAlmostEqual(distance, 6.22494979899, 5)
     self.assertTrue(([-1, -1, -1] == image).all())
     (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0])
     self.assertAlmostEqual(distance, 19.461500456028563, 5)
     # Test that old and new distance algo give the same ans for
     # "standard lattices"
     lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
     site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice)
     site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice)
     self.assertAlmostEqual(
         get_distance_and_image_old(site1, site2)[0],
         site1.distance_and_image(site2)[0])
     lattice = Lattice.from_parameters(1, 0.01, 1, 10, 10, 10)
     site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice)
     site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice)
     self.assertTrue(
         get_distance_and_image_old(site1, site2)[0] >
         site1.distance_and_image(site2)[0])
     site2 = PeriodicSite("Fe", np.random.rand(3), lattice)
     (dist_old, jimage_old) = get_distance_and_image_old(site1, site2)
     (dist_new, jimage_new) = site1.distance_and_image(site2)
     self.assertTrue(dist_old - dist_new > -1e-8,
                     "New distance algo should give smaller answers!")
     self.assertFalse((abs(dist_old - dist_new) < 1e-8) ^
                      (jimage_old == jimage_new).all(),
                      "If old dist == new dist, images must be the same!")
     latt = Lattice.from_parameters(3.0, 4.0, 10.0, 3.0, 1.0, 2.0)
     site = PeriodicSite("Fe", [0.1, 0.1, 0.1], latt)
     site2 = PeriodicSite("Fe", [0.99, 0.99, 0.99], latt)
     (dist, img) = site.distance_and_image(site2)
     self.assertAlmostEqual(dist, 1.1304420998572722)
     self.assertEqual(list(img), [0, -1, -1])
Esempio n. 8
0
 def setUp(self):
     self.lattice = Lattice.cubic(10.0)
     self.si = Element("Si")
     self.site = PeriodicSite("Fe", [0.25, 0.35, 0.45], self.lattice)
     self.site2 = PeriodicSite({"Si": 0.5}, [0, 0, 0], self.lattice)
     self.assertEqual(self.site2.species, Composition({Element('Si'): 0.5}),
                      "Inconsistent site created!")
     self.propertied_site = PeriodicSite(Specie("Fe", 2),
                                         [0.25, 0.35, 0.45],
                                         self.lattice,
                                         properties={
                                             'magmom': 5.1,
                                             'charge': 4.2
                                         })
     self.dummy_site = PeriodicSite("X", [0, 0, 0], self.lattice)
Esempio n. 9
0
    def test_standardization(self):
        import numpy as np
        from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
        from pymatgen.core.structure import Structure
        from pymatgen.core.lattice import Lattice
        from pymatgen.core.sites import PeriodicSite
        from supercellor.supercell import standardize_cell
        import itertools

        np.random.seed(10)
        for i in range(20):
            lattice = Lattice(1 * np.eye(3) + 0.5 *
                              (np.random.random((3, 3)) - 0.5))
            sites = []
            for pos in itertools.product([-0.5, 0.5], repeat=3):
                sites.append(
                    PeriodicSite("H", pos, lattice, coords_are_cartesian=True))
            structure = Structure.from_sites(sites)
            sga = SpacegroupAnalyzer(structure)
            standardized_pymatgen = sga.get_primitive_standard_structure()

            standardized_supercellor = standardize_cell(structure, False)
            sga2 = SpacegroupAnalyzer(standardized_supercellor)
            standardized_pymatgen2 = sga.get_primitive_standard_structure()
            # Checking if I get to the same lattice when standardizing the structure standardize
            # by the supercellor. Note: standardized_pymatgen != standardized_supercellor
            # because they do not use the same algorithm
            self.assertTrue(
                ((standardized_pymatgen._lattice.matrix -
                  standardized_pymatgen2._lattice.matrix)**2).sum() < 1e-6)
            self.assertTrue(standardized_pymatgen2 == standardized_pymatgen)
Esempio n. 10
0
def assign_single(s_ori, prop, cutoffs, v_species):
    remade_sites = []
    for site, site_prop in zip(s_ori, prop):
        site_element = make_element_string(str(site.specie))
        if site_element in Fix_Charges_dict:
            # No bayers process required.
            oxi = Fix_Charges_dict[site_element]
            site_sp = make_specie_string(site_element, oxi)
            #print('site_sp:',site_sp)
        else:
            site_v_sps = []
            site_cutoffs = []
            for cutoff, v_sp in zip(cutoffs, v_species):
                if make_element_string(v_sp) == site_element:
                    site_cutoffs.append(cutoff)
                    site_v_sps.append(v_sp)

            if site_prop > cutoffs[-1]:
                site_sp = None  #site_property overflowing! We assume this is not very frequent.
                return None
            elif site_prop < cutoffs[0]:
                site_sp = v_species[0]
            else:
                for idx in range(1, len(cutoffs)):
                    if site_prop > cutoffs[idx -
                                           1] and site_prop < cutoffs[idx]:
                        site_sp = v_species[idx]
                        break

        remade_site = PeriodicSite(site_sp, site.frac_coords, site.lattice)
        #print(remade_site)
        remade_sites.append(remade_site)

    return Structure.from_sites(remade_sites)
Esempio n. 11
0
 def operate_site(site):
     new_cart = symmop.operate(site.coords)
     new_frac = self._lattice.get_fractional_coords(new_cart)
     return PeriodicSite(site.species_and_occu,
                         new_frac,
                         self._lattice,
                         properties=site.properties)
Esempio n. 12
0
    def test_methods_compatibility(self):
        import json, numpy as np, itertools, os

        from pymatgen.core.structure import Structure
        from pymatgen.core.lattice import Lattice
        from pymatgen.core.sites import PeriodicSite
        from supercellor.supercell import make_supercell

        create_new = False
        if create_new:
            lattice = Lattice(1.1 * np.eye(3) +
                              (np.random.random((3, 3)) - 0.5))
            sites = []
            for pos in itertools.product([-0.5, 0.5], repeat=3):
                sites.append(
                    PeriodicSite("H", pos, lattice, coords_are_cartesian=True))

            structure = Structure.from_sites(sites)
            counter = 1
            while True:
                fname = 'data/structure-{}.json'.format(counter)
                if os.path.exists(fname):
                    counter += 1
                else:
                    break
                if counter > 100:
                    raise Exception("Reached 100 files")
            with open(fname, 'w') as f:
                json.dump(structure.as_dict(), f)
        else:
            with open('data/structure-1.json', 'r') as f:
                d = json.load(f)
                structure = Structure.from_dict(d)

        for radius in np.linspace(1.0, 5.0, 5):
            supercell1, scale1 = make_supercell(structure,
                                                distance=radius,
                                                method='hnf',
                                                implementation='pyth',
                                                verbosity=0,
                                                wrap=True,
                                                standardize=True,
                                                do_niggli_first=False)
            # make fortran work and test:
            supercell2, scale2 = make_supercell(structure,
                                                distance=radius,
                                                method='hnf',
                                                implementation='fort',
                                                verbosity=0,
                                                wrap=True,
                                                standardize=True,
                                                do_niggli_first=False)
            for idim in range(3):
                self.assertTrue(
                    np.linalg.norm(supercell1._lattice.matrix[idim]) >= radius)
                self.assertTrue(
                    np.linalg.norm(supercell2._lattice.matrix[idim]) >= radius)
            self.assertTrue(
                abs(supercell1._lattice.volume -
                    supercell2._lattice.volume) < 1e-6)
Esempio n. 13
0
    def test_get_symmetry_operations(self):

        for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]:

            pgops = sg.get_point_group_operations()
            fracsymmops = sg.get_symmetry_operations()
            symmops = sg.get_symmetry_operations(True)
            latt = structure.lattice
            for fop, op, pgop in zip(fracsymmops, symmops, pgops):
                # translation vector values should all be 0 or 0.5
                t = fop.translation_vector * 2
                self.assertArrayAlmostEqual(t - np.round(t), 0)

                self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix)
                for site in structure:
                    newfrac = fop.operate(site.frac_coords)
                    newcart = op.operate(site.coords)
                    self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac))
                    found = False
                    newsite = PeriodicSite(site.species, newcart, latt, coords_are_cartesian=True)
                    for testsite in structure:
                        if newsite.is_periodic_image(testsite, 1e-3):
                            found = True
                            break
                    self.assertTrue(found)

                # Make sure this works for any position, not just the atomic
                # ones.
                random_fcoord = np.random.uniform(size=(3))
                random_ccoord = latt.get_cartesian_coords(random_fcoord)
                newfrac = fop.operate(random_fcoord)
                newcart = op.operate(random_ccoord)
                self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac))
Esempio n. 14
0
    def get_bone_config(self):
        """
        :return:
            a configuration that has only terminated backbones
            a pmg structure that has only terminated backbones
            a list of pmg molecules
        """

        terminated_backbone_hmols = [
            conformer_addhmol(mc.backbone,
                              joints=mc.backbone_graph.joints,
                              original=mc) for mc in self.molconformers
        ]

        backbone_sites = []
        for b in terminated_backbone_hmols:
            backbone_sites += b.sites

        boneonly_psites = [
            PeriodicSite(s.species_string,
                         s.coords,
                         self.pstructure.lattice,
                         to_unit_cell=False,
                         coords_are_cartesian=True,
                         properties=s.properties) for s in backbone_sites
        ]
        boneonly_pstructure = Structure.from_sites(boneonly_psites)
        boneonly_molconformers = [
            MolConformer.from_pmgmol(m) for m in terminated_backbone_hmols
        ]
        return Config(
            boneonly_molconformers, boneonly_pstructure,
            occu=self.occu), boneonly_pstructure, terminated_backbone_hmols
Esempio n. 15
0
    def add_oxidation_state_by_site(self, oxidation_states):
        """
        Add oxidation states to a structure by site.

        Args:
            oxidation_states:
                List of oxidation states.
                E.g., [1, 1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 5, -2, -2, -2, -2]
        """
        try:
            for i, site in enumerate(self._sites):
                new_sp = {}
                for el, occu in site.species_and_occu.items():
                    sym = el.symbol
                    new_sp[Specie(sym, oxidation_states[i])] = occu
                new_site = PeriodicSite(new_sp,
                                        site.frac_coords,
                                        self._lattice,
                                        coords_are_cartesian=False,
                                        properties=site.properties)
                self._sites[i] = new_site

        except IndexError:
            raise ValueError("Oxidation state of all sites must be "
                             "specified in the dictionary.")
Esempio n. 16
0
def from_bson_voronoi_list2(bson_nb_voro_list2, structure):
    """
    Returns the voronoi_list needed for the VoronoiContainer object from a bson-encoded voronoi_list.

    Args:
        bson_nb_voro_list2: List of periodic sites involved in the Voronoi.
        structure: Structure object.

    Returns:
        The voronoi_list needed for the VoronoiContainer (with PeriodicSites as keys of the dictionary - not
        allowed in the BSON format).
    """
    voronoi_list = [None] * len(bson_nb_voro_list2)
    for isite, voro in enumerate(bson_nb_voro_list2):
        if voro is None or voro == "None":
            continue
        voronoi_list[isite] = []
        for psd, dd in voro:
            struct_site = structure[dd["index"]]
            periodic_site = PeriodicSite(
                struct_site._species,
                struct_site.frac_coords + psd[1],
                struct_site._lattice,
                properties=struct_site.properties,
            )
            dd["site"] = periodic_site
            voronoi_list[isite].append(dd)
    return voronoi_list
Esempio n. 17
0
 def graft_coordinates_onto_structure(self, coordstruc):
     """Graft coordinates from mast_coordinates Structure objects
         onto the appropriate structure
         Args:
             coordstruc <Structure>: Structure object with
                 the coordinates for grafting
             self.keywords['struc_work1'] will contain
                 the elements and lattice parameter, which
                 will not be touched.
         Returns:
             modified Structure object <Structure>
     """
     goodstruc = self.keywords['struc_work1'].copy()
     lengoodsites = len(goodstruc.sites)
     lencoordsites = len(coordstruc.sites)
     if not (lengoodsites == lencoordsites):
         raise MASTError(
             self.__class__.__name__,
             "Original and coordinate structures do not have the same amount of sites in %s"
             % self.keywords['name'])
     cct = 0
     newsites = list()
     mylattice = goodstruc.lattice
     while cct < lengoodsites:
         newcoords = coordstruc.sites[cct].frac_coords
         oldspecie = goodstruc.sites[cct].specie
         newsite = PeriodicSite(oldspecie, newcoords, mylattice)
         newsites.append(newsite)
         cct = cct + 1
     goodstruc.remove_sites(range(0, lengoodsites))
     for cct in range(0, lengoodsites):
         goodstruc.append(newsites[cct].specie, newsites[cct].frac_coords)
     return goodstruc
Esempio n. 18
0
    def add_oxidation_state_by_element(self, oxidation_states):
        """
        Add oxidation states to a structure.

        Args:
            structure:
                pymatgen.core.structure Structure object.
            oxidation_states:
                dict of oxidation states.
                E.g., {"Li":1, "Fe":2, "P":5, "O":-2}
        """
        try:
            for i, site in enumerate(self._sites):
                new_sp = {}
                for el, occu in site.species_and_occu.items():
                    sym = el.symbol
                    new_sp[Specie(sym, oxidation_states[sym])] = occu
                new_site = PeriodicSite(new_sp,
                                        site.frac_coords,
                                        self._lattice,
                                        coords_are_cartesian=False,
                                        properties=site.properties)
                self._sites[i] = new_site

        except KeyError:
            raise ValueError("Oxidation state of all elements must be "
                             "specified in the dictionary.")
Esempio n. 19
0
    def translate_sites(self, indices, vector, frac_coords=True):
        """
        Translate specific sites by some vector, keeping the sites within the
        unit cell.

        Args:
            sites:
                List of site indices on which to perform the translation.
            vector:
                Translation vector for sites.
            frac_coords:
                Boolean stating whether the vector corresponds to fractional or
                cartesian coordinates.
        """
        for i in indices:
            site = self._sites[i]
            if frac_coords:
                fcoords = site.frac_coords + vector
            else:
                fcoords = self._lattice.get_fractional_coords(site.coords +
                                                              vector)
            new_site = PeriodicSite(site.species_and_occu,
                                    fcoords,
                                    self._lattice,
                                    to_unit_cell=True,
                                    coords_are_cartesian=False,
                                    properties=site.properties)
            self._sites[i] = new_site
Esempio n. 20
0
 def setUp(self):
     self.struc = PymatgenTest.get_structure("VO2")
     V_index = self.struc.indices_from_symbol("V")[0]
     sub_site = PeriodicSite("Sr",
                             self.struc[V_index].coords,
                             self.struc.lattice,
                             coords_are_cartesian=True)
     self.substitution = Substitution(self.struc, sub_site)
Esempio n. 21
0
    def test_vacancy(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]
        vac = Vacancy(struc, struc[V_index])

        # test generation and super cell
        vac_struc = vac.generate_defect_structure(1)
        self.assertEqual(vac_struc.composition.as_dict(), {"V": 1, "O": 4})

        vac_struc = vac.generate_defect_structure(2)
        self.assertEqual(vac_struc.composition.as_dict(), {"V": 15, "O": 32})

        vac_struc = vac.generate_defect_structure(3)
        self.assertEqual(vac_struc.composition.as_dict(), {"V": 53, "O": 108})

        vac_struc = vac.generate_defect_structure([[2.0, 0, 0], [0, 0, -3.0],
                                                   [0, 2.0, 0]])
        self.assertEqual(vac_struc.composition.as_dict(), {"V": 23, "O": 48})

        # test charge
        vac = Vacancy(struc, struc[V_index])
        vac_struc = vac.generate_defect_structure(1)
        self.assertEqual(vac_struc.charge, 0.0)

        vac = Vacancy(struc, struc[V_index], charge=1.0)
        vac_struc = vac.generate_defect_structure(1)
        self.assertEqual(vac_struc.charge, 1.0)

        vac = Vacancy(struc, struc[V_index], charge=-1.0)
        vac_struc = vac.generate_defect_structure(1)
        self.assertEqual(vac_struc.charge, -1.0)

        # test multiplicity
        vac = Vacancy(struc, struc[V_index])
        self.assertEqual(vac.multiplicity, 2)

        O_index = struc.indices_from_symbol("O")[0]
        vac = Vacancy(struc, struc[O_index])
        self.assertEqual(vac.multiplicity, 4)

        # Test composition
        self.assertEqual(dict(vac.defect_composition.as_dict()), {
            "V": 2,
            "O": 3
        })

        # test lattice value error occurs for different lattices
        sc_scaled_struc = struc.copy()
        sc_scaled_struc.make_supercell(2)
        self.assertRaises(ValueError, Vacancy, struc, sc_scaled_struc[V_index])
        self.assertRaises(ValueError, Vacancy, sc_scaled_struc, struc[V_index])

        # test value error raised for site not in the structure
        non_site = PeriodicSite("V",
                                struc[V_index].frac_coords + [0.0, 0.0, 0.1],
                                struc.lattice)
        self.assertRaises(ValueError, Vacancy, struc, non_site)
Esempio n. 22
0
    def test_interstitial(self):
        struc = PymatgenTest.get_structure("VO2")
        V_index = struc.indices_from_symbol("V")[0]

        int_site = PeriodicSite("V", struc[V_index].coords + [0.1, 0.1, 0.1], struc.lattice)
        interstitial = Interstitial(struc, int_site)

        # test generation and super cell
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 3, "O": 4})
        # Ensure the site is in the right place
        self.assertEqual(int_site, int_struc.get_sites_in_sphere(int_site.coords, 0.1)[0][0])

        int_struc = interstitial.generate_defect_structure(2)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 17, "O": 32})

        int_struc = interstitial.generate_defect_structure(3)
        self.assertEqual(int_struc.composition.as_dict(), {"V": 55, "O": 108})

        int_struc = interstitial.generate_defect_structure([[2.0, 0, 0], [0, 0, -3.0], [0, 2.0, 0]])
        self.assertEqual(int_struc.composition.as_dict(), {"V": 25, "O": 48})

        # test charge
        interstitial = Interstitial(struc, int_site)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 0.0)

        interstitial = Interstitial(struc, int_site, charge=1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, 1.0)

        interstitial = Interstitial(struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertEqual(int_struc.charge, -1.0)

        # test multiplicity
        interstitial = Interstitial(struc, int_site)
        self.assertEqual(interstitial.multiplicity, 8.0)

        # test manual setting of multiplicity
        interstitial = Interstitial(struc, int_site, multiplicity=4.0)
        self.assertEqual(interstitial.multiplicity, 4.0)

        # Test composition
        self.assertEqual(dict(interstitial.defect_composition.as_dict()), {"V": 3, "O": 4})

        # test that structure generation doesn't break if velocities existed previously
        # (previously caused failures for structure printing)
        vel_struc = Structure(
            struc.lattice,
            struc.species,
            struc.frac_coords,
            site_properties={"velocities": [[0.0, 0.0, 0.0]] * len(struc)},
        )
        interstitial = Interstitial(vel_struc, int_site, charge=-1.0)
        int_struc = interstitial.generate_defect_structure(1)
        self.assertTrue("velocities" not in int_struc.site_properties)
Esempio n. 23
0
def reduceScale(structure, scale, dim):
    """
    Attempt to reduce the structure from a supercell
    
    inputs
    --------
        structure (Structure):  Pymatgen structure object to reduce
        
        scale (float): How much to scale the periodic lattice vectors by
        
        dim (int):  The number of periodic directions in "structure"
        
        
    outputs
    --------
        new_struct (Structure): Structure object for low-dimensional material
                                with non-periodic directions being 
                                orthogonal to the periodic directions
    
    """

    structure.translate_sites(indices=range(structure.num_sites),
                              vector=-1 * structure.sites[0].frac_coords +
                              [0, 0, .5])

    specs = structure.species
    cart = [x.coords for x in structure.sites]

    lat = np.array(structure.lattice.as_dict()['matrix'])
    lat[0] *= scale
    if dim == 2 or dim == 3:
        lat[1] *= scale
    if dim == 3:
        lat[2] *= scale
    fracs = np.array(np.linalg.solve(lat.T, np.array(cart).T).T)
    specs = []
    u_cart = []
    i = 0
    for frac in fracs:
        if frac[0] < 1 and frac[1] < 1 and frac[2] < 1:
            specs.append(structure.species[i])
            u_cart.append(cart[i])
        i += 1

    new_sites = []
    i = 0
    for site in u_cart:
        p = PeriodicSite(atoms_n_occu=Element(specs[i]),
                         lattice=Lattice(lat),
                         coords=site,
                         coords_are_cartesian=True)
        new_sites.append(p)
        i += 1

    new_struct = Structure.from_sites(new_sites)

    return (new_struct)
Esempio n. 24
0
    def _get_structures(self, num_structs):
        structs = []
        rs = subprocess.Popen(
            ["makestr.x", "struct_enum.out",
             str(0),
             str(num_structs - 1)],
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            close_fds=True)
        rs.communicate()
        if len(self.ordered_sites) > 0:
            original_latt = self.ordered_sites[0].lattice
            # Need to strip sites of site_properties, which would otherwise
            # result in an index error. Hence Structure is reconstructed in
            # the next step.
            ordered_structure = Structure(
                original_latt,
                [site.species_and_occu for site in self.ordered_sites],
                [site.frac_coords for site in self.ordered_sites])
            inv_org_latt = np.linalg.inv(original_latt.matrix)

        for n in range(1, num_structs + 1):
            with open("vasp.{:06d}".format(n)) as f:
                data = f.read()
                data = re.sub("scale factor", "1", data)
                data = re.sub("(\d+)-(\d+)", r"\1 -\2", data)
                poscar = Poscar.from_string(data, self.index_species)
                sub_structure = poscar.structure
                #Enumeration may have resulted in a super lattice. We need to
                #find the mapping from the new lattice to the old lattice, and
                #perform supercell construction if necessary.
                new_latt = sub_structure.lattice

                sites = []

                if len(self.ordered_sites) > 0:
                    transformation = np.dot(new_latt.matrix, inv_org_latt)
                    transformation = [[int(round(cell)) for cell in row]
                                      for row in transformation]
                    logger.debug("Supercell matrix: {}".format(transformation))
                    s = Structure.from_sites(ordered_structure)
                    s.make_supercell(transformation)
                    sites.extend([site.to_unit_cell for site in s])
                    super_latt = sites[-1].lattice
                else:
                    super_latt = new_latt

                for site in sub_structure:
                    if site.specie.symbol != "X":  # We exclude vacancies.
                        sites.append(
                            PeriodicSite(site.species_and_occu,
                                         site.frac_coords,
                                         super_latt).to_unit_cell)
                structs.append(Structure.from_sites(sorted(sites)))

        logger.debug("Read in a total of {} structures.".format(num_structs))
        return structs
Esempio n. 25
0
    def get_defect_site(self, initdef):

        siteinds = []

        ## this is relatively simple for vacancies and substitutionals
        ## which by definition are a pre-existing site in the structure
        if initdef["type"][0] == "v" or initdef["type"][0] == "s":
            siteind = self.get_site_ind(initdef["species"], initdef["index"],
                                        initdef["index_offset_basis"],
                                        initdef["index_offset_a"],
                                        initdef["index_offset_b"])
            siteinds.append(siteind)
            defect_site = self.structure_bulk[siteind]

        ## for interstitials/adatoms, the defect site coords are defined
        ## by the center (average) of the user-provided list of sites
        elif initdef["type"][0] == "i" or initdef["type"][0] == "a":
            siteind = [
                self.get_site_ind(sp, ind, offset_basis, offset_a, offset_b)
                for sp, ind, offset_basis, offset_a, offset_b in zip(
                    initdef["species"], initdef["index"],
                    initdef["index_offset_basis"], initdef["index_offset_a"],
                    initdef["index_offset_b"])
            ]
            siteinds.append(siteind)

            ## get the averaged position
            coords_ref = self.structure_bulk[siteind[0]].frac_coords
            #            print (coords_ref)
            defect_coords = coords_ref.copy()
            for i in siteind[1:]:
                coords = self.structure_bulk[i].frac_coords
                #                print (coords,coords_ref,np.array(coords[0:3])-np.array(coords_ref[0:3]))
                for j in [0, 1, 2]:
                    ## dealing with pbc
                    if (coords[j] - coords_ref[j]) > 0.501:
                        coords[j] -= 1.0
                    elif (coords_ref[j] - coords[j]) > 0.501:
                        coords[j] += 1.0
#                print (coords)
                defect_coords += coords
            defect_coords = defect_coords / len(siteind)
            #            print (defect_coords)

            ## we may want to further shift the position manually
            M = self.structure.lattice.matrix
            defect_coords += np.dot(
                np.linalg.inv(M).T,
                [initdef["shift_x"], initdef["shift_y"], initdef["shift_z"]])

            ## create the defect_site as a PeriodicSite object
            defect_site = PeriodicSite(initdef["species_new"],
                                       defect_coords,
                                       lattice=self.structure.lattice,
                                       coords_are_cartesian=False)

        return defect_site
Esempio n. 26
0
 def apply_tags(self):
     tags = {}
     for tag in self.tags:
         istruct = tag.get('istruct', 'all')
         if istruct != 'all':
             if istruct != self.istruct:
                 continue
         site_index = tag['site_index']
         color = tag.get('color', [0.5, 0.5, 0.5])
         opacity = tag.get('opacity', 0.5)
         if site_index == 'unit_cell_all':
             struct_radii = self.all_vis_radii[self.istruct]
             for isite, site in enumerate(self.current_structure):
                 vis_radius = 1.5 * tag.get('radius', struct_radii[isite])
                 tags[(isite, (0, 0, 0))] = {
                     'radius': vis_radius,
                     'color': color,
                     'opacity': opacity
                 }
             continue
         cell_index = tag['cell_index']
         if 'radius' in tag:
             vis_radius = tag['radius']
         elif 'radius_factor' in tag:
             vis_radius = tag['radius_factor'] * self.all_vis_radii[
                 self.istruct][site_index]
         else:
             vis_radius = 1.5 * self.all_vis_radii[self.istruct][site_index]
         tags[(site_index, cell_index)] = {
             'radius': vis_radius,
             'color': color,
             'opacity': opacity
         }
     for site_and_cell_index, tag_style in tags.items():
         isite, cell_index = site_and_cell_index
         site = self.current_structure[isite]
         if cell_index == (0, 0, 0):
             coords = site.coords
         else:
             fcoords = site.frac_coords + np.array(cell_index)
             site_image = PeriodicSite(site.species,
                                       fcoords,
                                       self.current_structure.lattice,
                                       to_unit_cell=False,
                                       coords_are_cartesian=False,
                                       properties=site.properties)
             self.add_site(site_image)
             coords = site_image.coords
         vis_radius = tag_style['radius']
         color = tag_style['color']
         opacity = tag_style['opacity']
         self.add_partial_sphere(coords=coords,
                                 radius=vis_radius,
                                 color=color,
                                 start=0,
                                 end=360,
                                 opacity=opacity)
Esempio n. 27
0
def get_freysoldt_correction(defect_type, defect_specie, path_to_defect_locpot,path_to_pure_locpot,charge,
                             dielectric_constant,defect_site_coordinates,energy_cutoff=500,get_plot=False):
    
    ''' Function to perform charge corrections according to the method proposed py Freysoldt
        If this correction is used, please reference Freysoldt's original paper.
        doi: 10.1103/PhysRevLett.102.016402
        
        Args:
            defect_type: 'vacancy' or 'interstitial'
            defect_specie: string with element occupying the defect site
            path_to_defect_locpot: path to LOCPOT file of defect structure
            path_to_pure_locpot: path to LOCPOT file of Pure structure
            charge: Charge of the defected system
            dielectric_constant: Dielectric constant
            defect_site_coordinates: numpy array with fractional coordinates of defect site
            energy_cutoff: Cut-off of plane wave expansion
            get_plot: return also Matplotlib object with plot
            
        Returns:
            Freysoldt corrections values as a dictionary 
            '''
    # acquiring data from LOCPOT files    
    locpot_pure = Locpot.from_file(path_to_pure_locpot)
    vol_data_pure = VolumetricData(locpot_pure.structure,locpot_pure.data)
    
    locpot_defect = Locpot.from_file(path_to_defect_locpot)
    vol_data_defect = VolumetricData(locpot_defect.structure,locpot_defect.data)
    
    parameters = {}
    parameters['axis_grid'] = []
    parameters['bulk_planar_averages'] = []
    parameters['defect_planar_averages'] = []
    for i in range(0,3):
        parameters['axis_grid'].append(vol_data_pure.get_axis_grid(i))
        parameters['bulk_planar_averages'].append(vol_data_pure.get_average_along_axis(i))
        parameters['defect_planar_averages'].append(vol_data_defect.get_average_along_axis(i))
    parameters['initial_defect_structure'] = locpot_defect.structure
    parameters['defect_frac_sc_coords'] = defect_site_coordinates
    
    structure_bulk = locpot_pure.structure
    defect_site = PeriodicSite(defect_specie, coords=defect_site_coordinates, lattice = locpot_pure.structure.lattice)
    
    module = importlib.import_module("pymatgen.analysis.defects.core")
    defect_class = getattr(module,defect_type)
    defect = defect_class(structure_bulk, defect_site, charge=charge, multiplicity=None)
    defect_entry = DefectEntry(defect,None,corrections=None,parameters=parameters)
    
    freysoldt_class = FreysoldtCorrection(dielectric_constant,energy_cutoff=energy_cutoff)
    
    freysoldt_corrections = freysoldt_class.get_correction(defect_entry)
  
    if get_plot:
        plt = freysoldt_class.plot(1)
        return freysoldt_corrections , plt
    else:    
        return freysoldt_corrections
def nearest_atom_mine(atoms, position, nth_closest=0):
    """

    args:
      atoms:
      position:
      nth_closest: pass 0 for nearest atom, 1 for 2nd neareset and so on...
    """
    #| - nearest_atom_mine
    struct = AseAtomsAdaptor.get_structure(atoms)
    Lattice = struct.lattice

    # #########################################################
    dummy_site_j = PeriodicSite("N",
                                position,
                                Lattice,
                                to_unit_cell=False,
                                coords_are_cartesian=True,
                                properties=None,
                                skip_checks=False)

    data_dict_list = []
    for index_i, site_i in enumerate(struct):
        data_dict_i = dict()
        # site_i = struct[32]

        distance_i, image_i = site_i.distance_and_image(dummy_site_j)
        # print("distance_i:", distance_i)

        # #####################################################
        data_dict_i["atoms_index"] = int(index_i)
        data_dict_i["distance"] = distance_i
        data_dict_i["image"] = image_i
        # #####################################################
        data_dict_list.append(data_dict_i)

    # #########################################################
    df_dist = pd.DataFrame(data_dict_list)
    df_dist = df_dist.sort_values("distance")

    # #########################################################
    closest_site = df_dist.iloc[nth_closest]

    closest_index = int(closest_site.atoms_index)
    closest_distance = closest_site.distance
    image = closest_site.image

    closest_atom = atoms[closest_index]

    out_dict = dict(
        closest_atom=closest_atom,
        closest_distance=closest_distance,
        image=image,
    )
    return (out_dict)
Esempio n. 29
0
    def insert_site(self,
                    i,
                    species,
                    coords,
                    coords_are_cartesian=False,
                    validate_proximity=True,
                    properties=None):
        """
        Insert a site to the structure.

        Args:
            i:
                index to insert site
            species:
                species of inserted site
            coords:
                coordinates of inserted site
            coords_are_cartesian:
                Whether coordinates are cartesian. Defaults to False.
            validate_proximity:
                Whether to check if inserted site is too close to an existing
                site. Defaults to True.
        """
        if not coords_are_cartesian:
            new_site = PeriodicSite(species,
                                    coords,
                                    self._lattice,
                                    properties=properties)
        else:
            frac_coords = self._lattice.get_fractional_coords(coords)
            new_site = PeriodicSite(species,
                                    frac_coords,
                                    self._lattice,
                                    properties=properties)

        if validate_proximity:
            for site in self._sites:
                if site.distance(new_site) < self.DISTANCE_TOLERANCE:
                    raise ValueError("New site is too close to an existing "
                                     "site!")

        self._sites.insert(i, new_site)
Esempio n. 30
0
    def write_input(self,
                    output_dir,
                    make_dir_if_not_present=True,
                    write_cif=False,
                    write_path_cif=False,
                    write_endpoint_inputs=False):
        """
        NEB inputs has a special directory structure where inputs are in 00,
        01, 02, ....

        Args:
            output_dir (str): Directory to output the VASP input files
            make_dir_if_not_present (bool): Set to True if you want the
                directory (and the whole path) to be created if it is not
                present.
            write_cif (bool): If true, writes a cif along with each POSCAR.
            write_path_cif (bool): If true, writes a cif for each image.
            write_endpoint_inputs (bool): If true, writes input files for
                running endpoint calculations.
        """

        if make_dir_if_not_present and not os.path.exists(output_dir):
            os.makedirs(output_dir)
        self.incar.write_file(os.path.join(output_dir, 'INCAR'))
        self.kpoints.write_file(os.path.join(output_dir, 'KPOINTS'))
        self.potcar.write_file(os.path.join(output_dir, 'POTCAR'))

        for i, p in enumerate(self.poscars):
            d = os.path.join(output_dir, str(i).zfill(2))
            if not os.path.exists(d):
                os.makedirs(d)
            p.write_file(os.path.join(d, 'POSCAR'))
            if write_cif:
                p.structure.to(filename=os.path.join(d, '{}.cif'.format(i)))
        if write_endpoint_inputs:
            end_point_param = MPRelaxSet(
                self.structures[0],
                user_incar_settings=self.user_incar_settings)

            for image in ['00', str(len(self.structures) - 1).zfill(2)]:
                end_point_param.incar.write_file(
                    os.path.join(output_dir, image, 'INCAR'))
                end_point_param.kpoints.write_file(
                    os.path.join(output_dir, image, 'KPOINTS'))
                end_point_param.potcar.write_file(
                    os.path.join(output_dir, image, 'POTCAR'))
        if write_path_cif:
            sites = set()
            l = self.structures[0].lattice
            for site in chain(*(s.sites for s in self.structures)):
                sites.add(
                    PeriodicSite(site.species_and_occu, site.frac_coords, l))
            path = Structure.from_sites(sorted(sites))
            path.to(filename=os.path.join(output_dir, 'path.cif'))