예제 #1
0
    def _preprocess(self, struct1, struct2, niggli=True):
        """
        Rescales, finds the reduced structures (primitive and niggli),
        and finds fu, the supercell size to make struct1 comparable to
        s2
        """
        struct1 = Structure.from_sites(struct1)
        struct2 = Structure.from_sites(struct2)

        if niggli:
            struct1 = struct1.get_reduced_structure(reduction_algo="niggli")
            struct2 = struct2.get_reduced_structure(reduction_algo="niggli")

        #primitive cell transformation
        if self._primitive_cell:
            struct1 = struct1.get_primitive_structure()
            struct2 = struct2.get_primitive_structure()

        if self._supercell:
            fu, s1_supercell = self._get_supercell_size(struct1, struct2)
        else:
            fu, s1_supercell = 1, True
        mult = fu if s1_supercell else 1/fu

        #rescale lattice to same volume
        if self._scale:
            ratio = (struct2.volume / (struct1.volume * mult)) ** (1 / 6)
            nl1 = Lattice(struct1.lattice.matrix * ratio)
            struct1.modify_lattice(nl1)
            nl2 = Lattice(struct2.lattice.matrix / ratio)
            struct2.modify_lattice(nl2)

        return struct1, struct2, fu, s1_supercell
def get_aligned_lattices(slab_sub, slab_2d, max_area=200,
                         max_mismatch=0.05,
                         max_angle_diff=1, r1r2_tol=0.2):
    """
    given the 2 slab structures and the alignment paramters, return
    slab structures with lattices that are aligned with respect to each
    other
    """
    # get the matching substrate and 2D material lattices
    uv_substrate, uv_mat2d = get_matching_lattices(slab_sub, slab_2d,
                                                   max_area=max_area,
                                                   max_mismatch=max_mismatch,
                                                   max_angle_diff=max_angle_diff,
                                                   r1r2_tol=r1r2_tol)
    if not uv_substrate and not uv_mat2d:
        print("no matching u and v, trying adjusting the parameters")
        sys.exit()
    substrate = Structure.from_sites(slab_sub)
    mat2d = Structure.from_sites(slab_2d)
    # map the intial slabs to the newly found matching lattices
    substrate_latt = Lattice(np.array(
            [
                uv_substrate[0][:],
                uv_substrate[1][:],
                substrate.lattice.matrix[2, :]
            ]))
    # to avoid numerical issues with find_mapping
    mat2d_fake_c = mat2d.lattice.matrix[2, :] / np.linalg.norm(mat2d.lattice.matrix[2, :]) * 5.0
    mat2d_latt = Lattice(np.array(
            [
                uv_mat2d[0][:],
                uv_mat2d[1][:],
                mat2d_fake_c
            ]))
    mat2d_latt_fake = Lattice(np.array(
            [
                mat2d.lattice.matrix[0, :],
                mat2d.lattice.matrix[1, :],
                mat2d_fake_c
            ]))
    _, __, scell = substrate.lattice.find_mapping(substrate_latt,
                                                  ltol=0.05,
                                                  atol=1)
    scell[2] = np.array([0, 0, 1])
    substrate.make_supercell(scell)
    _, __, scell = mat2d_latt_fake.find_mapping(mat2d_latt,
                                                ltol=0.05,
                                                atol=1)
    scell[2] = np.array([0, 0, 1])
    mat2d.make_supercell(scell)
    # modify the substrate lattice so that the 2d material can be
    # grafted on top of it
    lmap = Lattice(np.array(
            [
                substrate.lattice.matrix[0, :],
                substrate.lattice.matrix[1, :],
                mat2d.lattice.matrix[2, :]
            ]))
    mat2d.modify_lattice(lmap)
    return substrate, mat2d
예제 #3
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
예제 #4
0
    def get_s2_like_s1(self, struct1, struct2):
        """
        Performs transformations on struct2 to put it in a basis similar to
        struct1 (without changing any of the inter-site distances)

        Args:
            struct1 (Structure): Reference structure
            struct2 (Structure): Structure to transform.

        Returns:
            A structure object similar to struct1, obtained by making a
            supercell, sorting, and translating struct2.
        """
        trans = self.get_transformation(struct1, struct2)
        if trans is None:
            return None
        sc, t, mapping = trans
        temp = struct2.copy()
        temp.make_supercell(sc)
        temp.translate_sites(list(range(len(temp))), t)
        #translate sites to correct unit cell
        for i, j in enumerate(mapping[:len(struct1)]):
            if j is not None:
                vec = np.round(struct1[i].frac_coords - temp[j].frac_coords)
                temp.translate_sites(j, vec, to_unit_cell=False)

        return Structure.from_sites([temp.sites[i] for i in mapping if i is not None])
예제 #5
0
def _get_host(structure, species_to_remove):
    if species_to_remove:
        s = Structure.from_sites(structure)
        s.remove_species(species_to_remove)
        return s
    else:
        return structure
예제 #6
0
 def get_sorted_structure(self):
     """
     orders the structure according to increasing Z of the elements
     """
     sites = sorted(self.sites, key=lambda site: site.specie.Z)
     structure = Structure.from_sites(sites)
     return AbiStructure(structure)
예제 #7
0
    def best_first_ordering(self, structure, num_remove_dict):
        self.logger.debug("Performing best first ordering")
        starttime = time.time()
        self.logger.debug("Performing initial ewald sum...")
        ewaldsum = EwaldSummation(structure)
        self.logger.debug("Ewald sum took {} seconds.".format(time.time() - starttime))
        starttime = time.time()

        ematrix = ewaldsum.total_energy_matrix
        to_delete = []

        totalremovals = sum(num_remove_dict.values())
        removed = {k: 0 for k in num_remove_dict.keys()}
        for i in range(totalremovals):
            maxindex = None
            maxe = float("-inf")
            maxindices = None
            for indices in num_remove_dict.keys():
                if removed[indices] < num_remove_dict[indices]:
                    for ind in indices:
                        if ind not in to_delete:
                            energy = sum(ematrix[:, ind]) + sum(ematrix[:, ind]) - ematrix[ind, ind]
                            if energy > maxe:
                                maxindex = ind
                                maxe = energy
                                maxindices = indices
            removed[maxindices] += 1
            to_delete.append(maxindex)
            ematrix[:, maxindex] = 0
            ematrix[maxindex, :] = 0
        s = Structure.from_sites(structure.sites)
        s.remove_sites(to_delete)
        self.logger.debug("Minimizing Ewald took {} seconds.".format(time.time() - starttime))
        return [{"energy": sum(sum(ematrix)), "structure": s.get_sorted_structure()}]
예제 #8
0
 def test_magic(self):
     s = Structure.from_sites(self.structure)
     self.assertEqual(s, self.structure)
     self.assertNotEqual(s, None)
     s.apply_strain(0.5)
     self.assertNotEqual(s, self.structure)
     self.assertNotEqual(self.structure * 2, self.structure)
예제 #9
0
 def apply_transformation(self, structure):
     s = Structure.from_sites(structure.sites)
     for i, sp in enumerate(self._species):
         s.insert(i, sp, self._coords[i],
                  coords_are_cartesian=self._cartesian,
                  validate_proximity=self._validate_proximity)
     return s.get_sorted_structure()
예제 #10
0
    def __str__(self):
        """
        Sorts a Structure (by fractional co-ordinate), and
        prints sites with magnetic information. This is
        useful over Structure.__str__ because sites are in
        a consistent order, which makes visual comparison between
        two identical Structures with different magnetic orderings
        easier.
        :return:
        """

        frac_coords = self.structure.frac_coords
        sorted_indices = np.lexsort((frac_coords[:, 2],
                                     frac_coords[:, 1],
                                     frac_coords[:, 0]))
        s = Structure.from_sites([self.structure[idx] for idx in sorted_indices])

        # adapted from Structure.__repr__
        outs = ["Structure Summary", repr(s.lattice)]
        outs.append("Magmoms Sites")
        for site in s:
            if site.properties['magmom'] != 0:
                prefix = "{:+.2f}   ".format(site.properties['magmom'])
            else:
                prefix = "        "
            outs.append(prefix+repr(site))
        return "\n".join(outs)
예제 #11
0
    def get_s2_like_s1(self, struct1, struct2):
        """
        Performs transformations on struct2 to put it in a basis similar to
        struct1 (without changing any of the inter-site distances)

        Args:
            struct1 (Structure): Reference structure
            struct2 (Structure): Structure to transform.

        Returns:
            A structure object similar to struct1, obtained by making a
            supercell, sorting, and translating struct2.
        """
        if self._primitive_cell:
            raise ValueError("get_s2_like_s1 cannot be used with the primitive"
                             " cell option")

        s1, s2, fu, s1_supercell = self._preprocess(struct1, struct2, False)
        ratio = fu if s1_supercell else 1/fu
        if s1_supercell and fu > 1:
            raise ValueError("Struct1 must be the supercell, "
                             "not the other way around")

        temp = struct2.copy()
        if len(s1) * ratio >= len(s2):
            #s1 is superset
            match = self._strict_match(s1, s2, fu=fu, s1_supercell=False,
                                       use_rms=True, break_on_match=False)
            if match is None:
                return None
            temp.make_supercell(match[2])
            temp.translate_sites(list(range(len(temp))), match[3],
                                 to_unit_cell=False)
            # translate sites to be in correct unit cell
            for i, j in enumerate(match[4]):
                vec = np.round(s1[j].frac_coords - temp[i].frac_coords)
                temp.translate_sites(i, vec, to_unit_cell=False)
            #invert the mapping, since it needs to be from s2 to s1
            mapping = np.argsort(match[4])
        else:
            #s2 is superset
            match = self._strict_match(s2, s1, fu=fu, s1_supercell=True,
                                       use_rms=True, break_on_match=False)
            if match is None:
                return None
            temp.make_supercell(match[2])
            temp.translate_sites(list(range(len(temp))), -match[3],
                                 to_unit_cell=False)
            # translate sites to be in correct unit cell
            for i, j in enumerate(match[4]):
                vec = np.round(s1[i].frac_coords - temp[j].frac_coords)
                temp.translate_sites(j, vec, to_unit_cell=False)
            #add sites not included in the mapping
            not_included = list(range(len(temp)))
            for i in match[4]:
                not_included.remove(i)
            mapping = list(match[4]) + not_included

        return Structure.from_sites([temp.sites[i] for i in mapping])
 def translate_sites(self, lattice):
     s = Structure(lattice, [self.central_subsite.specie] + [site.specie for site in self.peripheral_subsites], [self.central_subsite.site.coords] + [site.site.coords for site in self.peripheral_subsites], coords_are_cartesian=True)
     trans = TranslateSitesTransformation(range(len(s)), -(lattice.get_fractional_coords(s[0].coords)))
     new_s = trans.apply_transformation(s)
     trans2 = TranslateSitesTransformation(range(len(s)), (-0.5, -0.5, -0.5))
     new_s = trans2.apply_transformation(Structure.from_sites(new_s.sites, to_unit_cell=True))
     self.peripheral_subsites = [SubStructureSite.from_coords_and_specie(site.coords, site.specie) for site in new_s.sites[1:]]
     self.central_subsite = SubStructureSite.from_coords_and_specie(new_s[0].coords, new_s[0].specie)
예제 #13
0
 def _process_species(self, structures):
     copied_structures = []
     for s in structures:
         ss = Structure.from_sites(s)
         if self._ignored_species:
             ss.remove_species(self._ignored_species)
         copied_structures.append(ss)
     return copied_structures
예제 #14
0
    def complete_ordering(self, structure, num_remove_dict):
        self.logger.debug("Performing complete ordering...")
        all_structures = []
        from pymatgen.symmetry.finder import SymmetryFinder
        symprec = 0.2
        s = SymmetryFinder(structure, symprec=symprec)
        self.logger.debug("Symmetry of structure is determined to be {}."
                          .format(s.get_spacegroup_symbol()))
        sg = s.get_spacegroup()
        tested_sites = []
        starttime = time.time()
        self.logger.debug("Performing initial ewald sum...")
        ewaldsum = EwaldSummation(structure)
        self.logger.debug("Ewald sum took {} seconds."
                          .format(time.time() - starttime))
        starttime = time.time()

        allcombis = []
        for ind, num in num_remove_dict.items():
            allcombis.append(itertools.combinations(ind, num))

        count = 0
        for allindices in itertools.product(*allcombis):
            sites_to_remove = []
            indices_list = []
            for indices in allindices:
                sites_to_remove.extend([structure[i] for i in indices])
                indices_list.extend(indices)
            s_new = Structure.from_sites(structure.sites)
            s_new.remove_sites(indices_list)
            energy = ewaldsum.compute_partial_energy(indices_list)
            already_tested = False
            for i, tsites in enumerate(tested_sites):
                tenergy = all_structures[i]["energy"]
                if abs((energy - tenergy) / len(s_new)) < 1e-5 and \
                        sg.are_symmetrically_equivalent(sites_to_remove,
                                                        tsites,
                                                        symm_prec=symprec):
                    already_tested = True

            if not already_tested:
                tested_sites.append(sites_to_remove)
                all_structures.append({"structure": s_new, "energy": energy})

            count += 1
            if count % 10 == 0:
                timenow = time.time()
                self.logger.debug("{} structures, {:.2f} seconds."
                                  .format(count, timenow - starttime))
                self.logger.debug("Average time per combi = {} seconds"
                                  .format((timenow - starttime) / count))
                self.logger.debug("{} symmetrically distinct structures found."
                                  .format(len(all_structures)))

        self.logger.debug("Total symmetrically distinct structures found = {}"
                          .format(len(all_structures)))
        all_structures = sorted(all_structures, key=lambda s: s["energy"])
        return all_structures
예제 #15
0
    def apply_transformation(self, structure, return_ranked_list=False):
        #Make a mutable structure first
        mods = Structure.from_sites(structure)
        for sp, spin in self.mag_species_spin.items():
            sp = get_el_sp(sp)
            oxi_state = getattr(sp, "oxi_state", 0)
            if spin:
                up = Specie(sp.symbol, oxi_state, {"spin": abs(spin)})
                down = Specie(sp.symbol, oxi_state, {"spin": -abs(spin)})
                mods.replace_species(
                    {sp: Composition({up: self.order_parameter,
                                      down: 1 - self.order_parameter})})
            else:
                mods.replace_species(
                    {sp: Specie(sp.symbol, oxi_state, {"spin": spin})})

        if mods.is_ordered:
            return [mods] if return_ranked_list > 1 else mods

        enum_args = self.enum_kwargs

        enum_args["min_cell_size"] = max(int(
            MagOrderingTransformation.determine_min_cell(
                structure, self.mag_species_spin,
                self.order_parameter)),
            enum_args.get("min_cell_size"))

        max_cell = self.enum_kwargs.get('max_cell_size')
        if max_cell:
            if enum_args["min_cell_size"] > max_cell:
                raise ValueError('Specified max cell size is smaller'
                                 ' than the minimum enumerable cell size')
        else:
            enum_args["max_cell_size"] = enum_args["min_cell_size"]

        t = EnumerateStructureTransformation(**enum_args)

        alls = t.apply_transformation(mods,
                                      return_ranked_list=return_ranked_list)

        try:
            num_to_return = int(return_ranked_list)
        except ValueError:
            num_to_return = 1

        if num_to_return == 1 or not return_ranked_list:
            return alls[0]["structure"] if num_to_return else alls

        m = StructureMatcher(comparator=SpinComparator())

        grouped = m.group_structures([d["structure"] for d in alls])

        alls = [{"structure": g[0], "energy": self.emodel.get_energy(g[0])}
                for g in grouped]

        self._all_structures = sorted(alls, key=lambda d: d["energy"])

        return self._all_structures[0:num_to_return]
예제 #16
0
파일: utils.py 프로젝트: albalu/pymatgen
 def get_structure_with_nodes(self):
     """
     Get the modified structure with the voronoi nodes inserted. The
     species is set as a DummySpecie X.
     """
     new_s = Structure.from_sites(self.structure)
     for v in self.vnodes:
         new_s.append("X", v.frac_coords)
     return new_s
예제 #17
0
    def get_s2_like_s1(self, struct1, struct2, include_ignored_species=True):
        """
        Performs transformations on struct2 to put it in a basis similar to
        struct1 (without changing any of the inter-site distances)

        Args:
            struct1 (Structure): Reference structure
            struct2 (Structure): Structure to transform.
            include_ignored_species (bool): Defaults to True,
                the ignored_species is also transformed to the struct1
                lattice orientation, though obviously there is no direct
                matching to existing sites.

        Returns:
            A structure object similar to struct1, obtained by making a
            supercell, sorting, and translating struct2.
        """
        s1, s2 = self._process_species([struct1, struct2])
        trans = self.get_transformation(s1, s2)
        if trans is None:
            return None
        sc, t, mapping = trans
        sites = [site for site in s2]
        # Append the ignored sites at the end.
        sites.extend([site for site in struct2 if site not in s2])
        temp = Structure.from_sites(sites)

        temp.make_supercell(sc)
        temp.translate_sites(list(range(len(temp))), t)
        # translate sites to correct unit cell
        for i, j in enumerate(mapping[:len(s1)]):
            if j is not None:
                vec = np.round(struct1[i].frac_coords - temp[j].frac_coords)
                temp.translate_sites(j, vec, to_unit_cell=False)

        sites = [temp.sites[i] for i in mapping if i is not None]

        if include_ignored_species:
            start = int(round(len(temp) / len(struct2) * len(s2)))
            sites.extend(temp.sites[start:])

        return Structure.from_sites(sites)
예제 #18
0
 def apply_transformation(self, structure):
     species_map = {}
     for k, v in self._species_map.items():
         if isinstance(v, dict):
             value = {smart_element_or_specie(x): y for x, y in v.items()}
         else:
             value = smart_element_or_specie(v)
         species_map[smart_element_or_specie(k)] = value
     s = Structure.from_sites(structure.sites)
     s.replace_species(species_map)
     return s
예제 #19
0
 def _process_species(self, structures):
     copied_structures = []
     for s in structures:
         # We need the copies to be actual Structure to work properly, not
         # subclasses. So do type(s) == Structure.
         ss = s.copy() if type(s) == Structure else \
             Structure.from_sites(s)
         if self._ignored_species:
             ss.remove_species(self._ignored_species)
         copied_structures.append(ss)
     return copied_structures
예제 #20
0
    def enumerate_ordering(self, structure):
        # Generate the disordered structure first.
        s = Structure.from_sites(structure.sites)
        for indices, fraction in zip(self._indices, self._fractions):
            for ind in indices:
                new_sp = {sp: occu * fraction for sp, occu in structure[ind].species_and_occu.items()}
                s[ind] = new_sp
        # Perform enumeration
        from pymatgen.transformations.advanced_transformations import EnumerateStructureTransformation

        trans = EnumerateStructureTransformation()
        return trans.apply_transformation(s, 10000)
def get_percolated_node_edge(origin_struct, node_struct, rad_dict, probe_rad):
    """
    The function "get_voronoi_node_edge" gave all node information, but we need the percolated nodes. This function 
    conbine with function "get_voronoi_percolate_nodes" to delete the isolated nodes and correct the neighbor 
    information in the Structure from get_voronoi_node_edge.
    """
    _, vor_accessible_node_struct, _, _ = get_voronoi_percolate_nodes(
        origin_struct, rad_dict, probe_rad)
    # print vor_accessible_node_struct.lattice == node_struct.lattice
    # print vor_accessible_node_struct
    # node_struct_copy = copy.deepcopy(node_struct)
    unaccess_list = []
    access_list = []
    for i_index, i in enumerate(node_struct):
        match = 0
        for j_index, j in enumerate(vor_accessible_node_struct):
            if i.is_periodic_image(j, tolerance=1e-3, check_lattice=True):
                match = 1
                break
        if match == 0:
            unaccess_list.append(i_index)
        else:
            access_list.append(i_index)
    new_id = range(len(access_list))
    old_new_corr = {}
    for i_index, i in enumerate(access_list):
        old_new_corr[i] = new_id[i_index]
    access_node_site_list = [copy.deepcopy(site) for site_index, site in enumerate(node_struct) \
                             if site_index in access_list]
    final_access_node_site_list = []
    for i_index, i in enumerate(access_node_site_list):
        neighbor_nodes = [copy.deepcopy(neighbor) for neighbor in i.properties['neighbor_nodes'] \
                          if neighbor[0] in access_list]
        for j_index, j in enumerate(neighbor_nodes):
            new_id = old_new_corr[j[0]]
            neighbor_nodes[j_index] = copy.deepcopy([new_id] + j[1:])
        properties = i.properties
        properties['neighbor_nodes'] = neighbor_nodes
        node_site = PeriodicSite(i.species_string,
                                 i.coords,
                                 i.lattice,
                                 to_unit_cell=False,
                                 coords_are_cartesian=True,
                                 properties=properties)
        final_access_node_site_list.append(node_site)
    if final_access_node_site_list:
        new_node_edge = Structure.from_sites(final_access_node_site_list,
                                             validate_proximity=False,
                                             to_unit_cell=False)
    else:
        new_node_edge = None
    return new_node_edge
예제 #22
0
 def plot_images(self, outfile):
     """
     Generates a POSCAR with the calculated diffusion path with respect to the first endpoint.
     :param outfile: Output file for the POSCAR
     """
     sum_struct = self.__images[0].sites
     for image in self.__images:
         for site_i in self.__relax_sites:
             sum_struct.append(PeriodicSite(image.sites[site_i].specie, image.sites[site_i].frac_coords,
                                            self.__images[0].lattice, to_unit_cell=True, coords_are_cartesian=False))
     sum_struct = Structure.from_sites(sum_struct, validate_proximity=False)
     p = Poscar(sum_struct)
     p.write_file(outfile)
예제 #23
0
파일: surface.py 프로젝트: adozier/pymatgen
    def from_dict(cls, d):
        lattice = Lattice.from_dict(d["lattice"])
        sites = [PeriodicSite.from_dict(sd, lattice) for sd in d["sites"]]
        s = Structure.from_sites(sites)

        return Slab(
            lattice=lattice,
            species=s.species_and_occu, coords=s.frac_coords,
            miller_index=d["miller_index"],
            oriented_unit_cell=Structure.from_dict(d["oriented_unit_cell"]),
            shift=d["shift"], scale_factor=d["scale_factor"],
            site_properties=s.site_properties, energy=d["energy"]
        )
예제 #24
0
    def from_dict(cls, d):
        lattice = Lattice.from_dict(d["lattice"])
        sites = [PeriodicSite.from_dict(sd, lattice) for sd in d["sites"]]
        s = Structure.from_sites(sites)

        return Slab(
            lattice=lattice,
            species=s.species_and_occu, coords=s.frac_coords,
            miller_index=d["miller_index"],
            oriented_unit_cell=Structure.from_dict(d["oriented_unit_cell"]),
            shift=d["shift"], scale_factor=d["scale_factor"],
            site_properties=s.site_properties, energy=d["energy"]
        )
예제 #25
0
def add_vacuum_padding(slab, vacuum, hkl=[0,0,1]):
    """
    add vacuum spacing to the given structure
    Args:
        slab: sructure/slab object to be padded 
        vacuum: in angstroms
        hkl: miller index
    Returns:
         Structure object
    """
    min_z = np.min([fcoord[2] for fcoord in slab.frac_coords])
    slab.translate_sites(list(range(len(slab))), [0, 0, -min_z])
    a, b, c = slab.lattice.matrix
    z = [coord[2] for coord in slab.cart_coords]
    zmax = np.max(z)
    zmin = np.min(z)
    thickness = zmax - zmin
    new_c = c / np.linalg.norm(c) * (thickness+vacuum)
    new_lattice = Lattice(np.array([a,b,new_c]))
    new_sites = []
    for site in slab:
        new_sites.append(PeriodicSite(site.species_and_occu,
                                      site.coords,
                                      new_lattice,
                                      properties=site.properties,
                                      coords_are_cartesian=True))
    new_struct = Structure.from_sites(new_sites)
    #center the slab
    avg_z = np.average([fcoord[2] for fcoord in new_struct.frac_coords])
    new_struct.translate_sites(list(range(len(new_struct))),
                               [0, 0, 0.5 - avg_z])
    return Slab(new_struct.lattice,
                new_struct.species_and_occu,
                new_struct.frac_coords,
                hkl,
                Structure.from_sites(new_struct,to_unit_cell=True),
                shift=0,
                scale_factor=np.eye(3, dtype=np.int),
                site_properties=new_struct.site_properties)
예제 #26
0
 def plot_images(self, outfile):
     """
     Generates a POSCAR with the calculated diffusion path with respect to the first endpoint.
     :param outfile: Output file for the POSCAR
     """
     sum_struct = self.__images[0].sites
     for image in self.__images:
         for site_i in self.__relax_sites:
             sum_struct.append(PeriodicSite(image.sites[site_i].specie, image.sites[site_i].frac_coords,
                                            self.__images[0].lattice, to_unit_cell=True, coords_are_cartesian=False))
     sum_struct = Structure.from_sites(sum_struct, validate_proximity=False)
     p = Poscar(sum_struct)
     p.write_file(outfile)
예제 #27
0
    def test_structures(self):
        import itertools
        import numpy as np

        from pymatgen.core.structure import Structure
        from pymatgen.core.lattice import Lattice
        from pymatgen.core.sites import PeriodicSite

        from supercellor.supercell import make_supercell

        NTESTS = 100  #100
        RADIUS = 100.0
        EPS = 1e-3
        DIAG = 4
        NOISE_R = 2
        tests_run = 0
        np.random.seed(10)
        while (tests_run < NTESTS):
            R = DIAG * np.eye(3, dtype=int) - np.random.randint(
                NOISE_R, size=(3, 3)) + NOISE_R
            #np.random.randint(10, size=(3,3)) -5
            S = RADIUS * np.eye(3)
            try:
                P = np.dot(np.linalg.inv(R), S)
            except np.linalg.LinAlgError:
                continue
            lattice = Lattice(P)
            if lattice.volume < 0.01 * RADIUS**3 / DIAG:
                print('skipping', lattice.volume)
                continue
            sites = []
            try:
                for pos in itertools.product([-0.5, 0.5], repeat=3):
                    sites.append(
                        PeriodicSite("H",
                                     pos,
                                     lattice,
                                     coords_are_cartesian=True))
            except np.linalg.LinAlgError:
                continue
            structure = Structure.from_sites(sites)

            supercell, scale = make_supercell(structure,
                                              distance=RADIUS - EPS,
                                              verbosity=0,
                                              wrap=True,
                                              standardize=True,
                                              do_niggli_first=True)
            self.assertTrue(
                np.sum(np.abs(supercell._lattice.matrix - S)) < EPS)
            tests_run += 1
예제 #28
0
    def test_niggli(self):
        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 make_supercell
        import numpy as np
        import itertools

        np.random.seed(4)
        DIST = 0.99

        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)

        supercell1, scale1 = make_supercell(structure,
                                            distance=DIST,
                                            verbosity=1,
                                            wrap=True,
                                            standardize=True,
                                            do_niggli_first=False)
        supercell2, scale2 = make_supercell(structure,
                                            distance=DIST,
                                            verbosity=1,
                                            wrap=True,
                                            standardize=True,
                                            do_niggli_first=True)

        sa = SpacegroupAnalyzer(supercell1, symprec=1e-21, angle_tolerance=-1)
        supercell_refine = sa.get_refined_structure()
        for i in range(3):
            for j in range(3):
                self.assertTrue(
                    abs(supercell1._lattice.matrix[i, j] -
                        supercell2._lattice.matrix[i, j]) < 1e-1,
                    '{} != {} for i,j={},{}'.format(
                        supercell1._lattice.matrix[i, j],
                        supercell2._lattice.matrix[i, j], i, j))
                self.assertTrue(
                    abs(supercell1._lattice.matrix[i, j] -
                        supercell_refine._lattice.matrix[i, j]) < 1e-1,
                    '{} != {} for i,j={},{}'.format(
                        supercell1._lattice.matrix[i, j],
                        supercell_refine._lattice.matrix[i, j], i, j))
예제 #29
0
    def get_structure_with_only_magnetic_atoms(self, make_primitive=True):
        """
        Returns a Structure with only magnetic atoms present.
        :return: Structure
        """

        sites = [site for site in self.structure if abs(site.properties["magmom"]) > 0]

        structure = Structure.from_sites(sites)

        if make_primitive:
            structure = structure.get_primitive_structure(use_site_props=True)

        return structure
예제 #30
0
    def fast_ordering(self, structure, num_remove_dict, num_to_return=1):
        """
        This method uses the matrix form of ewaldsum to calculate the ewald
        sums of the potential structures. This is on the order of 4 orders of
        magnitude faster when there are large numbers of permutations to
        consider. There are further optimizations possible (doing a smarter
        search of permutations for example), but this wont make a difference
        until the number of permutations is on the order of 30,000.
        """
        self.logger.debug("Performing fast ordering")
        starttime = time.time()
        self.logger.debug("Performing initial ewald sum...")

        ewaldmatrix = EwaldSummation(structure).total_energy_matrix
        self.logger.debug("Ewald sum took {} seconds."
                          .format(time.time() - starttime))
        starttime = time.time()
        m_list = []
        for indices, num in num_remove_dict.items():
            m_list.append([0, num, list(indices), None])

        self.logger.debug("Calling EwaldMinimizer...")
        minimizer = EwaldMinimizer(ewaldmatrix, m_list, num_to_return,
                                   PartialRemoveSitesTransformation.ALGO_FAST)
        self.logger.debug("Minimizing Ewald took {} seconds."
                          .format(time.time() - starttime))

        all_structures = []

        lowest_energy = minimizer.output_lists[0][0]
        num_atoms = sum(structure.composition.values())

        for output in minimizer.output_lists:
            s = Structure.from_sites(structure.sites)
            del_indices = []

            for manipulation in output[1]:
                if manipulation[1] is None:
                    del_indices.append(manipulation[0])
                else:
                    s.replace(manipulation[0], manipulation[1])
            s.remove_sites(del_indices)
            struct = s.get_sorted_structure()
            all_structures.append(
                {"energy": output[0],
                 "energy_above_minimum": (output[0] - lowest_energy)
                    / num_atoms,
                 "structure": struct})

        return all_structures
예제 #31
0
    def test_equivalence_fort_py(self):
        from datetime import datetime
        import itertools
        import numpy as np

        from pymatgen.core.structure import Structure
        from pymatgen.core.lattice import Lattice
        from pymatgen.core.sites import PeriodicSite

        from supercellor.supercell import make_supercell

        NTESTS = 10 #100
        VERBOSITY = 0
        for radius in np.arange(1.0, 3.1, 1.0):
            #RADIUS = 5.0
            tests_run = 0
            np.random.seed(10) # reinitialize seed!
            timings_f = 0.0
            timings_p = 0.0
            while (tests_run < NTESTS):
                P = np.eye(3)+ 0.1*(np.random.random((3,3)) -0.5)
                lattice = Lattice(P)
                if lattice.volume < 0.1:
                    print('skipping', lattice.volume)
                    continue
                sites = []
                try:
                    for pos in itertools.product([-0.5,0.5], repeat=3):
                        sites.append(PeriodicSite("H", pos, lattice, coords_are_cartesian=True))
                except np.linalg.LinAlgError:
                    continue
                structure = Structure.from_sites(sites)
                n = datetime.now()
                supercell_p, scale_p = make_supercell(structure, distance=radius,
                        verbosity=VERBOSITY, wrap=True, standardize=True, do_niggli_first=True,
                        implementation='pyth')
                timings_p += (datetime.now()-n).microseconds
                n = datetime.now()
                supercell_f, scale_f = make_supercell(structure, distance=radius,
                        verbosity=VERBOSITY, wrap=True, standardize=True, do_niggli_first=True,
                        implementation='fort')
                timings_f += (datetime.now()-n).microseconds
                self.assertTrue(np.sum((scale_p-scale_f)**2) ==0)
                self.assertTrue(np.sum((supercell_f._lattice.matrix -supercell_p._lattice.matrix)**2) < 1e-6)

                #~ self.assertTrue(np.sum(np.abs(supercell._lattice.matrix - S))< EPS)
                tests_run += 1
            print('Avg timing fortran impl rad={} {:.2e}'.format(radius, 1e-6*timings_f/ tests_run))
            print('Avg timing python  impl rad={} {:.2e}'.format(radius, 1e-6*timings_p/ tests_run))
예제 #32
0
파일: utils.py 프로젝트: albalu/pymatgen
 def vtk(self):
     if StructureVis is None:
         raise NotImplementedError("vtk must be present to view.")
     lattice = self.structure.lattice
     vis = StructureVis()
     vis.set_structure(Structure.from_sites(self.structure))
     for v in self.vnodes:
         vis.add_site(PeriodicSite("K", v.frac_coords, lattice))
         vis.add_polyhedron(
             [PeriodicSite("S", c, lattice, coords_are_cartesian=True) for c in v.polyhedron_coords],
             PeriodicSite("Na", v.frac_coords, lattice),
             color="element",
             draw_edges=True,
             edges_color=(0, 0, 0))
     vis.show()
예제 #33
0
파일: analyzer.py 프로젝트: zclpf/pymatgen
    def get_structure_with_only_magnetic_atoms(self, make_primitive=True):
        """
        Returns a Structure with only magnetic atoms present.
        :return: Structure
        """

        sites = [site for site in self.structure
                 if abs(site.properties['magmom']) > 0]

        structure = Structure.from_sites(sites)

        if make_primitive:
            structure = structure.get_primitive_structure(use_site_props=True)

        return structure
예제 #34
0
def write_structures(structures, file_name, format):
    import tempfile
    import zipfile
    from os.path import basename, join
    import os
    format_name, Writer = format
    file_type = format_name
    if len(structures) > 1:
        result_archive = zipfile.ZipFile(join(os.getcwd(),
                                              basename(file_name) + '.zip'),
                                         mode='w')
        for name, structure in structures.items():
            sorted_sites = list(
                sorted(structure.sites.copy(),
                       key=lambda site: site.specie.symbol))
            sorted_structure = Structure.from_sites(sorted_sites)
            with tempfile.NamedTemporaryFile() as tmpfile:
                Writer(sorted_structure).write_file(tmpfile.name)
                result_archive.write(tmpfile.name,
                                     arcname='{}.{}'.format(name, file_type))
        result_archive.close()
        write_message('Archive file: {0}'.format(
            join(os.getcwd(),
                 basename(file_name) + '.zip')),
                      level=DEBUG)
    else:
        #There is just one file write only that one
        structure_key = list(structures.keys())[0]
        sorted_sites = list(
            sorted(structures[structure_key].sites.copy(),
                   key=lambda site: site.specie.symbol))
        sorted_structure = Structure.from_sites(sorted_sites)
        p = Writer(sorted_structure)
        fname = join(os.getcwd(), '{}.{}'.format(structure_key, file_type))
        p.write_file(fname)
        write_message('Output file: {0}'.format(fname), level=DEBUG)
예제 #35
0
 def enumerate_ordering(self, structure):
     # Generate the disordered structure first.
     s = Structure.from_sites(structure.sites)
     for indices, fraction in zip(self._indices, self._fractions):
         for ind in indices:
             new_sp = {
                 sp: occu * fraction
                 for sp, occu in structure[ind].species_and_occu.items()
             }
             s[ind] = new_sp
     # Perform enumeration
     from pymatgen.transformations.advanced_transformations import \
         EnumerateStructureTransformation
     trans = EnumerateStructureTransformation()
     return trans.apply_transformation(s, 10000)
예제 #36
0
    def get_sorted_structure(self, key=None, reverse=False) -> Structure:
        """
        Get a sorted structure for the interface. The parameters have the same
        meaning as in list.sort. By default, sites are sorted by the
        electronegativity of the species.

        Args:
            key: Specifies a function of one argument that is used to extract
                a comparison key from each list element: key=str.lower. The
                default value is None (compare the elements directly).
            reverse (bool): If set to True, then the list elements are sorted
                as if each comparison were reversed.
        """
        struct_copy = Structure.from_sites(self)
        struct_copy.sort(key=key, reverse=reverse)
        return struct_copy
예제 #37
0
파일: utils.py 프로젝트: albalu/pymatgen
    def analyze_symmetry(self, tol):
        s = Structure.from_sites(self.framework)
        site_to_vindex = {}
        for i, v in enumerate(self.vnodes):
            s.append("Li", v.frac_coords)
            site_to_vindex[s[-1]] = i

        print(len(s))
        finder = SpacegroupAnalyzer(s, tol)
        print(finder.get_space_group_operations())
        symm_structure = finder.get_symmetrized_structure()
        print(len(symm_structure.equivalent_sites))
        return [[site_to_vindex[site]
                 for site in sites]
                for sites in symm_structure.equivalent_sites
                if sites[0].specie.symbol == "Li"]
예제 #38
0
    def test_offset_vector(self):
        interface = self.ib.interfaces[0]
        init_lattice = interface.lattice.matrix.copy()
        self.assertArrayAlmostEqual(interface.offset_vector,
                                    np.array([0, 0, 2.5]))
        init_film = interface.film
        init_sub = interface.substrate
        tst = Structure.from_sites(interface.sites)

        interface.z_shift += 1
        self.assertArrayAlmostEqual(interface.offset_vector,
                                    np.array([0, 0, 3.5]))
        tdm, idm = tst.distance_matrix, interface.distance_matrix
        diff = tdm - idm
        assert (tdm <= idm + 1e-10).all()
        assert (tdm + 0.5 < idm).any()
        self.assertArrayAlmostEqual(init_film.distance_matrix,
                                    interface.film.distance_matrix)
        self.assertArrayAlmostEqual(init_sub.distance_matrix,
                                    interface.substrate.distance_matrix)

        interface.z_shift -= 1
        self.assertArrayAlmostEqual(interface.offset_vector,
                                    np.array([0, 0, 2.5]))
        idm = interface.distance_matrix
        assert (np.abs(tdm - idm) < 1e-10).all()

        interface.ab_shift += np.array([0.2, 0.2])
        self.assertArrayAlmostEqual(interface.ab_shift, np.array([0.2, 0.2]))
        idm = interface.distance_matrix
        assert (np.abs(tdm - idm) > 0.9).any()
        self.assertArrayAlmostEqual(init_lattice, interface.lattice.matrix)
        self.assertArrayAlmostEqual(init_film.distance_matrix,
                                    interface.film.distance_matrix)
        self.assertArrayAlmostEqual(init_sub.distance_matrix,
                                    interface.substrate.distance_matrix)

        interface.ab_shift -= np.array([0.2, 0.2])
        self.assertArrayAlmostEqual(interface.offset_vector,
                                    np.array([0, 0, 2.5]))
        idm = interface.distance_matrix
        assert (np.abs(tdm - idm) < 1e-10).all()

        self.assertArrayAlmostEqual(init_film.distance_matrix,
                                    interface.film.distance_matrix)
        self.assertArrayAlmostEqual(init_sub.distance_matrix,
                                    interface.substrate.distance_matrix)
예제 #39
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'))
예제 #40
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'))
예제 #41
0
    def get_s2_like_s1(self, struct1, struct2):
        """
        Performs transformations on struct2 to put it in a basis similar to
        struct1 (without changing any of the inter-site distances)
        """
        if self._primitive_cell:
            raise ValueError("get_s2_like_s1 cannot be used with the primitive"
                             " cell option")
            
        s1, s2, fu, s1_supercell = self._preprocess(struct1, struct2, False)
        ratio = fu if s1_supercell else 1/fu
        
        if s1_supercell and fu > 1:
            raise ValueError("Struct1 must be the supercell, "
                             "not the other way around")
        
        if len(s1) * ratio >= len(s2):
            #s1 is superset
            match = self._match(s1, s2, fu=fu, s1_supercell=s1_supercell, 
                                use_rms=True, break_on_match=False)
        else:
            #s2 is superset
            match = self._match(s2, s1, fu=fu, s1_supercell=(not s1_supercell), 
                                use_rms=True, break_on_match=False)

        if match is None:
            return None
        
        temp = struct2.copy()
        temp.make_supercell(match[2])
        
        if len(struct1) >= len(temp):
            #invert the mapping, since it needs to be from s2 to s1
            mapping = np.argsort(match[4])
            tvec = match[3]
        else:
            #add sites not included in the mapping
            not_included = range(len(temp))
            for i in match[4]:
                not_included.remove(i)
            mapping = list(match[4]) + not_included
            tvec = -match[3]
            
        temp.translate_sites(range(len(temp)), tvec)
        return Structure.from_sites([temp.sites[i] for i in mapping])
예제 #42
0
    def get_oxi_state_decorated_structure(self, structure):
        """
        Get an oxidation state decorated structure. This currently works only
        for ordered structures only.

        Args:
            structure: Structure to analyze

        Returns:
            A modified structure that is oxidation state decorated.

        Raises:
            ValueError if the valences cannot be determined.
        """
        valences = self.get_valences(structure)
        s = Structure.from_sites(structure.sites)
        s.add_oxidation_state_by_site(valences)
        return s
예제 #43
0
    def get_structure_with_only_magnetic_atoms(self, make_primitive: bool = True) -> Structure:
        """Returns a Structure with only magnetic atoms present.

        Args:
          make_primitive: Whether to make structure primitive after
            removing non-magnetic atoms (Default value = True)

        Returns: Structure
        """

        sites = [site for site in self.structure if abs(site.properties["magmom"]) > 0]

        structure = Structure.from_sites(sites)

        if make_primitive:
            structure = structure.get_primitive_structure(use_site_props=True)

        return structure
예제 #44
0
def label_termination(slab: Structure) -> str:
    """Labels the slab surface termination"""
    frac_coords = slab.frac_coords
    n = len(frac_coords)

    if n == 1:
        # Clustering does not work when there is only one data point.
        form = slab.composition.reduced_formula
        sp_symbol = SpacegroupAnalyzer(slab,
                                       symprec=0.1).get_space_group_symbol()
        return f"{form}_{sp_symbol}_{len(slab)}"

    dist_matrix = np.zeros((n, n))
    h = slab.lattice.c
    # Projection of c lattice vector in
    # direction of surface normal.
    for i, j in combinations(list(range(n)), 2):
        if i != j:
            cdist = frac_coords[i][2] - frac_coords[j][2]
            cdist = abs(cdist - round(cdist)) * h
            dist_matrix[i, j] = cdist
            dist_matrix[j, i] = cdist

    condensed_m = squareform(dist_matrix)
    z = linkage(condensed_m)
    clusters = fcluster(z, 0.25, criterion="distance")

    clustered_sites: dict[int, list[Site]] = {c: [] for c in clusters}
    for i, c in enumerate(clusters):
        clustered_sites[c].append(slab[i])

    plane_heights = {
        np.average(np.mod([s.frac_coords[2] for s in sites], 1)): c
        for c, sites in clustered_sites.items()
    }
    top_plane_cluster = sorted(plane_heights.items(),
                               key=lambda x: x[0])[-1][1]
    top_plane_sites = clustered_sites[top_plane_cluster]
    top_plane = Structure.from_sites(top_plane_sites)

    sp_symbol = SpacegroupAnalyzer(top_plane,
                                   symprec=0.1).get_space_group_symbol()
    form = top_plane.composition.reduced_formula
    return f"{form}_{sp_symbol}_{len(top_plane)}"
예제 #45
0
    def __init__(self,
                 structure,
                 scaling_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1))):
        """
        Create a supercell.

        Args:
            structure:
                pymatgen.core.structure Structure object.
            scaling_matrix:
                a matrix of transforming the lattice vectors. Defaults to the
                identity matrix. Has to be all integers. e.g.,
                [[2,1,0],[0,3,0],[0,0,1]] generates a new structure with
                lattice vectors a' = 2a + b, b' = 3b, c' = c where a, b, and c
                are the lattice vectors of the original structure.
        """
        self._original_structure = structure
        old_lattice = structure.lattice
        scale_matrix = np.array(scaling_matrix)
        new_lattice = Lattice(np.dot(scale_matrix, old_lattice.matrix))
        new_sites = []

        def range_vec(i):
            return range(
                max(scale_matrix[:][:, i]) - min(scale_matrix[:][:, i]) + 1)

        for site in structure.sites:
            for (i, j, k) in itertools.product(range_vec(0), range_vec(1),
                                               range_vec(2)):
                fcoords = site.frac_coords + np.array([i, j, k])
                coords = old_lattice.get_cartesian_coords(fcoords)
                new_coords = new_lattice.get_fractional_coords(coords)
                new_site = PeriodicSite(site.species_and_occu,
                                        new_coords,
                                        new_lattice,
                                        properties=site.properties)
                contains_site = False
                for s in new_sites:
                    if s.is_periodic_image(new_site):
                        contains_site = True
                        break
                if not contains_site:
                    new_sites.append(new_site)
        self._modified_structure = Structure.from_sites(new_sites)
예제 #46
0
    def get_oxi_state_decorated_structure(self, structure):
        """
        Get an oxidation state decorated structure. This currently works only
        for ordered structures only.

        Args:
            structure:
                Structure to analyze

        Returns:
            A modified structure that is oxidation state decorated.

        Raises:
            A ValueError is the valences cannot be determined.
        """
        valences = self.get_valences(structure)
        s = Structure.from_sites(structure.sites)
        s.add_oxidation_state_by_site(valences)
        return s
예제 #47
0
    def get_sorted_structure(self, key=None, reverse=False):
        """
        Get a sorted copy of the structure. The parameters have the same
        meaning as in list.sort. By default, sites are sorted by the
        electronegativity of the species. Note that Slab has to override this
        because of the different __init__ args.

        Args:
            key: Specifies a function of one argument that is used to extract
                a comparison key from each list element: key=str.lower. The
                default value is None (compare the elements directly).
            reverse (bool): If set to True, then the list elements are sorted
                as if each comparison were reversed.
        """
        sites = sorted(self, key=key, reverse=reverse)
        s = Structure.from_sites(sites)
        return Slab(s.lattice, s.species_and_occu, s.frac_coords,
                    self.miller_index, self.oriented_unit_cell, self.shift,
                    self.scale_factor, site_properties=s.site_properties)
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)
예제 #49
0
    def test_hnf_dmpi(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
        np.random.seed(50)
        N = 1
        RMIN = 2
        RMAX = 3

        for trial in range(N):
            #~ for implementation in ('pyth', ):
            for implementation in ('fort', ):
                lattice = Lattice(1.0 * np.eye(3) + 0.2 *
                                  (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)

                for rad in range(RMIN, RMAX):
                    supercell1, scale1 = make_supercell(
                        structure,
                        distance=rad,
                        method='hnf',
                        implementation=implementation,
                        verbosity=0,
                        wrap=True,
                        standardize=False,
                        do_niggli_first=False)
                    reduced_supercell1 = supercell1.get_reduced_structure(
                        reduction_algo=u'LLL')
                    for dim in range(3):
                        self.assertTrue(
                            np.linalg.norm(reduced_supercell1._lattice.
                                           matrix[dim]) >= rad)
예제 #50
0
def slab_from_file(hkl, filename):
    """
    reads in structure from the file and returns slab object.
    useful for reading in 2d/substrate structures from file.
    Args:
         hkl: miller index of the slab in the input file.
         filename: structure file in any format 
                   supported by pymatgen
    Returns:
         Slab object
    """
    slab_input = Structure.from_file(filename)
    return Slab(slab_input.lattice,
                slab_input.species_and_occu,
                slab_input.frac_coords,
                hkl,
                Structure.from_sites(slab_input, to_unit_cell=True),
                shift=0,
                scale_factor=np.eye(3, dtype=np.int),
                site_properties=slab_input.site_properties)
예제 #51
0
    def best_first_ordering(self, structure, num_remove_dict):
        self.logger.debug("Performing best first ordering")
        starttime = time.time()
        self.logger.debug("Performing initial ewald sum...")
        ewaldsum = EwaldSummation(structure)
        self.logger.debug("Ewald sum took {} seconds.".format(time.time() -
                                                              starttime))
        starttime = time.time()

        ematrix = ewaldsum.total_energy_matrix
        to_delete = []

        totalremovals = sum(num_remove_dict.values())
        removed = {k: 0 for k in num_remove_dict.keys()}
        for i in xrange(totalremovals):
            maxindex = None
            maxe = float("-inf")
            maxindices = None
            for indices in num_remove_dict.keys():
                if removed[indices] < num_remove_dict[indices]:
                    for ind in indices:
                        if ind not in to_delete:
                            energy = sum(ematrix[:, ind]) + \
                                sum(ematrix[:, ind]) - ematrix[ind, ind]
                            if energy > maxe:
                                maxindex = ind
                                maxe = energy
                                maxindices = indices
            removed[maxindices] += 1
            to_delete.append(maxindex)
            ematrix[:, maxindex] = 0
            ematrix[maxindex, :] = 0
        s = Structure.from_sites(structure.sites)
        s.remove_sites(to_delete)
        self.logger.debug(
            "Minimizing Ewald took {} seconds.".format(time.time() -
                                                       starttime))
        return [{
            "energy": sum(sum(ematrix)),
            "structure": s.get_sorted_structure()
        }]
예제 #52
0
    def from_dict(cls, d):
        """
        :param d: dict
        :return: Creates slab from dict.
        """
        lattice = Lattice.from_dict(d["lattice"])
        sites = [PeriodicSite.from_dict(sd, lattice) for sd in d["sites"]]
        s = Structure.from_sites(sites)

        optional = dict(
            in_plane_offset=d.get("in_plane_offset"),
            gap=d.get("gap"),
            vacuum_over_film=d.get("vacuum_over_film"),
            interface_properties=d.get("interface_properties"),
        )
        return Interface(
            lattice=lattice,
            species=s.species_and_occu,
            coords=s.frac_coords,
            site_properties=s.site_properties,
            **{k: v
               for k, v in optional.items() if v is not None},
        )
예제 #53
0
    def __str__(self):
        """
        Sorts a Structure (by fractional co-ordinate), and
        prints sites with magnetic information. This is
        useful over Structure.__str__ because sites are in
        a consistent order, which makes visual comparison between
        two identical Structures with different magnetic orderings
        easier.
        """

        frac_coords = self.structure.frac_coords
        sorted_indices = np.lexsort((frac_coords[:, 2], frac_coords[:, 1], frac_coords[:, 0]))
        s = Structure.from_sites([self.structure[idx] for idx in sorted_indices])

        # adapted from Structure.__repr__
        outs = ["Structure Summary", repr(s.lattice)]
        outs.append("Magmoms Sites")
        for site in s:
            if site.properties["magmom"] != 0:
                prefix = "{:+.2f}   ".format(site.properties["magmom"])
            else:
                prefix = "        "
            outs.append(prefix + repr(site))
        return "\n".join(outs)
예제 #54
0
    def from_dict(cls, d):
        """
        :param d: Dict representation
        :return: Interface
        """
        lattice = Lattice.from_dict(d["lattice"])
        sites = [PeriodicSite.from_dict(sd, lattice) for sd in d["sites"]]
        s = Structure.from_sites(sites)

        return Interface(
            lattice=lattice,
            species=s.species_and_occu,
            coords=s.frac_coords,
            sub_plane=d["sub_plane"],
            film_plane=d["film_plane"],
            sub_init_cell=d["sub_init_cell"],
            film_init_cell=d["film_init_cell"],
            modified_sub_structure=d["modified_sub_structure"],
            modified_film_structure=d["modified_film_structure"],
            strained_sub_structure=d["strained_sub_structure"],
            strained_film_structure=d["strained_film_structure"],
            site_properties=s.site_properties,
            init_inplane_shift=d["init_inplane_shift"],
        )
예제 #55
0
 def copy(self):
     return Structure.from_sites(self)
예제 #56
0
def vac_antisite_def_struct_gen(mpid, mapi_key, cellmax, struct_file=None):
    if not mpid and not struct_file:
        print ("============\nERROR: Provide an mpid\n============")
        return

    # Get primitive structure from the Materials Project DB
    if not struct_file:
        if not mapi_key:
            with MPRester() as mp:
                struct = mp.get_structure_by_material_id(mpid)
        else:
            with MPRester(mapi_key) as mp:
                struct = mp.get_structure_by_material_id(mpid)
    else:
        struct = Structure.from_file(struct_file)

    sga = SpacegroupAnalyzer(struct)
    prim_struct = sga.find_primitive()
    #prim_struct_sites = len(prim_struct.sites)
    #conv_struct = sga.get_conventional_standard_structure()
    #conv_struct_sites = len(conv_struct.sites)
    #conv_prim_ratio = int(conv_struct_sites / prim_struct_sites)

    # Default VASP settings
    def_vasp_incar_param = {'ISIF':2, 'EDIFF':1e-6, 'EDIFFG':0.001,}
    kpoint_den = 15000

    # Create bulk structure and associated VASP files
    sc_scale = get_sc_scale(inp_struct=prim_struct, final_site_no=cellmax)
    blk_sc = prim_struct.copy()
    blk_sc.make_supercell(scaling_matrix=sc_scale)
    site_no = blk_sc.num_sites

    # Rescale if needed
    while site_no > cellmax:
        max_sc_dim = max(sc_scale)
        i = sc_scale.index(max_sc_dim)
        sc_scale[i] -= 1
        blk_sc = prim_struct.copy()
        blk_sc.make_supercell(scaling_matrix=sc_scale)
        site_no = blk_sc.num_sites
    
    blk_str_sites = set(blk_sc.sites)
    custom_kpoints = Kpoints.automatic_density(blk_sc, kppa=kpoint_den)
    mpvis = MPMetalRelaxSet(blk_sc, user_incar_settings=def_vasp_incar_param,
                            user_kpoints_settings=custom_kpoints)

    if mpid:
        root_fldr = mpid
    else:
        root_fldr = struct.composition.reduced_formula

    fin_dir = os.path.join(root_fldr, 'bulk')
    mpvis.write_input(fin_dir)
    if not mpid:    # write the input structure if mpid is not used
        struct.to(fmt='poscar', filename=os.path.join(fin_dir, 'POSCAR.uc'))

    # Create each defect structure and associated VASP files
    # First find all unique defect sites
    periodic_struct = sga.get_symmetrized_structure()
    unique_sites = list(set([periodic_struct.find_equivalent_sites(site)[0] \
                             for site in periodic_struct.sites]))
    temp_struct = Structure.from_sites(sorted(unique_sites))
    prim_struct2 = SpacegroupAnalyzer(temp_struct).find_primitive()
    prim_struct2.lattice = prim_struct.lattice  # a little hacky
    for i, site in enumerate(prim_struct2.sites):
        vac = Vacancy(structure=prim_struct, defect_site=site)
        vac_sc = vac.generate_defect_structure(supercell=sc_scale)

        # Get vacancy site information
        vac_str_sites = set(vac_sc.sites)
        vac_sites = blk_str_sites - vac_str_sites
        vac_site = next(iter(vac_sites))
        site_mult = vac.get_multiplicity()
        vac_site_specie = vac_site.specie
        vac_symbol = vac_site_specie.symbol

        custom_kpoints = Kpoints.automatic_density(vac_sc, kppa=kpoint_den)
        mpvis = MPMetalRelaxSet(vac_sc,
                                user_incar_settings=def_vasp_incar_param,
                                user_kpoints_settings=custom_kpoints)
        vac_dir = 'vacancy_{}_mult-{}_sitespecie-{}'.format(
                    str(i+1), site_mult, vac_symbol)
        fin_dir = os.path.join(root_fldr, vac_dir)
        mpvis.write_input(fin_dir)

        # Antisites generation at the vacancy site
        struct_species = blk_sc.species
        for specie in set(struct_species) - set([vac_site_specie]):
            specie_symbol = specie.symbol
            anti_sc = vac_sc.copy()
            anti_sc.append(specie, vac_site.frac_coords)
            mpvis = MPMetalRelaxSet(anti_sc,
                                    user_incar_settings=def_vasp_incar_param,
                                    user_kpoints_settings=custom_kpoints)
            anti_dir = 'antisite_{}_mult-{}_sitespecie-{}_subspecie-{}'.format(
                        str(i+1), site_mult, vac_symbol, specie_symbol)
            fin_dir = os.path.join(root_fldr, anti_dir)
            mpvis.write_input(fin_dir)
예제 #57
0
    def set_structure(self, structure, reset_camera=True):
        """
        Add a structure to the visualizer.

        Args:
            structure:
                structure to visualize
            reset_camera:
                Set to True to reset the camera to a default determined based
                on the structure.
        """
        self.ren.RemoveAllViewProps()

        has_lattice = hasattr(structure, "lattice")

        if has_lattice:
            s = Structure.from_sites(structure, to_unit_cell=True)
            s.make_supercell(self.supercell)
        else:
            s = structure

        inc_coords = []
        for site in s:
            self.add_site(site)
            inc_coords.append(site.coords)

        count = 0
        labels = ["a", "b", "c"]
        colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

        if has_lattice:
            matrix = s.lattice.matrix

        if self.show_unit_cell and has_lattice:
            #matrix = s.lattice.matrix
            self.add_text([0, 0, 0], "o")
            for vec in matrix:
                self.add_line((0, 0, 0), vec, colors[count])
                self.add_text(vec, labels[count], colors[count])
                count += 1
            for (vec1, vec2) in itertools.permutations(matrix, 2):
                self.add_line(vec1, vec1 + vec2)
            for (vec1, vec2, vec3) in itertools.permutations(matrix, 3):
                self.add_line(vec1 + vec2, vec1 + vec2 + vec3)

        if self.show_bonds or self.show_polyhedron:
            elements = sorted(s.composition.elements, key=lambda a: a.X)
            anion = elements[-1]

            def contains_anion(site):
                for sp in site.species_and_occu.keys():
                    if sp.symbol == anion.symbol:
                        return True
                return False

            anion_radius = anion.average_ionic_radius
            for site in s:
                exclude = False
                max_radius = 0
                color = np.array([0, 0, 0])
                for sp, occu in site.species_and_occu.items():
                    if sp.symbol in self.excluded_bonding_elements \
                            or sp == anion:
                        exclude = True
                        break
                    max_radius = max(max_radius, sp.average_ionic_radius)
                    color = color + \
                        occu * np.array(self.el_color_mapping.get(sp.symbol,
                                                                  [0, 0, 0]))

                if not exclude:
                    max_radius = (1 + self.poly_radii_tol_factor) * \
                        (max_radius + anion_radius)
                    nn = structure.get_neighbors(site, max_radius)
                    nn_sites = []
                    for nnsite, dist in nn:
                        if contains_anion(nnsite):
                            nn_sites.append(nnsite)
                            if not in_coord_list(inc_coords, nnsite.coords):
                                self.add_site(nnsite)
                    if self.show_bonds:
                        self.add_bonds(nn_sites, site)
                    if self.show_polyhedron:
                        color = [i / 255 for i in color]
                        self.add_polyhedron(nn_sites, site, color)

        if self.show_help:
            self.helptxt_actor = vtk.vtkActor2D()
            self.helptxt_actor.VisibilityOn()
            self.helptxt_actor.SetMapper(self.helptxt_mapper)
            self.ren.AddActor(self.helptxt_actor)
            self.display_help()

        camera = self.ren.GetActiveCamera()
        if reset_camera:
            if has_lattice:
                #Adjust the camera for best viewing
                lengths = s.lattice.abc
                pos = (matrix[1] + matrix[2]) * 0.5 + \
                    matrix[0] * max(lengths) / lengths[0] * 3.5
                camera.SetPosition(pos)
                camera.SetViewUp(matrix[2])
                camera.SetFocalPoint((matrix[0] + matrix[1] + matrix[2]) * 0.5)
            else:
                origin = s.center_of_mass
                max_site = max(
                    s, key=lambda site: site.distance_from_point(origin))
                camera.SetPosition(origin + 5 * (max_site.coords - origin))
                camera.SetFocalPoint(s.center_of_mass)

        self.structure = structure
        self.title = s.composition.formula
예제 #58
0
    def __init__(self,
                 initial_structure,
                 miller_index,
                 min_slab_size,
                 min_vacuum_size,
                 lll_reduce=False,
                 center_slab=False,
                 primitive=True,
                 max_normal_search=None):
        """
        Calculates the slab scale factor and uses it to generate a unit cell
        of the initial structure that has been oriented by its miller index.
        Also stores the initial information needed later on to generate a slab.

        Args:
            initial_structure (Structure): Initial input structure. Note that to
                ensure that the miller indices correspond to usual
                crystallographic definitions, you should supply a conventional
                unit cell structure.
            miller_index ([h, k, l]): Miller index of plane parallel to
                surface. Note that this is referenced to the input structure. If
                you need this to be based on the conventional cell,
                you should supply the conventional structure.
            min_slab_size (float): In Angstroms
            min_vac_size (float): In Angstroms
            lll_reduce (bool): Whether to perform an LLL reduction on the
                eventual structure.
            center_slab (bool): Whether to center the slab in the cell with
                equal vacuum spacing from the top and bottom.
            primitive (bool): Whether to reduce any generated slabs to a
                primitive cell (this does **not** mean the slab is generated
                from a primitive cell, it simply means that after slab
                generation, we attempt to find shorter lattice vectors,
                which lead to less surface area and smaller cells).
            max_normal_search (int): If set to a positive integer, the code will
                conduct a search for a normal lattice vector that is as
                perpendicular to the surface as possible by considering
                multiples linear combinations of lattice vectors up to
                max_normal_search. This has no bearing on surface energies,
                but may be useful as a preliminary step to generating slabs
                for absorption and other sizes. It is typical that this will
                not be the smallest possible cell for simulation. Normality
                is not guaranteed, but the oriented cell will have the c
                vector as normal as possible (within the search range) to the
                surface. A value of up to the max absolute Miller index is
                usually sufficient.
        """
        latt = initial_structure.lattice
        miller_index = reduce_vector(miller_index)
        #Calculate the surface normal using the reciprocal lattice vector.
        recp = latt.reciprocal_lattice_crystallographic
        normal = recp.get_cartesian_coords(miller_index)
        normal /= np.linalg.norm(normal)

        slab_scale_factor = []
        non_orth_ind = []
        eye = np.eye(3, dtype=np.int)
        for i, j in enumerate(miller_index):
            if j == 0:
                # Lattice vector is perpendicular to surface normal, i.e.,
                # in plane of surface. We will simply choose this lattice
                # vector as one of the basis vectors.
                slab_scale_factor.append(eye[i])
            else:
                #Calculate projection of lattice vector onto surface normal.
                d = abs(np.dot(normal, latt.matrix[i])) / latt.abc[i]
                non_orth_ind.append((i, d))

        # We want the vector that has maximum magnitude in the
        # direction of the surface normal as the c-direction.
        # Results in a more "orthogonal" unit cell.
        c_index, dist = max(non_orth_ind, key=lambda t: t[1])

        if len(non_orth_ind) > 1:
            lcm_miller = lcm(*[miller_index[i] for i, d in non_orth_ind])
            for (i, di), (j, dj) in itertools.combinations(non_orth_ind, 2):
                l = [0, 0, 0]
                l[i] = -int(round(lcm_miller / miller_index[i]))
                l[j] = int(round(lcm_miller / miller_index[j]))
                slab_scale_factor.append(l)
                if len(slab_scale_factor) == 2:
                    break

        if max_normal_search is None:
            slab_scale_factor.append(eye[c_index])
        else:
            index_range = sorted(reversed(
                range(-max_normal_search, max_normal_search + 1)),
                                 key=lambda x: abs(x))
            candidates = []
            for uvw in itertools.product(index_range, index_range,
                                         index_range):
                if (not any(uvw)) or abs(
                        np.linalg.det(slab_scale_factor + [uvw])) < 1e-8:
                    continue
                vec = latt.get_cartesian_coords(uvw)
                l = np.linalg.norm(vec)
                cosine = abs(np.dot(vec, normal) / l)
                candidates.append((uvw, cosine, l))
                if abs(abs(cosine) - 1) < 1e-8:
                    # If cosine of 1 is found, no need to search further.
                    break
            # We want the indices with the maximum absolute cosine,
            # but smallest possible length.
            uvw, cosine, l = max(candidates, key=lambda x: (x[1], -l))
            slab_scale_factor.append(uvw)

        slab_scale_factor = np.array(slab_scale_factor)

        # Let's make sure we have a left-handed crystallographic system
        if np.linalg.det(slab_scale_factor) < 0:
            slab_scale_factor *= -1

        # Make sure the slab_scale_factor is reduced to avoid
        # unnecessarily large slabs

        reduced_scale_factor = [reduce_vector(v) for v in slab_scale_factor]
        slab_scale_factor = np.array(reduced_scale_factor)

        single = initial_structure.copy()
        single.make_supercell(slab_scale_factor)

        self.oriented_unit_cell = Structure.from_sites(single,
                                                       to_unit_cell=True)
        self.parent = initial_structure
        self.lll_reduce = lll_reduce
        self.center_slab = center_slab
        self.slab_scale_factor = slab_scale_factor
        self.miller_index = miller_index
        self.min_vac_size = min_vacuum_size
        self.min_slab_size = min_slab_size
        self.primitive = primitive
        self._normal = normal
        a, b, c = self.oriented_unit_cell.lattice.matrix
        self._proj_height = abs(np.dot(normal, c))
예제 #59
0
    def _get_structures(self, num_structs):
        structs = []

        if ".py" in makestr_cmd:
            options = ["-input", "struct_enum.out", str(1), str(num_structs)]
        else:
            options = ["struct_enum.out", str(0), str(num_structs - 1)]

        rs = subprocess.Popen([makestr_cmd] + options,
                              stdout=subprocess.PIPE,
                              stdin=subprocess.PIPE,
                              close_fds=True)
        stdout, stderr = rs.communicate()
        if stderr:
            logger.warning(stderr.decode())

        # sites retrieved from enumlib will lack site properties
        # to ensure consistency, we keep track of what site properties
        # are missing and set them to None
        # TODO: improve this by mapping ordered structure to original
        # disorded structure, and retrieving correct site properties
        disordered_site_properties = {}

        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.
            site_properties = {}
            for site in self.ordered_sites:
                for k, v in site.properties.items():
                    disordered_site_properties[k] = None
                    if k in site_properties:
                        site_properties[k].append(v)
                    else:
                        site_properties[k] = [v]
            ordered_structure = Structure(
                original_latt, [site.species for site in self.ordered_sites],
                [site.frac_coords for site in self.ordered_sites],
                site_properties=site_properties)
            inv_org_latt = np.linalg.inv(original_latt.matrix)

        for file in glob.glob('vasp.*'):
            with open(file) as f:
                data = f.read()
                data = re.sub(r'scale factor', "1", data)
                data = re.sub(r'(\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 = ordered_structure * 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,
                                site.frac_coords,
                                super_latt,
                                to_unit_cell=True,
                                properties=disordered_site_properties))
                    else:
                        logger.debug("Skipping sites that include species X.")
                structs.append(Structure.from_sites(sorted(sites)))

        logger.debug("Read in a total of {} structures.".format(num_structs))
        return structs
예제 #60
0
 def get_sg_info(ss):
     finder = SpacegroupAnalyzer(Structure.from_sites(ss),
                                 self.symm_prec)
     return finder.get_space_group_number()