def test_apply_transformation(self):
        trans = MagOrderingTransformation({"Fe": 5})
        p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'),
                             check_for_POTCAR=False)
        s = p.structure
        alls = trans.apply_transformation(s, 10)
        self.assertEqual(len(alls), 3)
        f = SymmetryFinder(alls[0]["structure"], 0.1)
        self.assertEqual(f.get_spacegroup_number(), 31)

        model = IsingModel(5, 5)
        trans = MagOrderingTransformation({"Fe": 5},
                                          energy_model=model)
        alls2 = trans.apply_transformation(s, 10)
        #Ising model with +J penalizes similar neighbor magmom.
        self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"])
        self.assertEqual(alls[0]["structure"], alls2[2]["structure"])

        from pymatgen.io.smartio import read_structure
        s = read_structure(os.path.join(test_dir, 'Li2O.cif'))
        #Li2O doesn't have magnetism of course, but this is to test the
        # enumeration.
        trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3)
        alls = trans.apply_transformation(s, 100)
        self.assertEqual(len(alls), 10)
Ejemplo n.º 2
0
 def __init__(self, struct, source='', comment=''):
     """
     Args:
         struct:
             Structure object, See pymatgen.core.structure.Structure.
         source:
             User supplied identifier, i.e. for Materials Project this
             would be the material ID number
         comment:
             comment for first header line
     """
     if struct.is_ordered:
         self._struct = struct
         self._source = source
         self._site_symbols = []
         self._natoms = []
         sym = SymmetryFinder(struct)
         data = sym.get_symmetry_dataset()
         self._space_number = data["number"]
         self._space_group = data["international"]
         syms = [site.specie.symbol for site in struct]
         for (s, data) in itertools.groupby(syms):
             self._site_symbols.append(s)
             self._natoms.append(len(tuple(data)))
         if comment == '':
             self._comment = 'None Given'
         else:
             self._comment = comment
     else:
         raise ValueError("Structure with partial occupancies cannot be "
                          "converted into atomic coordinates!")
Ejemplo n.º 3
0
 def __init__(self, struct, source='', comment=''):
     """
     Args:
         struct:
             Structure object, See pymatgen.core.structure.Structure.
         source:
             User supplied identifier, i.e. for Materials Project this
             would be the material ID number
         comment:
             comment for first header line
     """
     if struct.is_ordered:
         self._struct = struct
         self._source = source
         self._site_symbols = []
         self._natoms = []
         sym = SymmetryFinder(struct)
         data = sym.get_symmetry_dataset()
         self._space_number = data["number"]
         self._space_group = data["international"]
         syms = [site.specie.symbol for site in struct]
         for (s, data) in itertools.groupby(syms):
             self._site_symbols.append(s)
             self._natoms.append(len(tuple(data)))
         if comment == '':
             self._comment = 'None Given'
         else:
             self._comment = comment
     else:
         raise ValueError("Structure with partial occupancies cannot be "
                          "converted into atomic coordinates!")
Ejemplo n.º 4
0
    def __init__(self, structures, spacegroup, symm_prec=0.1):
        """
        Args:
            structures:
                Sequence of structures to test.
            spacegroup:
                A spacegroup to test the structures.
            symm_prec:
                The symmetry precision to test with.
        """
        structure_symm = {}
        self.symm_prec = symm_prec
        self.spacegroup = spacegroup
        logger.debug("Computing spacegroups...")
        for i, s in enumerate(structures):
            finder = SymmetryFinder(s, symm_prec)
            structure_symm[s] = finder.get_spacegroup_number()
            logger.debug("Structure {} has spacegroup {}"
                         .format(i, structure_symm[s]))

        sorted_structures = sorted(structures,
                                   key=lambda s: -structure_symm[s])
        unique_groups = []
        for i, group in itertools.groupby(sorted_structures,
                                          key=lambda s: structure_symm[s]):
            logger.debug("Processing group of structures with sg number {}"
                         .format(i))
            subgroups = self._fit_group(group)
            unique_groups.extend(subgroups)
        self.unique_groups = unique_groups
Ejemplo n.º 5
0
def plot_chgint(args):
    chgcar = Chgcar.from_file(args.filename[0])
    s = chgcar.structure

    if args.inds:
        atom_ind = map(int, args.inds[0].split(","))
    else:
        finder = SymmetryFinder(s, symprec=0.1)
        sites = [
            sites[0]
            for sites in finder.get_symmetrized_structure().equivalent_sites
        ]
        atom_ind = [s.sites.index(site) for site in sites]

    from pymatgen.util.plotting_utils import get_publication_quality_plot
    plt = get_publication_quality_plot(12, 8)
    for i in atom_ind:
        d = chgcar.get_integrated_diff(i, args.radius, 30)
        plt.plot(d[:, 0],
                 d[:, 1],
                 label="Atom {} - {}".format(i, s[i].species_string))
    plt.legend(loc="upper left")
    plt.xlabel("Radius (A)")
    plt.ylabel("Integrated charge (e)")
    plt.tight_layout()
    plt.show()
Ejemplo n.º 6
0
    def from_structure(cls,
                       structure,
                       has_timerev=True,
                       symprec=1e-5,
                       angle_tolerance=5):
        """
        Takes a :class:`Structure` object. Uses pyspglib to perform various symmetry finding operations.

        Args:
            structure: :class:`Structure` object
            has_timerev: True is time-reversal symmetry is included.
            symprec: Tolerance for symmetry finding
            angle_tolerance: Angle tolerance for symmetry finding.

        .. warning::

            AFM symmetries are not supported.
        """
        # Call spglib to get the list of symmetry operations.
        finder = SymmetryFinder(structure,
                                symprec=symprec,
                                angle_tolerance=angle_tolerance)
        data = finder.get_symmetry_dataset()

        symrel = data["rotations"],

        return cls(spgid=data["number"],
                   symrel=symrel,
                   tnons=data["translations"],
                   symafm=len(symrel) * [1],
                   has_timerev=has_timerev,
                   inord="C")
Ejemplo n.º 7
0
    def from_structure(cls, structure, has_timerev=True, symprec=1e-5, angle_tolerance=5):
        """
        Takes a `Structure` object. Uses pyspglib to perform various symmetry finding operations.

        Args:
            structure:
                Structure object
            has_timerev:
                True is time-reversal symmetry is included.
            symprec:
                Tolerance for symmetry finding
            angle_tolerance:
                Angle tolerance for symmetry finding.

        .. warning::
            AFM symmetries are not supported.
        """
        # Call spglib to get the list of symmetry operations.
        finder = SymmetryFinder(structure, symprec=symprec, angle_tolerance=angle_tolerance)
        data = finder.get_symmetry_dataset()

        symrel = data["rotations"],

        return cls(spgid=data["number"],
                   symrel=symrel,
                   tnons=data["translations"],
                   symafm=len(symrel) * [1],
                   has_timerev=has_timerev,
                   inord="C")
Ejemplo n.º 8
0
    def symmetrize(self):
        tensor = self._reduced_tensor

        if self._is_real_space:
            real_lattice = self._lattice
        else:
            real_lattice = self._lattice.reciprocal_lattice

        # Create a fake structure to get point group
        real_structure = Structure(real_lattice,["H"],[[0,0,0]])
        real_finder = SymmetryFinder(real_structure)

        real_symmops = real_finder.get_point_group_operations(cartesian=True)

        cartesian_tensor = self.cartesian_tensor

        sym_tensor = np.zeros((3,3))

        my_tensor = cartesian_tensor

        for real_sym in real_symmops:
             mat = real_sym.rotation_matrix
             prod_sym = np.dot(np.transpose(mat),np.dot(cartesian_tensor,mat))
             sym_tensor = sym_tensor + prod_sym

        sym_tensor = sym_tensor/len(real_symmops)

        self._reduced_tensor = from_cart_to_red(sym_tensor,self._lattice)
Ejemplo n.º 9
0
    def __init__(self, structure, min_cell_size=1, max_cell_size=1,
                 symm_prec=0.1, enum_precision_parameter=0.001,
                 refine_structure=False):
        """
        Initializes the adapter with a structure and some parameters.

        Args:
            structure: An input structure.
            min_cell_size (int): The minimum cell size wanted. Defaults to 1.
            max_cell_size (int): The maximum cell size wanted. Defaults to 1.
            symm_prec (float): Symmetry precision. Defaults to 0.1.
            enum_precision_parameter (float): Finite precision parameter for
                enumlib. Default of 0.001 is usually ok, but you might need to
                tweak it for certain cells.
            refine_structure (bool): If you are starting from a structure that
                has been relaxed via some electronic structure code,
                it is usually much better to start with symmetry determination
                and then obtain a refined structure. The refined structure have
                cell parameters and atomic positions shifted to the expected
                symmetry positions, which makes it much less sensitive precision
                issues in enumlib. If you are already starting from an
                experimental cif, refinement should have already been done and
                it is not necessary. Defaults to False.
        """
        if refine_structure:
            finder = SymmetryFinder(structure, symm_prec)
            self.structure = finder.get_refined_structure()
        else:
            self.structure = structure
        self.min_cell_size = min_cell_size
        self.max_cell_size = max_cell_size
        self.symm_prec = symm_prec
        self.enum_precision_parameter = enum_precision_parameter
    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)

            mod = StructureEditor(structure)
            mod.delete_sites(indices_list)
            s_new = mod.modified_structure
            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
Ejemplo n.º 11
0
 def test_get_ir_kpoints(self):
     v = Vasprun(os.path.join(test_dir, 'vasprun_Si_bands.xml'))
     finder = SymmetryFinder(v.final_structure)
     actual_kpts = v.actual_kpoints
     mapping = finder.get_ir_kpoints_mapping(actual_kpts)
     irr_kpts = finder.get_ir_kpoints(actual_kpts)
     self.assertLess(len(irr_kpts), len(actual_kpts))
     self.assertEqual(len(irr_kpts), len(set(mapping)))
Ejemplo n.º 12
0
def get_primitive(fname):
    poscar = Poscar.from_file(fname)

    finder = SymmetryFinder(poscar.structure)
    spg_num = finder.get_spacegroup_number()

    primitive = finder.get_primitive_standard_structure()
    return spg_num, primitive
Ejemplo n.º 13
0
 def test_get_ir_kpoints(self):
     v = Vasprun(os.path.join(test_dir, 'vasprun_Si_bands.xml'))
     finder = SymmetryFinder(v.final_structure)
     actual_kpts = v.actual_kpoints
     mapping = finder.get_ir_kpoints_mapping(actual_kpts)
     irr_kpts = finder.get_ir_kpoints(actual_kpts)
     self.assertLess(len(irr_kpts), len(actual_kpts))
     self.assertEqual(len(irr_kpts), len(set(mapping)))
Ejemplo n.º 14
0
def main():
    def str_examples():
        examples = """
    Usage example:\n
        cif2spg.py silicon.cif     => Open CIF file and visualize info on the spacegroup.
        cif2spg.py -g silicon.cif  => Same as above but use the GUI. 
    """
        return examples

    def show_examples_and_exit(err_msg=None, error_code=1):
        """Display the usage of the script."""
        sys.stderr.write(str_examples())
        if err_msg: 
            sys.stderr.write("Fatal Error\n" + err_msg + "\n")

        sys.exit(error_code)


    parser = argparse.ArgumentParser(epilog=str_examples(), formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument('cif_file', nargs=1, help="CIF File")

    parser.add_argument('-g', '--gui', action="store_true", help="Enable GUI")

    # Parse command line.
    try:
        options = parser.parse_args()
    except: 
        show_examples_and_exit(error_code=1)

    cif_file = options.cif_file[0]
    structure = abilab.Structure.from_file(cif_file)
    #print(structure.to_abivars())

    finder = SymmetryFinder(structure, symprec=1e-5, angle_tolerance=5)

    data = finder.get_symmetry_dataset()
    from pprint import pprint

    if not options.gui:
        pprint(data)

    else:
        from StringIO import StringIO
        import wx
        from abipy.gui.editor import SimpleTextViewer

        stream = StringIO()
        pprint(data, stream=stream)
        stream.seek(0)
        text = "".join(stream)
        app = wx.App()
        frame = SimpleTextViewer(None, text=text)
        frame.Show()
        app.MainLoop()

    return 0
Ejemplo n.º 15
0
    def get_poscar(self, structure):
        """
        Get a POSCAR file with a primitive standardized cell of
        the giving structure.

        Args:
            structure (Structure/IStructure): structure to get POSCAR
        """
        sym_finder = SymmetryFinder(structure, symprec=self.sym_prec)
        return Poscar(sym_finder.get_primitive_standard_structure())
Ejemplo n.º 16
0
 def test_get_refined_structure(self):
     for a in self.sg.get_refined_structure().lattice.angles:
         self.assertEqual(a, 90)
     refined = self.disordered_sg.get_refined_structure()
     for a in refined.lattice.angles:
         self.assertEqual(a, 90)
     self.assertEqual(refined.lattice.a, refined.lattice.b)
     parser = CifParser(os.path.join(test_dir, 'Li2O.cif'))
     s = parser.get_structures()[0]
     sg = SymmetryFinder(s, 0.001)
     self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites)
Ejemplo n.º 17
0
 def test_get_refined_structure(self):
     for a in self.sg.get_refined_structure().lattice.angles:
         self.assertEqual(a, 90)
     refined = self.disordered_sg.get_refined_structure()
     for a in refined.lattice.angles:
         self.assertEqual(a, 90)
     self.assertEqual(refined.lattice.a, refined.lattice.b)
     parser = CifParser(os.path.join(test_dir, 'Li2O.cif'))
     s = parser.get_structures()[0]
     sg = SymmetryFinder(s, 0.001)
     self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites)
Ejemplo n.º 18
0
 def __init__(self, structure, min_cell_size=1, max_cell_size=1,
              symm_prec=0.1, enum_precision_parameter=0.001,
              refine_structure=False):
     if refine_structure:
         finder = SymmetryFinder(structure, symm_prec)
         self.structure = finder.get_refined_structure()
     else:
         self.structure = structure
     self.min_cell_size = min_cell_size
     self.max_cell_size = max_cell_size
     self.symm_prec = symm_prec
     self.enum_precision_parameter = enum_precision_parameter
Ejemplo n.º 19
0
    def get_structure_hash(self, structure):
        """
        Hash for structure.

        Args:
            structure: A structure

        Returns:
            Reduced formula for the structure is used as a hash for the
            SpeciesComparator.
        """
        f = SymmetryFinder(structure, 0.1)
        return "{} {}".format(f.get_spacegroup_number(), structure.composition.reduced_formula)
Ejemplo n.º 20
0
def _symmetry_reduced_voronoi_nodes(structure, rad_dict):
    """
    Obtain symmetry reduced voronoi nodes using Zeo++ and 
    pymatgen.symmetry.finder.SymmetryFinder

    Args:
        strucutre:
            pymatgen Structure object

    Returns:
        Symmetrically distinct voronoi nodes as pymatgen Strucutre
    """
    vor_node_struct = get_voronoi_nodes(structure, rad_dict)
    vor_symmetry_finder = SymmetryFinder(vor_node_struct, symprec=1e-1)
    vor_symm_struct = vor_symmetry_finder.get_symmetrized_structure()
    #print vor_symm_struct.lattice
    #print vor_symm_struct.lattice.abc, vor_symm_struct.lattice.angles
    #print vor_node_struct.lattice
    #print vor_node_struct.lattice.abc, vor_node_struct.lattice.angles
    equiv_sites_list = vor_symm_struct.equivalent_sites

    def add_closest_equiv_site(dist_sites, equiv_sites):
        if not dist_sites:
            dist_sites.append(equiv_sites[0])
        else:
            avg_dists = []
            for site in equiv_sites:
                dists = [
                    site.distance(dst_site, jimage=[0, 0, 0])
                    for dst_site in dist_sites
                ]
                avg_dist = sum(dists) / len(dist_sites)
                avg_dists.append(avg_dist)

            min_avg_dist = min(avg_dists)
            ind = avg_dists.index(min_avg_dist)
            dist_sites.append(equiv_sites[ind])

    dist_sites = []
    for equiv_sites in equiv_sites_list:
        add_closest_equiv_site(dist_sites, equiv_sites)

    #lat = structure.lattice
    #sp = [site.specie for site in sites]   # "Al" because to Zeo++
    #coords = [site.coords for site in sites]
    #vor_node_radii = [site.properties['voronoi_radius'] for site in sites]
    #vor_node_struct = Structure(lat, sp, coords,
    #        coords_are_cartesian=True,
    #        site_properties={'voronoi_radius':vor_node_radii}
    #        )
    return dist_sites
Ejemplo n.º 21
0
    def get_structure_hash(self, structure):
        """
        Hash for structure.

        Args:
            structure: A structure

        Returns:
            Reduced formula for the structure is used as a hash for the
            SpeciesComparator.
        """
        f = SymmetryFinder(structure, 0.1)
        return "{} {}".format(f.get_spacegroup_number(),
                              structure.composition.reduced_formula)
Ejemplo n.º 22
0
 def _make_struc_file(self, file_name):
     sym = SymmetryFinder(self._bs._structure, symprec=0.01)
     with open(file_name, "w") as f:
         f.write(self._bs._structure.composition.formula + " " + str(sym.get_spacegroup_symbol()) + "\n")
         for i in range(3):
             line = ""
             for j in range(3):
                 line += "%12.5f" % (Length(self._bs._structure.lattice.matrix[i][j], "ang").to("bohr"))
             f.write(line + "\n")
         ops = sym.get_symmetry_dataset()["rotations"]
         f.write(str(len(ops)) + "\n")
         for c in ops:
             f.write("\n".join([" ".join([str(int(i)) for i in row]) for row in c]))
             f.write("\n")
Ejemplo n.º 23
0
def parse_symmetry(args):

    tolerance = float(args.tolerance[0])

    for filename in args.filenames:
        s = read_structure(filename)
        if args.spacegroup:
            finder = SymmetryFinder(s, tolerance)
            dataset = finder.get_symmetry_dataset()
            print filename
            print "Spacegroup  : {}".format(dataset["international"])
            print "Int number  : {}".format(dataset["number"])
            print "Hall symbol : {}".format(dataset["hall"])
            print
Ejemplo n.º 24
0
def parse_symmetry(args):

    tolerance = float(args.tolerance[0])

    for filename in args.filenames:
        s = read_structure(filename)
        if args.spacegroup:
            finder = SymmetryFinder(s, tolerance)
            dataset = finder.get_symmetry_dataset()
            print filename
            print "Spacegroup  : {}".format(dataset["international"])
            print "Int number  : {}".format(dataset["number"])
            print "Hall symbol : {}".format(dataset["hall"])
            print
Ejemplo n.º 25
0
def symmetry_reduced_voronoi_nodes(structure, rad_dict):
    """
    Obtain symmetry reduced voronoi nodes using Zeo++ and 
    pymatgen.symmetry.finder.SymmetryFinder

    Args:
        strucutre:
            pymatgen Structure object

    Returns:
        Symmetrically distinct voronoi nodes as pymatgen Strucutre
    """
    vor_node_struct = get_voronoi_nodes(structure, rad_dict)
    vor_symmetry_finder = SymmetryFinder(vor_node_struct, symprec=1e-1)
    vor_symm_struct = vor_symmetry_finder.get_symmetrized_structure()
    #print vor_symm_struct.lattice
    #print vor_symm_struct.lattice.abc, vor_symm_struct.lattice.angles
    #print vor_node_struct.lattice
    #print vor_node_struct.lattice.abc, vor_node_struct.lattice.angles
    equiv_sites_list = vor_symm_struct.equivalent_sites

    def add_closest_equiv_site(dist_sites, equiv_sites):
        if not dist_sites:
            dist_sites.append(equiv_sites[0])
        else:
            avg_dists = []
            for site in equiv_sites:
                dists = [site.distance(dst_site, jimage=[0, 0, 0])
                         for dst_site in dist_sites]
                avg_dist = sum(dists) / len(dist_sites)
                avg_dists.append(avg_dist)

            min_avg_dist = min(avg_dists)
            ind = avg_dists.index(min_avg_dist)
            dist_sites.append(equiv_sites[ind])

    dist_sites = []
    for equiv_sites in equiv_sites_list:
        add_closest_equiv_site(dist_sites, equiv_sites)

    #lat = structure.lattice
    #sp = [site.specie for site in sites]   # "Al" because to Zeo++
    #coords = [site.coords for site in sites]
    #vor_node_radii = [site.properties['voronoi_radius'] for site in sites]
    #vor_node_struct = Structure(lat, sp, coords, 
    #        coords_are_cartesian=True, 
    #        site_properties={'voronoi_radius':vor_node_radii}
    #        )
    return dist_sites
Ejemplo n.º 26
0
 def test_find_primitive(self):
     """
     F m -3 m Li2O testing of converting to primitive cell
     """
     parser = CifParser(os.path.join(test_dir, 'Li2O.cif'))
     structure = parser.get_structures(False)[0]
     s = SymmetryFinder(structure)
     primitive_structure = s.find_primitive()
     self.assertEqual(primitive_structure.formula, "Li2 O1")
     # This isn't what is expected. All the angles should be 60
     self.assertAlmostEqual(primitive_structure.lattice.alpha, 60)
     self.assertAlmostEqual(primitive_structure.lattice.beta, 60)
     self.assertAlmostEqual(primitive_structure.lattice.gamma, 60)
     self.assertAlmostEqual(primitive_structure.lattice.volume,
                            structure.lattice.volume / 4.0)
Ejemplo n.º 27
0
 def test_find_primitive(self):
     """
     F m -3 m Li2O testing of converting to primitive cell
     """
     parser = CifParser(os.path.join(test_dir, 'Li2O.cif'))
     structure = parser.get_structures(False)[0]
     s = SymmetryFinder(structure)
     primitive_structure = s.find_primitive()
     self.assertEqual(primitive_structure.formula, "Li2 O1")
     # This isn't what is expected. All the angles should be 60
     self.assertAlmostEqual(primitive_structure.lattice.alpha, 60)
     self.assertAlmostEqual(primitive_structure.lattice.beta, 60)
     self.assertAlmostEqual(primitive_structure.lattice.gamma, 60)
     self.assertAlmostEqual(primitive_structure.lattice.volume,
                            structure.lattice.volume / 4.0)
Ejemplo n.º 28
0
    def __init__(self, structure, valences, radii):
        """
        Args:
            structure:
                pymatgen.core.structure.Structure
            valences:
                valences of elements as a dictionary 
            radii:
                Radii of elements as a dictionary
        """

        self._structure = structure
        self._valence_dict = valences
        self._rad_dict = radii
        # Store symmetrically distinct sites, their coordination numbers
        # coordinated_sites, effective charge
        symm_finder = SymmetryFinder(self._structure)
        symm_structure = symm_finder.get_symmetrized_structure()
        equiv_site_seq = symm_structure.equivalent_sites

        self._defect_sites = []
        for equiv_sites in equiv_site_seq:
            self._defect_sites.append(equiv_sites[0])

        self._vac_site_indices = []
        for site in self._defect_sites:
            for i in range(len(self._structure.sites)):
                if site == self._structure[i]:
                    self._vac_site_indices.append(i)

        coord_finder = VoronoiCoordFinder(self._structure)
        self._defectsite_coord_no = []
        self._defect_coord_sites = []
        for i in self._vac_site_indices:
            self._defectsite_coord_no.append(
                coord_finder.get_coordination_number(i)
            )
            self._defect_coord_sites.append(
                coord_finder.get_coordinated_sites(i)
            )

        # Store the ionic radii for the elements in the structure
        # (Used to  computing the surface are and volume)
        # Computed based on valence of each element

        self._vac_eff_charges = None
        self._vol = None
        self._sa = None
Ejemplo n.º 29
0
 def setUp(self):
     p = Poscar.from_file(os.path.join(test_dir, 'POSCAR'))
     self.structure = p.structure
     self.sg = SymmetryFinder(self.structure, 0.001)
     parser = CifParser(os.path.join(test_dir, 'Li10GeP2S12.cif'))
     self.disordered_structure = parser.get_structures()[0]
     self.disordered_sg = SymmetryFinder(self.disordered_structure, 0.001)
     s = p.structure
     editor = StructureEditor(s)
     site = s[0]
     editor.delete_site(0)
     editor.append_site(site.species_and_occu, site.frac_coords)
     self.sg3 = SymmetryFinder(editor.modified_structure, 0.001)
     parser = CifParser(os.path.join(test_dir, 'Graphite.cif'))
     graphite = parser.get_structures()[0]
     self.sg4 = SymmetryFinder(graphite, 0.001)
Ejemplo n.º 30
0
 def setUp(self):
     p = Poscar.from_file(os.path.join(test_dir, 'POSCAR'))
     self.structure = p.structure
     self.sg = SymmetryFinder(self.structure, 0.001)
     parser = CifParser(os.path.join(test_dir, 'Li10GeP2S12.cif'))
     self.disordered_structure = parser.get_structures()[0]
     self.disordered_sg = SymmetryFinder(self.disordered_structure, 0.001)
     s = p.structure.copy()
     site = s[0]
     del s[0]
     s.append(site.species_and_occu, site.frac_coords)
     self.sg3 = SymmetryFinder(s, 0.001)
     parser = CifParser(os.path.join(test_dir, 'Graphite.cif'))
     graphite = parser.get_structures()[0]
     graphite.add_site_property("magmom", [0.1] * len(graphite))
     self.sg4 = SymmetryFinder(graphite, 0.001)
Ejemplo n.º 31
0
class SpacegroupTest(unittest.TestCase):
    def setUp(self):
        p = Poscar.from_file(os.path.join(test_dir, 'POSCAR'))
        self.structure = p.structure
        self.sg1 = SymmetryFinder(self.structure, 0.001).get_spacegroup()

    def test_are_symmetrically_equivalent(self):
        sites1 = [self.structure[i] for i in [0, 1]]
        sites2 = [self.structure[i] for i in [2, 3]]
        self.assertTrue(
            self.sg1.are_symmetrically_equivalent(sites1, sites2, 1e-3))

        sites1 = [self.structure[i] for i in [0, 1]]
        sites2 = [self.structure[i] for i in [0, 2]]
        self.assertFalse(
            self.sg1.are_symmetrically_equivalent(sites1, sites2, 1e-3))
Ejemplo n.º 32
0
 def add_snl(self, snl):
     snl_id = self._get_next_snl_id()
     sf = SymmetryFinder(snl.structure, SPACEGROUP_TOLERANCE)
     sf.get_spacegroup()
     mpsnl = MPStructureNL.from_snl(snl, snl_id, sf.get_spacegroup_number(),
                                    sf.get_spacegroup_symbol(), sf.get_hall(),
                                    sf.get_crystal_system(), sf.get_lattice_type())
     snlgroup, add_new = self.add_mpsnl(mpsnl)
     return mpsnl, snlgroup.snlgroup_id
Ejemplo n.º 33
0
def get_symetry(lines, output):
    latt_tmp = [[float(x) for x in y.split()] for y in lines[0:3]]
    trans = [[float(x) for x in y.split()] for y in lines[3:6]]
    sites = [[float(x) for x in y.split()[0:3]] for y in lines[6:]]
    elements = [x.split()[3] for x in lines[6:]]
    latt = np.dot(np.array(trans),np.array(latt_tmp))
    latt_obj = mg.Lattice(latt)
    structure = mg.Structure(latt, elements, sites)
    finder = SymmetryFinder(structure)
    out = finder.get_spacegroup_symbol() + "\n"
    #structure = finder.find_primitive()
    #structure = finder.get_primitive_standard_structure()
    poscar = Poscar(structure)
    #cif = CifWriter(structure)
    out += poscar.__str__()
    #print(cif)
    return out
Ejemplo n.º 34
0
class SpacegroupTest(unittest.TestCase):

    def setUp(self):
        p = Poscar.from_file(os.path.join(test_dir, 'POSCAR'))
        self.structure = p.structure
        self.sg1 = SymmetryFinder(self.structure, 0.001).get_spacegroup()

    def test_are_symmetrically_equivalent(self):
        sites1 = [self.structure[i] for i in [0, 1]]
        sites2 = [self.structure[i] for i in [2, 3]]
        self.assertTrue(self.sg1.are_symmetrically_equivalent(sites1, sites2,
                                                              1e-3))

        sites1 = [self.structure[i] for i in [0, 1]]
        sites2 = [self.structure[i] for i in [0, 2]]
        self.assertFalse(self.sg1.are_symmetrically_equivalent(sites1, sites2,
                                                               1e-3))
Ejemplo n.º 35
0
    def __init__(self, structure, valences, radii):
        """
        Args:
            structure:
                pymatgen.core.structure.Structure
            valences:
                valences of elements as a dictionary 
            radii:
                Radii of elements as a dictionary
        """

        self._structure = structure
        self._valence_dict = valences
        self._rad_dict = radii
        # Store symmetrically distinct sites, their coordination numbers
        # coordinated_sites, effective charge
        symm_finder = SymmetryFinder(self._structure)
        symm_structure = symm_finder.get_symmetrized_structure()
        equiv_site_seq = symm_structure.equivalent_sites

        self._defect_sites = []
        for equiv_sites in equiv_site_seq:
            self._defect_sites.append(equiv_sites[0])

        self._vac_site_indices = []
        for site in self._defect_sites:
            for i in range(len(self._structure.sites)):
                if site == self._structure[i]:
                    self._vac_site_indices.append(i)

        coord_finder = VoronoiCoordFinder(self._structure)
        self._defectsite_coord_no = []
        self._defect_coord_sites = []
        for i in self._vac_site_indices:
            self._defectsite_coord_no.append(
                coord_finder.get_coordination_number(i))
            self._defect_coord_sites.append(
                coord_finder.get_coordinated_sites(i))

        # Store the ionic radii for the elements in the structure
        # (Used to  computing the surface are and volume)
        # Computed based on valence of each element

        self._vac_eff_charges = None
        self._vol = None
        self._sa = None
Ejemplo n.º 36
0
    def structure_lines(self, structure, cell_flg=True, frac_flg=True,
                        anion_shell_flg=True, cation_shell_flg=False,
                        symm_flg=True):
        """
        Generates GULP input string corresponding to pymatgen structure.

        Args:
            structure:
                pymatgen Structure object
            cell_flg (default = True):
                Option to use lattice parameters.
            fractional_flg (default = True):
                If True, fractional coordinates are used.
                Else, cartesian coodinates in Angstroms are used.
                ******
                GULP convention is to use fractional coordinates for periodic
                structures and cartesian coordinates for non-periodic
                structures.
                ******
            anion_shell_flg (default = True):
                If True, anions are considered polarizable.
            cation_shell_flg (default = False):
                If True, cations are considered polarizable.
            symm_flg (default = True):
                If True, symmetry information is also written.
        Returns:
            string containing structure for GULP input
        """
        gin = ""
        if cell_flg:
            gin += "cell\n"
            l = structure.lattice
            lat_str = map(str, [l.a, l.b, l.c, l.alpha, l.beta, l.gamma])
            gin += " ".join(lat_str) + "\n"

        if frac_flg:
            gin += "frac\n"
            coord_attr = "frac_coords"
        else:
            gin += "cart\n"
            coord_attr = "coords"
        for site in structure.sites:
            coord = map(str, list(getattr(site, coord_attr)))
            specie = site.specie
            core_site_desc = specie.symbol + " core " + " ".join(coord) + "\n"
            gin += core_site_desc
            if ((specie in _anions and anion_shell_flg) or
                    (specie in _cations and cation_shell_flg)):
                shel_site_desc = specie.symbol + " shel " + " ".join(
                    coord) + "\n"
                gin += shel_site_desc
            else:
                pass

        if symm_flg:
            gin += "space\n"
            gin += str(SymmetryFinder(structure).get_spacegroup_number()) + "\n"
        return gin
Ejemplo n.º 37
0
 def _make_struc_file(self, file_name):
     sym = SymmetryFinder(self._bs._structure, symprec=0.01)
     with open(file_name, 'w') as f:
         f.write(self._bs._structure.composition.formula+" " +
                 str(sym.get_spacegroup_symbol())+"\n")
         for i in range(3):
             line = ''
             for j in range(3):
                 line += "%12.5f" % (
                     Length(self._bs._structure.lattice.matrix[i][j],
                            "ang").to("bohr"))
             f.write(line+'\n')
         ops = sym.get_symmetry_dataset()['rotations']
         f.write(str(len(ops))+"\n")
         for c in ops:
             f.write('\n'.join([' '.join([str(int(i)) for i in row])
                                for row in c]))
             f.write('\n')
Ejemplo n.º 38
0
    def get_structure(vasp_run,
                      outcar=None,
                      initial_structure=False,
                      additional_info=False):
        """
        Process structure for static calculations from previous run.

        Args:
            vasp_run:
                Vasprun object that contains the final structure from previous
                run.
            outcar:
                Outcar object that contains the magnetization info from
                previous run.
            initial_structure:
                Whether to return the structure from previous run. Default is
                False.
            additional_info:
                Whether to return additional symmetry info related to the
                structure. If True, return a list of the refined structure (
                conventional cell), the conventional standard structure,
                the symmetry dataset and symmetry operations of the structure
                (see SymmetryFinder doc for details)

        Returns:
            Returns the magmom-decorated structure that can be passed to get
            Vasp input files, e.g. get_kpoints.
        """
        #TODO: fix magmom for get_*_structures
        if vasp_run.is_spin:
            if outcar and outcar.magnetization:
                magmom = {"magmom": [i['tot'] for i in outcar.magnetization]}
            else:
                magmom = {
                    "magmom": vasp_run.to_dict['input']['parameters']['MAGMOM']
                }
        else:
            magmom = None
        structure = vasp_run.final_structure
        if magmom:
            structure = structure.copy(site_properties=magmom)
        sym_finder = SymmetryFinder(structure, symprec=0.01)
        if initial_structure:
            return structure
        elif additional_info:
            info = [
                sym_finder.get_refined_structure(),
                sym_finder.get_conventional_standard_structure(),
                sym_finder.get_symmetry_dataset(),
                sym_finder.get_symmetry_operations()
            ]
            return [sym_finder.get_primitive_standard_structure(), info]
        else:
            return sym_finder.get_primitive_standard_structure()
Ejemplo n.º 39
0
    def get_structure(vasp_run, outcar=None, initial_structure=False,
                      refined_structure=False):
        """
        Process structure for static calculations from previous run.

        Args:
            vasp_run:
                Vasprun object that contains the final structure from previous
                run.
            outcar:
                Outcar object that contains the magnetization info from
                previous run.
            initial_structure:
                Whether to return the structure from previous run. Default is
                False.
            refined_structure:
                Whether to return the refined structure (conventional cell)

        Returns:
            Returns the magmom-decorated structure that can be passed to get
            Vasp input files, e.g. get_kpoints.
        """
        #TODO: fix magmom for get_*_structures
        if vasp_run.is_spin:
            if outcar and outcar.magnetization:
                magmom = {"magmom": [i['tot'] for i in outcar.magnetization]}
            else:
                magmom = {
                    "magmom": vasp_run.to_dict['input']['parameters']
                    ['MAGMOM']}
        else:
            magmom = None
        structure = vasp_run.final_structure
        if magmom:
            structure = structure.copy(site_properties=magmom)
        sym_finder = SymmetryFinder(structure, symprec=0.01)
        if initial_structure:
            return structure
        elif refined_structure:
            return (sym_finder.get_primitive_standard_structure(),
                    sym_finder.get_refined_structure())
        else:
            return sym_finder.get_primitive_standard_structure()
Ejemplo n.º 40
0
 def __init__(self, struct, source='', comment=''):
     if struct.is_ordered:
         self._struct = struct
         self._source = source
         self._site_symbols = []
         self._natoms = []
         sym = SymmetryFinder(struct)
         data = sym.get_symmetry_dataset()
         self._space_number = data["number"]
         self._space_group = data["international"]
         syms = [site.specie.symbol for site in struct]
         for (s, data) in itertools.groupby(syms):
             self._site_symbols.append(s)
             self._natoms.append(len(tuple(data)))
         if comment == '':
             self._comment = 'None Given'
         else:
             self._comment = comment
     else:
         raise ValueError("Structure with partial occupancies cannot be "
                          "converted into atomic coordinates!")
Ejemplo n.º 41
0
 def __init__(self, struct, source='', comment=''):
     if struct.is_ordered:
         self._struct = struct
         self._source = source
         self._site_symbols = []
         self._natoms = []
         sym = SymmetryFinder(struct)
         data = sym.get_symmetry_dataset()
         self._space_number = data["number"]
         self._space_group = data["international"]
         syms = [site.specie.symbol for site in struct]
         for (s, data) in itertools.groupby(syms):
             self._site_symbols.append(s)
             self._natoms.append(len(tuple(data)))
         if comment == '':
             self._comment = 'None Given'
         else:
             self._comment = comment
     else:
         raise ValueError("Structure with partial occupancies cannot be "
                          "converted into atomic coordinates!")
Ejemplo n.º 42
0
def _generate_entry(structure, params, name, energy, pressure):
    comp = structure.composition
    entry = {"structure": structure.to_dict, "name": name, "energy": energy, "energy_per_site": energy / comp.num_atoms,
             "pressure": pressure, "potential": {"name": "lennard_jones", "params": params.to_dict}}

    # Set the composition and formulas for the system
    el_amt = comp.get_el_amt_dict()
    entry.update({"unit_cell_formula": comp.to_dict,
                  "reduced_cell_formula": comp.to_reduced_dict,
                  "elements": list(el_amt.keys()),
                  "nelements": len(el_amt),
                  "pretty_formula": comp.reduced_formula,
                  "anonymous_formula": comp.anonymized_formula,
                  "nsites": comp.num_atoms,
                  "chemsys": "-".join(sorted(el_amt.keys()))})

    # Figure out the symmetry group
    sg = SymmetryFinder(structure, normalised_symmetry_precision(structure), -1)
    entry["spacegroup"] = {"symbol": unicode(sg.get_spacegroup_symbol(), errors="ignore"),
                           "number": sg.get_spacegroup_number(),
                           "point_group": unicode(sg.get_point_group(), errors="ignore"),
                           "source": "spglib",
                           "crystal_system": sg.get_crystal_system(),
                           "hall": sg.get_hall()}

    return entry
Ejemplo n.º 43
0
 def __init__(self,
              structure,
              min_cell_size=1,
              max_cell_size=1,
              symm_prec=0.1,
              enum_precision_parameter=0.001,
              refine_structure=False):
     """
     Args:
         structure:
             An input structure.
         min_cell_size:
             The minimum cell size wanted. Must be an int. Defaults to 1.
         max_cell_size:
             The maximum cell size wanted. Must be an int. Defaults to 1.
         symm_prec:
             Symmetry precision. Defaults to 0.1.
         enum_precision_parameter:
             Finite precision parameter for enumlib. Default of 0.001 is
             usually ok, but you might need to tweak it for certain cells.
         refine_structure:
             If you are starting from a structure that has been relaxed via
             some electronic structure code, it is usually much better to
             start with symmetry determination and then obtain a refined
             structure. The refined structure have cell parameters and
             atomic positions shifted to the expected symmetry positions,
             which makes it much less sensitive precision issues in enumlib.
             If you are already starting from an experimental cif, refinment
             should have already been done and it is not necessary. Defaults
             to False.
     """
     if refine_structure:
         finder = SymmetryFinder(structure, symm_prec)
         self.structure = finder.get_refined_structure()
     else:
         self.structure = structure
     self.min_cell_size = min_cell_size
     self.max_cell_size = max_cell_size
     self.symm_prec = symm_prec
     self.enum_precision_parameter = enum_precision_parameter
Ejemplo n.º 44
0
def main():
    parser = argparse.ArgumentParser(epilog=str_examples(), formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument('cif_file', nargs=1, help="CIF File")

    parser.add_argument('-g', '--gui', action="store_true", help="Enable GUI")

    # Parse command line.
    try:
        options = parser.parse_args()
    except: 
        show_examples_and_exit(error_code=1)

    cif_file = options.cif_file[0]
    structure = abilab.Structure.from_file(cif_file)
    #print(structure.to_abivars())

    finder = SymmetryFinder(structure, symprec=1e-5, angle_tolerance=5)

    data = finder.get_symmetry_dataset()
    from pprint import pprint

    if not options.gui:
        pprint(data)

    else:
        from StringIO import StringIO
        import wx
        from abipy.gui.editor import SimpleTextViewer

        stream = StringIO()
        pprint(data, stream=stream)
        stream.seek(0)
        text = "".join(stream)
        app = wx.App()
        frame = SimpleTextViewer(None, text=text)
        frame.Show()
        app.MainLoop()

    return 0
Ejemplo n.º 45
0
    def process_res(cls, resfile):
        fullpath = os.path.abspath(resfile)
        res = Res.from_file(resfile)
        d = res.to_dict
        d["file_name"] = fullpath

        s = res.structure
        # Set the composition and formulas for the system
        comp = s.composition
        el_amt = s.composition.get_el_amt_dict()
        d.update({"unit_cell_formula": comp.to_dict,
                  "reduced_cell_formula": comp.to_reduced_dict,
                  "elements": list(el_amt.keys()),
                  "nelements": len(el_amt),
                  "pretty_formula": comp.reduced_formula,
                  "anonymous_formula": comp.anonymized_formula,
                  "nsites": comp.num_atoms,
                  "chemsys": "-".join(sorted(el_amt.keys()))})
        #d["density"] = s.density

        # Figure out the symmetry group
        sg = SymmetryFinder(s, util.normalised_symmetry_precision(s), -1)
        d["spacegroup"] = {"symbol": unicode(sg.get_spacegroup_symbol(),
                                             errors="ignore"),
                           "number": sg.get_spacegroup_number(),
                           "point_group": unicode(sg.get_point_group(),
                                                  errors="ignore"),
                           "source": "spglib",
                           "crystal_system": sg.get_crystal_system(),
                           "hall": sg.get_hall()}

        return d
Ejemplo n.º 46
0
def produce(irreps):
    os.makedirs('irrep')
    for i, irrep in enumerate(irreps):
        poscar = Poscar(irrep)
        symbols = poscar.site_symbols
        natoms = poscar.natoms
        name_dict = {'Al': 'A', 'Ti': 'B'}
        tmp = ["{0}{1}".format(name_dict[x], y)
               for x, y in zip(symbols, natoms)]
        finder = SymmetryFinder(irrep)
        spg_num = finder.get_spacegroup_number()
        spg = "_".join(finder.get_spacegroup_symbol().split('/'))
        dirname = "No." + "{0:03d}".format(i) + "_" + spg + "_" + "".join(tmp)
        poscar.comment += "    (#" + str(spg_num) + ": " + spg + ")"

        standard = finder.get_conventional_standard_structure()
        stand_pos = Poscar(standard)
        stand_pos.comment += "    (#" + str(spg_num) + ": " + spg + ")"

        os.makedirs(os.path.join('irrep', dirname))
        poscar.write_file(os.path.join('irrep', dirname, 'POSCAR.prim'))
        stand_pos.write_file(os.path.join('irrep', dirname, 'POSCAR.std'))
Ejemplo n.º 47
0
 def setUp(self):
     p = Poscar.from_file(os.path.join(test_dir, 'POSCAR'))
     self.structure = p.structure
     self.sg = SymmetryFinder(self.structure, 0.001)
     parser = CifParser(os.path.join(test_dir, 'Li10GeP2S12.cif'))
     self.disordered_structure = parser.get_structures()[0]
     self.disordered_sg = SymmetryFinder(self.disordered_structure, 0.001)
     s = p.structure.copy()
     site = s[0]
     del s[0]
     s.append(site.species_and_occu, site.frac_coords)
     self.sg3 = SymmetryFinder(s, 0.001)
     parser = CifParser(os.path.join(test_dir, 'Graphite.cif'))
     graphite = parser.get_structures()[0]
     graphite.add_site_property("magmom", [0.1] * len(graphite))
     self.sg4 = SymmetryFinder(graphite, 0.001)
    def test_apply_transformation(self):
        trans = MagOrderingTransformation({"Fe": 5})
        p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'),
                             check_for_POTCAR=False)
        s = p.structure
        alls = trans.apply_transformation(s, 10)
        self.assertEqual(len(alls), 3)
        f = SymmetryFinder(alls[0]["structure"], 0.1)
        self.assertEqual(f.get_spacegroup_number(), 31)

        model = IsingModel(5, 5)
        trans = MagOrderingTransformation({"Fe": 5}, energy_model=model)
        alls2 = trans.apply_transformation(s, 10)
        #Ising model with +J penalizes similar neighbor magmom.
        self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"])
        self.assertEqual(alls[0]["structure"], alls2[2]["structure"])

        from pymatgen.io.smartio import read_structure
        s = read_structure(os.path.join(test_dir, 'Li2O.cif'))
        #Li2O doesn't have magnetism of course, but this is to test the
        # enumeration.
        trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3)
        alls = trans.apply_transformation(s, 100)
        self.assertEqual(len(alls), 10)
Ejemplo n.º 49
0
    def monkhorst_automatic(cls,
                            structure,
                            ngkpt,
                            chksymbreak=None,
                            use_symmetries=True,
                            use_time_reversal=True,
                            comment=None):
        """
        Convenient static constructor for an automatic Monkhorst-Pack mesh.

        Args:
            structure:
                paymatgen structure object.
            ngkpt:
                Subdivisions N_1, N_2 and N_3 along reciprocal lattice vectors.
            use_symmetries:
                Use spatial symmetries to reduce the number of k-points.
            use_time_reversal:
                Use time-reversal symmetry to reduce the number of k-points.

        Returns:
            KSampling object
        """
        sg = SymmetryFinder(structure)
        #sg.get_crystal_system()
        #sg.get_point_group()
        # TODO
        nshiftk = 1
        #shiftk = 3*(0.5,) # this is the default
        shiftk = 3 * (0.5, )

        #if lattice.ishexagonal:
        #elif lattice.isbcc
        #elif lattice.isfcc

        return cls.monkhorst(
            ngkpt,
            shiftk=shiftk,
            chksymbreak=chksymbreak,
            use_symmetries=use_symmetries,
            use_time_reversal=use_time_reversal,
            comment=comment if comment else "Automatic Monkhorst-Pack scheme",
        )
Ejemplo n.º 50
0
    def get_kpoints(self, structure, kpoints_density=1000):
        """
        Get a KPOINTS file for NonSCF calculation. In "Line" mode, kpoints are
        generated along high symmetry lines. In "Uniform" mode, kpoints are
        Gamma-centered mesh grid. Kpoints are written explicitly in both cases.

        Args:
            kpoints_density:
                kpoints density for the reciprocal cell of structure.
                Suggest to use a large kpoints_density.
                Might need to increase the default value when calculating
                metallic materials.
        """
        if self.mode == "Line":
            kpath = HighSymmKpath(structure)
            cart_k_points, k_points_labels = kpath.get_kpoints()
            frac_k_points = [
                kpath._prim_rec.get_fractional_coords(k) for k in cart_k_points
            ]
            return Kpoints(comment="Non SCF run along symmetry lines",
                           style="Reciprocal",
                           num_kpts=len(frac_k_points),
                           kpts=frac_k_points,
                           labels=k_points_labels,
                           kpts_weights=[1] * len(cart_k_points))
        else:
            num_kpoints = kpoints_density * \
                structure.lattice.reciprocal_lattice.volume
            kpoints = Kpoints.automatic_density(
                structure, num_kpoints * structure.num_sites)
            mesh = kpoints.kpts[0]
            ir_kpts = SymmetryFinder(structure, symprec=0.01)\
                .get_ir_reciprocal_mesh(mesh)
            kpts = []
            weights = []
            for k in ir_kpts:
                kpts.append(k[0])
                weights.append(int(k[1]))
            return Kpoints(comment="Non SCF run on uniform grid",
                           style="Reciprocal",
                           num_kpts=len(ir_kpts),
                           kpts=kpts,
                           kpts_weights=weights)
Ejemplo n.º 51
0
    def apply_transformation(self, structure, return_ranked_list=False):
        """
        Return either a single ordered structure or a sequence of all ordered
        structures.

        Args:
            structure:
                Structure to order.
            return_ranked_list:
                Boolean stating whether or not multiple structures are
                returned. If return_ranked_list is a number, that number of
                structures is returned.

        Returns:
            Depending on returned_ranked list, either a transformed structure
            or a list of dictionaries, where each dictionary is of the form
            {"structure" = .... , "other_arguments"}

            The list of ordered structures is ranked by ewald energy / atom, if
            the input structure is an oxidation state decorated structure.
            Otherwise, it is ranked by number of sites, with smallest number of
            sites first.
        """
        try:
            num_to_return = int(return_ranked_list)
        except ValueError:
            num_to_return = 1

        if structure.is_ordered:
            raise ValueError("Enumeration can be carried out only on "
                             "disordered structures!")

        if self.refine_structure:
            finder = SymmetryFinder(structure, self.symm_prec)
            structure = finder.get_refined_structure()

        contains_oxidation_state = True
        for sp in structure.composition.elements:
            if not hasattr(sp, "oxi_state"):
                contains_oxidation_state = False
                break

        adaptor = EnumlibAdaptor(structure,
                                 min_cell_size=self.min_cell_size,
                                 max_cell_size=self.max_cell_size,
                                 symm_prec=self.symm_prec,
                                 refine_structure=False)
        adaptor.run()
        structures = adaptor.structures
        original_latt = structure.lattice
        inv_latt = np.linalg.inv(original_latt.matrix)
        ewald_matrices = {}
        all_structures = []
        for s in structures:
            new_latt = s.lattice
            transformation = np.dot(new_latt.matrix, inv_latt)
            transformation = tuple([
                tuple([int(round(cell)) for cell in row])
                for row in transformation
            ])
            if contains_oxidation_state:
                if transformation not in ewald_matrices:
                    s = Structure.from_sites(structure.sites)
                    s.make_supercell(transformation)
                    ewald = EwaldSummation(s)
                    ewald_matrices[transformation] = ewald
                else:
                    ewald = ewald_matrices[transformation]
                energy = ewald.compute_sub_structure(s)
                all_structures.append({
                    "num_sites": len(s),
                    "energy": energy,
                    "structure": s
                })
            else:
                all_structures.append({"num_sites": len(s), "structure": s})

        def sort_func(s):
            return s["energy"] / s["num_sites"] if contains_oxidation_state \
                else s["num_sites"]

        self._all_structures = sorted(all_structures, key=sort_func)

        if return_ranked_list:
            return self._all_structures[0:num_to_return]
        else:
            return self._all_structures[0]["structure"]
Ejemplo n.º 52
0
    def generate_doc(cls, dir_name, vasprun_files, parse_dos,
                     additional_fields):
        """
        Process aflow style runs, where each run is actually a combination of
        two vasp runs.
        """
        try:
            fullpath = os.path.abspath(dir_name)
            #Defensively copy the additional fields first.  This is a MUST.
            #Otherwise, parallel updates will see the same object and inserts
            #will be overridden!!
            d = {k: v for k, v in additional_fields.items()} \
                if additional_fields else {}
            d["dir_name"] = fullpath
            d["schema_version"] = VaspToDbTaskDrone.__version__
            d["calculations"] = [
                cls.process_vasprun(dir_name, taskname, filename, parse_dos)
                for taskname, filename in vasprun_files.items()
            ]
            d1 = d["calculations"][0]
            d2 = d["calculations"][-1]

            #Now map some useful info to the root level.
            for root_key in [
                    "completed_at", "nsites", "unit_cell_formula",
                    "reduced_cell_formula", "pretty_formula", "elements",
                    "nelements", "cif", "density", "is_hubbard", "hubbards",
                    "run_type"
            ]:
                d[root_key] = d2[root_key]
            d["chemsys"] = "-".join(sorted(d2["elements"]))
            d["input"] = {"crystal": d1["input"]["crystal"]}
            vals = sorted(d2["reduced_cell_formula"].values())
            d["anonymous_formula"] = {
                string.ascii_uppercase[i]: float(vals[i])
                for i in xrange(len(vals))
            }
            d["output"] = {
                "crystal": d2["output"]["crystal"],
                "final_energy": d2["output"]["final_energy"],
                "final_energy_per_atom": d2["output"]["final_energy_per_atom"]
            }
            d["name"] = "aflow"
            d["pseudo_potential"] = {
                "functional": "pbe",
                "pot_type": "paw",
                "labels": d2["input"]["potcar"]
            }

            if len(d["calculations"]) == 2 or \
                    vasprun_files.keys()[0] != "relax1":
                d["state"] = "successful" if d2["has_vasp_completed"] \
                    else "unsuccessful"
            else:
                d["state"] = "stopped"

            s = Structure.from_dict(d2["output"]["crystal"])
            if not s.is_valid():
                d["state"] = "errored_bad_structure"

            d["analysis"] = get_basic_analysis_and_error_checks(d)

            sg = SymmetryFinder(Structure.from_dict(d["output"]["crystal"]),
                                0.1)
            d["spacegroup"] = {
                "symbol": sg.get_spacegroup_symbol(),
                "number": sg.get_spacegroup_number(),
                "point_group": unicode(sg.get_point_group(), errors="ignore"),
                "source": "spglib",
                "crystal_system": sg.get_crystal_system(),
                "hall": sg.get_hall()
            }
            d["last_updated"] = datetime.datetime.today()
            d["type"] = "VASP"  #PS

            return d
        except Exception as ex:
            logger.error("Error in " + os.path.abspath(dir_name) +
                         ".\nError msg: " + str(ex))
            return None
Ejemplo n.º 53
0
    def generate_doc(cls, dir_name, vasprun_files, parse_dos,
                     additional_fields):
        """Process aflow style and NEB runs."""
        print "TTM DEBUG: In generate_doc for NEB task drone."
        try:
            fullpath = os.path.abspath(dir_name)
            #Defensively copy the additional fields first.  This is a MUST.
            #Otherwise, parallel updates will see the same object and inserts
            #will be overridden!!
            d = {k: v for k, v in additional_fields.items()} \
                if additional_fields else {}
            d["dir_name"] = fullpath
            print "TTM DEBUG: fullpath: ", fullpath
            d["schema_version"] = NEBToDbTaskDrone.__version__
            d["calculations"] = [
                cls.process_vasprun(dir_name, taskname, filename, parse_dos)
                for taskname, filename in vasprun_files.items()
            ]
            d1 = d["calculations"][0]
            d2 = d["calculations"][-1]

            #Now map some useful info to the root level.
            for root_key in [
                    "completed_at", "nsites", "unit_cell_formula",
                    "reduced_cell_formula", "pretty_formula", "elements",
                    "nelements", "cif", "density", "is_hubbard", "hubbards",
                    "run_type"
            ]:
                d[root_key] = d2[root_key]
            d["chemsys"] = "-".join(sorted(d2["elements"]))
            d["input"] = {"crystal": d1["input"]["crystal"]}
            vals = sorted(d2["reduced_cell_formula"].values())
            d["anonymous_formula"] = {
                string.ascii_uppercase[i]: float(vals[i])
                for i in xrange(len(vals))
            }
            d["output"] = {
                "crystal": d2["output"]["crystal"],
                "final_energy": d2["output"]["final_energy"],
                "final_energy_per_atom": d2["output"]["final_energy_per_atom"]
            }
            d["name"] = "aflow"
            d["pseudo_potential"] = {
                "functional": "pbe",
                "pot_type": "paw",
                "labels": d2["input"]["potcar"]
            }

            if len(d["calculations"]) == 2 or \
                    vasprun_files.keys()[0] != "relax1":
                d["state"] = "successful" if d2["has_vasp_completed"] \
                    else "unsuccessful"
            else:
                d["state"] = "stopped"

            s = Structure.from_dict(d2["output"]["crystal"])
            if not s.is_valid():
                d["state"] = "errored_bad_structure"

            d["analysis"] = get_basic_analysis_and_error_checks(d)

            sg = SymmetryFinder(Structure.from_dict(d["output"]["crystal"]),
                                0.1)
            d["spacegroup"] = {
                "symbol": sg.get_spacegroup_symbol(),
                "number": sg.get_spacegroup_number(),
                "point_group": unicode(sg.get_point_group(), errors="ignore"),
                "source": "spglib",
                "crystal_system": sg.get_crystal_system(),
                "hall": sg.get_hall()
            }
            d["last_updated"] = datetime.datetime.today()

            # Process NEB runs. The energy and magnetic moments for each image are listed.
            # Some useful values are calculated.

            # Number of NEB images
            print "TTM DEBUG: At NEB processing stage."
            image_list = []
            for i in xrange(0, 9):
                append = "0" + str(i)
                newpath = os.path.join(fullpath, append)
                if os.path.exists(newpath):
                    image_list.append(newpath)
            d["num_images"] = len(image_list)
            print "TTM DEBUG: Image list:", image_list
            # Image energies and magnetic moments for specific folders
            list_image_energies = []
            list_image_mags = []
            for i in xrange(0, len(image_list)):
                append = "0" + str(i)
                oszicar = os.path.join(fullpath, append, "OSZICAR")
                if not os.path.isfile(oszicar):
                    return None
                val_energy = util2.getEnergy(oszicar)
                val_mag = util2.getMag(oszicar)
                d["E_" + append] = val_energy
                d["mag_" + append] = val_mag
                list_image_energies.append(val_energy)
                list_image_mags.append(val_mag)
            print "TTM DEBUG: first occurrence list_image_mags", list_image_mags
            # List of image energies and magnetic moments in order
            image_energies = ' '.join(map(str, list_image_energies))
            d["image_energies"] = image_energies

            # An simple way to visualize relative image energies and magnetic moments
            energy_contour = "-x-"
            if len(image_list) == 0:
                return None
            for i in xrange(1, len(image_list)):
                if (list_image_energies[i] > list_image_energies[i - 1]):
                    energy_contour += "/-x-"
                elif list_image_energies[i] < list_image_energies[i - 1]:
                    energy_contour += "\\-x-"
                else:
                    energy_contour += "=-x-"
            d["energy_contour"] = energy_contour
            print "TTM DEBUG: energy contour:", energy_contour

            # Difference between the first and maximum energies and magnetic moments
            deltaE_firstmax = max(list_image_energies) - list_image_energies[0]
            d["deltaE_firstmax"] = deltaE_firstmax
            # Difference between the last and maximum energies and magnetic moments
            deltaE_lastmax = max(list_image_energies) - list_image_energies[-1]
            d["deltaE_lastmax"] = deltaE_lastmax

            # Difference between the endpoint energies and magnetic moments
            deltaE_endpoints = list_image_energies[-1] - list_image_energies[0]
            d["deltaE_endpoints"] = deltaE_endpoints

            # Difference between the minimum and maximum energies and magnetic moments
            deltaE_maxmin = max(list_image_energies) - min(list_image_energies)
            d["deltaE_maxmin"] = deltaE_maxmin

            #INDENT THE NEXT LINES:
            if not (list_image_mags[0] == None):  #if ISPIN not 2, no mag info
                image_mags = ' '.join(map(str, list_image_mags))
                d["image_mags"] = image_mags
                mag_contour = "-o-"
                if len(image_list) == 0:
                    return None
                for i in xrange(1, len(image_list)):
                    if (list_image_mags[i] > list_image_mags[i - 1]):
                        mag_contour += "/-o-"
                    elif list_image_mags[i] < list_image_mags[i - 1]:
                        mag_contour += "\\-o-"
                    else:
                        mag_contour += "=-o-"
                d["mag_contour"] = mag_contour
                deltaM_firstmax = max(list_image_mags) - list_image_mags[0]
                d["deltaM_firstmax"] = deltaM_firstmax
                deltaM_lastmax = max(list_image_mags) - list_image_mags[-1]
                d["deltaM_lastmax"] = deltaM_lastmax
                deltaM_endpoints = list_image_mags[-1] - list_image_mags[0]
                d["deltaM_endpoints"] = deltaM_endpoints
                deltaM_maxmin = max(list_image_mags) - min(list_image_mags)
                d["deltaM_maxmin"] = deltaM_maxmin

            d["type"] = "NEB"

            return d

        except Exception as ex:
            logger.error("Error in " + os.path.abspath(dir_name) +
                         ".\nError msg: " + str(ex))
            return None
Ejemplo n.º 54
0
    def get_valences(self, structure):
        """
        Returns a list of valences for the structure. This currently works only
        for ordered structures only.

        Args:
            structure:
                Structure to analyze

        Returns:
            A list of valences for each site in the structure,
            e.g., [1, 1, -2].

        Raises:
            A ValueError is the valences cannot be determined.
        """
        els = [Element(el.symbol) for el in structure.composition.elements]

        if not set(els).issubset(set(BV_PARAMS.keys())):
            raise ValueError(
                "Structure contains elements not in set of BV parameters!")

        #Perform symmetry determination and get sites grouped by symmetry.
        if self.symm_tol:
            finder = SymmetryFinder(structure, self.symm_tol)
            symm_structure = finder.get_symmetrized_structure()
            equi_sites = symm_structure.equivalent_sites
        else:
            equi_sites = [[site] for site in structure]

        #Sort the equivalent sites by decreasing electronegativity.
        equi_sites = sorted(
            equi_sites,
            key=lambda sites: -sites[0].species_and_occu.average_electroneg)

        #Get a list of valences and probabilities for each symmetrically
        #distinct site.
        valences = []
        all_prob = []
        for sites in equi_sites:
            test_site = sites[0]
            nn = structure.get_neighbors(test_site, self.max_radius)
            prob = self._calc_site_probabilities(test_site, nn)
            all_prob.append(prob)
            val = list(prob.keys())
            #Sort valences in order of decreasing probability.
            val = sorted(val, key=lambda v: -prob[v])
            #Retain probabilities that are at least 1/100 of highest prob.
            valences.append(
                filter(lambda v: prob[v] > 0.01 * prob[val[0]], val))

        #make variables needed for recursion
        nsites = np.array(map(len, equi_sites))
        vmin = np.array(map(min, valences))
        vmax = np.array(map(max, valences))

        self._n = 0
        self._best_score = 0
        self._best_vset = None

        def evaluate_assignment(v_set):
            el_oxi = collections.defaultdict(list)
            for i, sites in enumerate(equi_sites):
                el_oxi[sites[0].specie.symbol].append(v_set[i])
            max_diff = max([max(v) - min(v) for v in el_oxi.values()])
            if max_diff > 1:
                return
            score = reduce(operator.mul,
                           [all_prob[i][v] for i, v in enumerate(v_set)])
            if score > self._best_score:
                self._best_vset = v_set
                self._best_score = score

        def _recurse(assigned=[]):
            #recurses to find permutations of valences based on whether a
            #charge balanced assignment can still be found
            if self._n > self.max_permutations:
                return

            i = len(assigned)
            highest = vmax.copy()
            highest[:i] = assigned
            highest *= nsites
            highest = np.sum(highest)

            lowest = vmin.copy()
            lowest[:i] = assigned
            lowest *= nsites
            lowest = np.sum(lowest)

            if highest < 0 or lowest > 0:
                self._n += 1
                return

            if i == len(valences):
                evaluate_assignment(assigned)
                self._n += 1
                return
            else:
                for v in valences[i]:
                    new_assigned = list(assigned)
                    _recurse(new_assigned + [v])

        _recurse()

        if self._best_vset:
            assigned = {}
            for val, sites in zip(self._best_vset, equi_sites):
                for site in sites:
                    assigned[site] = val

            return [int(assigned[site]) for site in structure]
        else:
            raise ValueError("Valences cannot be assigned!")
Ejemplo n.º 55
0
class HighSymmKpath(object):
    """
    This class looks for path along high symmetry lines in
    the Brillouin Zone.
    It is based on 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
    The symmetry is determined by spglib through the
    SymmetryFinder class
    """

    def __init__(self, structure, symprec=0.01, angle_tolerance=5):
        """
        Args:
            structure:
                Structure object
            symprec:
                Tolerance for symmetry finding
            angle_tolerance:
                Angle tolerance for symmetry finding.
        """
        self._structure = structure
        self._sym = SymmetryFinder(structure, symprec=symprec,
                                   angle_tolerance=angle_tolerance)
        self._prim = self._sym\
            .get_primitive_standard_structure()
        self._conv = self._sym.get_conventional_standard_structure()
        self._prim_rec = self._prim.lattice.reciprocal_lattice
        self._kpath = None

        lattice_type = self._sym.get_lattice_type() 
        spg_symbol = self._sym.get_spacegroup_symbol()

        if lattice_type == "cubic":
            if "P" in spg_symbol:
                self._kpath = self.cubic()
            elif "F" in spg_symbol:
                self._kpath = self.fcc()
            elif "I" in spg_symbol:
                self._kpath = self.bcc()
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "tetragonal":
            if "P" in spg_symbol:
                self._kpath = self.tet()
            elif "I" in spg_symbol:
                a = self._conv.lattice.abc[0]
                c = self._conv.lattice.abc[2]
                if c < a:
                    self._kpath = self.bctet1(c, a)
                else:
                    self._kpath = self.bctet2(c, a)
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "orthorhombic":
            a = self._conv.lattice.abc[0]
            b = self._conv.lattice.abc[1]
            c = self._conv.lattice.abc[2]

            if "P" in spg_symbol:
                self._kpath = self.orc()

            elif "F" in spg_symbol:
                if 1 / a ** 2 > 1 / b ** 2 + 1 / c ** 2:
                    self._kpath = self.orcf1(a, b, c)
                elif 1 / a ** 2 < 1 / b ** 2 + 1 / c ** 2:
                    self._kpath = self.orcf2(a, b, c)
                else:
                    self._kpath = self.orcf3(a, b, c)

            elif "I" in spg_symbol:
                self._kpath = self.orci(a, b, c)

            elif "C" in spg_symbol:
                self._kpath = self.orcc(a, b, c)
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "hexagonal":
            self._kpath = self.hex()

        elif lattice_type == "rhombohedral":
            alpha = self._prim.lattice.lengths_and_angles[1][0]
            if alpha < 90:
                self._kpath = self.rhl1(alpha * pi / 180)
            else:
                self._kpath = self.rhl2(alpha * pi / 180)

        elif lattice_type == "monoclinic":
            a, b, c = self._conv.lattice.abc
            alpha = self._conv.lattice.lengths_and_angles[1][0]

            if "P" in spg_symbol:
                self._kpath = self.mcl(b, c, alpha * pi / 180)

            elif "C" in spg_symbol:
                kgamma = self._prim_rec.lengths_and_angles[1][2]
                if kgamma > 90:
                    self._kpath = self.mclc1(a, b, c, alpha * pi / 180)
                if kgamma == 90:
                    self._kpath = self.mclc2(a, b, c, alpha * pi / 180)
                if kgamma < 90:
                    if b * cos(alpha * pi / 180) / c\
                            + b ** 2 * sin(alpha) ** 2 / a ** 2 < 1:
                        self._kpath = self.mclc3(a, b, c, alpha * pi / 180)
                    if b * cos(alpha * pi / 180) / c \
                            + b ** 2 * sin(alpha) ** 2 / a ** 2 == 1:
                        self._kpath = self.mclc4(a, b, c, alpha * pi / 180)
                    if b * cos(alpha * pi / 180) / c \
                            + b ** 2 * sin(alpha) ** 2 / a ** 2 > 1:
                        self._kpath = self.mclc5(a, b, c, alpha * pi / 180)
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "triclinic":
            kalpha = self._prim_rec.lengths_and_angles[1][0]
            kbeta = self._prim_rec.lengths_and_angles[1][1]
            kgamma = self._prim_rec.lengths_and_angles[1][2]
            if kalpha > 90 and kbeta > 90 and kgamma > 90:
                self._kpath = self.tria()
            if kalpha < 90 and kbeta < 90 and kgamma < 90:
                self._kpath = self.trib()
            if kalpha > 90 and kbeta > 90 and kgamma == 90:
                self._kpath = self.tria()
            if kalpha < 90 and kbeta < 90 and kgamma == 90:
                self._kpath = self.trib()

        else:
            warn("Unknown lattice type %s" % lattice_type)

    @property
    def structure(self):
        """
        Returns:
            The standardized primitive structure
        """
        return self._prim

    @property
    def kpath(self):
        """
        Returns:
            The symmetry line path in reciprocal space
        """
        return self._kpath

    def get_kpoints(self, line_density=20):
        """
            Returns:
                the kpoints along the paths in cartesian coordinates
                together with the labels for symmetry points -Wei
        """
        list_k_points = []
        sym_point_labels = []
        for b in self.kpath['path']:
            for i in range(1, len(b)):
                start = np.array(self.kpath['kpoints'][b[i - 1]])
                end = np.array(self.kpath['kpoints'][b[i]])
                distance = np.linalg.norm(
                    self._prim_rec.get_cartesian_coords(start) -
                    self._prim_rec.get_cartesian_coords(end))
                nb = int(ceil(distance * line_density))
                sym_point_labels.extend([b[i - 1]] + [''] * (nb - 1) + [b[i]])
                list_k_points.extend(
                    [self._prim_rec.get_cartesian_coords(start)
                     + float(i) / float(nb) *
                     (self._prim_rec.get_cartesian_coords(end)
                      - self._prim_rec.get_cartesian_coords(start))
                     for i in range(0, nb + 1)])
        return list_k_points, sym_point_labels

    def get_kpath_plot(self, **kwargs):
        """
        Gives the plot (as a matplotlib object) of the symmetry line path in
        the Brillouin Zone.

        Returns:
            `matplotlib` figure.
                                                                                         
        ================  ==============================================================
        kwargs            Meaning
        ================  ==============================================================
        show              True to show the figure (Default).
        savefig           'abc.png' or 'abc.eps'* to save the figure to a file.
        ================  ==============================================================
        """
        import itertools
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d import axes3d

        def _plot_shape_skeleton(bz, style):
            for iface in range(len(bz)):
                for line in itertools.combinations(bz[iface], 2):
                    for jface in range(len(bz)):
                        if iface < jface and line[0] in bz[jface]\
                                and line[1] in bz[jface]:
                            ax.plot([line[0][0], line[1][0]],
                                    [line[0][1], line[1][1]],
                                    [line[0][2], line[1][2]], style)

        def _plot_lattice(lattice):
            vertex1 = lattice.get_cartesian_coords([0.0, 0.0, 0.0])
            vertex2 = lattice.get_cartesian_coords([1.0, 0.0, 0.0])
            ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]],
                    [vertex1[2], vertex2[2]], color='g', linewidth=3)
            vertex2 = lattice.get_cartesian_coords([0.0, 1.0, 0.0])
            ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]],
                    [vertex1[2], vertex2[2]], color='g', linewidth=3)
            vertex2 = lattice.get_cartesian_coords([0.0, 0.0, 1.0])
            ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]],
                    [vertex1[2], vertex2[2]], color='g', linewidth=3)

        def _plot_kpath(kpath, lattice):
            for line in kpath['path']:
                for k in range(len(line) - 1):
                    vertex1 = lattice.get_cartesian_coords(kpath['kpoints']
                                                           [line[k]])
                    vertex2 = lattice.get_cartesian_coords(kpath['kpoints']
                                                           [line[k + 1]])
                    ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]],
                            [vertex1[2], vertex2[2]], color='r', linewidth=3)

        def _plot_labels(kpath, lattice):
            for k in kpath['kpoints']:
                label = k
                if k.startswith("\\") or k.find("_") != -1:
                    label = "$" + k + "$"
                off = 0.01
                ax.text(lattice.get_cartesian_coords(kpath['kpoints'][k])[0]
                        + off,
                        lattice.get_cartesian_coords(kpath['kpoints'][k])[1]
                        + off,
                        lattice.get_cartesian_coords(kpath['kpoints'][k])[2]
                        + off,
                        label, color='b', size='25')
                ax.scatter([lattice.get_cartesian_coords(
                            kpath['kpoints'][k])[0]],
                           [lattice.get_cartesian_coords(
                            kpath['kpoints'][k])[1]],
                           [lattice.get_cartesian_coords(
                            kpath['kpoints'][k])[2]], color='b')
        fig = plt.figure()
        ax = axes3d.Axes3D(fig)
        _plot_lattice(self._prim_rec)
        _plot_shape_skeleton(self._prim_rec.get_wigner_seitz_cell(), '-k')
        _plot_kpath(self.kpath, self._prim_rec)
        _plot_labels(self.kpath, self._prim_rec)
        ax.axis("off")

        show = kwargs.pop("show", True)
        if show:
            plt.show()

        savefig = kwargs.pop("savefig", None)
        if savefig:
            fig.savefig(savefig)

        return fig

    def cubic(self):
        self.name = "CUB"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'X': np.array([0.0, 0.5, 0.0]),
                   'R': np.array([0.5, 0.5, 0.5]),
                   'M': np.array([0.5, 0.5, 0.0])}
        path = [["\Gamma", "X", "M", "\Gamma", "R", "X"], ["M", "R"]]
        return {'kpoints': kpoints, 'path': path}

    def fcc(self):
        self.name = "FCC"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'K': np.array([3.0 / 8.0, 3.0 / 8.0, 3.0 / 4.0]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'U': np.array([5.0 / 8.0, 1.0 / 4.0, 5.0 / 8.0]),
                   'W': np.array([0.5, 1.0 / 4.0, 3.0 / 4.0]),
                   'X': np.array([0.5, 0.0, 0.5])}
        path = [["\Gamma", "X", "W", "K",
                 "\Gamma", "L", "U", "W", "L", "K"], ["U", "X"]]
        return {'kpoints': kpoints, 'path': path}

    def bcc(self):
        self.name = "BCC"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'H': np.array([0.5, -0.5, 0.5]),
                   'P': np.array([0.25, 0.25, 0.25]),
                   'N': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "H", "N", "\Gamma", "P", "H"], ["P", "N"]]
        return {'kpoints': kpoints, 'path': path}

    def tet(self):
        self.name = "TET"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'A': np.array([0.5, 0.5, 0.5]),
                   'M': np.array([0.5, 0.5, 0.0]),
                   'R': np.array([0.0, 0.5, 0.5]),
                   'X': np.array([0.0, 0.5, 0.0]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "X", "M", "\Gamma", "Z", "R", "A", "Z"], ["X", "R"],
                ["M", "A"]]
        return {'kpoints': kpoints, 'path': path}

    def bctet1(self, c, a):
        self.name = "BCT1"
        eta = (1 + c ** 2 / a ** 2) / 4.0
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'M': np.array([-0.5, 0.5, 0.5]),
                   'N': np.array([0.0, 0.5, 0.0]),
                   'P': np.array([0.25, 0.25, 0.25]),
                   'X': np.array([0.0, 0.0, 0.5]),
                   'Z': np.array([eta, eta, -eta]),
                   'Z_1': np.array([-eta, 1 - eta, eta])}
        path = [["\Gamma", "X", "M", "\Gamma", "Z", "P", "N", "Z_1", "M"],
                ["X", "P"]]
        return {'kpoints': kpoints, 'path': path}

    def bctet2(self, c, a):
        self.name = "BCT2"
        eta = (1 + a ** 2 / c ** 2) / 4.0
        zeta = a ** 2 / (2 * c ** 2)
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'N': np.array([0.0, 0.5, 0.0]),
                   'P': np.array([0.25, 0.25, 0.25]),
                   '\Sigma': np.array([-eta, eta, eta]),
                   '\Sigma_1': np.array([eta, 1 - eta, -eta]),
                   'X': np.array([0.0, 0.0, 0.5]),
                   'Y': np.array([-zeta, zeta, 0.5]),
                   'Y_1': np.array([0.5, 0.5, -zeta]),
                   'Z': np.array([0.5, 0.5, -0.5])}
        path = [["\Gamma", "X", "Y", "\Sigma", "\Gamma", "Z",
                 "\Sigma_1", "N", "P", "Y_1", "Z"], ["X", "P"]]
        return {'kpoints': kpoints, 'path': path}

    def orc(self):
        self.name = "ORC"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'R': np.array([0.5, 0.5, 0.5]),
                   'S': np.array([0.5, 0.5, 0.0]),
                   'T': np.array([0.0, 0.5, 0.5]),
                   'U': np.array([0.5, 0.0, 0.5]),
                   'X': np.array([0.5, 0.0, 0.0]),
                   'Y': np.array([0.0, 0.5, 0.0]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "X", "S", "Y", "\Gamma",
                 "Z", "U", "R", "T", "Z"], ["Y", "T"], ["U", "X"], ["S", "R"]]
        return {'kpoints': kpoints, 'path': path}

    def orcf1(self, a, b, c):
        self.name = "ORCF1"
        zeta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4
        eta = (1 + a ** 2 / b ** 2 + a ** 2 / c ** 2) / 4

        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'A': np.array([0.5, 0.5 + zeta, zeta]),
                   'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'T': np.array([1, 0.5, 0.5]),
                   'X': np.array([0.0, eta, eta]),
                   'X_1': np.array([1, 1 - eta, 1 - eta]),
                   'Y': np.array([0.5, 0.0, 0.5]),
                   'Z': np.array([0.5, 0.5, 0.0])}
        path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"],
                ["T", "X_1"], ["X", "A", "Z"], ["L", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def orcf2(self, a, b, c):
        self.name = "ORCF2"
        phi = (1 + c ** 2 / b ** 2 - c ** 2 / a ** 2) / 4
        eta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4
        delta = (1 + b ** 2 / a ** 2 - b ** 2 / c ** 2) / 4
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'C': np.array([0.5, 0.5 - eta, 1 - eta]),
                   'C_1': np.array([0.5, 0.5 + eta, eta]),
                   'D': np.array([0.5 - delta, 0.5, 1 - delta]),
                   'D_1': np.array([0.5 + delta, 0.5, delta]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'H': np.array([1 - phi, 0.5 - phi, 0.5]),
                   'H_1': np.array([phi, 0.5 + phi, 0.5]),
                   'X': np.array([0.0, 0.5, 0.5]),
                   'Y': np.array([0.5, 0.0, 0.5]),
                   'Z': np.array([0.5, 0.5, 0.0])}
        path = [["\Gamma", "Y", "C", "D", "X", "\Gamma",
                 "Z", "D_1", "H", "C"], ["C_1", "Z"], ["X", "H_1"], ["H", "Y"],
                ["L", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def orcf3(self, a, b, c):
        self.name = "ORCF3"
        zeta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4
        eta = (1 + a ** 2 / b ** 2 + a ** 2 / c ** 2) / 4
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'A': np.array([0.5, 0.5 + zeta, zeta]),
                   'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'T': np.array([1, 0.5, 0.5]),
                   'X': np.array([0.0, eta, eta]),
                   'X_1': np.array([1, 1 - eta, 1 - eta]),
                   'Y': np.array([0.5, 0.0, 0.5]),
                   'Z': np.array([0.5, 0.5, 0.0])}
        path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"],
                ["X", "A", "Z"], ["L", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def orci(self, a, b, c):
        self.name = "ORCI"
        zeta = (1 + a ** 2 / c ** 2) / 4
        eta = (1 + b ** 2 / c ** 2) / 4
        delta = (b ** 2 - a ** 2) / (4 * c ** 2)
        mu = (a ** 2 + b ** 2) / (4 * c ** 2)
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'L': np.array([-mu, mu, 0.5 - delta]),
                   'L_1': np.array([mu, -mu, 0.5 + delta]),
                   'L_2': np.array([0.5 - delta, 0.5 + delta, -mu]),
                   'R': np.array([0.0, 0.5, 0.0]),
                   'S': np.array([0.5, 0.0, 0.0]),
                   'T': np.array([0.0, 0.0, 0.5]),
                   'W': np.array([0.25, 0.25, 0.25]),
                   'X': np.array([-zeta, zeta, zeta]),
                   'X_1': np.array([zeta, 1 - zeta, -zeta]),
                   'Y': np.array([eta, -eta, eta]),
                   'Y_1': np.array([1 - eta, eta, -eta]),
                   'Z': np.array([0.5, 0.5, -0.5])}
        path = [["\Gamma", "X", "L", "T", "W", "R", "X_1", "Z",
                 "\Gamma", "Y", "S", "W"], ["L_1", "Y"], ["Y_1", "Z"]]
        return {'kpoints': kpoints, 'path': path}

    def orcc(self, a, b, c):
        self.name = "ORCC"
        zeta = (1 + a ** 2 / b ** 2) / 4
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'A': np.array([zeta, zeta, 0.5]),
                   'A_1': np.array([-zeta, 1 - zeta, 0.5]),
                   'R': np.array([0.0, 0.5, 0.5]),
                   'S': np.array([0.0, 0.5, 0.0]),
                   'T': np.array([-0.5, 0.5, 0.5]),
                   'X': np.array([zeta, zeta, 0.0]),
                   'X_1': np.array([-zeta, 1 - zeta, 0.0]),
                   'Y': np.array([-0.5, 0.5, 0]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "X", "S", "R", "A", "Z",
                 "\Gamma", "Y", "X_1", "A_1", "T", "Y"], ["Z", "T"]]
        return {'kpoints': kpoints, 'path': path}

    def hex(self):
        self.name = "HEX"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'A': np.array([0.0, 0.0, 0.5]),
                   'H': np.array([1.0 / 3.0, 1.0 / 3.0, 0.5]),
                   'K': np.array([1.0 / 3.0, 1.0 / 3.0, 0.0]),
                   'L': np.array([0.5, 0.0, 0.5]),
                   'M': np.array([0.5, 0.0, 0.0])}
        path = [["\Gamma", "M", "K", "\Gamma", "A", "L", "H", "A"], ["L", "M"],
                ["K", "H"]]
        return {'kpoints': kpoints, 'path': path}

    def rhl1(self, alpha):
        self.name = "RHL1"
        eta = (1 + 4 * cos(alpha)) / (2 + 4 * cos(alpha))
        nu = 3.0 / 4.0 - eta / 2.0
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'B': np.array([eta, 0.5, 1.0 - eta]),
                   'B_1': np.array([1.0 / 2.0, 1.0 - eta, eta - 1.0]),
                   'F': np.array([0.5, 0.5, 0.0]),
                   'L': np.array([0.5, 0.0, 0.0]),
                   'L_1': np.array([0.0, 0.0, -0.5]),
                   'P': np.array([eta, nu, nu]),
                   'P_1': np.array([1.0 - nu, 1.0 - nu, 1.0 - eta]),
                   'P_2': np.array([nu, nu, eta - 1.0]),
                   'Q': np.array([1.0 - nu, nu, 0.0]),
                   'X': np.array([nu, 0.0, -nu]),
                   'Z': np.array([0.5, 0.5, 0.5])}
        path = [["\Gamma", "L", "B_1"], ["B", "Z", "\Gamma", "X"],
                ["Q", "F", "P_1", "Z"], ["L", "P"]]
        return {'kpoints': kpoints, 'path': path}

    def rhl2(self, alpha):
        self.name = "RHL2"
        eta = 1 / (2 * tan(alpha / 2.0) ** 2)
        nu = 3.0 / 4.0 - eta / 2.0
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'F': np.array([0.5, -0.5, 0.0]),
                   'L': np.array([0.5, 0.0, 0.0]),
                   'P': np.array([1 - nu, -nu, 1 - nu]),
                   'P_1': np.array([nu, nu - 1.0, nu - 1.0]),
                   'Q': np.array([eta, eta, eta]),
                   'Q_1': np.array([1.0 - eta, -eta, -eta]),
                   'Z': np.array([0.5, -0.5, 0.5])}
        path = [["\Gamma", "P", "Z", "Q", "\Gamma",
                 "F", "P_1", "Q_1", "L", "Z"]]
        return {'kpoints': kpoints, 'path': path}

    def mcl(self, b, c, alpha):
        self.name = "MCL"
        eta = (1 - b * cos(alpha) / c) / (2 * sin(alpha) ** 2)
        nu = 0.5 - eta * c * cos(alpha) / b
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'A': np.array([0.5, 0.5, 0.0]),
                   'C': np.array([0.0, 0.5, 0.5]),
                   'D': np.array([0.5, 0.0, 0.5]),
                   'D_1': np.array([0.5, 0.5, -0.5]),
                   'E': np.array([0.5, 0.5, 0.5]),
                   'H': np.array([0.0, eta, 1.0 - nu]),
                   'H_1': np.array([0.0, 1.0 - eta, nu]),
                   'H_2': np.array([0.0, eta, -nu]),
                   'M': np.array([0.5, eta, 1.0 - nu]),
                   'M_1': np.array([0.5, 1 - eta, nu]),
                   'M_2': np.array([0.5, 1 - eta, nu]),
                   'X': np.array([0.0, 0.5, 0.0]),
                   'Y': np.array([0.0, 0.0, 0.5]),
                   'Y_1': np.array([0.0, 0.0, -0.5]),
                   'Z': np.array([0.5, 0.0, 0.0])}
        path = [["\Gamma", "Y", "H", "C", "E", "M_1", "A", "X", "H_1"],
                ["M", "D", "Z"], ["Y", "D"]]
        return {'kpoints': kpoints, 'path': path}

    def mclc1(self, a, b, c, alpha):
        self.name = "MCLC1"
        zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha) ** 2)
        eta = 0.5 + 2 * zeta * c * cos(alpha) / b
        psi = 0.75 - a ** 2 / (4 * b ** 2 * sin(alpha) ** 2)
        phi = psi + (0.75 - psi) * b * cos(alpha) / c
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'N': np.array([0.5, 0.0, 0.0]),
                   'N_1': np.array([0.0, -0.5, 0.0]),
                   'F': np.array([1 - zeta, 1 - zeta, 1 - eta]),
                   'F_1': np.array([zeta, zeta, eta]),
                   'F_2': np.array([-zeta, -zeta, 1 - eta]),
                   #'F_3': np.array([1 - zeta, -zeta, 1 - eta]),
                   'I': np.array([phi, 1 - phi, 0.5]),
                   'I_1': np.array([1 - phi, phi - 1, 0.5]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'M': np.array([0.5, 0.0, 0.5]),
                   'X': np.array([1 - psi, psi - 1, 0.0]),
                   'X_1': np.array([psi, 1 - psi, 0.0]),
                   'X_2': np.array([psi - 1, -psi, 0.0]),
                   'Y': np.array([0.5, 0.5, 0.0]),
                   'Y_1': np.array([-0.5, -0.5, 0.0]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"],
                ["Y", "X_1"], ["X", "\Gamma", "N"], ["M", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def mclc2(self, a, b, c, alpha):
        self.name = "MCLC2"
        zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha) ** 2)
        eta = 0.5 + 2 * zeta * c * cos(alpha) / b
        psi = 0.75 - a ** 2 / (4 * b ** 2 * sin(alpha) ** 2)
        phi = psi + (0.75 - psi) * b * cos(alpha) / c
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'N': np.array([0.5, 0.0, 0.0]),
                   'N_1': np.array([0.0, -0.5, 0.0]),
                   'F': np.array([1 - zeta, 1 - zeta, 1 - eta]),
                   'F_1': np.array([zeta, zeta, eta]),
                   'F_2': np.array([-zeta, -zeta, 1 - eta]),
                   'F_3': np.array([1 - zeta, -zeta, 1 - eta]),
                   'I': np.array([phi, 1 - phi, 0.5]),
                   'I_1': np.array([1 - phi, phi - 1, 0.5]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'M': np.array([0.5, 0.0, 0.5]),
                   'X': np.array([1 - psi, psi - 1, 0.0]),
                   'X_1': np.array([psi, 1 - psi, 0.0]),
                   'X_2': np.array([psi - 1, -psi, 0.0]),
                   'Y': np.array([0.5, 0.5, 0.0]),
                   'Y_1': np.array([-0.5, -0.5, 0.0]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"],
                ["N", "\Gamma", "M"]]
        return {'kpoints': kpoints, 'path': path}

    def mclc3(self, a, b, c, alpha):
        self.name = "MCLC3"
        mu = (1 + b ** 2 / a ** 2) / 4.0
        delta = b * c * cos(alpha) / (2 * a ** 2)
        zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\
            / (4 * sin(alpha) ** 2)
        eta = 0.5 + 2 * zeta * c * cos(alpha) / b
        phi = 1 + zeta - 2 * mu
        psi = eta - 2 * delta
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'F': np.array([1 - phi, 1 - phi, 1 - psi]),
                   'F_1': np.array([phi, phi - 1, psi]),
                   'F_2': np.array([1 - phi, -phi, 1 - psi]),
                   'H': np.array([zeta, zeta, eta]),
                   'H_1': np.array([1 - zeta, -zeta, 1 - eta]),
                   'H_2': np.array([-zeta, -zeta, 1 - eta]),
                   'I': np.array([0.5, -0.5, 0.5]),
                   'M': np.array([0.5, 0.0, 0.5]),
                   'N': np.array([0.5, 0.0, 0.0]),
                   'N_1': np.array([0.0, -0.5, 0.0]),
                   'X': np.array([0.5, -0.5, 0.0]),
                   'Y': np.array([mu, mu, delta]),
                   'Y_1': np.array([1 - mu, -mu, -delta]),
                   'Y_2': np.array([-mu, -mu, -delta]),
                   'Y_3': np.array([mu, mu - 1, delta]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "Y", "F", "H", "Z", "I", "F_1"],
                ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def mclc4(self, a, b, c, alpha):
        self.name = "MCLC4"
        mu = (1 + b ** 2 / a ** 2) / 4.0
        delta = b * c * cos(alpha) / (2 * a ** 2)
        zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\
            / (4 * sin(alpha) ** 2)
        eta = 0.5 + 2 * zeta * c * cos(alpha) / b
        phi = 1 + zeta - 2 * mu
        psi = eta - 2 * delta
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'F': np.array([1 - phi, 1 - phi, 1 - psi]),
                   'F_1': np.array([phi, phi - 1, psi]),
                   'F_2': np.array([1 - phi, -phi, 1 - psi]),
                   'H': np.array([zeta, zeta, eta]),
                   'H_1': np.array([1 - zeta, -zeta, 1 - eta]),
                   'H_2': np.array([-zeta, -zeta, 1 - eta]),
                   'I': np.array([0.5, -0.5, 0.5]),
                   'M': np.array([0.5, 0.0, 0.5]),
                   'N': np.array([0.5, 0.0, 0.0]),
                   'N_1': np.array([0.0, -0.5, 0.0]),
                   'X': np.array([0.5, -0.5, 0.0]),
                   'Y': np.array([mu, mu, delta]),
                   'Y_1': np.array([1 - mu, -mu, -delta]),
                   'Y_2': np.array([-mu, -mu, -delta]),
                   'Y_3': np.array([mu, mu - 1, delta]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "Y", "F", "H", "Z", "I"],
                ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def mclc5(self, a, b, c, alpha):
        self.name = "MCLC5"
        zeta = (b ** 2 / a ** 2 + (1 - b * cos(alpha) / c)
                / sin(alpha) ** 2) / 4
        eta = 0.5 + 2 * zeta * c * cos(alpha) / b
        mu = eta / 2 + b ** 2 / (4 * a ** 2) \
            - b * c * cos(alpha) / (2 * a ** 2)
        nu = 2 * mu - zeta
        rho = 1 - zeta * a ** 2 / b ** 2
        omega = (4 * nu - 1 - b ** 2 * sin(alpha) ** 2 / a ** 2)\
            * c / (2 * b * cos(alpha))
        delta = zeta * c * cos(alpha) / b + omega / 2 - 0.25
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'F': np.array([nu, nu, omega]),
                   'F_1': np.array([1 - nu, 1 - nu, 1 - omega]),
                   'F_2': np.array([nu, nu - 1, omega]),
                   'H': np.array([zeta, zeta, eta]),
                   'H_1': np.array([1 - zeta, -zeta, 1 - eta]),
                   'H_2': np.array([-zeta, -zeta, 1 - eta]),
                   'I': np.array([rho, 1 - rho, 0.5]),
                   'I_1': np.array([1 - rho, rho - 1, 0.5]),
                   'L': np.array([0.5, 0.5, 0.5]),
                   'M': np.array([0.5, 0.0, 0.5]),
                   'N': np.array([0.5, 0.0, 0.0]),
                   'N_1': np.array([0.0, -0.5, 0.0]),
                   'X': np.array([0.5, -0.5, 0.0]),
                   'Y': np.array([mu, mu, delta]),
                   'Y_1': np.array([1 - mu, -mu, -delta]),
                   'Y_2': np.array([-mu, -mu, -delta]),
                   'Y_3': np.array([mu, mu - 1, delta]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "H", "F_1"],
                ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def tria(self):
        self.name = "TRI1a"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'L': np.array([0.5, 0.5, 0.0]),
                   'M': np.array([0.0, 0.5, 0.5]),
                   'N': np.array([0.5, 0.0, 0.5]),
                   'R': np.array([0.5, 0.5, 0.5]),
                   'X': np.array([0.5, 0.0, 0.0]),
                   'Y': np.array([0.0, 0.5, 0.0]),
                   'Z': np.array([0.0, 0.0, 0.5])}
        path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"],
                ["N", "\Gamma", "M"], ["R", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}

    def trib(self):
        self.name = "TRI1b"
        kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]),
                   'L': np.array([0.5, -0.5, 0.0]),
                   'M': np.array([0.0, 0.0, 0.5]),
                   'N': np.array([-0.5, -0.5, 0.5]),
                   'R': np.array([0.0, -0.5, 0.5]),
                   'X': np.array([0.0, -0.5, 0.0]),
                   'Y': np.array([0.5, 0.0, 0.0]),
                   'Z': np.array([-0.5, 0.0, 0.5])}
        path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"],
                ["N", "\Gamma", "M"], ["R", "\Gamma"]]
        return {'kpoints': kpoints, 'path': path}
Ejemplo n.º 56
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
Ejemplo n.º 57
0
 def setUp(self):
     p = Poscar.from_file(os.path.join(test_dir, 'POSCAR'))
     self.structure = p.structure
     self.sg1 = SymmetryFinder(self.structure, 0.001).get_spacegroup()
Ejemplo n.º 58
0
    def __init__(self, structure, symprec=0.01, angle_tolerance=5):
        """
        Args:
            structure:
                Structure object
            symprec:
                Tolerance for symmetry finding
            angle_tolerance:
                Angle tolerance for symmetry finding.
        """
        self._structure = structure
        self._sym = SymmetryFinder(structure, symprec=symprec,
                                   angle_tolerance=angle_tolerance)
        self._prim = self._sym\
            .get_primitive_standard_structure()
        self._conv = self._sym.get_conventional_standard_structure()
        self._prim_rec = self._prim.lattice.reciprocal_lattice
        self._kpath = None

        lattice_type = self._sym.get_lattice_type() 
        spg_symbol = self._sym.get_spacegroup_symbol()

        if lattice_type == "cubic":
            if "P" in spg_symbol:
                self._kpath = self.cubic()
            elif "F" in spg_symbol:
                self._kpath = self.fcc()
            elif "I" in spg_symbol:
                self._kpath = self.bcc()
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "tetragonal":
            if "P" in spg_symbol:
                self._kpath = self.tet()
            elif "I" in spg_symbol:
                a = self._conv.lattice.abc[0]
                c = self._conv.lattice.abc[2]
                if c < a:
                    self._kpath = self.bctet1(c, a)
                else:
                    self._kpath = self.bctet2(c, a)
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "orthorhombic":
            a = self._conv.lattice.abc[0]
            b = self._conv.lattice.abc[1]
            c = self._conv.lattice.abc[2]

            if "P" in spg_symbol:
                self._kpath = self.orc()

            elif "F" in spg_symbol:
                if 1 / a ** 2 > 1 / b ** 2 + 1 / c ** 2:
                    self._kpath = self.orcf1(a, b, c)
                elif 1 / a ** 2 < 1 / b ** 2 + 1 / c ** 2:
                    self._kpath = self.orcf2(a, b, c)
                else:
                    self._kpath = self.orcf3(a, b, c)

            elif "I" in spg_symbol:
                self._kpath = self.orci(a, b, c)

            elif "C" in spg_symbol:
                self._kpath = self.orcc(a, b, c)
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "hexagonal":
            self._kpath = self.hex()

        elif lattice_type == "rhombohedral":
            alpha = self._prim.lattice.lengths_and_angles[1][0]
            if alpha < 90:
                self._kpath = self.rhl1(alpha * pi / 180)
            else:
                self._kpath = self.rhl2(alpha * pi / 180)

        elif lattice_type == "monoclinic":
            a, b, c = self._conv.lattice.abc
            alpha = self._conv.lattice.lengths_and_angles[1][0]

            if "P" in spg_symbol:
                self._kpath = self.mcl(b, c, alpha * pi / 180)

            elif "C" in spg_symbol:
                kgamma = self._prim_rec.lengths_and_angles[1][2]
                if kgamma > 90:
                    self._kpath = self.mclc1(a, b, c, alpha * pi / 180)
                if kgamma == 90:
                    self._kpath = self.mclc2(a, b, c, alpha * pi / 180)
                if kgamma < 90:
                    if b * cos(alpha * pi / 180) / c\
                            + b ** 2 * sin(alpha) ** 2 / a ** 2 < 1:
                        self._kpath = self.mclc3(a, b, c, alpha * pi / 180)
                    if b * cos(alpha * pi / 180) / c \
                            + b ** 2 * sin(alpha) ** 2 / a ** 2 == 1:
                        self._kpath = self.mclc4(a, b, c, alpha * pi / 180)
                    if b * cos(alpha * pi / 180) / c \
                            + b ** 2 * sin(alpha) ** 2 / a ** 2 > 1:
                        self._kpath = self.mclc5(a, b, c, alpha * pi / 180)
            else:
                warn("Unexpected value for spg_symbol: %s" % spg_symbol)

        elif lattice_type == "triclinic":
            kalpha = self._prim_rec.lengths_and_angles[1][0]
            kbeta = self._prim_rec.lengths_and_angles[1][1]
            kgamma = self._prim_rec.lengths_and_angles[1][2]
            if kalpha > 90 and kbeta > 90 and kgamma > 90:
                self._kpath = self.tria()
            if kalpha < 90 and kbeta < 90 and kgamma < 90:
                self._kpath = self.trib()
            if kalpha > 90 and kbeta > 90 and kgamma == 90:
                self._kpath = self.tria()
            if kalpha < 90 and kbeta < 90 and kgamma == 90:
                self._kpath = self.trib()

        else:
            warn("Unknown lattice type %s" % lattice_type)
Ejemplo n.º 59
0
    def __init__(self, struct, find_spacegroup=False):
        block = CifFile.CifBlock()
        latt = struct.lattice
        comp = struct.composition
        no_oxi_comp = Composition(comp.formula)
        spacegroup = ("P 1", 1)
        if find_spacegroup:
            sf = SymmetryFinder(struct, 0.001)
            spacegroup = (sf.get_spacegroup_symbol(),
                          sf.get_spacegroup_number())
        block["_symmetry_space_group_name_H-M"] = spacegroup[0]
        for cell_attr in ['a', 'b', 'c']:
            block["_cell_length_" + cell_attr] = str(getattr(latt, cell_attr))
        for cell_attr in ['alpha', 'beta', 'gamma']:
            block["_cell_angle_" + cell_attr] = float(getattr(latt, cell_attr))
        block["_chemical_name_systematic"] = "Generated by pymatgen"
        block["_symmetry_Int_Tables_number"] = spacegroup[1]
        block["_chemical_formula_structural"] = str(
            no_oxi_comp.reduced_formula)
        block["_chemical_formula_sum"] = str(no_oxi_comp.formula)
        block["_cell_volume"] = str(latt.volume)

        reduced_comp = Composition.from_formula(no_oxi_comp.reduced_formula)
        el = no_oxi_comp.elements[0]
        amt = comp[el]
        fu = int(amt / reduced_comp[Element(el.symbol)])

        block["_cell_formula_units_Z"] = str(fu)
        block.AddCifItem(
            ([["_symmetry_equiv_pos_site_id",
               "_symmetry_equiv_pos_as_xyz"]], [[["1"], ["x, y, z"]]]))

        contains_oxidation = True
        try:
            symbol_to_oxinum = {
                str(el): float(el.oxi_state)
                for el in comp.elements
            }
        except AttributeError:
            symbol_to_oxinum = {el.symbol: 0 for el in comp.elements}
            contains_oxidation = False
        if contains_oxidation:
            block.AddCifItem(
                ([["_atom_type_symbol", "_atom_type_oxidation_number"]],
                 [[symbol_to_oxinum.keys(),
                   symbol_to_oxinum.values()]]))

        atom_site_type_symbol = []
        atom_site_symmetry_multiplicity = []
        atom_site_fract_x = []
        atom_site_fract_y = []
        atom_site_fract_z = []
        atom_site_attached_hydrogens = []
        atom_site_B_iso_or_equiv = []
        atom_site_label = []
        atom_site_occupancy = []
        count = 1
        for site in struct:
            for sp, occu in site.species_and_occu.items():
                atom_site_type_symbol.append(str(sp))
                atom_site_symmetry_multiplicity.append("1")
                atom_site_fract_x.append("{0:f}".format(site.a))
                atom_site_fract_y.append("{0:f}".format(site.b))
                atom_site_fract_z.append("{0:f}".format(site.c))
                atom_site_attached_hydrogens.append("0")
                atom_site_B_iso_or_equiv.append(".")
                atom_site_label.append("{}{}".format(sp.symbol, count))
                atom_site_occupancy.append(str(occu))
                count += 1

        block["_atom_site_type_symbol"] = atom_site_type_symbol
        block.AddToLoop("_atom_site_type_symbol",
                        {"_atom_site_label": atom_site_label})
        block.AddToLoop("_atom_site_type_symbol", {
            "_atom_site_symmetry_multiplicity":
            atom_site_symmetry_multiplicity
        })
        block.AddToLoop("_atom_site_type_symbol",
                        {"_atom_site_fract_x": atom_site_fract_x})
        block.AddToLoop("_atom_site_type_symbol",
                        {"_atom_site_fract_y": atom_site_fract_y})
        block.AddToLoop("_atom_site_type_symbol",
                        {"_atom_site_fract_z": atom_site_fract_z})
        block.AddToLoop(
            "_atom_site_type_symbol",
            {"_atom_site_attached_hydrogens": atom_site_attached_hydrogens})
        block.AddToLoop(
            "_atom_site_type_symbol",
            {"_atom_site_B_iso_or_equiv": atom_site_B_iso_or_equiv})
        block.AddToLoop("_atom_site_type_symbol",
                        {"_atom_site_occupancy": atom_site_occupancy})

        self._cf = CifFile.CifFile()
        # AJ says: CIF Block names cannot be more than 75 characters or you
        # get an Exception
        self._cf[comp.reduced_formula[0:74]] = block