Beispiel #1
0
def get_kpoints_path(structure, parameters):
    """
    Return the kpoint path information for band structure given a
    crystal structure, using the paths from the chosen recipe/reference.
    The parameters are the same
    as get get_path in __init__, but here all structures are
    input and returned as AiiDA structures rather than tuples.


    If you use this module, please cite the paper of the corresponding
    recipe (see documentation of seekpath).

    :param structure: The crystal structure for which we want to obtain
        the suggested path. It should be an AiiDA StructureData object.

    :param parameters: A dictionary whose key-value pairs are passed as
        additional kwargs to the ``seekpath.get_path`` function.

    :return: A dictionary with three nodes:

        - ``parameters``: a Dict, whose content is
          the same dictionary as returned by the ``seekpath.get_path`` function
          (see `seekpath documentation <https://seekpath.readthedocs.io/>`_),
          except that:

          - ``conv_lattice``, ``conv_positions``, ``conv_types``
            are removed and replaced by the ``conv_structure`` output node

          - ``primitive_lattice``, ``primitive_positions``, ``primitive_types``
            are removed and replaced by the ``primitive_structure`` output node

        - ``primitive_structure``: A StructureData with the primitive structure

        - ``conv_structure``: A StructureData with the primitive structure
    """
    from aiida.tools.data.structure import spglib_tuple_to_structure, structure_to_spglib_tuple

    structure_tuple, kind_info, kinds = structure_to_spglib_tuple(structure)

    result = {}
    rawdict = seekpath.get_path(structure=structure_tuple, **parameters)

    result['parameters'] = Dict(dict=rawdict)

    # Replace conv structure with AiiDA StructureData
    conv_lattice = rawdict.pop('conv_lattice')
    conv_positions = rawdict.pop('conv_positions')
    conv_types = rawdict.pop('conv_types')
    result['conv_structure'] = spglib_tuple_to_structure(
        (conv_lattice, conv_positions, conv_types), kind_info, kinds)

    # Replace primitive structure with AiiDA StructureData
    primitive_lattice = rawdict.pop('primitive_lattice')
    primitive_positions = rawdict.pop('primitive_positions')
    primitive_types = rawdict.pop('primitive_types')
    result['primitive_structure'] = spglib_tuple_to_structure(
        (primitive_lattice, primitive_positions, primitive_types), kind_info,
        kinds)

    return result
Beispiel #2
0
def get_path_using_seekpath(structure, band_resolution=30):
    import seekpath

    phonopy_structure = phonopy_bulk_from_structure(structure)
    cell = phonopy_structure.get_cell()
    scaled_positions = phonopy_structure.get_scaled_positions()
    numbers = phonopy_structure.get_atomic_numbers()

    structure = (cell, scaled_positions, numbers)
    path_data = seekpath.get_path(structure)

    labels = path_data['point_coords']

    band_ranges = []
    for set in path_data['path']:
        band_ranges.append([labels[set[0]], labels[set[1]]])

    bands = []
    for q_start, q_end in band_ranges:
        band = []
        for i in range(band_resolution + 1):
            band.append(
                np.array(q_start) +
                (np.array(q_end) - np.array(q_start)) / band_resolution * i)
        bands.append(band)

    band_structure = BandStructureData(bands=bands,
                                       labels=path_data['path'],
                                       unitcell=phonopy_structure.get_cell())
    return band_structure
Beispiel #3
0
def get_path_using_seekpath(structure, band_resolution=30):
    import seekpath

    cell = structure.cell
    positions = [site.position for site in structure.sites]
    scaled_positions = np.dot(positions, np.linalg.inv(cell))
    numbers = np.unique([site.kind_name for site in structure.sites],
                        return_inverse=True)[1]
    structure2 = (cell, scaled_positions, numbers)
    path_data = seekpath.get_path(structure2)

    labels = path_data['point_coords']

    band_ranges = []
    for set in path_data['path']:
        band_ranges.append([labels[set[0]], labels[set[1]]])

    bands = []
    for q_start, q_end in band_ranges:
        band = []
        for i in range(band_resolution + 1):
            band.append(
                np.array(q_start) +
                (np.array(q_end) - np.array(q_start)) / band_resolution * i)
        bands.append(band)

    return {'ranges': bands, 'labels': path_data['path']}
    def get_path_using_seek_path(self):

        """ Obtain the path in reciprocal space to plot the phonon band structure

        :return: dictionary with list of q-points and labels of high symmetry points
        """

        try:
            import seekpath

            cell = self._structure.get_cell()
            positions = self._structure.get_scaled_positions()
            numbers = np.unique(self._structure.get_chemical_symbols(), return_inverse=True)[1]

            path_data = seekpath.get_path((cell, positions, numbers))

            labels = path_data['point_coords']

            band_ranges = []
            for set in path_data['path']:
                band_ranges.append([labels[set[0]], labels[set[1]]])

            return {'ranges': band_ranges,
                    'labels': path_data['path']}
        except ImportError:
            print ('Seekpath not installed. Autopath is deactivated')
            band_ranges = ([[[0.0, 0.0, 0.0], [0.5, 0.0, 0.5]]])
            return {'ranges': band_ranges,
                    'labels': [['GAMMA', '1/2 0 1/2']]}
Beispiel #5
0
def get_spacegroup_and_kpath(structure, symprec=1.0e-9):
    """
    :param: structure is an instance of crystal()
    """
    lattice = structure.cell
    positions = []
    numbers = []
    a = np.sqrt(structure.cell[0][0]**2 + structure.cell[0][1]**2 +
                structure.cell[0][2]**2)
    b = np.sqrt(structure.cell[1][0]**2 + structure.cell[1][1]**2 +
                structure.cell[1][2]**2)
    c = np.sqrt(structure.cell[2][0]**2 + structure.cell[2][1]**2 +
                structure.cell[2][2]**2)

    frac_coord = structure.get_fractional()
    for i in range(len(frac_coord)):
        positions.append(
            [frac_coord[i][1], frac_coord[i][2],
             frac_coord[i][3]])  # must be fractional coordinates
        numbers.append(element[frac_coord[i][0]].number)

    cell = (lattice, positions, numbers)

    return [
        spglib.get_spacegroup(cell, symprec=symprec),
        seekpath.get_path(cell)
    ]
Beispiel #6
0
def gen_bzpath(structure):

    cell = (structure.lattice.matrix, structure.frac_coords,
            structure.atomic_numbers)

    path_info = seekpath.get_path(cell, True, "hpkot", 1.0e-3, 1.0e-3, 1.0)

    return path_info
Beispiel #7
0
 def setUp(self):
     # Create trivial function object so attributes can be assigned to it
     NaH = type('', (), {})()
     cell_vec = [[0.0, 2.3995, 2.3995], [2.3995, 0.0, 2.3995],
                 [2.3995, 2.3995, 0.0]]
     ion_r = [[0.5, 0.5, 0.5], [0.0, 0.0, 0.0]]
     ion_num = [1, 2]
     cell = (cell_vec, ion_r, ion_num)
     NaH.point_labels = seekpath.get_path(cell)["point_coords"]
     self.NaH = NaH
Beispiel #8
0
def get_band_qpoints_by_seekpath(primitive, npoints, is_const_interval=False):
    """q-points along BZ high symmetry paths are generated using seekpath.

    Parameters
    ----------
    primitive : PhonopyAtoms
        Primitive cell.
    npoints : int
        Number of q-points sampled along a path including end points.
    is_const_interval : bool, optional
        When True, q-points are sampled in a similar interval. The longest
        path length divided by npoints including end points is used as the
        reference interval. Default is False.

    Returns
    -------
    bands : List of ndarray
        Sets of qpoints that can be passed to phonopy.set_band_structure().
        shape of each ndarray : (npoints, 3)
    labels : List of pairs of str
        Symbols of end points of paths.
    connections : List of bool
        This gives one path is connected to the next path, i.e., if False,
        there is a jump of q-points. Number of elements is the same at
        that of paths.

    """

    try:
        import seekpath
    except ImportError:
        raise ImportError("You need to install seekpath.")

    band_path = seekpath.get_path(primitive.totuple())
    point_coords = band_path['point_coords']
    qpoints_of_paths = []
    if is_const_interval:
        reclat = np.linalg.inv(primitive.get_cell())
    else:
        reclat = None
    band_paths = [[point_coords[path[0]], point_coords[path[1]]]
                  for path in band_path['path']]
    npts = _get_npts(band_paths, npoints, reclat)
    for c, path in enumerate(band_path['path']):
        q_s = np.array(point_coords[path[0]])
        q_e = np.array(point_coords[path[1]])
        band = [q_s + (q_e - q_s) / (npts[c] - 1) * i for i in range(npts[c])]
        qpoints_of_paths.append(band)
    labels, path_connections = _get_labels(band_path['path'])

    return qpoints_of_paths, labels, path_connections
Beispiel #9
0
def _recip_space_labels(qpts, cell=None):
    """
    Gets q-points point labels (e.g. GAMMA, X, L) for the q-points at
    which the path through reciprocal space changes direction

    Parameters
    ----------
    qpts : (n_qpts, 3) float ndarray
        The q-points to get labels for
    cell : (list, list, list), optional
        The cell structure as defined by spglib. Can be obtained by
        Crystal.to_spglib_cell. If not provided, the labels will be
        generic e.g. '1/3 1/2 0' rather than high-symmetry point labels

    Returns
    -------
    labels : (n_qpts_direction_changed,) string ndarray
        List of the labels for each q-point at which the path through
        reciprocal space changes direction
    qpts_with_labels : (n_qpts_direction_changed,) int ndarray
        List of the indices of the q-points at which the path through
        reciprocal space changes direction
    """

    # First and last q-points should always be labelled
    if len(qpts) <= 2:
        qpt_has_label = np.ones(len(qpts), dtype=bool)
    else:
        qpt_has_label = np.concatenate(
            ([True],
             np.logical_or(direction_changed(qpts),
                           is_gamma(qpts[1:-1])), [True]))
    qpts_with_labels = np.where(qpt_has_label)[0]

    if cell is None:
        sym_label_to_coords = _generic_qpt_labels()
    else:
        try:
            sym_label_to_coords = seekpath.get_path(cell)["point_coords"]
        except SymmetryDetectionError:
            warnings.warn(('Could not determine cell symmetry, using generic '
                           'q-point labels'),
                          stacklevel=2)
            sym_label_to_coords = _generic_qpt_labels()

    # Get labels for each q-point
    labels = np.array([])
    for qpt in qpts[qpts_with_labels]:
        labels = np.append(labels, _get_qpt_label(qpt, sym_label_to_coords))

    return labels, qpts_with_labels
Beispiel #10
0
def get_band_qpoints_by_seekpath(primitive, npoints, is_const_interval=False):
    """q-points along BZ high symmetry paths are generated using seekpath.

    Parameters
    ----------
    primitive : PhonopyAtoms
        Primitive cell.
    npoints : int
        Number of q-points sampled along a path including end points.
    is_const_interval : bool, optional
        When True, q-points are sampled in a similar interval. The longest
        path length divided by npoints including end points is used as the
        reference interval. Default is False.

    Returns
    -------
    bands : List of ndarray
        Sets of qpoints that can be passed to phonopy.set_band_structure().
        shape of each ndarray : (npoints, 3)
    labels : List of pairs of str
        Symbols of end points of paths.
    connections : List of bool
        This gives one path is connected to the next path, i.e., if False,
        there is a jump of q-points. Number of elements is the same at
        that of paths.

    """

    try:
        import seekpath
    except ImportError:
        raise ImportError("You need to install seekpath.")

    band_path = seekpath.get_path(primitive.totuple())
    point_coords = band_path['point_coords']
    qpoints_of_paths = []
    if is_const_interval:
        reclat = np.linalg.inv(primitive.get_cell())
    else:
        reclat = None
    band_paths = [[point_coords[path[0]], point_coords[path[1]]]
                  for path in band_path['path']]
    npts = _get_npts(band_paths, npoints, reclat)
    for c, path in enumerate(band_path['path']):
        q_s = np.array(point_coords[path[0]])
        q_e = np.array(point_coords[path[1]])
        band = [q_s + (q_e - q_s) / (npts[c] - 1) * i for i in range(npts[c])]
        qpoints_of_paths.append(band)
    labels, path_connections = _get_labels(band_path['path'])

    return qpoints_of_paths, labels, path_connections
Beispiel #11
0
    def test_correct_file_examples(self):
        """Check if these valid structures are properly parsed"""
        with open(os.path.join(this_folder, 'file_examples',
                               'list.json')) as f:
            list_files = json.load(f)

        for the_format, examples in list_files.items():
            for example in examples:
                filename = example['file']
                extra_data = example.get('extra_data', None)
                with open(os.path.join(this_folder, 'file_examples',
                                       filename)) as f:
                    structure = structure_importers.get_structure_tuple(
                        f, the_format, extra_data=extra_data)
                seekpath_results = seekpath.get_path(structure)
Beispiel #12
0
def recip_space_labels(data):
    """
    Gets high symmetry point labels (e.g. GAMMA, X, L) for the q-points at
    which the path through reciprocal space changes direction

    Parameters
    ----------
    data: Data object
        Data object containing the cell vectors, q-points and optionally ion
        types and coordinates (used for determining space group)

    Returns
    -------
    labels : (n_qpts_direction_changed,) string ndarray
        List of the labels for each q-point at which the path through
        reciprocal space changes direction
    qpts_with_labels : (n_qpts_direction_changed,) int ndarray
        List of the indices of the q-points at which the path through
        reciprocal space changes direction
    """

    # First and last q-points should always be labelled
    if len(data.qpts) <= 2:
        qpt_has_label = np.ones(len(data.qpts), dtype=bool)
    else:
        qpt_has_label = np.concatenate(
            ([True], direction_changed(data.qpts), [True]))
    qpts_with_labels = np.where(qpt_has_label)[0]

    # Get dict of high symmetry point labels to their coordinates for this
    # space group. If space group can't be determined use a generic dictionary
    # of fractional points
    sym_label_to_coords = {}
    if hasattr(data, 'ion_r'):
        _, ion_num = np.unique(data.ion_type, return_inverse=True)
        cell_vec = (data.cell_vec.to('angstrom')).magnitude
        cell = (cell_vec, data.ion_r, ion_num)
        sym_label_to_coords = seekpath.get_path(cell)["point_coords"]
    else:
        sym_label_to_coords = generic_qpt_labels()
    # Get labels for each q-point
    labels = np.array([])
    for qpt in data.qpts[qpts_with_labels]:
        labels = np.append(labels, get_qpt_label(qpt, sym_label_to_coords))

    return labels, qpts_with_labels
Beispiel #13
0
    def get_kpath(self,
                  numbers: list = [],
                  with_time_reversal: bool = True,
                  recipe: str = 'hpkot',
                  threshold: float = 1e-7,
                  symprec: float = 1e-5,
                  angle_tolerance: float = -1) -> Tuple[Stru, Kpt]:
        """Obtain primitive cell and its band paths in the Brillouin zone of crystal structures.

        :params numbers: list of number of k points between two adjacent special k points.
        :params with_time_reversal: if time-reversal symmetry is present or not. Default: True
        :params recipe: currently only the string 'hpkot' is supported. Default: 'hpkot'
        :params threshold: numerical threshold. Default: 1e-7
        :params symprec: distance tolerance in Cartesian coordinates to find crystal symmetry. Default: 1e-5
        :params angle_tolerance: tolerance of angle between basis vectors in degrees to be tolerated in the symmetry finding. Default: -1
        """
        import seekpath

        if numbers:
            set_already = True
        else:
            set_already = False

        res = seekpath.get_path(self.spgcell, with_time_reversal, recipe,
                                threshold, symprec, angle_tolerance)
        newcell = (res['primitive_lattice'], res['primitive_positions'],
                   res['primitive_types'])
        stru = self.modified_stru(newcell)
        klabel = []
        special_k = []
        for k_tuple in res['path']:
            klabel.append(k_tuple[0])
            if not set_already:
                numbers.append(20)
        klabel.append(k_tuple[1])
        if not set_already:
            numbers.append(1)
        for label in klabel:
            special_k.append(res['point_coords'][label])
        kpt = Kpt(mode='Line',
                  numbers=numbers,
                  special_k=special_k,
                  klabel=klabel)

        return stru, kpt
Beispiel #14
0
def get_seekpath(cell: tuple) -> dict:
    """
    Get seekpath results.

    Args:
        cell (tuple): Cell.

    Returns:
        dict: Labels and corresponding qpoints.
    """
    if type(cell[2][0]) is str:
        numbers = get_numbers_from_symbols(cell[2])
        _cell = (cell[0], cell[1], numbers)
    else:
        _cell = cell
    skp = seekpath.get_path(_cell)

    return skp
Beispiel #15
0
def create_k_and_symmetry_space(atoms, n_k_points=300, symprec=1e-05):
    spg_struct = convert_to_spg_structure(atoms)
    autopath = seekpath.get_path(spg_struct, symprec=symprec)
    path_cleaned = []
    for edge in autopath['path']:
        edge_cleaned = []
        for point in edge:
            if point == 'GAMMA':
                edge_cleaned.append('G')
            else:
                edge_cleaned.append(point.replace('_', ''))
        path_cleaned.append(edge_cleaned)
    point_coords_cleaned = {}
    for key in autopath['point_coords'].keys():
        if key == 'GAMMA':
            point_coords_cleaned['G'] = autopath['point_coords'][key]
        else:
            point_coords_cleaned[key.replace(
                '_', '')] = autopath['point_coords'][key]

    density = n_k_points / 5
    bandpath = atoms.cell.bandpath(path=path_cleaned,
                                   density=density,
                                   special_points=point_coords_cleaned)

    previous_point_position = -1.
    kpath = bandpath.kpts
    points_positions = []
    points_names = []
    kpoint_axis = bandpath.get_linear_kpoint_axis()
    for i in range(len(kpoint_axis[-2])):
        point_position = kpoint_axis[-2][i]
        point_name = kpoint_axis[-1][i]
        if point_position != previous_point_position:
            points_positions.append(point_position)
            points_names.append(point_name)
        previous_point_position = point_position

    points_positions = np.array(points_positions)
    points_positions /= points_positions.max()
    for i in range(len(points_names)):
        if points_names[i] == 'GAMMA':
            points_names[i] = '$\\Gamma$'
    return kpath, points_positions, points_names
Beispiel #16
0
    def test_failing_file_examples(self):
        """These should be files that are valid in format but invalid when looking for symmetry"""
        with open(
                os.path.join(this_folder, 'file_examples_failing',
                             'list.json')) as f:
            list_files = json.load(f)

        for the_format, examples in list_files.items():
            for example in examples:
                filename = example['file']
                extra_data = example.get('extra_data', None)
                with open(
                        os.path.join(this_folder, 'file_examples_failing',
                                     filename)) as f:
                    structure = structure_importers.get_structure_tuple(
                        f, the_format, extra_data=extra_data)
                # No additional check, just check if it works
                with self.assertRaises(SymmetryDetectionError):
                    seekpath_results = seekpath.get_path(structure)
Beispiel #17
0
def k_path_info_with_seekpath():
    """
    https://seekpath.readthedocs.io/en/latest/maindoc.html#how-to-use
    Returns
     {'GAMMA': [0.0, 0.0, 0.0], 'X': [0.5, 0.0, 0.5], 'L': [0.5, 0.5, 0.5], 'W': [0.5, 0.25, 0.75],
     'W_2': [0.75, 0.25, 0.5], 'K': [0.375, 0.375, 0.75], 'U': [0.625, 0.25, 0.625]}
     [('GAMMA', 'X'), ('X', 'U'), ('K', 'GAMMA'), ('GAMMA', 'L'), ('L', 'W'), ('W', 'X')]

     # Path from materials project: https://materialsproject.org/materials/mp-149/
    :return:
    """
    cell = [[0., 2.7145, 2.7145], [2.7145, 0., 2.7145], [2.7145, 2.7145, 0.]]
    positions = [[0.00, 0.00, 0.00], [0.25, 0.25, 0.25]]
    unique_indices = [14, 14]
    structure = (cell, positions, unique_indices)

    path_info = seekpath.get_path(structure, True, 'hpkot')
    points = path_info['point_coords']
    paths = path_info['path']
Beispiel #18
0
def get_band_qpoints_by_seekpath(primitive, npoints):
    """q-points along BZ high symmetry paths are generated using seekpath.

    Parameters
    ----------
    primitive : PhonopyAtoms
        Primitive cell.
    npoints : int
        Number of q-points sampled along a path including end points.

    Returns
    -------
    bands : List of ndarray
        Sets of qpoints that can be passed to phonopy.set_band_structure().
        shape of each ndarray : (npoints, 3)
    labels : List of pairs of str
        Symbols of end points of paths.
    connections : List of bool
        This gives one path is connected to the next path, i.e., if False,
        there is a jump of q-points. Number of elements is the same at
        that of paths.

    """

    try:
        import seekpath
    except ImportError:
        raise ImportError("You need to install seekpath.")

    band_path = seekpath.get_path(primitive)
    point_coords = band_path['point_coords']
    qpoints_of_paths = []
    for path in band_path['path']:
        q_s = np.array(point_coords[path[0]])
        q_e = np.array(point_coords[path[1]])
        band = [q_s + (q_e - q_s) / (npoints - 1) * i for i in range(npoints)]
        qpoints_of_paths.append(band)

    labels, path_connections = _get_labels(band_path['path'])

    return qpoints_of_paths, labels, path_connections
Beispiel #19
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))
Beispiel #20
0
    def __init__(self, structure, symprec=1e-3):
        self.structure = structure

        # use sym as a quick way to access the cell data
        sym = SpacegroupAnalyzer(structure, symprec=symprec)
        self._spg_data = sym.get_symmetry_dataset()

        # make primitive and conventional cell from seekpath output
        std = spglib.refine_cell(sym._cell, symprec=symprec)
        self._seek_data = seekpath.get_path(std)

        prim_lattice = self._seek_data["primitive_lattice"]
        prim_scaled_positions = self._seek_data["primitive_positions"]
        prim_numbers = self._seek_data["primitive_types"]
        prim_atoms = [sym._unique_species[i - 1] for i in prim_numbers]
        self.prim = Structure(prim_lattice, prim_atoms, prim_scaled_positions)

        conv_lattice = self._seek_data["conv_lattice"]
        conv_scaled_positions = self._seek_data["conv_positions"]
        conv_numbers = self._seek_data["conv_types"]
        conv_atoms = [sym._unique_species[i - 1] for i in conv_numbers]
        self.conv = Structure(conv_lattice, conv_atoms, conv_scaled_positions)
Beispiel #21
0
    def get_path_using_seek_path(self):
        try:
            import seekpath

            cell = self.get_cell().T
            positions = self.get_scaled_positions()
            numbers = np.unique(self.get_atomic_elements(),
                                return_inverse=True)[1]
            structure = (cell, positions, numbers)
            path_data = seekpath.get_path(structure)

            labels = path_data['point_coords']

            band_ranges = []
            for set in path_data['path']:
                band_ranges.append([labels[set[0]], labels[set[1]]])

            return {'ranges': band_ranges, 'labels': path_data['path']}
        except ImportError:
            print('Seekpath not installed. Autopath is deactivated')
            band_ranges = ([[[0.0, 0.0, 0.0], [0.5, 0.0, 0.5]]])
            return {'ranges': band_ranges, 'labels': [['GAMMA', '1/2,0,1/2']]}
Beispiel #22
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'))
Beispiel #23
0
 def read_poscar(self):
     try:
         with open(self.filename, "r") as f:
             file = f.readlines()
     except FileNotFoundError:
         print("Not find %s"%filename)
         sys.exit(0)
 
     lists = []
 
     for a in [2, 3, 4]:
         row = []
         for b in file[a].split():
             row.append(float(b))
         lists.append(row)
     self.lattice = np.array(lists) * float(file[1])
 
     num     = 0
     self.numbers = []
     self.atmtyp  = file[5].strip().split()
     self.elenu   = file[6].split()
 
     for ine,a in enumerate(self.elenu):
         for i in range(int(a)):
             self.numbers.append(self.__symbol_map.get(self.atmtyp[ine])[0])
         num = num + int(a)
 
     self.positions = []
     for a in range(8, 8 + num):
         row = []
         for b in file[a].split():
             row.append(float(b))
         self.positions.append(row)
 
     self.structure = (self.lattice, self.positions, self.numbers)
     hkpts_dict = seekpath.get_path(self.structure)['point_coords']
     self.hkpts = np.round(np.array(list(hkpts_dict.values())), 4)
Beispiel #24
0
def kpath(
        infile=None,
        outfile='KPOINTS',
        grid_size=40,
        with_time_reversal=True,
        recipe='hpkot',
        threshold=1e-07,
        symprec=1e-05,
        angle_tolerence=-1.0,
        supercell_matrix=np.eye(3),
):
    """
    This module creates a KPOINTS file for band structure
    plotting.

    Parameters
    ----------

    infile : str, optional

    outfile : str, optional

    grid_size : int, optional

    with_time_reversal : bool, optional

    recepie : str, optional

    threshold : float, optional

    symprec : float, optional

    angle_tolerence : float, optional

    supercell_matrix: list, int

    """
    welcome()

    file = open(infile, "r")
    POSCAR = file.readlines()

    # cell
    cell_matrix = POSCAR[2:5]
    cell = np.zeros(shape=(3, 3))

    for i in range(len(cell_matrix)):
        cell_matrix0 = np.array(cell_matrix[i].split())
        cell[i, :] = (cell_matrix0.astype(np.float)) * np.array(
            POSCAR[1].split()).astype(np.float)

    # positions
    # POSCAR index changed by Nicholas Pike from 5 -> 6 and from 7 -> 8
    # Previously, POSCAR[5] referenced the atom names i.e. Na Cl and not the
    # atom numbers
    atoms = np.array(POSCAR[6].split()).astype(np.int)
    positions_matrix = POSCAR[8:8 + sum(atoms)]
    positions = np.zeros(shape=(np.sum(atoms), 3))

    for j in range(len(positions_matrix)):
        positions_matrix0 = np.array(positions_matrix[j].split())[0:3]
        positions[j, :] = positions_matrix0.astype(np.float)

    # numbers
    numbers = np.zeros(sum(atoms))
    counter = 0
    atom_counter = 1

    for ii in atoms:
        for kk in range(ii):
            numbers[counter] = atom_counter
            counter = counter + 1
        atom_counter = atom_counter + 1

    # seekpath
    structure = (cell, positions, numbers)
    kpath_dictionary = seekpath.get_path(structure, with_time_reversal, recipe,
                                         threshold, symprec, angle_tolerence)

    path_array = [""] * 2 * len(kpath_dictionary["path"])
    count = 0
    count2 = 1
    for path_counter in kpath_dictionary["path"]:
        path_array[count] = path_counter[0]
        path_array[count2] = path_counter[1]
        count = count + 2
        count2 = count2 + 2

    coord_matrix = np.zeros(shape=(2 * len(kpath_dictionary["path"]), 3))
    path_array_counter = 0
    for mm in range(len(coord_matrix)):
        coord_matrix[mm, :] = np.dot(
            kpath_dictionary["point_coords"][path_array[path_array_counter]],
            supercell_matrix,
        )
        path_array_counter = path_array_counter + 1

    k_file = open(outfile, "w+")
    k_file.write("KPOINTS generated by PyProcar\n")
    k_file.write("%d ! Grid points\n" % grid_size)
    k_file.write("Line_mode\n")
    k_file.write("reciprocal\n")
    for iterator in range(len(coord_matrix)):
        if iterator % 2 == 0:
            k_file.write("%f %f %f ! %s\n" % (
                coord_matrix[iterator, 0],
                coord_matrix[iterator, 1],
                coord_matrix[iterator, 2],
                path_array[iterator],
            ))
        else:
            k_file.write("%f %f %f ! %s\n\n" % (
                coord_matrix[iterator, 0],
                coord_matrix[iterator, 1],
                coord_matrix[iterator, 2],
                path_array[iterator],
            ))
    k_file.close()
    return
Beispiel #25
0
(options, args) = parser.parse_args()

structure = io.read(options.input_file)
numbers = structure.get_atomic_numbers()
inp = (structure.cell, structure.get_scaled_positions(), numbers)

explicit_data = seekpath.get_explicit_k_path(
    inp, reference_distance=options.resolution)

kpath = explicit_data['explicit_kpoints_rel']

weight = 0.
with open(options.output_file, 'a') as outfile:
    for point in kpath:
        outfile.write("%8.6f %8.6f %8.6f %5.3f\n" %
                      (point[0], point[1], point[2], weight))

print('Output written to {}'.format(options.output_file))

# Write new conventions cell, to ensure compliance with the kpoints
new_data = seekpath.get_path(inp)

new_cell = ase.Atoms(positions=new_data['conv_positions'],
                     cell=new_data['conv_lattice'],
                     pbc=[True, True, True])
new_cell.set_scaled_positions(new_data['conv_positions'])
new_cell.set_atomic_numbers(new_data['conv_types'])

print('New coordinates written to CONTCAR.conventional')
io.write('CONTCAR.conventional', new_cell)
Beispiel #26
0
if UseSeeKpath:
	explicit_data = seekpath.get_explicit_k_path(inp,reference_distance=0.1)
	k_labels = (explicit_data['explicit_kpoints_labels'])
	kpoint_labels = []
	for label in k_labels:
		label = r"$\Gamma$" if label == 'GAMMA' else label
		kpoint_labels.append(label)
	kpoint_positions = (explicit_data['explicit_kpoints_rel'])
	BandPath = [(tuple(pos), lab) for lab,pos in zip(kpoint_labels,kpoint_positions) if lab != '']
	BandPaths = [BandPath[i:j] for i, j in zip([0]+BandPathBreaks, BandPathBreaks+[None])]

if BandPaths == None:
	sys.exit('You need to set up the BandPath explicitly or use seeKpath to do it for you!')


new_data = seekpath.get_path(inp)
ReciprocalLatticeVectors = new_data['reciprocal_primitive_lattice']

#EndRegion


#Region: Functions

def _ReadBandEnergies(filePath):
	bandEnergies = [];

	inputReader = open(filePath, 'rU');
	inputReaderCSV = csv.reader(inputReader);

	next(inputReaderCSV);
	next(inputReaderCSV);
import numpy as np
import seekpath
from phonopy import Phonopy
from phonopy.structure.atoms import PhonopyAtoms
from phonopy.interface.calculator import read_crystal_structure
unitcell, _ = read_crystal_structure("POSCAR", interface_mode='vasp')
cell=unitcell.get_cell()
positions = unitcell.get_scaled_positions()
numbers = np.unique(unitcell.get_chemical_symbols(), return_inverse=True)[1]
path_data = seekpath.get_path((cell, positions, numbers))
labels = path_data['point_coords']
band_ranges = []
for set in path_data['path']:
                band_ranges.append([labels[set[0]], labels[set[1]]])

dict= {'ranges': band_range , 'labels': path_data['path']}
with open("output.txt","w") as f :
    for i  in range(len(dict['labels'])):
         f.writelines(str(dict['labels'][i])+":"+str(dict['ranges'][i]))
Beispiel #28
0
def get_seekpath_kpoint_path(doc,
                             standardize=True,
                             explicit=True,
                             spacing=0.01,
                             threshold=1e-7,
                             debug=False,
                             symmetry_tol=None):
    """ Return the conventional kpoint path of the relevant crystal system
    according to the definitions by "HKPOT" in
    Comp. Mat. Sci. 128, 2017:

    http://dx.doi.org/10.1016/j.commatsci.2016.10.015

    Parameters:
        doc (dict/tuple): matador doc or spglib tuple to find kpoint path for.

    Keyword arguments:
        spacing (float): desired kpoint spacing
        threshold (float): internal seekpath threshold
        symmetry_tol (float): spglib symmetry tolerance

    Returns:
        dict: standardized version of input doc
        list: list of kpoint positions
        dict: full dictionary of all seekpath results

    """
    try:
        from seekpath import get_explicit_k_path, get_path
    except ImportError:
        raise ImportError(
            "SeeK-Path dependency missing, please install it with `pip install seekpath`."
        )

    if symmetry_tol is None:
        symmetry_tol = 1e-5

    if isinstance(doc, tuple):
        spg_structure = doc
    else:
        if standardize:
            spg_structure = doc2spg(
                standardize_doc_cell(doc, symprec=symmetry_tol))
        else:
            spg_structure = doc2spg(doc)

    if explicit:
        seekpath_results = get_explicit_k_path(spg_structure,
                                               reference_distance=spacing,
                                               with_time_reversal=True,
                                               symprec=symmetry_tol,
                                               threshold=threshold)

        kpt_path = seekpath_results['explicit_kpoints_rel']
    else:
        seekpath_results = get_path(spg_structure)
        kpt_path = []

    primitive_doc = dict()
    primitive_doc['lattice_cart'] = seekpath_results['primitive_lattice']
    primitive_doc['positions_frac'] = seekpath_results['primitive_positions']
    primitive_doc['atom_types'] = [
        str(elements[i]) for i in seekpath_results['primitive_types']
    ]
    primitive_doc['num_atoms'] = len(primitive_doc['atom_types'])
    primitive_doc['lattice_abc'] = cart2abc(primitive_doc['lattice_cart'])
    primitive_doc['cell_volume'] = cart2volume(primitive_doc['lattice_cart'])
    if debug:
        print('Found lattice type {}'.format(
            seekpath_results['bravais_lattice_extended']))
        print('Old lattice:\n', np.asarray(doc['lattice_cart']))
        print('Contained {} atoms'.format(doc['num_atoms']))
        print('New lattice:\n', np.asarray(primitive_doc['lattice_cart']))
        print('Contains {} atoms'.format(primitive_doc['num_atoms']))
        print('k-point path contains {} points.'.format(len(kpt_path)))

    if 'site_occupancy' in doc:
        if min(doc['site_occupancy']) < 1 - EPS:
            print('Ignoring any site occupancy found in this cell.')
        primitive_doc['site_occupancy'] = [
            1 for atom in primitive_doc['atom_types']
        ]

    return primitive_doc, kpt_path, seekpath_results
Beispiel #29
0
    def gen_param(self, key):

        # Count the atoms
        if key == "nat":
            return len(self["atoms"])

        # Count the atom types
        if key == "ntyp":
            return len(self["species"])

        # Get a list of the species
        # with masses and pseudo names
        if key == "species":
            spec = []
            for a in self["atoms"]:
                if a[0] in spec: continue
                spec.append(a[0])

            for i, s in enumerate(spec):
                spec[i] = [s, elements[s]["mass number"], s + ".UPF"]

            return spec

        if key == "a": return np.linalg.norm(self["lattice"][0])
        if key == "b": return np.linalg.norm(self["lattice"][1])
        if key == "c": return np.linalg.norm(self["lattice"][2])

        if key == "alpha":
            lat = self["lattice"]
            ret = np.dot(lat[1], lat[2])
            ret = np.arccos(ret) * 180 / np.pi
            return ret

        if key == "beta":
            lat = self["lattice"]
            ret = np.dot(lat[0], lat[2])
            ret = np.arccos(ret) * 180 / np.pi
            return ret

        if key == "gamma":
            lat = self["lattice"]
            ret = np.dot(lat[0], lat[1])
            ret = np.arccos(ret) * 180 / np.pi
            return ret

        # Work out the space group
        if key == "space_group_name":
            self.eval_symmetry()
            return self["space_group_name"]

        # Work out the number of symmetry operations
        if key == "sym_ops":
            self.eval_symmetry()
            return self["sym_ops"]

        # Work out a good BZ path
        if key == "bz_path" or key == "high_symmetry_bz_points":
            try:
                import seekpath
            except ImportError:
                log("Could not import seekpath!")
                raise ImportError("Could not import SeeKpath!")

            # Convert the structure into a form that SeeKpath can digest
            frac_coords = []
            atom_numbers = []
            unique_names = []

            for a in self["atoms"]:
                if not a[0] in unique_names:
                    unique_names.append(a[0])

            for a in self["atoms"]:
                frac_coords.append(a[1])
                atom_numbers.append(unique_names.index(a[0]))

            # Call SeeKpath to get the BZ path
            structure = (self["lattice"], frac_coords, atom_numbers)
            path = seekpath.get_path(structure,
                                     with_time_reversal=True,
                                     symprec=0.001,
                                     angle_tolerance=0.5,
                                     threshold=0)

            # Work out how many points we have along each segment of the BZ path
            pc = path["point_coords"]
            segs = [[np.array(pc[p[0]]),
                     np.array(pc[p[1]])] for p in path["path"]]
            seg_names = [[p[0], p[1]] for p in path["path"]]
            seg_lengths = [np.linalg.norm(s[1] - s[0]) for s in segs]
            tot_length = sum(seg_lengths)
            seg_counts = [
                max(int(self["bz_path_points"] * l / tot_length), 2)
                for l in seg_lengths
            ]

            kpoints = []  # Will contain the k-points in the path
            high_symm_points = {
            }  # Will contain the names of high-symmetry points along the path

            for i, c in enumerate(seg_counts):
                pts = np.linspace(0.0, 1.0, c)
                pts = [segs[i][0] + (segs[i][1] - segs[i][0]) * p for p in pts]
                high_symm_points[len(kpoints)] = seg_names[i][0]
                kpoints.extend(pts)

                if i + 1 < len(seg_names) and seg_names[i][1] == seg_names[
                        i + 1][0]:
                    kpoints.pop()  # Remove repeated high symmetry point
                else:
                    high_symm_points[len(kpoints) - 1] = seg_names[i][1]

            self["high_symmetry_bz_points"] = high_symm_points
            self["bz_path"] = kpoints

            if key == "bz_path": return kpoints
            else: return high_symm_points

        # Find the pseudo_dir that contains
        # all of the needed pseudopotentials
        if key == "pseudo_dir":

            # Work out which pseudo_dirs contain
            # which pseudopotentials
            found_in = {}
            for s, m, p in self["species"]:
                found_in[p] = []
                for pd in self["pseudo_dirs"]:
                    if not os.path.isdir(pd): continue
                    if p in os.listdir(pd):
                        found_in[p].append(pd)

            # See if any one pseudo_dir contains
            # all of the needed pseudods
            for pd in self["pseudo_dirs"]:

                has_all = True
                for p in found_in:
                    if not pd in found_in[p]:
                        has_all = False
                        break

                # This pseudo_dir contains all the
                # needed pseudos, go ahead and use it
                if has_all: return pd

            # See if we can combine pseudos from
            # multiple directories
            for p in found_in:

                if len(found_in[p]) == 0:
                    err = "Could not find the pseudopotentail "
                    err += p + " in any of:"
                    for pd in self["pseudo_dirs"]:
                        err += "\n" + pd
                    raise ParamNotFound(err)

            # Create a file with the pseudopotential origin locations
            pof = open("pseudopotential_origin", "w")

            # We have found all the pseudos, collect
            # them into the working directory
            for p in found_in:

                # Copy the fist found pseudo to
                # working directory
                os.system("cp " + found_in[p][0] + "/" + p + " .")
                pof.write(p + " from " + found_in[p][0] + "\n")

            pof.close()
            return "./"

        # Get a dictionary of the form atom name : count
        if key == "atom_counts":
            atom_counts = defaultdict(lambda: 0)
            for a in self["atoms"]:
                if a[0] in atom_counts: atom_counts[a[0]] += 1
                else: atom_counts[a[0]] = 1
            return atom_counts

        # Reurn the stochiometry
        # of the given cell as a string
        if key == "stoichiometry_string":
            atom_counts = self["atom_counts"]
            ss = ""
            for a in atom_counts:
                ss += a + "_{0}_".format(atom_counts[a])
            ss = ss[0:-1]
            return ss

        # Get an estimate for the volume of the
        # cell by approximating each atom as
        # a covalent-radius sphere
        if key == "covalent_volume":
            vol = 0.0
            for a in self["atoms"]:
                vol += elements[a[0]]["covalent radius"]**3.0
            return np.pi * vol * 4.0 / 3.0

        # Default to ecutrho = 10*ecutwfc
        if key == "ecutrho": return 10 * self["ecutwfc"]

        # Generate the qpoint grid
        if key == "qpoint_grid":

            # Generate qpoint grid from spacing/min_q_grid_size
            rlat = np.linalg.inv(self["lattice"]).T
            qps = float(self["qpoint_spacing"])
            b2q = lambda b: int(np.linalg.norm(b) / qps)
            grid = [max(self["min_q_grid_size"], b2q(b)) for b in rlat]
            if self["force_cube_grids"]: grid = [max(grid) for g in grid]
            return grid

        # Get individual components of qpoint grid
        if key == "nq1": return self["qpoint_grid"][0]
        if key == "nq2": return self["qpoint_grid"][1]
        if key == "nq3": return self["qpoint_grid"][2]

        # Get individial components of interpolated qpoint grid
        if key == "ph_interp_nq1":
            return self["qpoint_grid"][0] * self["ph_interp_amt"]
        if key == "ph_interp_nq2":
            return self["qpoint_grid"][0] * self["ph_interp_amt"]
        if key == "ph_interp_nq3":
            return self["qpoint_grid"][0] * self["ph_interp_amt"]

        # Phonon interpolation output files from prefix
        if key == "ph_interp_dos_file":
            return self["ph_interp_prefix"] + ".dos"
        if key == "ph_interp_freq_file":
            return self["ph_interp_prefix"] + ".freq"
        if key == "ph_interp_modes_file":
            return self["ph_interp_prefix"] + ".modes"
        if key == "ph_interp_eig_file":
            return self["ph_interp_prefix"] + ".eig"

        # Generate the kpoint grid
        if key == "kpoint_grid":

            if "kpoint_spacing" in self.par:

                # Generate kpoint grid from spacing
                rlat = np.linalg.inv(self["lattice"]).T
                kps = float(self["kpoint_spacing"])
                b2k = lambda b: int(np.linalg.norm(b) / kps)
                return [b2k(b) for b in rlat]

            elif "kpts_per_qpt" in self.par:

                # Generate kpoint grid from qpoint grid
                kpq = self["kpts_per_qpt"]
                qpg = self["qpoint_grid"]
                return [kpq * q for q in qpg]

            else:

                msg = "Could not generate k-point grid from parameter set."
                raise ParamNotFound(msg)

        # Default to k-point parallelism
        if key == "pools": return self["cores_per_node"] * self["nodes"]
        if key == "images": return 1

        # Get the default k-point grids for calculating Tc
        if key == "tc_kpqs":
            return [self["kpts_per_qpt"] - 1, self["kpts_per_qpt"]]

        # Default q-e bin/ path = environment path
        if key == "path_override": return ""

        # If total_walltime is > 0, this will be the time returned by
        # time.time() when we will run out of walltime. Otherwise is -1.
        if key == "end_time":
            if self["total_walltime"] < 0:
                return -1
            else:
                return parameters.first_init_time + self["total_walltime"]

        # Returns the maximum seconds we let a calculation run for
        # from this moment in time. Is equal to the end_time minus
        # the current time minus the tidy_up_time.
        if key == "max_seconds":
            if self["end_time"] < 0:
                return 10e7  # No end time => essentially infinite time
            return max(self["end_time"] - time.time() - self["tidy_up_time"],
                       0)

        # This wasn't one of the generatable objects, treat
        # this as a KeyError, so we use the QE default value
        # (if there is one)
        exept = "Key \"{0}\" cold not be generated in parameters object."
        raise KeyError(exept.format(key))
Beispiel #30
0
def kpath(infile,grid_size,with_time_reversal,recipe,threshhold,symprec,angle_tolerence, supercell_matrix=np.eye(3)):
	file = open(infile,'r')
	POSCAR = file.readlines()

	#cell
	cell_matrix = POSCAR[2:5]
	cell = np.zeros(shape=(3,3))

	for i in range(len(cell_matrix)):
		cell_matrix0= np.array(cell_matrix[i].split())
		cell[i,:]  = (cell_matrix0.astype(np.float))*np.array(POSCAR[1].split()).astype(np.float)
	


	#positions
	atoms = np.array(POSCAR[5].split()).astype(np.int)
	positions_matrix = POSCAR[7:7+sum(atoms)]	
	positions = np.zeros(shape=(np.sum(atoms),3))

	for j in range(len(positions_matrix)):
		positions_matrix0= np.array(positions_matrix[j].split())[0:3]
		positions[j,:]  = positions_matrix0.astype(np.float)

		
		
	#numbers
	numbers = np.zeros(sum(atoms))
	counter=0
	atom_counter=1

	for ii in atoms:
		for kk in range(ii):
			numbers[counter]=atom_counter
			counter=counter+1
		atom_counter=atom_counter+1



	#seekpath
	structure = (cell,positions,numbers)	
	kpath_dictionary = seekpath.get_path(structure,with_time_reversal,recipe,threshhold,symprec,angle_tolerence)
	
	path_array = ['']*2*len(kpath_dictionary['path'])
	count=0
	count2=1
	for path_counter in kpath_dictionary['path']:
		path_array[count]=path_counter[0]
		path_array[count2]=path_counter[1]
		count=count+2
		count2=count2+2

	coord_matrix=np.zeros(shape=(2*len(kpath_dictionary['path']),3))
	path_array_counter = 0
	for mm in range(len(coord_matrix)):
		coord_matrix[mm,:] = np.dot(kpath_dictionary['point_coords'][path_array[path_array_counter]], supercell_matrix)
		path_array_counter=path_array_counter+1

	k_file = open('KPOINTS','w+')
	k_file.write("KPOINTS generated by PyProcar\n")
	k_file.write("%d ! Grid points\n"%grid_size)
	k_file.write("Line_mode\n")
	k_file.write("reciprocal\n")
	for iterator in range(len(coord_matrix)):
		if iterator%2==0:
			k_file.write('%f %f %f ! %s\n'% (coord_matrix[iterator,0],coord_matrix[iterator,1],coord_matrix[iterator,2],path_array[iterator])   )
		else:
			k_file.write('%f %f %f ! %s\n\n'% (coord_matrix[iterator,0],coord_matrix[iterator,1],coord_matrix[iterator,2],path_array[iterator])   )
	k_file.close()
def reduce_to_primitive(parameters):

    try:
        import seekpath
        # Return a modified parameter
        # set with the primitive geometry

        frac_coords = []
        atom_numbers = []
        unique_names = []

        for a in parameters["atoms"]:
            if not a[0] in unique_names:
                unique_names.append(a[0])

        for a in parameters["atoms"]:
            frac_coords.append(a[1:])
            atom_numbers.append(unique_names.index(a[0]))

        # Use seekpath to get primitive geometry
        structure = (parameters["lattice"], frac_coords, atom_numbers)
        prim_geom = seekpath.get_path(
            structure,
            with_time_reversal=True,
            symprec=parameters["symm_tol_cart"],
            angle_tolerance=parameters["symm_tol_angle"],
            threshold=0)

        # Convert back to our representation
        new_atoms = []
        for t, f in zip(prim_geom["primitive_types"],
                        prim_geom["primitive_positions"]):
            new_atoms.append([unique_names[t], f[0], f[1], f[2]])

        # Overwrite new structure
        parameters["lattice"] = prim_geom["primitive_lattice"]
        parameters["atoms"] = new_atoms
        parameters["bz_path"] = prim_geom["path"]
        parameters["high_symm_points"] = prim_geom["point_coords"]

        # Convert k-points to cartesian coords in units of
        # 2pi/a0, because that's what q.e uses for some reason
        #recip_prim_lattice = np.array(prim_geom["reciprocal_primitive_lattice"])
        #a0 = np.linalg.norm(parameters["lattice"])
        #for p in parameters["high_symm_points"]:
        #    frac_coords = parameters["high_symm_points"][p]
        #    cart_coords = np.matmul(recip_prim_lattice.T, frac_coords)
        #    parameters["high_symm_points"][p] = cart_coords*a0/(2*np.pi)

        outf = parameters["out_file"]
        outf.write(
            "Successfully reduced to primitive geometry using seekpath.\n")

    except ImportError:
        err = "Could not import seekpath =>\n"
        err += "  1. We cannot reduce to the primitive geometry\n"
        err += "  2. We cannot obtain Brilloin zone paths\n"
        err += "  3. 2 => we cannot calculate bandstructures\n"
        parameters["out_file"].write(err)

        if parameters["require_prim_geom"]:
            ex_mess = "Could not reduce to primitive geometry/find BZ path. "
            ex_mess += "Perhaps the version of python you're using does not "
            ex_mess += "have access to the seeKpath module."
            raise Exception(ex_mess)

    # Work out qpoint_grid
    if "qpoint_grid" in parameters:

        # Warn user we're using an explicit q-point grid
        if "qpoint_spacing" in parameters:
            parameters["out_file"].write(
                "Explicit q-point grid specified, ignoring q-point spacing\n")

    elif "qpoint_spacing" in parameters:

        # Work out qpoint_grid from qpoint_spacing
        parameters["qpoint_grid"] = get_kpoint_grid(
            parameters["lattice"], parameters["qpoint_spacing"])

    # Ensure we have at least 1 q-point in each direction
    parameters["qpoint_grid"] = [max(1, q) for q in parameters["qpoint_grid"]]

    if parameters["kpoint_grid"] is None:
        # Work out k-point grid from q-point grid and
        # k-points per qpoint
        kpq = parameters["kpts_per_qpt"]
        qpg = parameters["qpoint_grid"]
        parameters["kpoint_grid"] = [int(q * k) for q, k in zip(qpg, kpq)]
        mess = "Generating k-point grid from q-point grid: {0}x{1}x{2}\n"
    else:
        # Use explicitly specified k-point grid
        mess = "Using explicit k-point grid: {0}x{1}x{2}\n"

    # Tell user the k-point grid we're using and how we got it
    parameters["out_file"].write(mess.format(*parameters["kpoint_grid"]))

    # Return resulting new parameter set
    return parameters
Beispiel #32
0
def main():
    parser = argparse.ArgumentParser()

    parser.add_argument("-i",
                        "--input",
                        type=str,
                        required=True,
                        help="input structure file")

    parser.add_argument("-o",
                        "--output",
                        type=str,
                        default="kpath-from-seekpath.txt",
                        help="the output kpoitns file")

    parser.add_argument(
        "--join",
        type=int,
        default=15,
        help=
        "default number of kpoint to connect the connected high symmetry k point"
    )

    # ===============================================================================
    args = parser.parse_args()

    structure = read_structure(filepath=args.input)

    lattice = structure.cell
    positions = []
    numbers = []
    a = np.sqrt(structure.cell[0][0]**2 + structure.cell[0][1]**2 +
                structure.cell[0][2]**2)
    b = np.sqrt(structure.cell[1][0]**2 + structure.cell[1][1]**2 +
                structure.cell[1][2]**2)
    c = np.sqrt(structure.cell[2][0]**2 + structure.cell[2][1]**2 +
                structure.cell[2][2]**2)

    frac_coord = structure.get_fractional()
    for i in range(len(frac_coord)):
        positions.append(
            [frac_coord[i][1], frac_coord[i][2],
             frac_coord[i][3]])  # must be fractional coordinates
        numbers.append(element[frac_coord[i][0]].number)

    cell = (lattice, positions, numbers)

    kpoints_seekpath = seekpath.get_path(cell)

    kpath = []
    # [[kx, ky, kz, label, connect_indicator], ...] like [[0.0, 0.0, 0.0, 'GAMMA', 15], ...]
    # if connect_indicator in a kpoint is an integer, then it will connect to the following point
    # through the number of kpoints defined by connect_indicator.
    # if connect_indicator in a kpoint is '|', then it will not connect to the following point,
    kpath.append([
        float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"][0][0]]
              [0]),
        float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"][0][0]]
              [1]),
        float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"][0][0]]
              [2]),
        kpoints_seekpath["path"][0][0],
        args.join,
    ])
    kpath.append([
        float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"][0][1]]
              [0]),
        float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"][0][1]]
              [1]),
        float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"][0][1]]
              [2]),
        kpoints_seekpath["path"][0][1],
        args.
        join,  # first set to args.join here, and it will be reset by the following path by judge whether it is connected
    ])
    for i in range(1, len(kpoints_seekpath["path"])):
        if kpoints_seekpath["path"][i][0] == kpoints_seekpath["path"][i -
                                                                      1][1]:
            kpath[-1][4] = args.join
            kpath.append([
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][1]][0]),
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][1]][1]),
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][1]][2]),
                kpoints_seekpath["path"][i][1],
                args.join,
            ])
        else:
            kpath[-1][4] = "|"
            kpath.append([
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][0]][0]),
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][0]][1]),
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][0]][2]),
                kpoints_seekpath["path"][i][0],
                args.join,
            ])
            kpath.append([
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][1]][0]),
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][1]][1]),
                float(kpoints_seekpath["point_coords"][kpoints_seekpath["path"]
                                                       [i][1]][2]),
                kpoints_seekpath["path"][i][1],
                args.join,
            ])
    #
    with open(args.output, 'w') as fout:
        fout.write("%d\n" % len(kpath))
        for kpoint in kpath:
            fout.write(
                "%f %f %f #%s %s\n" %
                (kpoint[0], kpoint[1], kpoint[2], kpoint[3], str(kpoint[4])))
    #

    print("===========================================\n")
    print("calculated using seekpath\n")
    print("===========================================\n")
    print("Warning:\n")
    print("the result is not guaranteed to be correct\n")
    print("-------------------------------------------\n")
    print("suggested k path calculated using seekpath:\n")
    print(kpoints_seekpath)