Source code for bands_inspect.kpoints._path

# -*- coding: utf-8 -*-

# (c) 2017-2019, ETH Zurich, Institut fuer Theoretische Physik
# Author: Dominik Gresch <greschd@gmx.ch>
"""
Defines the data class for a k-point path.
"""

from types import MappingProxyType
from collections import namedtuple

import numpy as np
from fsc.export import export
from fsc.hdf5_io import subscribe_hdf5, to_hdf5, from_hdf5

from ..lattice import Lattice
from ..io._legacy import _hdf5_utils
from ._base import KpointsBase


[docs]@export @subscribe_hdf5('bands_inspect.kpoints_path', extra_tags=('kpoints_path', )) class KpointsPath(KpointsBase): """ Defines a k-point path. :param paths: List of paths. Each path is a list of special points. :type paths: list :param special_points: Mapping of special k-points. The key is the identifier of the special k-point, and the value is its position in reduced coordinates. :type special_points: dict :param kpoint_distance: Approximate distance between two neighbouring k-points along the path. :type kpoint_distance: float :param unit_cell: Unit cell of the material. The basis vectors are given as rows in a matrix. :type unit_cell: numpy.ndarray """ def __init__( self, *, paths, special_points=MappingProxyType({}), kpoint_distance=1e-3, unit_cell='auto' ): self._paths = [[_Vertex(pt, special_points) for pt in single_path] for single_path in paths] dimensions = set( pt.dimension for single_path in self._paths for pt in single_path ) if len(dimensions) != 1: raise ValueError('Inconsistent dimensions: {}'.format(dimensions)) dim = dimensions.pop() if unit_cell is 'auto': # pylint: disable=literal-comparison uc = np.eye(dim) # pylint: disable=invalid-name else: uc = np.array(unit_cell) # pylint: disable=invalid-name if uc.shape != (dim, dim): raise ValueError( 'Inconsistent shape of the unit cell: {}, should be {}'.format( uc.shape, (dim, dim) ) ) self._lattice = Lattice(matrix=uc) self._kpoint_distance = kpoint_distance self._evaluate_paths() def _evaluate_paths(self): """ Evaluate all paths and calculate the corresponding explicit k-points. """ self._kpoints_explicit = [] self._labels = [] for single_path in self._paths: self._evaluate_single_path(single_path) self._kpoints_explicit = np.array(self._kpoints_explicit) self._kpoints_explicit.flags.writeable = False def _evaluate_single_path(self, single_path): """ Evaluate a single path (connected line of k-points), and calculate the explicit k-points. """ num_kpoints_initial = len(self._kpoints_explicit) self._kpoints_explicit.append(single_path[0].frac) self._labels.append( _KpointLabel( index=num_kpoints_initial, label=single_path[0].label ) ) for start, end in zip(single_path, single_path[1:]): self._evaluate_line(start, end) def _evaluate_line(self, start, end): """ Calculate the explicit k-points between two vertices which are part of the path. """ dist = self._lattice.get_reciprocal_cartesian_distance( start.frac, end.frac ) npoints = max(int(np.round_(dist / self._kpoint_distance)) + 1, 2) steps = np.linspace(0, 1, npoints)[1:] kpoints = [(1 - s) * start.frac + s * end.frac for s in steps] self._kpoints_explicit.extend(kpoints) self._labels.append( _KpointLabel( index=len(self._kpoints_explicit) - 1, label=end.label ) ) @property def kpoints_explicit(self): return self._kpoints_explicit @property def labels(self): return self._labels
[docs] def to_hdf5(self, hdf5_handle): path_labels = [[pt.label for pt in single_path] for single_path in self._paths] to_hdf5(path_labels, hdf5_handle.create_group('path_labels')) special_points = { pt.label: pt.frac for special_path in self._paths for pt in special_path } to_hdf5(special_points, hdf5_handle.create_group('special_points')) hdf5_handle['kpoint_distance'] = self._kpoint_distance hdf5_handle['unit_cell'] = self._lattice.matrix
[docs] @classmethod def from_hdf5(cls, hdf5_handle): try: path_labels = from_hdf5(hdf5_handle['path_labels']) special_points = from_hdf5(hdf5_handle['special_points']) except ValueError: path_labels = _hdf5_utils.nested_list_from_hdf5( hdf5_handle['path_labels'] ) special_points = _hdf5_utils.dict_from_hdf5( hdf5_handle['special_points'] ) kpoint_distance = hdf5_handle['kpoint_distance'][()] unit_cell = hdf5_handle['unit_cell'][()] return cls( paths=path_labels, special_points=special_points, kpoint_distance=kpoint_distance, unit_cell=unit_cell )
class _Vertex: """ Defines a vertex in the k-point path. """ def __init__(self, point, special_points): self.frac = np.array(special_points.get(point, point)) self.label = str(point) @property def dimension(self): return self.frac.shape[0] _KpointLabel = namedtuple('_KpointLabel', ['index', 'label'])