Source code for wulfric.bravais_lattice.standardize

# 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/>.

import numpy as np

import wulfric.cell as Cell
from wulfric.exceptions import StandardizationTypeMismatch
from wulfric.numerical import ABS_TOL, ABS_TOL_ANGLE, REL_TOL, compare_numerically

__all__ = [
    "get_S_matrix",
    "CUB_get_S_matrix",
    "FCC_get_S_matrix",
    "BCC_get_S_matrix",
    "TET_get_S_matrix",
    "BCT_get_S_matrix",
    "ORC_get_S_matrix",
    "ORCF_get_S_matrix",
    "ORCI_get_S_matrix",
    "ORCC_get_S_matrix",
    "HEX_get_S_matrix",
    "RHL_get_S_matrix",
    "MCL_get_S_matrix",
    "MCLC_get_S_matrix",
    "TRI_get_S_matrix",
]


# Main routine, serves as interface to all of them
[docs] def get_S_matrix(cell, correct_lattice_type, rtol=REL_TOL, atol=ABS_TOL): r""" Analyse arbitrary cell and redefine it if required to ensure the unique choice of lattice vectors. .. versionchanged:: 0.4.0 Renamed from ``standardize_cell`` See :ref:`docs for each Bravais lattice <user-guide_conventions_bravais-lattices>` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. correct_lattice_type : str Correct lattice type. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` """ cell = np.array(cell) functions = { "CUB": CUB_get_S_matrix, "FCC": FCC_get_S_matrix, "BCC": BCC_get_S_matrix, "TET": TET_get_S_matrix, "BCT": BCT_get_S_matrix, "ORC": ORC_get_S_matrix, "ORCF": ORCF_get_S_matrix, "ORCI": ORCI_get_S_matrix, "ORCC": ORCC_get_S_matrix, "HEX": HEX_get_S_matrix, "RHL": RHL_get_S_matrix, "MCL": MCL_get_S_matrix, "MCLC": MCLC_get_S_matrix, "TRI": TRI_get_S_matrix, } return functions[correct_lattice_type](cell, rtol=rtol, atol=atol)
[docs] def CUB_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary cubic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``CUB_standardize_cell`` See :ref:`guide_cub` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. Ignored here, but preserved for the unification of input. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Ignored here, but preserved for the unification of input. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S`. Notes ----- It is assumed that the ``cell`` has the symmetries of the cubic lattice. If the cell is not cubic, the function will not work correctly. """ return np.eye(3, dtype=float)
[docs] def FCC_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary face-centered cubic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``FCC_standardize_cell`` See :ref:`guide_fcc` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. Ignored here, but preserved for the unification of input. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Ignored here, but preserved for the unification of input. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S`. Notes ----- It is assumed that the ``cell`` has the symmetries of the face-centered cubic lattice. If the cell is not face-centered cubic, the function will not work correctly. """ return np.eye(3, dtype=float)
[docs] def BCC_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary body-centered cubic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``BCC_standardize_cell`` See :ref:`guide_fcc` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. Ignored here, but preserved for the unification of input. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Ignored here, but preserved for the unification of input. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S`. Notes ----- It is assumed that the ``cell`` has the symmetries of the body-centered cubic lattice. If the cell is not body-centered cubic, the function will not work correctly. """ return np.eye(3, dtype=float)
[docs] def TET_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary tetragonal cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``TET_standardize_cell`` See :ref:`guide_tet` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the tetragonal lattice. If the cell is not tetragonal, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the tetragonal conditions are satisfied. """ a, b, c, alpha, beta, gamma = Cell.params(cell) if compare_numerically(a, "==", b, rtol=rtol, atol=atol) and compare_numerically( b, "!=", c, rtol=rtol, atol=atol ): S = np.eye(3, dtype=float) elif compare_numerically(b, "==", c, rtol=rtol, atol=atol) and compare_numerically( c, "!=", a, rtol=rtol, atol=atol ): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif compare_numerically(a, "==", c, rtol=rtol, atol=atol) and compare_numerically( c, "!=", b, rtol=rtol, atol=atol ): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("tetragonal") return S
[docs] def BCT_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary body-centered tetragonal cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``BCT_standardize_cell`` See :ref:`guide_bct` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) :numpy:`ndarray` Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the body-centered tetragonal lattice. If the cell is not body-centered tetragonal, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the body-centered tetragonal conditions are satisfied. """ cell = np.array(cell) a, b, c, alpha, beta, gamma = Cell.params(cell) if compare_numerically( alpha, "==", beta, rtol=rtol, atol=atol ) and compare_numerically(beta, "!=", gamma, rtol=rtol, atol=atol): S = np.eye(3, dtype=float) elif compare_numerically( beta, "==", gamma, rtol=rtol, atol=atol ) and compare_numerically(gamma, "!=", alpha, rtol=rtol, atol=atol): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif compare_numerically( alpha, "==", gamma, rtol=rtol, atol=atol ) and compare_numerically(gamma, "!=", beta, rtol=rtol, atol=atol): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("body-centered tetragonal") return S
[docs] def ORC_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary orthorhombic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``ORC_standardize_cell`` See :ref:`guide_orc` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the orthorhombic lattice. If the cell is not orthorhombic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the orthorhombic conditions are satisfied. """ a, b, c, alpha, beta, gamma = Cell.params(cell) if compare_numerically(c, ">", b, rtol=rtol, atol=atol) and compare_numerically( b, ">", a, rtol=rtol, atol=atol ): S = np.eye(3, dtype=float) elif compare_numerically(c, ">", a, rtol=rtol, atol=atol) and compare_numerically( a, ">", b, rtol=rtol, atol=atol ): S = np.array([[0, -1, 0], [-1, 0, 0], [0, 0, -1]], dtype=float) elif compare_numerically(b, ">", c, rtol=rtol, atol=atol) and compare_numerically( c, ">", a, rtol=rtol, atol=atol ): S = np.array([[-1, 0, 0], [0, 0, -1], [0, -1, 0]], dtype=float) elif compare_numerically(b, ">", a, rtol=rtol, atol=atol) and compare_numerically( a, ">", c, rtol=rtol, atol=atol ): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) elif compare_numerically(a, ">", c, rtol=rtol, atol=atol) and compare_numerically( c, ">", b, rtol=rtol, atol=atol ): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif compare_numerically(a, ">", b, rtol=rtol, atol=atol) and compare_numerically( b, ">", c, rtol=rtol, atol=atol ): S = np.array([[0, 0, -1], [0, -1, 0], [-1, 0, 0]], dtype=float) else: raise StandardizationTypeMismatch("orthorhombic") return S
[docs] def ORCF_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary face-centered orthorhombic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``ORCF_standardize_cell`` See :ref:`guide_orcf` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the face-centered orthorhombic lattice. If the cell is not face-centered orthorhombic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the face-centered orthorhombic conditions are satisfied. """ a, b, c, alpha, beta, gamma = Cell.params(cell) if compare_numerically(c, "<", b, rtol=rtol, atol=atol) and compare_numerically( b, "<", a, rtol=rtol, atol=atol ): S = np.eye(3, dtype=float) elif compare_numerically(c, "<", a, rtol=rtol, atol=atol) and compare_numerically( a, "<", b, rtol=rtol, atol=atol ): S = np.array([[0, -1, 0], [-1, 0, 0], [0, 0, -1]], dtype=float) elif compare_numerically(b, "<", c, rtol=rtol, atol=atol) and compare_numerically( c, "<", a, rtol=rtol, atol=atol ): S = np.array([[-1, 0, 0], [0, 0, -1], [0, -1, 0]], dtype=float) elif compare_numerically(b, "<", a, rtol=rtol, atol=atol) and compare_numerically( a, "<", c, rtol=rtol, atol=atol ): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) elif compare_numerically(a, "<", c, rtol=rtol, atol=atol) and compare_numerically( c, "<", b, rtol=rtol, atol=atol ): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif compare_numerically(a, "<", b, rtol=rtol, atol=atol) and compare_numerically( b, "<", c, rtol=rtol, atol=atol ): S = np.array([[0, 0, -1], [0, -1, 0], [-1, 0, 0]], dtype=float) else: raise StandardizationTypeMismatch("face-centered orthorhombic") return S
[docs] def ORCI_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary body-centered orthorhombic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``ORCI_standardize_cell`` See :ref:`guide_orci` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the body-centered orthorhombic lattice. If the cell is not body-centered orthorhombic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the body-centered orthorhombic conditions are satisfied. """ sp23, sp13, sp12 = Cell.scalar_products(cell) if compare_numerically( sp12, ">", sp13, rtol=rtol, atol=atol ) and compare_numerically(sp13, ">", sp23, rtol=rtol, atol=atol): S = np.eye(3, dtype=float) elif compare_numerically( sp12, ">", sp23, rtol=rtol, atol=atol ) and compare_numerically(sp23, ">", sp13, rtol=rtol, atol=atol): S = np.array([[0, -1, 0], [-1, 0, 0], [0, 0, -1]], dtype=float) elif compare_numerically( sp13, ">", sp12, rtol=rtol, atol=atol ) and compare_numerically(sp12, ">", sp23, rtol=rtol, atol=atol): S = np.array([[-1, 0, 0], [0, 0, -1], [0, -1, 0]], dtype=float) elif compare_numerically( sp13, ">", sp23, rtol=rtol, atol=atol ) and compare_numerically(sp23, ">", sp12, rtol=rtol, atol=atol): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) elif compare_numerically( sp23, ">", sp12, rtol=rtol, atol=atol ) and compare_numerically(sp12, ">", sp13, rtol=rtol, atol=atol): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif compare_numerically( sp23, ">", sp13, rtol=rtol, atol=atol ) and compare_numerically(sp13, ">", sp12, rtol=rtol, atol=atol): S = np.array([[0, 0, -1], [0, -1, 0], [-1, 0, 0]], dtype=float) else: raise StandardizationTypeMismatch("body-centered orthorhombic") return S
[docs] def ORCC_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary base-centered orthorhombic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``ORCC_standardize_cell`` See :ref:`guide_orcc` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the base-centered orthorhombic lattice. If the cell is not base-centered orthorhombic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the base-centered orthorhombic conditions are satisfied. """ sp23, sp13, sp12 = Cell.scalar_products(cell) if ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "<", 0.0, rtol=rtol, atol=atol) ): S = np.eye(3, dtype=float) elif ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, ">", 0.0, rtol=rtol, atol=atol) ): S = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]], dtype=float) elif ( compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp23, "<", 0.0, rtol=rtol, atol=atol) ): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif ( compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp23, ">", 0.0, rtol=rtol, atol=atol) ): S = np.array([[0, 0, 1], [0, -1, 0], [1, 0, 0]], dtype=float) elif ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "<", 0.0, rtol=rtol, atol=atol) ): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) elif ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, ">", 0.0, rtol=rtol, atol=atol) ): S = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("base-centered orthorhombic") return S
[docs] def HEX_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary hexagonal cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``HEX_standardize_cell`` See :ref:`guide_hex` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the hexagonal lattice. If the cell is not hexagonal, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the hexagonal conditions are satisfied. """ sp23, sp13, sp12 = Cell.scalar_products(cell) if ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "<", 0.0, rtol=rtol, atol=atol) ): S = np.eye(3, dtype=float) elif ( compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp23, "<", 0.0, rtol=rtol, atol=atol) ): S = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "<", 0.0, rtol=rtol, atol=atol) ): S = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("hexagonal") return S
[docs] def RHL_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary rhombohedral cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``RHL_standardize_cell`` See :ref:`guide_rhl` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. Ignored here, but preserved for the unification of input. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Ignored here, but preserved for the unification of input. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the rhombohedral lattice. If the cell is not rhombohedral, the function will not work correctly. """ return np.eye(3, dtype=float)
[docs] def MCL_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary monoclinic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``MCL_standardize_cell`` See :ref:`guide_mcl` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the monoclinic lattice. If the cell is not monoclinic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the monoclinic conditions are satisfied. """ # Step 1 sp23, sp13, sp12 = Cell.scalar_products(cell) if ( compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp23, "!=", 0.0, rtol=rtol, atol=atol) ): S1 = np.eye(3, dtype=float) elif ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "!=", 0.0, rtol=rtol, atol=atol) ): S1 = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif ( compare_numerically(sp23, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp13, "==", 0.0, rtol=rtol, atol=atol) and compare_numerically(sp12, "!=", 0.0, rtol=rtol, atol=atol) ): S1 = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("monoclinic", step="First") # Step 2 cell1 = np.linalg.inv(S1.T) @ cell a, b, c, alpha, beta, gamma = Cell.params(cell1) if b < c: S2 = np.eye(3, dtype=float) elif b > c: S2 = np.array([[-1, 0, 0], [0, 0, 1], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("monoclinic", step="Second") # Step 3 cell2 = np.linalg.inv(S2.T) @ cell1 sp23, sp13, sp12 = Cell.scalar_products(cell2) if compare_numerically(sp23, ">", 0, rtol=rtol, atol=atol): S3 = np.eye(3, dtype=float) elif compare_numerically(sp23, "<", 0, rtol=rtol, atol=atol): S3 = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]], dtype=float) else: raise StandardizationTypeMismatch("monoclinic", step="Third") return S3 @ S2 @ S1
[docs] def MCLC_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary base-centered monoclinic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``MCLC_standardize_cell`` See :ref:`guide_mclc` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the base-centered monoclinic lattice. If the cell is not base-centered monoclinic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the base-centered monoclinic conditions are satisfied. """ # Step 1 a, b, c, alpha, beta, gamma = Cell.params(cell) if compare_numerically(a, "==", b, rtol=rtol, atol=atol) and compare_numerically( b, "!=", c, rtol=rtol, atol=atol ): S1 = np.eye(3, dtype=float) elif compare_numerically(b, "==", c, rtol=rtol, atol=atol) and compare_numerically( c, "!=", a, rtol=rtol, atol=atol ): S1 = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) elif compare_numerically(c, "==", a, rtol=rtol, atol=atol) and compare_numerically( a, "!=", b, rtol=rtol, atol=atol ): S1 = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) else: raise StandardizationTypeMismatch("base-centered monoclinic", step="First") # Step 2 cell1 = np.linalg.inv(S1.T) @ cell a, b, c, alpha, beta, gamma = Cell.params(cell1) sp23, sp13, sp12 = Cell.scalar_products(cell1) if compare_numerically( 2 * a**2 * (1 + sp12 / a / b), "<=", c**2, rtol=rtol, atol=atol ): S2 = np.eye(3, dtype=float) else: S2 = np.array([[-0.5, 0.5, 1], [0.5, -0.5, 1], [0.5, 0.5, 0]], dtype=float) # Step 3 cell2 = np.linalg.inv(S2.T) @ cell1 sp23, sp13, sp12 = Cell.scalar_products(cell2) if compare_numerically(sp23, ">", 0, rtol=rtol, atol=atol): S3 = np.eye(3, dtype=float) elif compare_numerically(sp23, "<", 0, rtol=rtol, atol=atol): S3 = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]], dtype=float) else: raise StandardizationTypeMismatch("base-centered monoclinic", step="Third") return S3 @ S2 @ S1
[docs] def TRI_get_S_matrix(cell, rtol=REL_TOL, atol=ABS_TOL): r""" For arbitrary triclinic cell returns matrix S that transforms it to the standardized form. .. versionchanged:: 0.4.0 Renamed from ``TRI_standardize_cell`` See :ref:`guide_tri` and :ref:`user-guide_conventions_main_standardization` for the details. Parameters ---------- cell : (3,3) |array-like|_ Primitive unit cell. rtol : float, default ``REL_TOL`` Relative tolerance for numerical comparison. atol : float, default ``ABS_TOL`` Absolute tolerance for numerical comparison. Returns ------- S : (3,3) :numpy:`ndarray` Transformation matrix :math:`S` Notes ----- It is assumed that the ``cell`` has the symmetries of the triclinic lattice. If the cell is not triclinic, the function will not work correctly. Raises ------ :py:class:`.StandardizationTypeMismatch` If none of the triclinic conditions are satisfied. """ # Compute reciprocal cell rcell = Cell.reciprocal(cell) # Step 1 sp23, sp13, sp12 = Cell.scalar_products(rcell) a, b, c, alpha, beta, gamma = Cell.params(rcell) if ( compare_numerically(alpha, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, ">=", 90.0, rtol=rtol, atol=atol) ) or ( compare_numerically(alpha, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, "<=", 90.0, rtol=rtol, atol=atol) ): S1 = np.eye(3, dtype=float) elif ( compare_numerically(alpha, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, "<=", 90.0, rtol=rtol, atol=atol) ) or ( compare_numerically(alpha, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, ">=", 90.0, rtol=rtol, atol=atol) ): S1 = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]], dtype=float) elif ( compare_numerically(alpha, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, ">=", 90.0, rtol=rtol, atol=atol) ) or ( compare_numerically(alpha, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, "<=", 90.0, rtol=rtol, atol=atol) ): S1 = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, -1]], dtype=float) elif ( compare_numerically(alpha, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, ">=", 90.0, rtol=rtol, atol=atol) ) or ( compare_numerically(alpha, ">=", 90.0, rtol=rtol, atol=atol) and compare_numerically(beta, "<=", 90.0, rtol=rtol, atol=atol) and compare_numerically(gamma, "<=", 90.0, rtol=rtol, atol=atol) ): S1 = np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]], dtype=float) else: raise StandardizationTypeMismatch("triclinic", step="First") # Step 2 rcell1 = np.linalg.inv(S1.T) @ rcell sp23, sp13, sp12 = Cell.scalar_products(rcell1) a, b, c, alpha, beta, gamma = Cell.params(rcell1) if ( gamma == min(alpha, beta, gamma) and compare_numerically(gamma, ">=", 90.0) or (gamma == max(alpha, beta, gamma) and compare_numerically(gamma, "<=", 90.0)) ): S2 = np.eye(3, dtype=float) elif ( beta == min(alpha, beta, gamma) and compare_numerically(beta, ">=", 90.0) or (beta == max(alpha, beta, gamma) and compare_numerically(beta, "<=", 90.0)) ): S2 = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]], dtype=float) elif ( alpha == min(alpha, beta, gamma) and compare_numerically(alpha, ">=", 90.0) or (alpha == max(alpha, beta, gamma) and compare_numerically(alpha, "<=", 90.0)) ): S2 = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]], dtype=float) else: raise StandardizationTypeMismatch("triclinic", step="Second") return S2 @ S1