Source code for wulfric.lattice

# Wulfric - Crystal, Lattice, Atoms, K-path.
# Copyright (C) 2023-2024 Andrey Rybakov
#
# e-mail: anry@uv.es, web: adrybakov.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

from copy import deepcopy

import numpy as np
from scipy.spatial import Voronoi

import wulfric.cell as Cell
from wulfric.bravais_lattice.hs_points import (
    BCC_hs_points,
    BCT_hs_points,
    CUB_hs_points,
    FCC_hs_points,
    HEX_hs_points,
    MCL_hs_points,
    MCLC_hs_points,
    ORC_hs_points,
    ORCC_hs_points,
    ORCF_hs_points,
    ORCI_hs_points,
    RHL_hs_points,
    TET_hs_points,
    TRI_hs_points,
)
from wulfric.bravais_lattice.standardize import get_S_matrix
from wulfric.bravais_lattice.variations import (
    BCT_variation,
    MCLC_variation,
    ORCF_variation,
    RHL_variation,
    TRI_variation,
)
from wulfric.constants import (
    BRAVAIS_LATTICE_NAMES,
    C_MATRICES,
    DEFAULT_K_PATHS,
    HS_PLOT_NAMES,
    PEARSON_SYMBOLS,
    STANDARDIZATION_CONVENTIONS,
)
from wulfric.geometry import angle, volume
from wulfric.identify import lepage
from wulfric.kpoints import Kpoints
from wulfric.numerical import ABS_TOL_ANGLE, REL_TOL

__all__ = ["Lattice"]


[docs] class Lattice: r""" General 3D lattice. When created from the cell orientation of the cell is respected, however the lattice vectors may be renamed with respect to [1]_. Since v0.2.2 the standardization of the lattice is not performed by default at the time of the lattice creation. The standardization is performed when is is required, for example, when the kpoints are computed. Lattice can be created in a three alternative ways: .. doctest:: >>> import wulfric as wulf >>> l = wulf.Lattice(cell = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> l = wulf.Lattice(a1 = [1,0,0], a2 = [0,1,0], a3 = [0,0,1]) >>> l = wulf.Lattice(a=1, b=1, c=1, alpha=90, beta=90, gamma=90) Parameters ---------- cell : (3, 3) |array-like|_ Unit cell, rows are vectors, columns are coordinates. a1 : (3,) |array-like|_ First vector of unit cell (cell[0]). a2 : (3,) |array-like|_ SEcond vector of unit cell (cell[1]). a3 : (3,) |array-like|_ Third vector of unit cell (cell[2]). a : float, default=1 Length of the :math:`a_1` vector. b : float, default=1 Length of the :math:`a_2` vector. c : float, default=1 Length of the :math:`a_3` vector. alpha : float, default=90 Angle between vectors :math:`a_2` and :math:`a_3`. In degrees. beta : float, default=90 Angle between vectors :math:`a_1` and :math:`a_3`. In degrees. gamma : float, default=90 Angle between vectors :math:`a_1` and :math:`a_2`. In degrees. eps_rel : float, default 1e-4 Relative tolerance for distance. angle_tol : float, default 1e-4 Absolute tolerance for angles, in degrees. Attributes ---------- eps_rel : float, default 1e-4 Relative error for the :ref:`library_lepage` algorithm. References ---------- .. [1] Setyawan, W. and Curtarolo, S., 2010. High-throughput electronic band structure calculations: Challenges and tools. Computational materials science, 49(2), pp.299-312. """ def __init__( self, *args, eps_rel=REL_TOL, angle_tol=ABS_TOL_ANGLE, **kwargs, ) -> None: self._eps_rel = eps_rel self._angle_tol = angle_tol self._cell = None self._type = None self._kpoints = None self._standardization_convention = "sc" self._standardized = False if "cell" in kwargs: cell = kwargs["cell"] elif "a1" in kwargs and "a2" in kwargs and "a3" in kwargs: cell = np.array([kwargs["a1"], kwargs["a2"], kwargs["a3"]]) elif ( "a" in kwargs and "b" in kwargs and "c" in kwargs and "alpha" in kwargs and "beta" in kwargs and "gamma" in kwargs ): cell = Cell.from_params( kwargs["a"], kwargs["b"], kwargs["c"], kwargs["alpha"], kwargs["beta"], kwargs["gamma"], ) elif len(args) == 1: cell = np.array(args[0]) elif len(args) == 3: cell = np.array(args) elif len(args) == 6: a, b, c, alpha, beta, gamma = args cell = Cell.from_params(a, b, c, alpha, beta, gamma) elif len(args) == 0 and len(kwargs) == 0: cell = np.eye(3) else: raise ValueError( "Unable to identify input parameters. " + "Supported: cell ((3,3) array-like), " + "or a1, a2, a3 (each is an (3,) array-like), " + "or a, b, c, alpha, beta, gamma (floats)." ) self.cell = cell ################################################################################ # Cell standardization # ################################################################################ @property def S_matrix(self): r""" Transformation matrix that transforms the primitive cell to the standardized primitive cell. See :ref:`user-guide_conventions_main_standardization` for details. """ return get_S_matrix(self._cell, self.type(), rtol=self.eps_rel, atol=self.eps)
[docs] def standardize(self): R""" Standardize cell with respect to the Bravais lattice type as defined in [1]_. .. versionadded:: 0.3.0 References ---------- .. [1] Setyawan, W. and Curtarolo, S., 2010. High-throughput electronic band structure calculations: Challenges and tools. Computational materials science, 49(2), pp.299-312. """ self._cell = np.linalg.inv(self.S_matrix.T) @ self._cell self._standardized = True # Remove any K-points, as the cell is changed self._kpoints = None
@property def convention(self) -> str: r""" Convention used for the standardization of the unit cell. By default we use the convention of Setyawan and Curtarolo [1]_. Supported conventions: * ``SC`` - Setyawan and Curtarolo [1]_. References ---------- .. [1] Setyawan, W. and Curtarolo, S., 2010. High-throughput electronic band structure calculations: Challenges and tools. Computational materials science, 49(2), pp.299-312. """ return self._standardization_convention @convention.setter def convention(self, new_value: str): new_value = str(new_value).lower() if new_value not in STANDARDIZATION_CONVENTIONS: raise ValueError( f"Unsupported convention for the standardization of the unit cell: {new_value}." ) self._standardization_convention = str(new_value) ################################################################################ # Primitive cell # ################################################################################ @property def cell(self): r""" Unit cell of the lattice. Notes ----- In order to rotate the cell with an arbitrary rotation matrix :math:`R` use the syntax: .. code-block:: python rotated_cell = cell @ R.T Transpose is required, since the vectors are stored as rows. Returns ------- cell : (3, 3) :numpy:`ndarray` Unit cell, rows are vectors, columns are coordinates. """ if self._cell is None: raise AttributeError(f"Cell is not defined for lattice {self}") return np.array(self._cell) @cell.setter def cell(self, new_cell): try: new_cell = np.array(new_cell) except: raise ValueError(f"New cell is not array-like: {new_cell}") if new_cell.shape != (3, 3): raise ValueError(f"New cell is not 3 x 3 matrix.") self._cell = new_cell # Reset type self._type = None @property def a1(self): r""" First lattice vector :math:`\boldsymbol{a_1}`. Returns ------- a1 : (3,) :numpy:`ndarray` First lattice vector :math:`\boldsymbol{a_1}`. """ return self.cell[0] @property def a2(self): r""" Second lattice vector :math:`\boldsymbol{a_2}`. Returns ------- a2 : (3,) :numpy:`ndarray` Second lattice vector :math:`\boldsymbol{a_2}`. """ return self.cell[1] @property def a3(self): r""" Third lattice vector :math:`\boldsymbol{a_3}`. Returns ------- a3 : (3,) :numpy:`ndarray` Third lattice vector :math:`\boldsymbol{a_3}`. """ return self.cell[2] @property def a(self): r""" Length of the first lattice vector :math:`\vert\boldsymbol{a_1}\vert`. Returns ------- a : float """ return np.linalg.norm(self.cell[0]) @property def b(self): r""" Length of the second lattice vector :math:`\vert\boldsymbol{a_2}\vert`. Returns ------- b : float """ return np.linalg.norm(self.cell[1]) @property def c(self): r""" Length of the third lattice vector :math:`\vert\boldsymbol{a_3}\vert`. Returns ------- c : float """ return np.linalg.norm(self.cell[2]) @property def alpha(self): r""" Angle between second and third lattice vector. Returns ------- angle : float In degrees """ return angle(self.a2, self.a3) @property def beta(self): r""" Angle between first and third lattice vector. Returns ------- angle : float In degrees """ return angle(self.a1, self.a3) @property def gamma(self): r""" Angle between first and second lattice vector. Returns ------- angle : float In degrees """ return angle(self.a1, self.a2) @property def unit_cell_volume(self): r""" Volume of the unit cell. Returns ------- volume : float Unit cell volume. """ return volume(self.a1, self.a2, self.a3) @property def parameters(self): r""" Return cell parameters. :math:`(a, b, c, \alpha, \beta, \gamma)` Returns ------- a : float b : float c : float alpha : float beta : float gamma : float """ return self.a, self.b, self.c, self.alpha, self.beta, self.gamma ################################################################################ # Conventional cell # ################################################################################ @property def C_matrix(self): r""" Transformation matrix that transforms primitive cell (:py:meth:`Lattice.cell`) to the **conventional standardized** cell. See :ref:`user-guide_conventions_main_conventional` for details. """ return C_MATRICES[self.type()] @property def conv_cell(self): r""" Conventional cell. .. math:: (\boldsymbol{a_1}, \boldsymbol{a_2}, \boldsymbol{a_3}) = (\boldsymbol{a^{cs}}_1, \boldsymbol{a^{cs}}_2, \boldsymbol{a^{cs}}_3) (\boldsymbol{C}\boldsymbol{S}) .. code-block:: python conv_cell = np.linalg.inv(C @ S).T @ cell Returns ------- conv_cell : (3, 3) :numpy:`ndarray` Conventional cell, rows are vectors, columns are coordinates. """ return np.linalg.inv(self.C_matrix @ self.S_matrix).T @ self.cell @property def conv_a1(self): r""" First vector of the conventional cell. Requires the lattice to be standardized. Returns ------- conv_a1 : (3,) :numpy:`ndarray` First vector of the conventional cell. """ return self.conv_cell[0] @property def conv_a2(self): r""" Second vector of the conventional cell. Requires the lattice to be standardized. Returns ------- conv_a2 : (3,) :numpy:`ndarray` Second vector of the conventional cell. """ return self.conv_cell[1] @property def conv_a3(self): r""" Third vector of the conventional cell. Requires the lattice to be standardized. Returns ------- conv_a3 : (3,) :numpy:`ndarray` Third vector of the conventional cell. """ return self.conv_cell[2] @property def conv_a(self): r""" Length of the first vector of the conventional cell. Requires the lattice to be standardized. Returns ------- conv_a : float Length of the first vector of the conventional cell. """ return np.linalg.norm(self.conv_a1) @property def conv_b(self): r""" Length of the second vector of the conventional cell. Requires the lattice to be standardized. Returns ------- conv_b : float Length of the second vector of the conventional cell. """ return np.linalg.norm(self.conv_a2) @property def conv_c(self): r""" Length of the third vector of the conventional cell. Requires the lattice to be standardized. Returns ------- conv_c : float Length of the third vector of the conventional cell. """ return np.linalg.norm(self.conv_a3) @property def conv_alpha(self): r""" Angle between second and third conventional lattice vector. Requires the lattice to be standardized. Returns ------- angle : float In degrees. """ return angle(self.conv_a2, self.conv_a3) @property def conv_beta(self): r""" Angle between first and third conventional lattice vector. Requires the lattice to be standardized. Returns ------- angle : float In degrees. """ return angle(self.conv_a1, self.conv_a3) @property def conv_gamma(self): r""" Angle between first and second conventional lattice vector. Requires the lattice to be standardized. Returns ------- angle : float In degrees. """ return angle(self.conv_a1, self.conv_a2) @property def conv_unit_cell_volume(self): r""" Volume of the conventional unit cell. Requires the lattice to be standardized. Returns ------- volume : float Unit cell volume. """ return volume(self.conv_a1, self.conv_a2, self.conv_a3) @property def conv_parameters(self): r""" Return conventional cell parameters. :math:`(a, b, c, \alpha, \beta, \gamma)` Requires the lattice to be standardized. Returns ------- a : float b : float c : float alpha : float beta : float gamma : float """ return ( self.conv_a, self.conv_b, self.conv_c, self.conv_alpha, self.conv_beta, self.conv_gamma, ) ################################################################################ # Reciprocal cell # ################################################################################ @property def reciprocal_cell(self): r""" Reciprocal cell. Always primitive. Returns ------- reciprocal_cell : (3, 3) :numpy:`ndarray` Reciprocal cell, rows are vectors, columns are coordinates. """ return Cell.reciprocal(self.cell) @property def rcell(self): r""" Reciprocal cell. Shortcut for :py:attr:`.reciprocal_cell`. Returns ------- reciprocal_cell : (3, 3) :numpy:`ndarray` Reciprocal cell, rows are vectors, columns are coordinates. """ return self.reciprocal_cell @property def b1(self): r""" First reciprocal lattice vector. .. math:: \boldsymbol{b_1} = \frac{2\pi}{V}\boldsymbol{a_2}\times\boldsymbol{a_3} where :math:`V = \boldsymbol{a_1}\cdot(\boldsymbol{a_2}\times\boldsymbol{a_3})` Returns ------- b1 : (3,) :numpy:`ndarray` First reciprocal lattice vector :math:`\boldsymbol{b_1}`. """ return self.reciprocal_cell[0] @property def b2(self): r""" Second reciprocal lattice vector. .. math:: \boldsymbol{b_2} = \frac{2\pi}{V}\boldsymbol{a_3}\times\boldsymbol{a_1} where :math:`V = \boldsymbol{a_1}\cdot(\boldsymbol{a_2}\times\boldsymbol{a_3})` Returns ------- b2 : (3,) :numpy:`ndarray` Second reciprocal lattice vector :math:`\boldsymbol{b_2}`. """ return self.reciprocal_cell[1] @property def b3(self): r""" Third reciprocal lattice vector. .. math:: \boldsymbol{b_3} = \frac{2\pi}{V}\boldsymbol{a_1}\times\boldsymbol{a_2} where :math:`V = \boldsymbol{a_1}\cdot(\boldsymbol{a_2}\times\boldsymbol{a_3})` Returns ------- b3 : (3,) :numpy:`ndarray` Third reciprocal lattice vector :math:`\boldsymbol{b_3}`. """ return self.reciprocal_cell[2] @property def k_a(self): r""" Length of the first reciprocal lattice vector :math:`\vert\boldsymbol{b_1}\vert`. Returns ------- k_a : float """ return np.linalg.norm(self.b1) @property def k_b(self): r""" Length of the second reciprocal lattice vector :math:`\vert\boldsymbol{b_2}\vert`. Returns ------- k_b : float """ return np.linalg.norm(self.b2) @property def k_c(self): r""" Length of the third reciprocal lattice vector :math:`\vert\boldsymbol{b_3}\vert`. Returns ------- k_c : float """ return np.linalg.norm(self.b3) @property def k_alpha(self): r""" Angle between second and third reciprocal lattice vector. Returns ------- angle : float In degrees. """ return angle(self.b2, self.b3) @property def k_beta(self): r""" Angle between first and third reciprocal lattice vector. Returns ------- angle : float In degrees. """ return angle(self.b1, self.b3) @property def k_gamma(self): r""" Angle between first and second reciprocal lattice vector. Returns ------- angle : float In degrees. """ return angle(self.b1, self.b2) @property def reciprocal_cell_volume(self): r""" Volume of the reciprocal cell. .. math:: V = \boldsymbol{b_1}\cdot(\boldsymbol{b_2}\times\boldsymbol{b_3}) Returns ------- volume : float Volume of the reciprocal cell. """ return volume(self.b1, self.b2, self.b3) @property def reciprocal_parameters(self): r""" Return reciprocal cell parameters. :math:`(a, b, c, \alpha, \beta, \gamma)` Returns ------- a : float b : float c : float alpha : float beta : float gamma : float """ return self.k_a, self.k_b, self.k_c, self.k_alpha, self.k_beta, self.k_gamma ################################################################################ # Numerical accuracy # ################################################################################ @property def eps_rel(self) -> float: r""" Relative tolerance for the distance. Connected with :py:attr:`.eps` as .. math:: \epsilon = \epsilon_{rel}\cdot V^{\frac{1}{3}} Returns ------- eps_rel : float Relative tolerance for the distance. See Also -------- angle_tol eps """ return self._eps_rel @eps_rel.setter def eps_rel(self, value): if value < 0: raise ValueError(f"Relative tolerance should be non-negative. Got {value}.") self._eps_rel = float(value) # Reset Bravais lattice type self._type = None @property def eps(self) -> float: r""" Absolute tolerance for the distance. Derived from :py:attr:`.eps_rel` as .. math:: \epsilon = \epsilon_{rel}\cdot V^{\frac{1}{3}} See Also -------- angle_tol eps_rel """ return self._eps_rel * abs(self.unit_cell_volume) ** (1 / 3.0) @eps.setter def eps(self, value): if value < 0: raise ValueError(f"Absolute tolerance should be non-negative. Got {value}.") self._eps_rel = float(value) / abs(self.unit_cell_volume) ** (1 / 3.0) # Reset Bravais lattice type self._type = None @property def angle_tol(self) -> float: r""" Absolute tolerance for the angle. Returns ------- angle_tol : float Absolute tolerance for the angle. See Also -------- eps eps_rel """ return self._angle_tol @angle_tol.setter def angle_tol(self, value): if value < 0: raise ValueError(f"Angle tolerance should be non-negative. Got {value}.") self._angle_tol = float(value) # Reset Bravais lattice type self._type = None ################################################################################ # Lattice type and stats # ################################################################################
[docs] def type(self, eps_rel=None, angle_tol=None): r""" Identify the lattice type. Parameters ---------- eps_rel : float, optional Relative tolerance for the LePage algorithm. By default it is equal to :py:attr:`.eps_rel`. angle_tol : float, optional Angle tolerance for the LePage algorithm. Try to reduce it if the desired lattice type is not identified. In degrees. By default it is equal to :py:attr:`.angle_tol`. Returns ------- lattice_type : str Bravais lattice type. See Also -------- lepage : Algorithm for the lattice type identification variation : Variation of the lattice. """ if self._type is None or eps_rel is not None or angle_tol is not None: if eps_rel is None: eps_rel = self.eps_rel if angle_tol is None: angle_tol = self.angle_tol lattice_type = lepage( self.a, self.b, self.c, self.alpha, self.beta, self.gamma, eps_rel=eps_rel, delta_max=angle_tol, ) self._type = lattice_type return self._type
@property def variation(self): r""" Variation of the lattice, if any. Requires the lattice to be standardized. For the Bravais lattice with only one variation the :py:meth:`.Lattice.type` is returned. Returns ------- variation : str Variation of the lattice. Examples -------- .. doctest:: >>> import wulfric as wulf >>> l = wulf.lattice_example("CUB") >>> l.standardize() >>> l.variation 'CUB' .. doctest:: >>> import wulfric as wulf >>> l = wulf.lattice_example("BCT1") >>> l.standardize() >>> l.variation 'BCT1' .. doctest:: >>> import wulfric as wulf >>> l = wulf.lattice_example("MCLC4") >>> l.standardize() >>> l.variation 'MCLC4' See Also -------- :py:meth:`.Lattice.type` """ lattice_type = self.type() if lattice_type == "BCT": result = BCT_variation(self.conv_a, self.conv_c) elif lattice_type == "ORCF": result = ORCF_variation(self.conv_a, self.conv_b, self.conv_c, self.eps) elif lattice_type == "RHL": result = RHL_variation(self.conv_alpha, self.eps) elif lattice_type == "MCLC": result = MCLC_variation( self.conv_a, self.conv_b, self.conv_c, self.conv_alpha, self.k_gamma, self.eps, ) elif lattice_type == "TRI": result = TRI_variation(self.k_alpha, self.k_beta, self.k_gamma, self.eps) else: result = lattice_type return result @property def name(self): r""" Human-readable name of the Bravais lattice type. Returns ------- name : str Name of the Bravais lattice type. """ return BRAVAIS_LATTICE_NAMES[self.type()] @property def pearson_symbol(self): r""" Pearson symbol. Returns ------- pearson_symbol : str Pearson symbol of the lattice. Raises ------ RuntimeError If the type of the lattice is not defined. Notes ----- See: |PearsonSymbol|_ """ return PEARSON_SYMBOLS[self.type()] @property def crystal_family(self): r""" Crystal family. Returns ------- crystal_family : str Crystal family of the lattice. Raises ------ ValueError If the type of the lattice is not defined. Notes ----- See: |PearsonSymbol|_ """ return self.pearson_symbol[0] @property def centring_type(self): r""" Centring type. Returns ------- centring_type : str Centring type of the lattice. Raises ------ ValueError If the type of the lattice is not defined. Notes ----- See: |PearsonSymbol|_ """ return self.pearson_symbol[1] ################################################################################ # Helpers for plotting # ################################################################################ def _lattice_points(self, relative=False, reciprocal=False, normalize=False): r""" Compute lattice points Parameters ---------- relative : bool, default False Whether to return relative or absolute coordinates. reciprocal : bool, default False Whether to use reciprocal or real cell. normalize : bool, default False Whether to normalize corresponding vectors to have the volume equal to one. Returns ------- lattice_points : (N, 3) :numpy:`ndarray` N lattice points. Each element is a vector :math:`v = (v_x, v_y, v_z)`. """ if reciprocal: cell = self.reciprocal_cell else: cell = self.cell if normalize: cell /= volume(cell) ** (1 / 3.0) lattice_points = np.zeros((27, 3), dtype=float) for i in [-1, 0, 1]: for j in [-1, 0, 1]: for k in [-1, 0, 1]: point = np.array([i, j, k]) if not relative: point = point @ cell lattice_points[9 * (i + 1) + 3 * (j + 1) + (k + 1)] = point return lattice_points
[docs] def voronoi_cell(self, reciprocal=False, normalize=False): r""" Computes Voronoi edges around (0,0,0) point. Parameters ---------- reciprocal : bool, default False Whether to use reciprocal or real cell. Returns ------- edges : (N, 2, 3) :numpy:`ndarray` N edges of the Voronoi cell around (0,0,0) point. Each elements contains two vectors of the points of the voronoi vertices forming an edge. vertices : (M, 3) :numpy:`ndarray` M vertices of the Voronoi cell around (0,0,0) point. Each element is a vector :math:`v = (v_x, v_y, v_z)`. normalize : bool, default False Whether to normalize corresponding vectors to have the volume equal to one. """ voronoi = Voronoi( self._lattice_points( relative=False, reciprocal=reciprocal, normalize=normalize ) ) edges_index = set() # Thanks ase for the idea. 13 - is the index of (0,0,0) point. for rv, rp in zip(voronoi.ridge_vertices, voronoi.ridge_points): if -1 not in rv and 13 in rp: for j in range(0, len(rv)): if (rv[j - 1], rv[j]) not in edges_index and ( rv[j], rv[j - 1], ) not in edges_index: edges_index.add((rv[j - 1], rv[j])) edges_index = np.array(list(edges_index)) edges = np.zeros((edges_index.shape[0], 2, 3), dtype=voronoi.vertices.dtype) for i in range(edges_index.shape[0]): edges[i][0] = voronoi.vertices[edges_index[i][0]] edges[i][1] = voronoi.vertices[edges_index[i][1]] return edges, voronoi.vertices[np.unique(edges_index.flatten())]
################################################################################ # K points # ################################################################################ @property def kpoints(self) -> Kpoints: r""" Instance of :py:class:`.Kpoints` with the high symmetry points and path. Returns ------- kpoints : :py:class:`.Kpoints` Instance of the :py:class:`.Kpoints` class. See Also -------- Kpoints : Class for the high symmetry points and path. """ if self._kpoints is None: self._kpoints = Kpoints(self.b1, self.b2, self.b3) if self.type() == "CUB": hs_points = CUB_hs_points() elif self.type() == "FCC": hs_points = FCC_hs_points() elif self.type() == "BCC": hs_points = BCC_hs_points() elif self.type() == "TET": hs_points = TET_hs_points() elif self.type() == "BCT": hs_points = BCT_hs_points(self.variation, self.conv_a, self.conv_c) elif self.type() == "ORC": hs_points = ORC_hs_points() elif self.type() == "ORCF": hs_points = ORCF_hs_points( self.variation, self.conv_a, self.conv_b, self.conv_c ) elif self.type() == "ORCI": hs_points = ORCI_hs_points(self.conv_a, self.conv_b, self.conv_c) elif self.type() == "ORCC": hs_points = ORCC_hs_points(self.conv_a, self.conv_b) elif self.type() == "HEX": hs_points = HEX_hs_points() elif self.type() == "RHL": hs_points = RHL_hs_points(self.variation, self.conv_alpha) elif self.type() == "MCL": hs_points = MCL_hs_points(self.conv_b, self.conv_c, self.conv_alpha) elif self.type() == "MCLC": hs_points = MCLC_hs_points( self.variation, self.conv_a, self.conv_b, self.conv_c, self.conv_alpha, ) elif self.type() == "TRI": hs_points = TRI_hs_points(self.variation) for point in hs_points: # Compute relative coordinates with respect to the # non-standardized primitive cell hs_points[point] = self.S_matrix.T @ hs_points[point] # Post-process two edge cases if point == "S" and self.type() == "BCT": self._kpoints.add_hs_point( point, hs_points[point], label="$\\Sigma$" ) elif point == "S1" and self.type() == "BCT": self._kpoints.add_hs_point( point, hs_points[point], label="$\\Sigma_1$" ) # General assignment else: self._kpoints.add_hs_point( point, hs_points[point], label=HS_PLOT_NAMES[point] ) self._kpoints.path = DEFAULT_K_PATHS[self.variation] return self._kpoints ################################################################################ # Copy # ################################################################################
[docs] def copy(self): r""" Create a copy of the lattice. .. versionadded:: 0.3.0 .. versionchanged:: 0.4.0 Fixe the bug (it was never returned) Returns ------- lattice : :py:class:`.Lattice` Copy of the lattice. """ return deepcopy(self)