Source code for wulfric.crystal._hpkot_extended_bl_symbol

# ================================== LICENSE ===================================
# Wulfric - Cell, Atoms, K-path, visualization.
# Copyright (C) 2023 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/>.
#
# ================================ END LICENSE =================================
from math import cos, sin, sqrt

import numpy as np

from wulfric.cell._basic_manipulation import get_params, get_reciprocal
from wulfric.crystal._crystal_validation import validate_atoms
from wulfric._spglib_interface import get_spglib_data, validate_spglib_data, SpglibData
from wulfric.crystal._conventional import get_conventional
from wulfric._exceptions import PotentialBugError
from wulfric.constants import TORADIANS

__all__ = ["hpkot_get_extended_bl_symbol"]


[docs] def hpkot_get_extended_bl_symbol(cell, atoms, spglib_data=None): r""" Returns extended bravais lattice symbol as defined in the paper by Hinuma, Pizzi, Kumagai, Oba, and Tanaka [1]_. .. versionadded:: 0.6.3 Parameters ---------- cell : (3, 3) |array-like|_ Matrix of a cell, rows are interpreted as vectors. atoms : dict Dictionary with N atoms. Expected keys: * "positions" : (N, 3) |array-like|_ Positions of the atoms in the basis of lattice vectors (``cell``). In other words - relative coordinates of atoms. * "names" : (N, ) list of str, optional See Notes * "species" : (N, ) list of str, optional See Notes * "spglib_types" : (N, ) list of int, optional See Notes .. hint:: Pass ``atoms = dict(positions=[[0, 0, 0]], spglib_types=[1])`` if you would like to interpret the ``cell`` alone (effectively assuming that the ``cell`` is a primitive one). spglib_data : :py:class:`.SpglibData`, optional If you need more control on the parameters passed to the spglib, then you can get ``spglib_data`` manually and pass it to this function. Use wulfric's interface to |spglib|_ as .. code-block:: python spglib_data = wulfric.get_spglib_data(...) using the same ``cell`` and ``atoms["positions"]`` that you are passing to this function. Returns ------- extended_bl_type : str Extended Bravais lattice symbol. Notes ----- |spglib|_ uses ``types`` to distinguish the atoms. To see how wulfric deduces the ``types`` for given atoms see :py:func:`wulfric.get_spglib_types`. References ---------- .. [1] Hinuma, Y., Pizzi, G., Kumagai, Y., Oba, F. and Tanaka, I., 2017. Band structure diagram paths based on crystallography. Computational Materials Science, 128, pp.140-184. Examples -------- .. doctest:: >>> import wulfric >>> wulfric.crystal.hpkot_get_extended_bl_symbol( ... cell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]], ... atoms=dict(positions=[[0, 0, 0]], spglib_types=[1]), ... ) 'cP2' """ # Validate that the atoms dictionary is what expected of it validate_atoms(atoms=atoms, required_keys=["positions"], raise_errors=True) # Call spglib if spglib_data is None: spglib_data = get_spglib_data(cell=cell, atoms=atoms) # Or check that spglib_data were *most likely* produced via wulfric's interface elif not isinstance(spglib_data, SpglibData): raise TypeError( f"Are you sure that spglib_data were produced via wulfric's interface? Expected SpglibData, got {type(spglib_data)}." ) # Validate that user-provided spglib_data match user-provided structure else: validate_spglib_data(cell=cell, atoms=atoms, spglib_data=spglib_data) cell = np.array(cell, dtype=float) lattice_type = spglib_data.crystal_family + spglib_data.centring_type # Lattice types that do not require computation of lattice parameters if lattice_type in ["cI", "tP", "oP", "mP"]: return f"{lattice_type}1" if lattice_type == "cP": if 195 <= spglib_data.space_group_number <= 206: return "cP1" elif 207 <= spglib_data.space_group_number <= 230: return "cP2" else: raise PotentialBugError( error_summary=f'(convention="HPKOT"), lattice type cP, space group {spglib_data.space_group_number}. Failed to define extended Bravais lattice symbol.' ) if lattice_type == "cF": if 195 <= spglib_data.space_group_number <= 206: return "cF1" elif 207 <= spglib_data.space_group_number <= 230: return "cF2" else: raise PotentialBugError( error_summary=f'(convention="HPKOT"), lattice type cF, space group {spglib_data.space_group_number}. Failed to define extended Bravais lattice symbol.' ) if lattice_type == "hP": if ( 143 <= spglib_data.space_group_number <= 149 or 159 <= spglib_data.space_group_number <= 163 or spglib_data.space_group_number in [151, 153, 157] ): return "hP1" else: return "hP2" # Lattice types that require computation of lattice parameters conventional_cell, _ = get_conventional( cell=cell, atoms=atoms, convention="HPKOT", spglib_data=spglib_data ) a, b, c, _, beta, _ = get_params(cell=conventional_cell) if lattice_type == "tI": if c <= a: return "tI1" else: return "tI2" if lattice_type == "oF": if 1 / a**2 > 1 / b**2 + 1 / c**2: return "oF1" elif 1 / c**2 > 1 / a**2 + 1 / b**2: return "oF2" else: return "oF3" if lattice_type == "oI": if c >= a and c >= b: return "oI1" if a >= b and a >= c: return "oI2" if b >= a and b >= c: return "oI3" if lattice_type == "oC": if a <= b: return "oC1" else: return "oC2" if lattice_type == "oA": if b <= c: return "oA1" else: return "oA2" if lattice_type == "hR": if sqrt(3) * a <= sqrt(2) * c: return "hR1" else: return "hR2" if lattice_type == "mC": if b <= a * sin(beta * TORADIANS): return "mC1" else: if ( -a * cos(beta * TORADIANS) / c + ((a * sin(beta * TORADIANS)) / b) ** 2 <= 1 ): return "mC2" else: return "mC3" if lattice_type == "aP": _, _, _, r_alpha, r_beta, r_gamma = get_params( cell=get_reciprocal(cell=conventional_cell) ) if r_alpha >= 90 and r_beta >= 90 and r_gamma >= 90: return "aP2" else: return "aP3" # If lattice type is not one of the expected ones raise PotentialBugError( f'(convention="HPKOT"), lattice type {lattice_type}, space group {spglib_data.space_group_number}.. Failed to identify lattice type (not one of supported).' )