Example #1
0
def test_get_uc_pos():
    errors = []

    # set up parameters to initiate get_uc_pos
    uc_lattice = mg_Li.symm_structure.lattice
    isite = [x for x in input_struct_i.sites if x.species_string == "Li"][0]
    esite = [x for x in input_struct_e.sites if x.species_string == "Li"][0]
    sm = StructureMatcher(ignored_species=[list(mg_Li.m_graph.graph.edges(data=True))[0][2]["hop"].isite.specie.name])
    wi_specie = mg_Li.symm_structure[-1].specie

    p0, p1, p2 = get_uc_pos(isite, esite, mg_Li.symm_structure, input_struct_i, sm)

    # generate correct sites to compare
    test_p0 = PeriodicSite(
        wi_specie, np.array([2.91418875, 1.02974425, 4.4933425]), uc_lattice, coords_are_cartesian=True
    )
    test_p1 = PeriodicSite(
        wi_specie, np.array([4.82950555, 1.0247028, 4.10369437]), uc_lattice, coords_are_cartesian=True
    )
    test_p2 = PeriodicSite(
        wi_specie, np.array([6.74482475, 1.01967025, 3.7140425]), uc_lattice, coords_are_cartesian=True
    )

    if not test_p0.__eq__(p0):
        errors.append("Initial site does not match")
    if not test_p1.__eq__(p1):
        errors.append("Middle site does not match")
    if not test_p2.__eq__(p2):
        errors.append("Ending site does not match")

    assert not errors, "errors occured:\n" + "\n".join(errors)
def get_uc_pos(
    isite: PeriodicSite,
    esite: PeriodicSite,
    uc: Structure,
    sc: Structure,
    sm: StructureMatcher,
) -> Tuple[PeriodicSite, PeriodicSite, PeriodicSite]:
    """Take positions in the supercel and transform into the unitcell positions

    Args:
        isite: initial site in the SC
        esite: ending site in the SC
        uc: Unit Cell structre
        sc: Super Cell structure
        sm: StructureMatcher object with the working ion ignored

    Returns:
        The positions in the unit cell
    """
    mapping = get_matched_structure_mapping(base=uc, inserted=sc, sm=sm)
    if mapping is None:
        raise ValueError(
            "Cannot obtain inverse mapping, consider lowering tolerances "
            "in StructureMatcher")
    sc_m, total_t = mapping
    sc_ipos = isite.frac_coords
    sc_ipos_t = sc_ipos - total_t
    uc_ipos = sc_ipos_t.dot(sc_m)
    image_trans = np.floor(uc_ipos)
    uc_ipos = uc_ipos - image_trans
    uc_ipos = _get_first_close_site(uc_ipos, uc)

    sc_epos = esite.frac_coords
    sc_epos_t = sc_epos - total_t
    uc_epos = sc_epos_t.dot(sc_m)
    uc_epos = uc_epos - image_trans
    uc_epos = _get_first_close_site(uc_epos, uc)

    sc_msite = PeriodicSite(
        esite.specie,
        (sc_ipos + sc_epos) / 2,
        esite.lattice,
    )
    sc_mpos = sc_msite.frac_coords

    sc_mpos_t = sc_mpos - total_t
    uc_mpos = sc_mpos_t.dot(sc_m)
    uc_mpos = uc_mpos - image_trans
    uc_mpos = _get_first_close_site(uc_mpos, uc)

    p0 = PeriodicSite(isite.specie, uc_ipos, uc.lattice)
    p1 = PeriodicSite(esite.specie, uc_mpos, uc.lattice)
    p2 = PeriodicSite(esite.specie, uc_epos, uc.lattice)
    return p0, p1, p2
Example #3
0
def test_add_sp_hydrogen():
    """Add H on simplified case with one neighbor"""
    site_b_coord = [0, 0, 0]
    site_a_coord = [0.5, 0, 0]
    lattice = Lattice.from_parameters(1, 1, 1, 90, 90, 90)
    site_a = PeriodicSite(Composition("H"), site_a_coord, lattice)
    site_b = ConnectedSite(
        PeriodicSite(Composition("H"), site_b_coord, lattice))

    hydrogen = add_sp_hydrogen(site_a, [site_b])
    assert len(hydrogen) == 3

    assert np.abs(np.linalg.norm(np.array(site_a_coord) - hydrogen) - 1) < 0.01
    assert np.linalg.norm(hydrogen[1]) < 0.01
    assert np.linalg.norm(hydrogen[2]) < 0.01
Example #4
0
    def delete_bt_layer(self, bt, tol=0.25, axis=2):
        """
        Delete bottom or top layer of the structure.
        Args:
            bt (str): Specify whether it's a top or bottom layer delete. "b"
                means bottom layer and "t" means top layer.
            tol (float), Angstrom: Tolerance factor to determine whether two
                atoms are at the same plane.
                Default to 0.25
            axis (int): The direction of top and bottom layers. 0: x, 1: y, 2: z

        """
        if bt == "t":
            l1, l2 = (-1, -2)
        else:
            l1, l2 = (0, 1)

        l = self.lattice.abc[axis]
        layers = self.sort_sites_in_layers(tol=tol, axis=axis)
        l_dist = abs(layers[l1][0].coords[axis] - layers[l2][0].coords[axis])
        l_vector = [1, 1]
        l_vector.insert(axis, (l - l_dist) / l)
        new_lat = Lattice(self.lattice.matrix * np.array(l_vector)[:, None])

        layers.pop(l1)
        sites = reduce(lambda x, y: np.concatenate((x, y), axis=0), layers)
        new_sites = []
        l_dist = 0 if bt == "t" else l_dist
        l_vector = [0, 0]
        l_vector.insert(axis, l_dist)
        for i in sites:
            new_sites.append(PeriodicSite(i.specie, i.coords - l_vector,
                                          new_lat, coords_are_cartesian=True))
        self._sites = new_sites
        self._lattice = new_lat
Example #5
0
def create_saturated_interstitial_structure(interstitial_def, dist_tol=0.1):
    """
    this takes a Interstitial defect object and generates the
    sublattice for it based on the structure's space group.
    Useful for understanding multiplicity of an interstitial
    defect in thermodynamic analysis.

    NOTE: if large relaxation happens to interstitial or
        defect involves a complex then there may be additional
        degrees of freedom that need to be considered for
        the multiplicity.

    Args:
        dist_tol: changing distance tolerance of saturated structure,
                allowing for possibly overlapping sites
                but ensuring space group is maintained

    Returns:
        Structure object decorated with interstitial site equivalents
    """
    sga = SpacegroupAnalyzer(interstitial_def.bulk_structure.copy())
    sg_ops = sga.get_symmetry_operations(cartesian=True)

    # copy bulk structure to make saturated interstitial structure out of
    # artificially lower distance_tolerance to allow for distinct interstitials
    # with lower symmetry to be replicated - This is OK because one would never
    # actually use this structure for a practical calcualtion...
    saturated_defect_struct = interstitial_def.bulk_structure.copy()
    saturated_defect_struct.DISTANCE_TOLERANCE = dist_tol

    for sgo in sg_ops:
        new_interstit_coords = sgo.operate(interstitial_def.site.coords[:])
        poss_new_site = PeriodicSite(
            interstitial_def.site.specie,
            new_interstit_coords,
            saturated_defect_struct.lattice,
            to_unit_cell=True,
            coords_are_cartesian=True,
        )
        try:
            # will raise value error if site already exists in structure
            saturated_defect_struct.append(
                poss_new_site.specie,
                poss_new_site.coords,
                coords_are_cartesian=True,
                validate_proximity=True,
            )
        except ValueError:
            pass

    # do final space group analysis to make sure symmetry not lowered by saturating defect structure
    saturated_sga = SpacegroupAnalyzer(saturated_defect_struct)
    if saturated_sga.get_space_group_number() != sga.get_space_group_number():
        raise ValueError(
            "Warning! Interstitial sublattice generation "
            "has changed space group symmetry. Recommend "
            "reducing dist_tol and trying again..."
        )

    return saturated_defect_struct
def get_nearest_neighbours_from_point(vec_cartesian,struct):
    site = PeriodicSite(DummySpecie(),vec_cartesian,struct.lattice,coords_are_cartesian=True)
    dists = [i[1] for i in struct.get_neighbors(site,10,include_index=True) if i[1]>0.1]
    min_dist = min(dists)
    nearest_neighbour_infos=struct.get_neighbors(site,min_dist+0.2,include_index=True)
    nearest_neighbours=[i[2] for i in nearest_neighbour_infos if i[1]>0.1]
    return nearest_neighbours
Example #7
0
 def setUp(self):
     self.lattice = Lattice.cubic(10.0)
     self.si = Element("Si")
     self.site = PeriodicSite("Fe", np.array([0.25, 0.35, 0.45]), self.lattice)
     self.site2 = PeriodicSite({"Si":0.5}, np.array([0, 0, 0]), self.lattice)
     self.assertEquals(self.site2.species_and_occu, {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})
Example #8
0
 def test_get_symmetry_operations(self):
     fracsymmops = self.sg.get_symmetry_operations()
     symmops = self.sg.get_symmetry_operations(True)
     self.assertEqual(len(symmops), 8)
     latt = self.structure.lattice
     for fop, op in zip(fracsymmops, symmops):
         for site in self.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_and_occu, newcart, latt, coords_are_cartesian=True)
             for testsite in self.structure:
                 if newsite.is_periodic_image(testsite, 1e-3):
                     found = True
                     break
             self.assertTrue(found)
Example #9
0
def test_add_sp3_hydrogens_on_cn1():
    """Test on a toy example with one neighbor on the x axis"""
    site_b_coord = [0, 0, 0]
    site_a_coord = [0.5, 0, 0]

    lattice = Lattice.from_parameters(1, 1, 1, 90, 90, 90)
    site_a = PeriodicSite(Composition("H"), site_a_coord, lattice)
    site_b = ConnectedSite(
        PeriodicSite(Composition("H"), site_b_coord, lattice))

    vectors = add_sp3_hydrogens_on_cn1(site_a, [site_b])

    for vector in vectors:
        assert (np.linalg.norm(vector - np.array(site_a_coord)) - 1) < 0.01
        assert vector[0] > 0.5
        assert vector[1] != 0
        assert vector[2] != 0
Example #10
0
 def from_dict(cls, d):
     return cls(ComputedStructureEntry.from_dict(d['entry']),
                PeriodicSite.from_dict(d['site']),
                multiplicity=d.get('multiplicity', None),
                supercell_size=d.get('supercell_size', [1, 1, 1]),
                charge=d.get('charge', 0.0),
                charge_correction=d.get('charge_correction', 0.0),
                other_correction=d.get('other_correction', 0.0),
                name=d.get('name', None))
Example #11
0
 def test_to_from_dict(self):
     d = self.site2.to_dict
     site = PeriodicSite.from_dict(d)
     self.assertEqual(site, self.site2)
     self.assertNotEqual(site, self.site)
     d = self.propertied_site.to_dict
     site = Site.from_dict(d)
     self.assertEqual(site.magmom, 5.1)
     self.assertEqual(site.charge, 4.2)
Example #12
0
def test_add_sp2_hydrogen():
    """simplified  test case of existing CN2 coordination"""
    site_b_coord = [0.1, 0.1, 0]
    site_a_coord = [0, 0.5, 0]
    site_c_coord = [0.1, 0.9, 0]

    lattice = Lattice.from_parameters(1, 1, 1, 90, 90, 90)
    site_a = PeriodicSite(Composition("H"), site_a_coord, lattice)
    site_b = ConnectedSite(
        PeriodicSite(Composition("H"), site_b_coord, lattice))
    site_c = ConnectedSite(
        PeriodicSite(Composition("H"), site_c_coord, lattice))

    hydrogen = add_sp2_hydrogen(site_a, [site_b, site_c])
    assert len(hydrogen) == 3

    assert np.abs(np.linalg.norm(hydrogen - np.array(site_a_coord)) - 1) < 0.01
    assert np.abs(hydrogen[1] - 0.5) < 0.001
    assert hydrogen[0] < 0
    assert np.abs(hydrogen[2]) < 0.001
Example #13
0
def test_add_methylene_hydrogens():
    """simplified  test case of existing CN2 coordination"""
    site_b_coord = [0.1, 0.1, 0]
    site_a_coord = [0, 0.5, 0]
    site_c_coord = [0.1, 0.9, 0]

    lattice = Lattice.from_parameters(1, 1, 1, 90, 90, 90)
    site_a = PeriodicSite(Composition("H"), site_a_coord, lattice)
    site_b = ConnectedSite(
        PeriodicSite(Composition("H"), site_b_coord, lattice))
    site_c = ConnectedSite(
        PeriodicSite(Composition("H"), site_c_coord, lattice))

    hydrogens = add_methylene_hydrogens(site_a, [site_b, site_c])

    assert len(hydrogens) == 2
    for vector in hydrogens:
        assert np.abs(np.linalg.norm(vector - np.array(site_a_coord)) -
                      1) < 0.01
        assert np.abs(vector[1] - 0.5) < 0.01
        assert vector[0] < 0.5
        assert vector[2] <= 0.5
Example #14
0
    def setUp(self):
        l = Lattice([[3.52,0.0,2.033], [1.174,3.32,2.033], \
                [0.0,0.0,4.066]])
        s_bulk = Structure(l, ['Ga', 'As'], \
                [[0.0000, 0.0000, 0.0000], \
                [0.2500, 0.2500, 0.2500]])
        defect_site = PeriodicSite('As', [0.25, 0.25, 0.25], l)
        defect = Vacancy(s_bulk, defect_site, charge=1.)
        defect_entry = DefectEntry(defect, 0.)

        entries = [defect_entry]
        vbm = 0.2
        band_gap = 1.
        dpd = DefectPhaseDiagram(entries, vbm, band_gap)
        self.dp = DefectPlotter(dpd)
Example #15
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.assertAlmostEquals(distance, 6.22494979899, 5)
     self.assertTrue(([-1, -1, -1] == image).all())
     (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0])
     self.assertAlmostEquals(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.assertTrue(site1.distance_and_image_old(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(site1.distance_and_image_old(site2)[0] > site1.distance_and_image(site2)[0])
     site2 = PeriodicSite("Fe", np.random.rand(3), lattice)
     (dist_old, jimage_old) = site1.distance_and_image_old(site2)
     (dist_new, jimage_new) = site1.distance_and_image(site2)
     self.assertTrue(dist_old >= dist_new, "New distance algo should always give smaller answers!")
     self.assertFalse((dist_old == dist_new) ^ (jimage_old == jimage_new).all(), "If old dist == new dist, the images returned must be the same!")
def get_reconstructed_structure(components: List[Component],
                                simplify_molecules: bool = True) -> Structure:
    """Reconstructs a structure from a list of components.

    Has the option to simplify molecular components into a single site
    positioned at the centre of mass of the molecular. If using this option,
    the components must have been generated with ``inc_molecule_graph=True``.

    Args:
        components: A list of structure components, generated using
            :obj:`pymatgen.analysis.dimensionality.get_structure_components`,
            with ``inc_molecule_graph=True``.
        simplify_molecules: Whether to simplify the molecular components into
            a single site positioned at the centre of mass of the molecule.

    Returns:
        The reconstructed structure.
    """
    mol_sites = []
    other_sites = []

    if simplify_molecules:
        mol_components, components = filter_molecular_components(components)

        if mol_components:
            lattice = mol_components[0]["structure_graph"].structure.lattice

            mol_sites = [
                PeriodicSite(
                    c["structure_graph"].structure[0].specie,
                    c["molecule_graph"].molecule.center_of_mass,
                    lattice,
                    coords_are_cartesian=True,
                ) for c in mol_components
            ]

    if components:
        other_sites = [
            site for c in components for site in c["structure_graph"].structure
        ]

    return Structure.from_sites(other_sites + mol_sites)
Example #17
0
    def are_symmetrically_equivalent(self, sites1, sites2, symm_prec=1e-3):
        """
        Given two sets of PeriodicSites, test if they are actually
        symmetrically equivalent under this space group.  Useful, for example,
        if you want to test if selecting atoms 1 and 2 out of a set of 4 atoms
        are symmetrically the same as selecting atoms 3 and 4, etc.

        One use is in PartialRemoveSpecie transformation to return only
        symmetrically distinct arrangements of atoms.

        Args:
            sites1 ([Site]): 1st set of sites
            sites2 ([Site]): 2nd set of sites
            symm_prec (float): Tolerance in atomic distance to test if atoms
                are symmetrically similar.

        Returns:
            (bool): Whether the two sets of sites are symmetrically
            equivalent.
        """
        def in_sites(site):
            for test_site in sites1:
                if test_site.is_periodic_image(site, symm_prec, False):
                    return True
            return False

        for op in self:
            newsites2 = [
                PeriodicSite(site.species_and_occu,
                             op.operate(site.frac_coords), site.lattice)
                for site in sites2
            ]
            ismapping = True
            for site in newsites2:
                if not in_sites(site):
                    ismapping = False
                    break
            if ismapping:
                return True
        return False
Example #18
0
    def make_supercell(self, scaling_matrix):
        """
        Create a supercell. Very similar to pymatgen's Structure.make_supercell
        However, we need to make sure that all fractional coordinates that equal
        to 1 will become 0 and the lattice are redefined so that x_c = [0, 0, c]

        Args:
            scaling_matrix (3x3 matrix): The scaling matrix to make supercell.
        """
        s = self * scaling_matrix
        for i, site in enumerate(s):
            f_coords = np.mod(site.frac_coords, 1)
            # The following for loop is probably not necessary. But I will leave
            # it here for now.
            for j, v in enumerate(f_coords):
                if abs(v - 1) < 1e-6:
                    f_coords[j] = 0
            s[i] = PeriodicSite(site.specie, f_coords, site.lattice,
                                properties=site.properties)
        self._sites = s.sites
        self._lattice = s.lattice
        new_lat = Lattice.from_parameters(*s.lattice.parameters)
        self.lattice = new_lat
Example #19
0
    def get_primitive_standard_structure(self, international_monoclinic=True):
        """
        Gives a structure with a primitive cell according to certain standards
        the standards are defined in Setyawan, W., & Curtarolo, S. (2010).
        High-throughput electronic band structure calculations:
        Challenges and tools. Computational Materials Science,
        49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010

        Returns:
            The structure in a primitive standardized cell
        """
        conv = self.get_conventional_standard_structure(
            international_monoclinic=international_monoclinic)
        lattice = self.get_lattice_type()

        if "P" in self.get_spacegroup_symbol() or lattice == "hexagonal":
            return conv

        if lattice == "rhombohedral":
            # check if the conventional representation is hexagonal or
            # rhombohedral
            lengths, angles = conv.lattice.lengths_and_angles
            if abs(lengths[0] - lengths[2]) < 0.0001:
                transf = np.eye
            else:
                transf = np.array([[-1, 1, 1], [2, 1, 1], [-1, -2, 1]],
                                  dtype=np.float) / 3

        elif "I" in self.get_spacegroup_symbol():
            transf = np.array([[-1, 1, 1], [1, -1, 1], [1, 1, -1]],
                              dtype=np.float) / 2
        elif "F" in self.get_spacegroup_symbol():
            transf = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]],
                              dtype=np.float) / 2
        elif "C" in self.get_spacegroup_symbol():
            if self.get_crystal_system() == "monoclinic":
                transf = np.array([[1, 1, 0], [-1, 1, 0], [0, 0, 2]],
                                  dtype=np.float) / 2
            else:
                transf = np.array([[1, -1, 0], [1, 1, 0], [0, 0, 2]],
                                  dtype=np.float) / 2
        else:
            transf = np.eye(3)

        new_sites = []
        latt = Lattice(np.dot(transf, conv.lattice.matrix))
        for s in conv:
            new_s = PeriodicSite(s.specie,
                                 s.coords,
                                 latt,
                                 to_unit_cell=True,
                                 coords_are_cartesian=True,
                                 properties=s.properties)
            if not any(map(new_s.is_periodic_image, new_sites)):
                new_sites.append(new_s)

        if lattice == "rhombohedral":
            prim = Structure.from_sites(new_sites)
            lengths, angles = prim.lattice.lengths_and_angles
            a = lengths[0]
            alpha = math.pi * angles[0] / 180
            new_matrix = [[a * cos(alpha / 2), -a * sin(alpha / 2), 0],
                          [a * cos(alpha / 2), a * sin(alpha / 2), 0],
                          [
                              a * cos(alpha) / cos(alpha / 2), 0,
                              a * math.sqrt(1 - (cos(alpha)**2 /
                                                 (cos(alpha / 2)**2)))
                          ]]
            new_sites = []
            latt = Lattice(new_matrix)
            for s in prim:
                new_s = PeriodicSite(s.specie,
                                     s.frac_coords,
                                     latt,
                                     to_unit_cell=True,
                                     properties=s.properties)
                if not any(map(new_s.is_periodic_image, new_sites)):
                    new_sites.append(new_s)
            return Structure.from_sites(new_sites)

        return Structure.from_sites(new_sites)
Example #20
0
 def __init__(self, structure, max_min_oxid, allowed_subst, oxid_states, min_dis=13.,
              inter=False, interstitials_extr_elts=[], vac=True, extrapolation=True):
     """
     Args:
         structure:
             the bulk structure
         max_min_oxid:
             the minimal and maximum oxidation state of each element as a dict. For instance
             {Element("O"):(-2,0)}
         allowed_subst:
             the allowed substitutions between elements. Including intrinsic (e.g., anti-sites) and
             extrinsic. Example: {Element("Co"):[Element("Zn"),Element("Mn")]} means Co sites can be substituted
             by Mn or Zn.
         oxid_states:
             the oxidation state of the elements in the compound e.g. {Element("Fe"):2,Element("O"):-2}
         size_limit:
             maximum atom numbers allowed in the supercell
         interstitials_sites:
             a list of PeriodicSites in the bulk structure on which we put an interstitial
         standardized:
             True means we use a standardized primitive cell
     """
     DefectStructMaker.__init__(self, structure, min_dis, extrapolation)
     self.defects = []
     nb_per_elts = {e:0 for e in structure.composition.elements}
     
     ### bulk###
     def get_bulk_sc(stru,sc_size):
         s=stru.copy()
         s.make_supercell(sc_size,to_unit_cell=True)
         return s
     self.defects.append({'short_name':'bulk','uc_type':self.uc_type,'sc_type':self.sc_type,'bulk_unitcell':self.struct_orig,'supercells':
            [{'size': s_size,'structure':get_bulk_sc(self.struct_orig, s_size)} for s_size in self.optimized_supercell]})
     self.defects.append({'short_name':'dielectric','structure':self.struct_orig,'uc_type':self.uc_type})
     charges_limit=range(-100,100)
     for s in self.struct.equivalent_sites:
         nb_per_elts[s[0].specie] = nb_per_elts[s[0].specie]+1
         #vac
         if vac==True:
             list_charges=[]
             for c in range(max_min_oxid[s[0].specie][0], max_min_oxid[s[0].specie][1]+1):
                 list_charges.append(-c)
             if 0 not in list_charges:
                 list_charges.append(0)
             list_charges=range(min(list_charges),max(list_charges)+1)
             list_charges=list(set(charges_limit)&set(list_charges))
             self.defects.append({'short_name': s[0].specie.symbol+str(nb_per_elts[s[0].specie])+"_vac",
                                  'unique_sites': s[0],
                                  'supercells':[{'size': s_size,'structure':self.make_defect_cell_vacancy(s[0], s_size), 
                                  'struct_no_move':self.make_defect_cell_vacancy(s[0], s_size,move_neighbours=False)} 
                                  for s_size in self.optimized_supercell],
                                  'charges':list_charges,
                                  'uc_type':self.uc_type,'sc_type':self.sc_type,
                                  'bulk_unitcell':self.struct_orig})
         #sub
         if s[0].specie in allowed_subst:
             for subst in allowed_subst[s[0].specie]:
                 list_charges_subst=[c-oxid_states[s[0].specie] for c in range(max_min_oxid[subst][0], max_min_oxid[subst][1]+1)]
                 if 0 not in list_charges_subst:
                     list_charges_subst.append(0)
                 list_charges_subst=range(min(list_charges_subst),max(list_charges_subst)+1)
                 list_charges_subst=list(set(charges_limit)&set(list_charges_subst))
                 self.defects.append({'short_name':s[0].specie.symbol+str(nb_per_elts[s[0].specie])+"_subst_"
                             +subst.symbol, 'unique_sites':s[0],'supercells':[{'size':s_size,'structure':
                             self.make_defect_cell_intrinsic_subst_defects(s[0], subst, s_size),
                             'struct_no_move':self.make_defect_cell_intrinsic_subst_defects(
                             s[0], subst, s_size,move_neighbours=False)} for s_size in self.optimized_supercell],
                             'charges':list_charges_subst,'uc_type':self.uc_type,'sc_type':self.sc_type,'bulk_unitcell':self.struct_orig})
         
     #interstitials
     if inter:
         for elt in self.struct.composition.elements:
             count = 1
             list_charges_inter=[c for c in range(max_min_oxid[elt][0],max_min_oxid[elt][1]+1)]
             if 0 not in list_charges_inter:
                 list_charges_inter.append(0)
             list_charges_inter=range(min(list_charges_inter),max(list_charges_inter)+1)
             list_charges_inter=list(set(charges_limit)&set(list_charges_inter))
             for frac_coord in self.inter_sites:
                 self.defects.append({'short_name':elt.symbol+str(count)+"_inter",
                                      'unique_sites':PeriodicSite(elt, frac_coord, structure.lattice),
                                      'supercells':[{'size':s_size,
                                                     'structure':self.make_defect_interstitial(
                                                         PeriodicSite(elt, frac_coord, self.struct_orig.lattice), s_size)}
                                                    for s_size in self.optimized_supercell],
                                     'charges':list_charges_inter,
                                     'uc_type':self.uc_type,'sc_type':self.sc_type,
                                     'bulk_unitcell':self.struct_orig})
                 count = count+1
     for elt in interstitials_extr_elts:
         count = 1
         list_charges_subst=[c for c in range(max_min_oxid[elt][0],max_min_oxid[elt][1]+1)]
         if 0 not in list_charges_subst:
             list_charges_subst.append(0)
         list_charges_subst=range(min(list_charges_subst),max(list_charges_subst)+1)
         list_charges_subst=list(set(charges_limit)&set(list_charges_subst))
         for frac_coord in self.inter_sites:
             self.defects.append({'short_name':elt.symbol+str(count)+"_inter",
                                  'unique_sites':PeriodicSite(elt, frac_coord, structure.lattice),
                                  'supercells':[{'size':s_size,
                                                 'structure':self.make_defect_interstitial(
                                                     PeriodicSite(elt, frac_coord, self.struct_orig.lattice), s_size)}
                                                for s_size in self.optimized_supercell],
                                  'charges':list_charges_subst,'uc_type':self.uc_type,'sc_type':self.sc_type,
                                 'bulk_unitcell':self.struct_orig})
             count = count+1
Example #21
0
 def test_equality(self):
     other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice)
     self.assertTrue(self.site.__eq__(self.site))
     self.assertFalse(other_site.__eq__(self.site))
     self.assertFalse(self.site.__ne__(self.site))
     self.assertTrue(other_site.__ne__(self.site))
Example #22
0
    def get_primitive_standard_structure(self):
        """
        Gives a structure with a primitive cell according to certain standards
        the standards are defined in Setyawan, W., & Curtarolo, S. (2010).
        High-throughput electronic band structure calculations:
        Challenges and tools. Computational Materials Science,
        49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010

        Returns:
            The structure in a primitive standardized cell
        """
        conv = self.get_conventional_standard_structure()
        lattice = self.get_lattice_type()

        if "P" in self.get_spacegroup_symbol() or lattice == "hexagonal":
            return conv

        if lattice == "rhombohedral":
            conv = self.get_refined_structure()
            lengths, angles = conv.lattice.lengths_and_angles
            a = lengths[0]
            alpha = math.pi * angles[0] / 180
            new_matrix = [
                [a * cos(alpha / 2), -a * sin(alpha / 2), 0],
                [a * cos(alpha / 2), a * sin(alpha / 2), 0],
                [a * cos(alpha) / cos(alpha / 2), 0,
                 a * math.sqrt(1 - (cos(alpha) ** 2 / (cos(alpha / 2) ** 2)))]]
            new_sites = []
            for s in conv.sites:
                new_s = PeriodicSite(
                    s.specie, s.frac_coords, Lattice(new_matrix),
                    to_unit_cell=True, properties=s.properties)
                unique = True
                for t in new_sites:
                    if new_s.is_periodic_image(t):
                        unique = False
                if unique:
                    new_sites.append(new_s)
            return Structure.from_sites(new_sites)

        transf = np.eye(3)
        if "I" in self.get_spacegroup_symbol():
            transf = np.array([[-1, 1, 1], [1, -1, 1], [1, 1, -1]],
                              dtype=np.float) / 2
        elif "F" in self.get_spacegroup_symbol():
            transf = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]],
                              dtype=np.float) / 2
        elif "C" in self.get_spacegroup_symbol():
            if self.get_crystal_system() == "monoclinic":
                transf = np.array([[1, 1, 0], [-1, 1, 0], [0, 0, 2]],
                                  dtype=np.float) / 2
            else:
                transf = np.array([[1, -1, 0], [1, 1, 0], [0, 0, 2]],
                                  dtype=np.float) / 2
        new_sites = []
        for s in conv.sites:
            new_s = PeriodicSite(
                s.specie, s.coords,
                Lattice(np.dot(transf, conv.lattice.matrix)),
                to_unit_cell=True, coords_are_cartesian=True,
                properties=s.properties)
            unique = True
            for t in new_sites:
                if new_s.is_periodic_image(t):
                    unique = False
            if unique:
                new_sites.append(new_s)
        return Structure.from_sites(new_sites)
Example #23
0
def apply_symmop(psites, ops):
    """
    symmop and xyz in cif file:

    lets say xyz -- op1 --> x'y'z' and xyz -- op2 --> x!y!z! and
    it is possible to have x'y'z' is_close x!y!z!

    this means one should take only x'y'z' or x!y!z!, aka op1 is equivalent to op2 due to the symmetry implicated by
    xyz/the asymmectric unit, e.g. ALOVOO.cif -- Z=2, asymmectric unit given by cif is one molecule, but there're 4 ops

    so we need first check if the cif file behaves like this

    """
    op_xyzs = []
    for op in ops:
        n_xyzs = []
        for ps in psites:
            new_coord = op.operate(ps.frac_coords)
            # new_coord = np.array([i - math.floor(i) for i in new_coord])
            n_xyzs.append(new_coord)
        op_xyzs.append(n_xyzs)

    latt = psites[0].lattice

    def pbc_dist(fc1, fc2, lattice):
        v, d2 = pbc_shortest_vectors(lattice, fc1, fc2, return_d2=True)
        return math.sqrt(d2[0, 0])

    def pbc_distmat(fcl1, fcl2):
        distmat = np.zeros((len(fcl1), len(fcl1)))
        for i in range(len(fcl1)):
            for j in range(i, len(fcl1)):
                distmat[i][j] = pbc_dist(fcl1[i], fcl2[j], latt)
                distmat[j][i] = distmat[i][j]
        return distmat

    def two_xyzs_close(xyzs1, xyzs2, tol=1e-5):
        dmat = pbc_distmat(xyzs1, xyzs2)
        almost_zeros = dmat[(dmat < tol)]
        if len(almost_zeros) > 0:
            return True
        return False

    op_identities = np.zeros((len(ops), len(ops)), dtype=bool)
    for i, j in itertools.combinations(range(len(ops)), 2):
        ixyzs = op_xyzs[i]
        jxyzs = op_xyzs[j]
        if two_xyzs_close(ixyzs, jxyzs):
            op_identities[i][j] = True
            op_identities[j][i] = True

    groups = [[0]]
    for i in range(len(ops)):
        for ig in range(len(groups)):
            if all(op_identities[i][j] for j in groups[ig]):
                groups[ig].append(i)
        if i not in [item for sublist in groups for item in sublist]:
            groups.append([i])
    unique_ops = [ops[g[0]] for g in groups]

    new_psites = []
    for ps in psites:
        iasym = 0
        for op in unique_ops:
            new_coord = op.operate(ps.frac_coords)
            new_coord = np.array([i - math.floor(i) for i in new_coord])
            new_properties = deepcopy(ps.properties)
            new_properties['iasym'] = iasym
            new_ps = PeriodicSite(ps.species_string,
                                  new_coord,
                                  ps.lattice,
                                  properties=deepcopy(new_properties))
            new_psites.append(new_ps)
            iasym += 1

    return new_psites, unique_ops
Example #24
0
class PeriodicSiteTest(unittest.TestCase):

    def setUp(self):
        self.lattice = Lattice.cubic(10.0)
        self.si = Element("Si")
        self.site = PeriodicSite("Fe", np.array([0.25, 0.35, 0.45]), self.lattice)
        self.site2 = PeriodicSite({"Si":0.5}, np.array([0, 0, 0]), self.lattice)
        self.assertEquals(self.site2.species_and_occu, {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})

    def test_properties(self):
        """
        Test the properties for a site
        """
        self.assertEquals(self.site.a, 0.25)
        self.assertEquals(self.site.b, 0.35)
        self.assertEquals(self.site.c, 0.45)
        self.assertEquals(self.site.x, 2.5)
        self.assertEquals(self.site.y, 3.5)
        self.assertEquals(self.site.z, 4.5)
        self.assertTrue(self.site.is_ordered)
        self.assertFalse(self.site2.is_ordered)
        self.assertEqual(self.propertied_site.magmom, 5.1)
        self.assertEqual(self.propertied_site.charge, 4.2)

    def test_distance(self):
        other_site = PeriodicSite("Fe", np.array([0, 0, 0]), self.lattice)
        self.assertAlmostEquals(self.site.distance(other_site), 6.22494979899, 5)

    def test_distance_from_point(self):
        self.assertNotAlmostEqual(self.site.distance_from_point(np.array([0.1, 0.1, 0.1])), 6.22494979899, 5)
        self.assertAlmostEqual(self.site.distance_from_point(np.array([0.1, 0.1, 0.1])), 6.0564015718906887, 5)

    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.assertAlmostEquals(distance, 6.22494979899, 5)
        self.assertTrue(([-1, -1, -1] == image).all())
        (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0])
        self.assertAlmostEquals(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.assertTrue(site1.distance_and_image_old(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(site1.distance_and_image_old(site2)[0] > site1.distance_and_image(site2)[0])
        site2 = PeriodicSite("Fe", np.random.rand(3), lattice)
        (dist_old, jimage_old) = site1.distance_and_image_old(site2)
        (dist_new, jimage_new) = site1.distance_and_image(site2)
        self.assertTrue(dist_old >= dist_new, "New distance algo should always give smaller answers!")
        self.assertFalse((dist_old == dist_new) ^ (jimage_old == jimage_new).all(), "If old dist == new dist, the images returned must be the same!")

    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))
        self.assertFalse(self.site.is_periodic_image(other), "Different lattices should result in different periodic sites.")

    def test_equality(self):
        other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice)
        self.assertTrue(self.site.__eq__(self.site))
        self.assertFalse(other_site.__eq__(self.site))
        self.assertFalse(self.site.__ne__(self.site))
        self.assertTrue(other_site.__ne__(self.site))

    def test_to_from_dict(self):
        d = self.site2.to_dict
        site = PeriodicSite.from_dict(d)
        self.assertEqual(site, self.site2)
        self.assertNotEqual(site, self.site)
        d = self.propertied_site.to_dict
        site = Site.from_dict(d)
        self.assertEqual(site.magmom, 5.1)
        self.assertEqual(site.charge, 4.2)