Esempio n. 1
0
    def add_snl(self, snl, force_new=False, snlgroup_guess=None):
        try:
            self.lock_db()
            snl_id = self._get_next_snl_id()

            spstruc = snl.structure.copy()
            spstruc.remove_oxidation_states()
            sf = SpacegroupAnalyzer(spstruc, SPACEGROUP_TOLERANCE)
            sf.get_space_group_operations()
            sgnum = sf.get_space_group_number() if sf.get_space_group_number() \
                else -1
            sgsym = sf.get_space_group_symbol() if sf.get_space_group_symbol() \
                else 'unknown'
            sghall = sf.get_hall() if sf.get_hall() else 'unknown'
            sgxtal = sf.get_crystal_system() if sf.get_crystal_system() \
                else 'unknown'
            sglatt = sf.get_lattice_type() if sf.get_lattice_type() else 'unknown'
            sgpoint = sf.get_point_group_symbol()

            mpsnl = MPStructureNL.from_snl(snl, snl_id, sgnum, sgsym, sghall,
                                           sgxtal, sglatt, sgpoint)
            snlgroup, add_new, spec_group = self.add_mpsnl(mpsnl, force_new, snlgroup_guess)
            self.release_lock()
            return mpsnl, snlgroup.snlgroup_id, spec_group
        except:
            self.release_lock()
            traceback.print_exc()
            raise ValueError("Error while adding SNL!")
Esempio n. 2
0
    def add_snl(self, snl, force_new=False, snlgroup_guess=None):
        try:
            self.lock_db()
            snl_id = self._get_next_snl_id()

            spstruc = snl.structure.copy()
            spstruc.remove_oxidation_states()
            sf = SpacegroupAnalyzer(spstruc, SPACEGROUP_TOLERANCE)
            sf.get_spacegroup()
            sgnum = sf.get_spacegroup_number() if sf.get_spacegroup_number() \
                else -1
            sgsym = sf.get_spacegroup_symbol() if sf.get_spacegroup_symbol() \
                else 'unknown'
            sghall = sf.get_hall() if sf.get_hall() else 'unknown'
            sgxtal = sf.get_crystal_system() if sf.get_crystal_system() \
                else 'unknown'
            sglatt = sf.get_lattice_type() if sf.get_lattice_type(
            ) else 'unknown'
            sgpoint = sf.get_point_group()

            mpsnl = MPStructureNL.from_snl(snl, snl_id, sgnum, sgsym, sghall,
                                           sgxtal, sglatt, sgpoint)
            snlgroup, add_new, spec_group = self.add_mpsnl(
                mpsnl, force_new, snlgroup_guess)
            self.release_lock()
            return mpsnl, snlgroup.snlgroup_id, spec_group
        except:
            self.release_lock()
            traceback.print_exc()
            raise ValueError("Error while adding SNL!")
Esempio n. 3
0
    def _get_sigmas_options_and_ratio(structure, rotation_axis):

        rotation_axis = [int(i) for i in rotation_axis]

        lat_type = (
            "c"  # assume cubic if no structure specified, just to set initial choices
        )
        ratio = None
        if structure:
            sga = SpacegroupAnalyzer(structure)
            lat_type = sga.get_lattice_type()[
                0]  # this should be fixed in pymatgen
            try:
                ratio = GrainBoundaryGenerator(structure).get_ratio()
            except Exception:
                ratio = None

        cutoff = 10

        if lat_type.lower() == "c":
            sigmas = GrainBoundaryGenerator.enum_sigma_cubic(
                cutoff=cutoff, r_axis=rotation_axis)
        elif lat_type.lower() == "t":
            sigmas = GrainBoundaryGenerator.enum_sigma_tet(
                cutoff=cutoff, r_axis=rotation_axis, c2_a2_ratio=ratio)
        elif lat_type.lower() == "o":
            sigmas = GrainBoundaryGenerator.enum_sigma_ort(
                cutoff=cutoff, r_axis=rotation_axis, c2_b2_a2_ratio=ratio)
        elif lat_type.lower() == "h":
            sigmas = GrainBoundaryGenerator.enum_sigma_hex(
                cutoff=cutoff, r_axis=rotation_axis, c2_a2_ratio=ratio)
        elif lat_type.lower() == "r":
            sigmas = GrainBoundaryGenerator.enum_sigma_rho(
                cutoff=cutoff, r_axis=rotation_axis, ratio_alpha=ratio)
        else:
            return [], None, ratio

        options = []
        subscript_unicode_map = {
            0: "₀",
            1: "₁",
            2: "₂",
            3: "₃",
            4: "₄",
            5: "₅",
            6: "₆",
            7: "₇",
            8: "₈",
            9: "₉",
        }
        for sigma in sorted(sigmas.keys()):
            sigma_label = "Σ{}".format(sigma)
            for k, v in subscript_unicode_map.items():
                sigma_label = sigma_label.replace(str(k), v)
            options.append({"label": sigma_label, "value": sigma})

        return sigmas, options, ratio
Esempio n. 4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f',
                        '--file',
                        default='POSCAR',
                        type=str,
                        help='path to input file')
    parser.add_argument('-t',
                        '--tol',
                        default=1e-3,
                        type=float,
                        help='symmetry tolerance (default 1e-3)')
    parser.add_argument('-o',
                        '--output',
                        default='poscar',
                        help='output file format')
    args = parser.parse_args()

    struct = Structure.from_file(args.file)
    sym = SpacegroupAnalyzer(struct, symprec=args.tol)
    data = sym.get_symmetry_dataset()

    print("Initial structure has {} atoms".format(struct.num_sites))
    print("\tSpace group number: {}".format(data['number']))
    print("\tInternational symbol: {}".format(data['international']))
    print("\tLattice type: {}".format(sym.get_lattice_type()))

    # seekpath conventional cell definition different from spglib
    std = spglib.refine_cell(sym._cell, symprec=args.tol)
    seek_data = seekpath.get_path(std)

    # now remake the structure
    lattice = seek_data['conv_lattice']
    scaled_positions = seek_data['conv_positions']
    numbers = seek_data['conv_types']
    species = [sym._unique_species[i - 1] for i in numbers]
    conv = Structure(lattice, species, scaled_positions)
    conv.get_sorted_structure().to(filename="{}_conv".format(args.file),
                                   fmt=args.output)

    print("Final structure has {} atoms".format(conv.num_sites))
Esempio n. 5
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f',
                        '--file',
                        type=str,
                        default='POSCAR',
                        help='path to input file')
    parser.add_argument('-t',
                        '--tol',
                        default=1e-3,
                        type=float,
                        help='symmetry tolerance (default 1e-3)')
    args = parser.parse_args()

    struct = Structure.from_file(args.file)
    sym = SpacegroupAnalyzer(struct, symprec=args.tol)
    data = sym.get_symmetry_dataset()

    print("Space group number: {}".format(data['number']))
    print("International symbol: {}".format(data['international']))
    print("Lattice type: {}".format(sym.get_lattice_type()))
Esempio n. 6
0
def structure_symmetry():
    structs, fnames = read_structures()
    multi_structs(structs, fnames)
    for struct, fname in zip(structs, fnames):
        if isinstance(struct, Structure):
            sa = SpacegroupAnalyzer(struct)
            print("file name: {}".format(fname))
            print("{} : {}".format('Structure Type', 'periodicity'))
            print("{} : {}".format('Lattice Type', sa.get_lattice_type()))
            print("{} : {}".format('Space Group ID',
                                   sa.get_space_group_number()))
            print("{} : {}".format('International Symbol',
                                   sa.get_space_group_symbol()))
            print("{} : {}".format('Hall Symbol', sa.get_hall()))
            sepline()
        if isinstance(struct, Molecule):
            print("file name: {}".format(fname))
            sa = PointGroupAnalyzer(struct)
            print("{} : {}".format('Structure Type', 'non-periodicity'))
            print("{} : {}".format('International Symbol',
                                   ast.get_pointgroup()))
    return True
Esempio n. 7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f', '--file', default='POSCAR', type=str,
                        help='path to input file')
    parser.add_argument('-t', '--tol', default=1e-3, type=float,
                        help='symmetry tolerance (default 1e-3)')
    parser.add_argument('-o', '--output', default='poscar',
                        help='output file format')
    args = parser.parse_args()

    struct = Structure.from_file(args.file)
    sym = SpacegroupAnalyzer(struct, symprec=args.tol)
    data = sym.get_symmetry_dataset()

    print('Initial structure has {} atoms'.format(struct.num_sites))
    print('\tSpace group number: {}'.format(data['number']))
    print('\tInternational symbol: {}'.format(data['international']))
    print('\tLattice type: {}'.format(sym.get_lattice_type()))

    # first standardise the cell using the tolerance we want (seekpath has no
    # tolerance setting)
    std = spglib.refine_cell(sym._cell, symprec=args.tol)
    seek_data = seekpath.get_path(std)

    transform = seek_data['primitive_transformation_matrix']

    # now remake the structure
    lattice = seek_data['primitive_lattice']
    scaled_positions = seek_data['primitive_positions']
    numbers = seek_data['primitive_types']
    species = [sym._unique_species[i - 1] for i in numbers]
    prim = Structure(lattice, species, scaled_positions)
    prim.get_sorted_structure().to(filename='{}_prim'.format(args.file),
                                   fmt=args.output)

    print('Final structure has {} atoms'.format(prim.num_sites))
    print('Conv -> Prim transformation matrix:')
    print('\t' + str(transform).replace('\n', '\n\t'))
Esempio n. 8
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
    SpacegroupAnalyzer class

    Args:
        structure (Structure): Structure object
        symprec (float): Tolerance for symmetry finding
        angle_tolerance (float): Angle tolerance for symmetry finding.
    """

    def __init__(self, structure, symprec=0.01, angle_tolerance=5):
        self._structure = structure
        self._sym = SpacegroupAnalyzer(structure, symprec=symprec,
                                   angle_tolerance=angle_tolerance)
        self._prim = self._sym\
            .get_primitive_standard_structure(international_monoclinic=False)
        self._conv = self._sym.get_conventional_standard_structure(international_monoclinic=False)
        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]
            #beta = self._conv.lattice.lengths_and_angles[1][1]

            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, coords_are_cartesian=True):
        """
        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)])
        if coords_are_cartesian:
            return list_k_points, sym_point_labels
        else:
            frac_k_points = [self._prim_rec.get_fractional_coords(k)
                             for k in list_k_points]
            return frac_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
        ================  ====================================================
        title             Title of the plot (Default: None).
        show              True to show the figure (default: True).
        savefig           'abc.png' or 'abc.eps' to save the figure to a file.
        size_kwargs       Dictionary with options passed to fig.set_size_inches
                          example: size_kwargs=dict(w=3, h=4)
        tight_layout      True if to call fig.tight_layout (default: False)
        ================  ====================================================
        """

        lines = [[self.kpath['kpoints'][k] for k in p] for p in self.kpath['path']]
        return plot_brillouin_zone(bz_lattice=self._prim_rec, lines=lines, labels=self.kpath['kpoints'], **kwargs)


    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, beta):
        self.name = "MCL"
        eta = (1 - b * cos(beta) / c) / (2 * sin(beta) ** 2)
        nu = 0.5 - eta * c * cos(beta) / 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}
Esempio n. 9
0
    def update_contents(self, new_store_contents, symprec, angle_tolerance):

        try:
            # input sanitation
            symprec = float(literal_eval(str(symprec)))
            angle_tolerance = float(literal_eval(str(angle_tolerance)))
        except:
            raise PreventUpdate

        struct_or_mol = self.from_data(new_store_contents)

        if not isinstance(struct_or_mol, Structure):
            return html.Div(
                "Can only analyze symmetry of crystal structures at present.")

        sga = SpacegroupAnalyzer(struct_or_mol,
                                 symprec=symprec,
                                 angle_tolerance=angle_tolerance)

        try:
            data = {}
            data["Crystal System"] = sga.get_crystal_system().title()
            data["Lattice System"] = sga.get_lattice_type().title()
            data["Hall Number"] = sga.get_hall()
            data["International Number"] = sga.get_space_group_number()
            data["Symbol"] = unicodeify_spacegroup(
                sga.get_space_group_symbol())
            data["Point Group"] = unicodeify_spacegroup(
                sga.get_point_group_symbol())

            sym_struct = sga.get_symmetrized_structure()
        except:
            return html.Span(
                f"Failed to calculate symmetry with this combination of "
                f"symmetry-finding ({symprec}) and angle tolerances ({angle_tolerance})."
            )

        datalist = get_data_list(data)

        wyckoff_contents = []

        wyckoff_data = sorted(
            zip(sym_struct.wyckoff_symbols, sym_struct.equivalent_sites),
            key=lambda x: "".join(filter(lambda w: w.isalpha(), x[0])),
        )

        for symbol, equiv_sites in wyckoff_data:
            wyckoff_contents.append(
                html.Label(
                    f"{symbol}, {unicodeify_species(equiv_sites[0].species_string)}",
                    className="mpc-label",
                ))
            site_data = [(
                pretty_frac_format(site.frac_coords[0]),
                pretty_frac_format(site.frac_coords[1]),
                pretty_frac_format(site.frac_coords[2]),
            ) for site in equiv_sites]
            wyckoff_contents.append(get_table(site_data))

        return Columns([
            Column([H5("Overview"), datalist]),
            Column([H5("Wyckoff Positions"),
                    html.Div(wyckoff_contents)]),
        ])
Esempio n. 10
0
        def update_contents(data, symprec, angle_tolerance):

            if not data:
                return html.Div()

            struct = self.from_data(data)

            if not isinstance(struct, Structure):
                return html.Div(
                    "Can only analyze symmetry of crystal structures at present."
                )

            kwargs = self.reconstruct_kwargs_from_state(
                callback_context.inputs)
            symprec = kwargs["symprec"]
            angle_tolerance = kwargs["angle_tolerance"]

            if symprec <= 0:
                return html.Span(
                    f"Please use a positive symmetry-finding tolerance (currently {symprec})."
                )

            sga = SpacegroupAnalyzer(struct,
                                     symprec=symprec,
                                     angle_tolerance=angle_tolerance)

            try:
                data = dict()
                data["Crystal System"] = sga.get_crystal_system().title()
                data["Lattice System"] = sga.get_lattice_type().title()
                data["Hall Number"] = sga.get_hall()
                data["International Number"] = sga.get_space_group_number()
                data["Symbol"] = unicodeify_spacegroup(
                    sga.get_space_group_symbol())
                data["Point Group"] = unicodeify_spacegroup(
                    sga.get_point_group_symbol())

                sym_struct = sga.get_symmetrized_structure()
            except Exception:
                return html.Span(
                    f"Failed to calculate symmetry with this combination of "
                    f"symmetry-finding ({symprec}) and angle tolerances ({angle_tolerance})."
                )

            datalist = get_data_list(data)

            wyckoff_contents = []

            wyckoff_data = sorted(
                zip(sym_struct.wyckoff_symbols, sym_struct.equivalent_sites),
                key=lambda x: "".join(filter(lambda w: w.isalpha(), x[0])),
            )

            for symbol, equiv_sites in wyckoff_data:
                wyckoff_contents.append(
                    html.Label(
                        f"{symbol}, {unicodeify_species(equiv_sites[0].species_string)}",
                        className="mpc-label",
                    ))
                site_data = [(
                    self.pretty_frac_format(site.frac_coords[0]),
                    self.pretty_frac_format(site.frac_coords[1]),
                    self.pretty_frac_format(site.frac_coords[2]),
                ) for site in equiv_sites]
                wyckoff_contents.append(get_table(site_data))

            return Columns([
                Column([H5("Overview"), datalist]),
                Column([H5("Wyckoff Positions"),
                        html.Div(wyckoff_contents)]),
            ])
Esempio n. 11
0
    def calc_shiftk(self, symprec=0.01, angle_tolerance=5):
        """
        Find the values of shiftk and nshiftk appropriate for the sampling of the Brillouin zone.

        Returns
            Suggested value of shiftk

        .. note:

            When the primitive vectors of the lattice do NOT form a FCC or a BCC lattice, 
            the usual (shifted) Monkhorst-Pack grids are formed by using nshiftk=1 and shiftk 0.5 0.5 0.5 . 
            This is often the preferred k point sampling. For a non-shifted Monkhorst-Pack grid, 
            use nshiftk=1 and shiftk 0.0 0.0 0.0 , but there is little reason to do that.

            2) When the primitive vectors of the lattice form a FCC lattice, with rprim

                    0.0 0.5 0.5
                    0.5 0.0 0.5
                    0.5 0.5 0.0

            the (very efficient) usual Monkhorst-Pack sampling will be generated by using nshiftk= 4 and shiftk

                    0.5 0.5 0.5
                    0.5 0.0 0.0
                    0.0 0.5 0.0
                    0.0 0.0 0.5

            3) When the primitive vectors of the lattice form a BCC lattice, with rprim

                   -0.5  0.5  0.5
                    0.5 -0.5  0.5
                    0.5  0.5 -0.5

            the usual Monkhorst-Pack sampling will be generated by using nshiftk= 2 and shiftk

                    0.25  0.25  0.25
                   -0.25 -0.25 -0.25

            However, the simple sampling nshiftk=1 and shiftk 0.5 0.5 0.5 is excellent.

            4) For hexagonal lattices with hexagonal axes, e.g. rprim

                    1.0  0.0       0.0
                   -0.5  sqrt(3)/2 0.0
                    0.0  0.0       1.0

            one can use nshiftk= 1 and shiftk 0.0 0.0 0.5

            In rhombohedral axes, e.g. using angdeg 3*60., this corresponds to shiftk 0.5 0.5 0.5, 
            to keep the shift along the symmetry axis. 
        """
        # Find lattice type.
        sym = SpacegroupAnalyzer(self, symprec=symprec, angle_tolerance=angle_tolerance)
        lattice_type = sym.get_lattice_type() 
        spg_symbol = sym.get_spacegroup_symbol()

        # Generate the appropriate set of shifts.
        shiftk = None

        if lattice_type == "cubic":
            if "F" in spg_symbol:  
                # FCC
                shiftk = [0.5, 0.5, 0.5,
                          0.5, 0.0, 0.0,
                          0.0, 0.5, 0.0,
                          0.0, 0.0, 0.5]

            elif "I" in spg_symbol:  
                # BCC
                shiftk = [0.25,  0.25,  0.25,
                         -0.25, -0.25, -0.25]

                #shiftk = [0.5, 0.5, 05])

        elif lattice_type == "hexagonal":
            # Find the hexagonal axis and set the shift along it.
            for i, angle in enumerate(self.lattice.angles):
                if abs(angle - 120) < 1.0:
                    j = (i + 1) % 3
                    k = (i + 2) % 3
                    hex_ax = [ax for ax in range(3) if ax not in [j,k]][0] 
                    break
            else:
                raise ValueError("Cannot find hexagonal axis")

            shiftk = [0.0, 0.0, 0.0]
            shiftk[hex_ax] = 0.5 

        if shiftk is None:
            # Use default value.
            shiftk = [0.5, 0.5, 0.5]

        return np.reshape(shiftk, (-1,3))
Esempio n. 12
0
class HighSymmKpath:
    """
    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
    It should be used with primitive structures that
    comply with the definition from the paper.
    The symmetry is determined by spglib through the
    SpacegroupAnalyzer class. The analyzer can be used to
    produce the correct primitive structure (method
    get_primitive_standard_structure(international_monoclinic=False)).
    A warning will signal possible compatibility problems
    with the given structure.

    Args:
        structure (Structure): Structure object
        symprec (float): Tolerance for symmetry finding
        angle_tolerance (float): Angle tolerance for symmetry finding.
        atol (float): Absolute tolerance used to compare the input
            structure with the one expected as primitive standard.
            A warning will be issued if the lattices don't match.
    """
    def __init__(self, structure, symprec=0.01, angle_tolerance=5, atol=1e-8):
        self._structure = structure
        self._sym = SpacegroupAnalyzer(structure,
                                       symprec=symprec,
                                       angle_tolerance=angle_tolerance)
        self._prim = self._sym \
            .get_primitive_standard_structure(international_monoclinic=False)
        self._conv = self._sym.get_conventional_standard_structure(
            international_monoclinic=False)
        self._prim_rec = self._prim.lattice.reciprocal_lattice
        self._kpath = None

        # Note: this warning will be issued for space groups 38-41, since the primitive cell must be
        # reformatted to match Setyawan/Curtarolo convention in order to work with the current k-path
        # generation scheme.
        if not np.allclose(self._structure.lattice.matrix,
                           self._prim.lattice.matrix,
                           atol=atol):
            warnings.warn(
                "The input structure does not match the expected standard primitive! "
                "The path can be incorrect. Use at your own risk.")

        lattice_type = self._sym.get_lattice_type()
        spg_symbol = self._sym.get_space_group_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 or "A" 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]
            # beta = self._conv.lattice.lengths_and_angles[1][1]

            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 * pi / 180) ** 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 * pi / 180) ** 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 * pi / 180) ** 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 conventional(self):
        """
        Returns:
            The conventional cell structure
        """
        return self._conv

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

    @property
    def prim_rec(self):
        """
        Returns:
            The primitive reciprocal cell structure
        """
        return self._prim_rec

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

    def get_kpoints(self, line_density=20, coords_are_cartesian=True):
        """
        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)
                ])
        if coords_are_cartesian:
            return list_k_points, sym_point_labels
        else:
            frac_k_points = [
                self._prim_rec.get_fractional_coords(k) for k in list_k_points
            ]
            return frac_k_points, sym_point_labels

    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, beta):
        self.name = "MCL"
        eta = (1 - b * cos(beta) / c) / (2 * sin(beta)**2)
        nu = 0.5 - eta * c * cos(beta) / 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}
Esempio n. 13
0
        except (ValueError, IndexError):
            print("-d must be followed by an integer")
            exit(1)

# read structure
if os.path.exists(fstruct):
    struct = mg.Structure.from_file(fstruct)
else:
    print("File %s does not exist" % fstruct)
    exit(1)

# symmetry information
struct_sym = SpacegroupAnalyzer(struct)
print("\nLattice details:")
print("----------------")
print("lattice type : {0}".format(struct_sym.get_lattice_type()))
print("space group  : {0} ({1})".format(struct_sym.get_spacegroup_symbol(),
                                        struct_sym.get_spacegroup_number()))

# Compute first brillouin zone
ibz = HighSymmKpath(struct)
print("ibz type     : {0}".format(ibz.name))
ibz.get_kpath_plot(savefig="path.png")

# print specific kpoints in the first brillouin zone
print("\nList of high symmetry k-points:")
print("-------------------------------")
for key, val in ibz.kpath["kpoints"].items():
    print("%8s %s" % (key, str(val)))

# suggested path for the band structure
Esempio n. 14
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
    It should be used with primitive structures that
    comply with the definition from the paper.
    The symmetry is determined by spglib through the
    SpacegroupAnalyzer class. The analyzer can be used to
    produce the correct primitive structure (method
    get_primitive_standard_structure(international_monoclinic=False)).
    A warning will signal possible compatibility problems
    with the given structure.

    Args:
        structure (Structure): Structure object
        symprec (float): Tolerance for symmetry finding
        angle_tolerance (float): Angle tolerance for symmetry finding.
        atol (float): Absolute tolerance used to compare the input
            structure with the one expected as primitive standard.
            A warning will be issued if the lattices don't match.
    """

    def __init__(self, structure, symprec=0.01, angle_tolerance=5, atol=1e-8):
        self._structure = structure
        self._sym = SpacegroupAnalyzer(structure, symprec=symprec,
                                   angle_tolerance=angle_tolerance)
        self._prim = self._sym\
            .get_primitive_standard_structure(international_monoclinic=False)
        self._conv = self._sym.get_conventional_standard_structure(international_monoclinic=False)
        self._prim_rec = self._prim.lattice.reciprocal_lattice
        self._kpath = None

        #Note: this warning will be issued for space groups 38-41, since the primitive cell must be 
        #reformatted to match Setyawan/Curtarolo convention in order to work with the current k-path 
        #generation scheme.
        if not np.allclose(self._structure.lattice.matrix, self._prim.lattice.matrix, atol=atol):
            warnings.warn("The input structure does not match the expected standard primitive! "
                          "The path can be incorrect. Use at your own risk.")

        lattice_type = self._sym.get_lattice_type()
        spg_symbol = self._sym.get_space_group_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 or "A" 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]
            #beta = self._conv.lattice.lengths_and_angles[1][1]

            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 * pi / 180) ** 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 * pi / 180) ** 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 * pi / 180) ** 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 conventional(self):
        """
        Returns:
            The conventional cell structure
        """
        return self._conv

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

    @property
    def prim_rec(self):
        """
        Returns:
            The primitive reciprocal cell structure
        """
        return self._prim_rec

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

    def get_kpoints(self, line_density=20, coords_are_cartesian=True):
        """
        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)])
        if coords_are_cartesian:
            return list_k_points, sym_point_labels
        else:
            frac_k_points = [self._prim_rec.get_fractional_coords(k)
                             for k in list_k_points]
            return frac_k_points, sym_point_labels

    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, beta):
        self.name = "MCL"
        eta = (1 - b * cos(beta) / c) / (2 * sin(beta) ** 2)
        nu = 0.5 - eta * c * cos(beta) / 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}
Esempio n. 15
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
    SpacegroupAnalyzer class

    Args:
        structure (Structure): Structure object
        symprec (float): Tolerance for symmetry finding
        angle_tolerance (float): Angle tolerance for symmetry finding.
    """
    def __init__(self, structure, symprec=0.01, angle_tolerance=5):
        self._structure = structure
        self._sym = SpacegroupAnalyzer(structure,
                                       symprec=symprec,
                                       angle_tolerance=angle_tolerance)
        self._prim = self._sym\
            .get_primitive_standard_structure(international_monoclinic=False)
        self._conv = self._sym.get_conventional_standard_structure(
            international_monoclinic=False)
        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]
            #beta = self._conv.lattice.lengths_and_angles[1][1]

            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, coords_are_cartesian=True):
        """
        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)
                ])
        if coords_are_cartesian:
            return list_k_points, sym_point_labels
        else:
            frac_k_points = [
                self._prim_rec.get_fractional_coords(k) for k in list_k_points
            ]
            return frac_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, beta):
        self.name = "MCL"
        eta = (1 - b * cos(beta) / c) / (2 * sin(beta)**2)
        nu = 0.5 - eta * c * cos(beta) / 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}
Esempio n. 16
0
def drawkpt(struct, ndiv="10"):

    # symmetry information
    struct_sym = SpacegroupAnalyzer(struct)
    print("\nLattice details:")
    print("----------------")
    print("lattice type : {0}".format(struct_sym.get_lattice_type()))
    print(
        "space group  : {0} ({1})".format(
            struct_sym.get_space_group_symbol(),
            struct_sym.get_space_group_number()))

    # Compute first brillouin zone

    ibz = HighSymmKpath(struct)
    print("ibz type     : {0}".format(ibz.name))
    [x, y, z] = list(map(list, zip(*ibz.get_kpoints()[0])))

    fig = plt.figure("Brillouin Zone and High Symm Pts")
    ax = fig.gca(projection='3d')
    ax.plot(x, y, z)

    for i, name in enumerate(ibz.get_kpoints()[1]):
        if name != '':
            #print(" name {0} : [{1},{2},{3}]".format(name, x[i],y[i],z[i]))
            ax.text(x[i], y[i], z[i], '%s' % (name),
                    color='k', size="15")

    new_lat = ibz.prim_rec
    bz_array = new_lat.get_wigner_seitz_cell()
    bz_faces = Poly3DCollection(bz_array)

    bz_faces.set_edgecolor('k')
    bz_faces.set_facecolor((0, 1, 1, 0.4))
    ax.add_collection3d(bz_faces)

    ax.set_xlim(-1, 1)
    ax.set_ylim(-1, 1)
    ax.set_zlim(-1, 1)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')

    fig.suptitle(
        "Brillouin Zone and K_Path of \n {0}".format(
            struct.get_primitive_structure().formula))

    fig.show()

    # if input("press [s]ave to save brillouin zone figure as it is \n") == "s":
    #     fig.savefig("BZ_KPath.svg", bbox_inches='tight')

    # plt.close(fig)

    # print specific kpoints in the first brillouin zone
    print("\nList of high symmetry k-points:")
    print("-------------------------------")
    for key, val in ibz.kpath["kpoints"].items():
        print("%8s %s" % (key, str(val)))

    # suggested path for the band structure
    print("\nSuggested paths in first brillouin zone:")
    print("----------------------------------------")
    for i, path in enumerate(ibz.kpath["path"]):
        print("   %2d:" % (i + 1), " -> ".join(path))

    # write the KPOINTS file
    print("\nWrite file KPOINTS")
    kpt = Kpoints.automatic_linemode(ndiv, ibz)

    # if input("write kpt in cwd ?") == "Y":
    #     kpt.write_file(os.path.join(
    #                    folder, "linear_KPOINTS"))
    return(kpt)
Esempio n. 17
0
        except (ValueError, IndexError):
            print("-d must be followed by an integer")
            exit(1)

# read structure
if os.path.exists(fstruct):
    struct = mg.Structure.from_file(fstruct)
else:
    print("File %s does not exist" % fstruct)
    exit(1)

# symmetry information
struct_sym = SpacegroupAnalyzer(struct)
print("\nLattice details:")
print("----------------")
print("lattice type : {0}".format(struct_sym.get_lattice_type()))
print("space group  : {0} ({1})".format(struct_sym.get_space_group_symbol(),
                                        struct_sym.get_space_group_number()))

# Compute first brillouin zone
ibz = HighSymmKpath(struct)
print("ibz type     : {0}".format(ibz.name))
#ibz.get_kpath_plot(savefig="path.png")

# print specific kpoints in the first brillouin zone
print("\nList of high symmetry k-points:")
print("-------------------------------")
for key, val in ibz.kpath["kpoints"].items():
    print("%8s %s" % (key, str(val)))

# suggested path for the band structure
Esempio n. 18
0
class SpaceGroup(object):
    def __init__(self, configfile, symprec=0.01, angle_trelance=6):
        self.config_obj = ParseConfig(configfile)
        self.symprec = symprec
        self.angle_trelance = angle_trelance
        self.main()

    def set_structure(self):
        #
        # ======= ATOMIC POSITIONS =======
        #
        a, b, c = self.config_obj.lattice_length[:3]
        alpha, beta, gamma = self.config_obj.lattice_angle[:3]
        lattice = mg.Lattice.from_parameters(a, b, c, alpha, beta, gamma)

        self.atoms = self.config_obj.atom_list
        atomic_positions = self.config_obj.atomic_position
        self.structure = mg.Structure(lattice, self.atoms, atomic_positions)

    def main(self):
        self.set_structure()
        #
        # generate instance for space group
        #
        self.spg = SpacegroupAnalyzer(self.structure,
                                      symprec=self.symprec,
                                      angle_tolerance=self.angle_trelance)

    def show_info(self):
        print('----- symmetrized structure(conventional unit cell) -----')
        print(self.spg.get_symmetrized_structure())
        print()
        print('----- primitive structure -----')
        print(self.spg.find_primitive())
        print()
        #
        # name of space group
        #
        print('--- infomation of space group ---')
        print('  HM symbol: {} '.format(self.spg.get_space_group_symbol()))
        print('  Space Group number = #{}'.format(
            self.spg.get_space_group_number()))
        print('  point group : {}'.format(self.spg.get_point_group_symbol()))
        print()
        print()
        print('--- crystal system ---')
        print('  crystal system:{}'.format(self.spg.get_crystal_system()))
        print('  lattice type:{}'.format(self.spg.get_lattice_type()))

        #
        # total data set
        #
        dataset = self.spg.get_symmetry_dataset()
        wyckoff_position = dataset['wyckoffs']
        atom_pos = []
        atom_name = []
        wyckoff_data = []
        for (i, wyckoff) in enumerate(wyckoff_position):
            aname = self.atoms[i]
            if aname not in atom_name or wyckoff not in atom_pos:
                info = {
                    'site_type_symbol': aname,
                    'wyckoff_letter': wyckoff,
                    'multiply': 0
                }
                wyckoff_data.append(info)
                atom_pos.append(wyckoff)
                atom_name.append(aname)
        for (i, wyckoff) in enumerate(wyckoff_position):
            aname = self.atoms[i]
            for info in wyckoff_data:
                if info['site_type_symbol'] == aname:
                    if info['wyckoff_letter'] == wyckoff:
                        info['multiply'] += 1
        print('  # of kinds of atoms = {}'.format(len(wyckoff_data)))
        print()
        for info in wyckoff_data:
            site_name = '{0}{1}-site'.format(info['multiply'],
                                             info['wyckoff_letter'])
            atom_name = info['site_type_symbol']
            print('  atom:{0}  wyckoff: {1}'.format(atom_name, site_name))
        return

    def symmetrized(self):
        self.get_symmetrized_structure()
Esempio n. 19
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
    SpacegroupAnalyzer class

    Args:
        structure (Structure): Structure object
        symprec (float): Tolerance for symmetry finding
        angle_tolerance (float): Angle tolerance for symmetry finding.
    """

    def __init__(self, structure, symprec=0.01, angle_tolerance=5):
        self._structure = structure
        self._sym = SpacegroupAnalyzer(structure, symprec=symprec,
                                   angle_tolerance=angle_tolerance)
        self._prim = self._sym\
            .get_primitive_standard_structure(international_monoclinic=False)
        self._conv = self._sym.get_conventional_standard_structure(international_monoclinic=False)
        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]
            #beta = self._conv.lattice.lengths_and_angles[1][1]

            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, beta):
        self.name = "MCL"
        eta = (1 - b * cos(beta) / c) / (2 * sin(beta) ** 2)
        nu = 0.5 - eta * c * cos(beta) / 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}
Esempio n. 20
0
    def __init__(self,
                 structure: Structure,
                 conventional_base: bool = True,
                 max_num_atoms: int = 400,
                 min_num_atoms: int = 50,
                 criterion: float = 0.12,
                 rhombohedral_angle: float = 70,
                 symprec: float = SYMMETRY_TOLERANCE,
                 angle_tolerance: float = ANGLE_TOL):
        """Constructs a set of supercells satisfying an isotropic criterion.

        Args:
            structure (pmg structure class object):
                Unitcell structure
            conventional_base (bool):
                Conventional cell is expanded when True, otherwise primitive
                cell is expanded.
            max_num_atoms (int):
                Maximum number of atoms in the supercell.
            min_num_atoms (int):
                Minimum number of atoms in the supercell.
            criterion (float):
                Criterion to judge if a supercell is isotropic or not.
            rhombohedral_angle (float):
                Rhombohedral primitive cells may have very small or very large
                lattice angles not suited for first-principles calculations.
                Therefore, only the supercells with
                rhombohedral_angle <= lattice angle <= 180 - rhombohedral_angle
                are returned. Then, the new supercells are iteratively
                created by multiplying [[1, 1, -1], [-1, 1, 1], [1, -1, 1]] or
                [[1, 1, 0], [0, 1, 1], [1, 0, 1]].
            symprec (float):
                Precision used for symmetry analysis in angstrom.
            angle_tolerance (float):
                Angle tolerance for symmetry analysis in degree.
        """
        primitive_cell, _ = \
            find_spglib_primitive(structure, symprec, angle_tolerance)
        if max_num_atoms < len(primitive_cell):
            raise CellSizeError("Number of atoms in unitcell is too large.")

        self.unitcell = primitive_cell.get_sorted_structure()
        sga = SpacegroupAnalyzer(structure, symprec, angle_tolerance)
        symmetry_dataset = sga.get_symmetry_dataset()
        logger.info(f"Space group: {symmetry_dataset['international']}")

        self.conventional_base = conventional_base
        lattice = sga.get_lattice_type()
        centering = symmetry_dataset["international"][0]
        if conventional_base:
            to_unitcell_mat = transmat_primitive2standard(centering)
            rhombohedral = False
            tetragonal = lattice == "tetragonal"
        else:
            to_unitcell_mat = np.eye(3, dtype=int)
            rhombohedral = lattice == "rhombohedral"
            if lattice == "tetragonal" and centering == "P":
                tetragonal = True
            else:
                tetragonal = False

        self.supercells = []
        # Isotropically incremented matrix one by one
        trans_mat = to_unitcell_mat
        incremented_mat = np.eye(3, dtype=int)
        rotation_matrix = np.eye(3, dtype=int)

        for i in range(int(max_num_atoms / len(primitive_cell))):
            isotropy, angle = calc_isotropy(self.unitcell, trans_mat)
            # int is needed when numpy.float is rounded.
            multiplicity = int(round(np.linalg.det(trans_mat)))
            num_atoms = multiplicity * len(primitive_cell)
            if num_atoms > max_num_atoms:
                break

            if isotropy < criterion and num_atoms >= min_num_atoms:
                self.supercells.append(
                    Supercell(self.unitcell, trans_mat, multiplicity))

            rhombohedral_shape = None
            if rhombohedral:
                if angle < rhombohedral_angle:
                    rhombohedral_shape = "sharp"
                elif angle > 180 - rhombohedral_angle:
                    rhombohedral_shape = "blunt"

            if rhombohedral_shape == "sharp":
                m = np.array([[1, 1, -1], [-1, 1, 1], [1, -1, 1]])
                rotation_matrix = np.dot(rotation_matrix, m)
            elif rhombohedral_shape == "blunt":
                m = np.array([[1, 1, 0], [0, 1, 1], [1, 0, 1]])
                rotation_matrix = np.dot(rotation_matrix, m)
            else:
                if tetragonal:
                    s = self.unitcell * trans_mat
                    if s.lattice.a < s.lattice.c:
                        if rotation_matrix[0, 1] == 0:
                            a = incremented_mat[0, 0]
                            if (a + 1)**2 < a**2 * 2:
                                incremented_mat[0, 0] += 1
                                incremented_mat[1, 1] += 1
                            else:
                                rotation_matrix = \
                                    np.array([[1, 1, 0], [-1, 1, 0], [0, 0, 1]])
                        else:
                            incremented_mat[0, 0] += 1
                            incremented_mat[1, 1] += 1
                            rotation_matrix = np.eye(3, dtype=int)

                        incremented_mat *= rotation_matrix
                    else:
                        incremented_mat[2, 2] += 1
                else:
                    super_abc = (self.unitcell * trans_mat).lattice.abc
                    # multi indices within 1.05a, where a is the shortest
                    # supercell lattice length, are incremented simultaneously.
                    for j in range(3):
                        if super_abc[j] / min(super_abc) < 1.05:
                            incremented_mat[j, j] += 1

            trans_mat = np.dot(np.dot(incremented_mat, rotation_matrix),
                               to_unitcell_mat)
Esempio n. 21
0
def calc_shiftk(structure, symprec=0.01, angle_tolerance=5):
    """
    Find the values of ``shiftk`` and ``nshiftk`` appropriated for the sampling of the Brillouin zone.

    When the primitive vectors of the lattice do NOT form a FCC or a BCC lattice,
    the usual (shifted) Monkhorst-Pack grids are formed by using nshiftk=1 and shiftk 0.5 0.5 0.5 .
    This is often the preferred k point sampling. For a non-shifted Monkhorst-Pack grid,
    use `nshiftk=1` and `shiftk 0.0 0.0 0.0`, but there is little reason to do that.

    When the primitive vectors of the lattice form a FCC lattice, with rprim::

            0.0 0.5 0.5
            0.5 0.0 0.5
            0.5 0.5 0.0

    the (very efficient) usual Monkhorst-Pack sampling will be generated by using nshiftk= 4 and shiftk::

        0.5 0.5 0.5
        0.5 0.0 0.0
        0.0 0.5 0.0
        0.0 0.0 0.5

    When the primitive vectors of the lattice form a BCC lattice, with rprim::

           -0.5  0.5  0.5
            0.5 -0.5  0.5
            0.5  0.5 -0.5

    the usual Monkhorst-Pack sampling will be generated by using nshiftk= 2 and shiftk::

            0.25  0.25  0.25
           -0.25 -0.25 -0.25

    However, the simple sampling nshiftk=1 and shiftk 0.5 0.5 0.5 is excellent.

    For hexagonal lattices with hexagonal axes, e.g. rprim::

            1.0  0.0       0.0
           -0.5  sqrt(3)/2 0.0
            0.0  0.0       1.0

    one can use nshiftk= 1 and shiftk 0.0 0.0 0.5
    In rhombohedral axes, e.g. using angdeg 3*60., this corresponds to shiftk 0.5 0.5 0.5,
    to keep the shift along the symmetry axis.

    Returns:
        Suggested value of shiftk.
    """
    # Find lattice type.
    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer

    sym = SpacegroupAnalyzer(structure,
                             symprec=symprec,
                             angle_tolerance=angle_tolerance)
    lattice_type, spg_symbol = sym.get_lattice_type(
    ), sym.get_space_group_symbol()

    # Check if the cell is primitive
    is_primitive = len(sym.find_primitive()) == len(structure)

    # Generate the appropriate set of shifts.
    shiftk = None

    if is_primitive:
        if lattice_type == "cubic":
            if "F" in spg_symbol:
                # FCC
                shiftk = [
                    0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5
                ]

            elif "I" in spg_symbol:
                # BCC
                shiftk = [0.25, 0.25, 0.25, -0.25, -0.25, -0.25]
                # shiftk = [0.5, 0.5, 05])

        elif lattice_type == "hexagonal":
            # Find the hexagonal axis and set the shift along it.
            for i, angle in enumerate(structure.lattice.angles):
                if abs(angle - 120) < 1.0:
                    j = (i + 1) % 3
                    k = (i + 2) % 3
                    hex_ax = [ax for ax in range(3) if ax not in [j, k]][0]
                    break
            else:
                raise ValueError("Cannot find hexagonal axis")

            shiftk = [0.0, 0.0, 0.0]
            shiftk[hex_ax] = 0.5

        elif lattice_type == "tetragonal":
            if "I" in spg_symbol:
                # BCT
                shiftk = [0.25, 0.25, 0.25, -0.25, -0.25, -0.25]

    if shiftk is None:
        # Use default value.
        shiftk = [0.5, 0.5, 0.5]

    return np.reshape(shiftk, (-1, 3))
Esempio n. 22
0
class SpaceGroup(object):
    def __init__(self, configfile, symprec=0.01,  angle_trelance=6):
        self.config_obj = ParseConfig(configfile)
        self.symprec = symprec
        self.angle_trelance = angle_trelance
        self.main()

    def set_structure(self):
        #
        # ======= ATOMIC POSITIONS =======
        #
        a, b, c = self.config_obj.lattice_length[:3]
        alpha, beta, gamma = self.config_obj.lattice_angle[:3]
        lattice = mg.Lattice.from_parameters(a, b, c, alpha, beta, gamma)

        self.atoms = self.config_obj.atom_list
        atomic_positions = self.config_obj.atomic_position
        self.structure = mg.Structure(lattice, self.atoms, atomic_positions)

    def main(self):
        self.set_structure()
        #
        # generate instance for space group
        #
        self.spg = SpacegroupAnalyzer(self.structure,
                                      symprec=self.symprec,
                                      angle_tolerance=self.angle_trelance)
        try:
            self.hmname = self.spg.get_space_group_symbol()
            self.ispg = self.spg.get_space_group_number()
        except TypeError:
            print()
            print(' **** INTERNAL LIBRARY WARNING ****')
            print('   pymatgen and spglib cannot identify space group', end='')
            print(' for smaller primitive cell.')
            print('   we expect this bug will be fixed near future.', end='')
            print('metis uses original primitive cell.')
            self.spg = None
            self.hmname = None
            self.ispg = None

    def generate_primitive_lattice(self):
        #
        # in this case, spglib cannot identify space group
        #
        if self.spg is None:
            return

        my_data = str(self.spg.find_primitive())
        data_region = False
        atomic_positions = []
        for line in my_data.split('\n'):
            linebuf = line.strip()
            if re.search('^abc\s+:', linebuf):
                lattice_length = \
                    [float(x) for x in linebuf.split(':')[1].split()]
            if re.search('^angles:', linebuf):
                lattice_angle = \
                    [float(x) for x in linebuf.split(':')[1].split()]
            if re.search('^#', linebuf) and 'SP' in linebuf:
                data_region = True
                continue
            if data_region:
                if re.search('^---', linebuf):
                    continue
                element = linebuf.split()[1]
                pos = [float(x) for x in linebuf.split()[2:]]
                info = {'element': element, 'position': pos}
                atomic_positions.append(info)
                lattice_type = self.hmname[0]
        compound_name = self.get_compound_name(atomic_positions)
        return {'ispg': self.ispg, 'hmname': self.hmname,
                'lattice_length': lattice_length,
                'lattice_angle': lattice_angle,
                'lattice_type': lattice_type,
                'atomic_positions': atomic_positions,
                'compound_name': compound_name}

    def get_compound_name(self, atomic_positions):
        natoms = None
        compound = ''
        pre_element = None
        for atom in atomic_positions:
            element = atom['element']
            if pre_element != element:
                if pre_element is not None:
                    compound += str(natoms)
                compound += element
                natoms = 1
                pre_element = element
            else:
                natoms += 1
        compound += str(natoms)
        return compound

    def show_info(self):
        print('----- symmetrized structure(conventional unit cell) -----')
        print(self.spg.get_symmetrized_structure())
        print()
        print('----- primitive structure -----')
        print(self.spg.find_primitive())
        print()
        #
        # name of space group
        #
        print('--- infomation of space group ---')
        print('  HM symbol: {} '.format(self.hmname))
        print('  Space Group number = #{}'.format(self.ispg))
        print('  point group : {}'.format(self.spg.get_point_group_symbol()))
        print()
        print()
        print('--- crystal system ---')
        print('  crystal system:{}'.format(self.spg.get_crystal_system()))
        print('  lattice type:{}'.format(self.spg.get_lattice_type()))
        print()

        #
        # total data set
        #
        dataset = self.spg.get_symmetry_dataset()
        wyckoff_position = dataset['wyckoffs']
        atom_pos = []
        atom_name = []
        wyckoff_data = []
        for (i, wyckoff) in enumerate(wyckoff_position):
            aname = self.atoms[i]
            if aname not in atom_name or wyckoff not in atom_pos:
                info = {'site_type_symbol': aname,
                        'wyckoff_letter': wyckoff,
                        'multiply': 0}
                wyckoff_data.append(info)
                atom_pos.append(wyckoff)
                atom_name.append(aname)
        for (i, wyckoff) in enumerate(wyckoff_position):
            aname = self.atoms[i]
            for info in wyckoff_data:
                if info['site_type_symbol'] == aname:
                    if info['wyckoff_letter'] == wyckoff:
                        info['multiply'] += 1
        print('  # of kinds of atoms = {}'.format(len(wyckoff_data)))
        print()
        for info in wyckoff_data:
            site_name = '{0}{1}-site'.format(info['multiply'],
                                             info['wyckoff_letter'])
            atom_name = info['site_type_symbol']
            print('  atom:{0}  wyckoff: {1}'.format(atom_name, site_name))
        return

    def get_conventional_cell(self):
        #
        # infomation of original primitive cell
        #
        self.prim_atom_info = {}
        data_set = self.spg.get_symmetry_dataset()
        wyckoffs = data_set['wyckoffs']
        natoms = len(self.atoms)
        atom_info_tmp = []
        for iatom in range(natoms):
            element = self.atoms[iatom],
            wyckoff_letter = wyckoffs[iatom]
            info = {'element': self.atoms[iatom],
                    'wyckoff_letter': wyckoffs[iatom]}
            atom_info_tmp.append(info)

        element_list = []
        atom_info = []
        for info in atom_info_tmp:
            element = info['element']
            wyckoff_letter = info['wyckoff_letter']
            if element not in element_list:
                element_list.append(element)
                info = {}
                info['element'] = element
                info['wyckoff_letter'] = [wyckoff_letter]
                atom_info.append(info)
            else:
                atom_info[-1]['wyckoff_letter'].append(wyckoff_letter)

        self.primitive_cell_info = {'ispg': self.ispg,
                                    'natoms': natoms,
                                    'atom_info': atom_info}

        #
        # conventional unit cell
        #
        data = str(self.spg.get_conventional_standard_structure())
        data_set = self.spg.get_symmetry_dataset()
        wyckoffs = data_set['wyckoffs']
        data_region = False
        atom_info = []
        self.atoms = []
        atomic_positions = []
        for line in data.split('\n'):
            linebuf = line.strip()
            if re.search('abc\s+:', linebuf):
                lattice_length = \
                    [float(x) for x in linebuf.split(':')[1].split()]
            if re.search('angles\s*:', linebuf):
                lattice_angle = \
                    [float(x) for x in linebuf.split(':')[1].split()]
            if re.search('^#\s+SP', linebuf):
                data_region = True
                continue
            if data_region:
                if re.search('^---', linebuf):
                    continue
                data_line = linebuf.split()
                element = data_line[1]
                position = [float(x) for x in data_line[2:]]
                self.atoms.append(element)
                atomic_positions.append(position)
        #
        # generate conventional infomation
        #
        a, b, c = lattice_length
        alpha, beta, gamma = lattice_angle
        lattice = mg.Lattice.from_parameters(a, b, c, alpha, beta, gamma)
        try:
            self.structure = mg.Structure(lattice, self.atoms,
                                          atomic_positions)
            self.spg = SpacegroupAnalyzer(self.structure,
                                          symprec=self.symprec,
                                          angle_tolerance=self.angle_trelance)
            self.ispg = self.spg.get_space_group_number()
            self.hmname = self.spg.get_space_group_symbol()
        except TypeError:
            print()
            print(' **** INTERNAL LIBRARY WARNING ****')
            print('   pymatgen and spglib cannot identify space group', end='')
            print(' for smaller primitive cell.')
            print('   we expect this bug will be fixed near future.', end='')
            print(' metis uses original primitive cell.')
            self.spg = None
            self.ispg = None
            self.hmname = None
        return self

    def symmetrized(self):
        self.get_symmetrized_structure()