"""Lattice reduction operations."""
# Copyright (C) 2015 Atsushi Togo
# This file is part of spglib.
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import numpy as np
from numpy.typing import ArrayLike
from . import _spglib
from .error import _set_no_error, _set_or_throw_error
__all__ = [
"delaunay_reduce",
"niggli_reduce",
]
[docs]
def delaunay_reduce(
lattice: ArrayLike[np.double], eps: float = 1e-5
) -> np.ndarray | None:
r"""Run Delaunay reduction. When the search failed, `None` is returned.
The transformation from original basis vectors
:math:`( \mathbf{a} \; \mathbf{b} \; \mathbf{c} )`
to final basis vectors :math:`( \mathbf{a}' \; \mathbf{b}' \; \mathbf{c}' )` is achieved by linear
combination of basis vectors with integer coefficients without
rotating coordinates. Therefore the transformation matrix is obtained
by :math:`\mathbf{P} = ( \mathbf{a} \; \mathbf{b} \; \mathbf{c} ) ( \mathbf{a}' \; \mathbf{b}' \; \mathbf{c}' )^{-1}` and the matrix
elements have to be almost integers.
The algorithm is found in the international tables for crystallography volume A.
Parameters
----------
lattice: ndarray, (3, 3)
Lattice parameters in the form of
.. code-block::
[[a_x, a_y, a_z],
[b_x, b_y, b_z],
[c_x, c_y, c_z]]
eps: float
Tolerance parameter, but unlike `symprec` the unit is not a length.
Tolerance to check if volume is close to zero or not and
if two basis vectors are orthogonal by the value of dot
product being close to zero or not.
Returns
-------
delaunay_lattice: ndarray, (3, 3)
Reduced lattice parameters are given as a numpy 'double' array:
.. code-block::
[[a_x, a_y, a_z],
[b_x, b_y, b_z],
[c_x, c_y, c_z]]
Notes
-----
.. versionadded:: 1.9.4
""" # noqa: E501
_set_no_error()
delaunay_lattice = np.array(np.transpose(lattice), dtype="double", order="C")
try:
_spglib.delaunay_reduce(delaunay_lattice, float(eps))
except Exception as exc:
_set_or_throw_error(exc)
return None
return np.array(np.transpose(delaunay_lattice), dtype="double", order="C")
[docs]
def niggli_reduce(
lattice: ArrayLike[np.double], eps: float = 1e-5
) -> np.ndarray | None:
r"""Run Niggli reduction. When the search failed, ``None`` is returned.
The transformation from original basis vectors :math:`( \mathbf{a} \; \mathbf{b} \; \mathbf{c} )` to final basis vectors :math:`( \mathbf{a}' \; \mathbf{b}' \; \mathbf{c}' )` is achieved by linear
combination of basis vectors with integer coefficients without
rotating coordinates. Therefore the transformation matrix is obtained
by :math:`\mathbf{P} = ( \mathbf{a} \; \mathbf{b} \; \mathbf{c} ) ( \mathbf{a}' \; \mathbf{b}' \; \mathbf{c}' )^{-1}` and the matrix
elements have to be almost integers.
The algorithm detail is found at https://atztogo.github.io/niggli/ and
the references are there in.
Parameters
----------
lattice: ndarray
Lattice parameters in the form of
.. code-block::
[[a_x, a_y, a_z],
[b_x, b_y, b_z],
[c_x, c_y, c_z]]
eps: float
Tolerance parameter, but unlike `symprec` the unit is not a length.
This is used to check if difference of norms of two basis
vectors is close to zero or not and if two basis vectors are
orthogonal by the value of dot product being close to zero or
not.
The detail is shown at https://atztogo.github.io/niggli/.
Returns
-------
niggli_lattice: ndarray, (3, 3)
if the Niggli reduction succeeded:
Reduced lattice parameters are given as a numpy 'double' array:
.. code-block::
[[a_x, a_y, a_z],
[b_x, b_y, b_z],
[c_x, c_y, c_z]]
otherwise None is returned.
Notes
-----
.. versionadded:: 1.9.4
""" # noqa: E501
_set_no_error()
niggli_lattice = np.array(np.transpose(lattice), dtype="double", order="C")
try:
_spglib.niggli_reduce(niggli_lattice, float(eps))
except Exception as exc:
_set_or_throw_error(exc)
return None
return np.array(np.transpose(niggli_lattice), dtype="double", order="C")