Source code for httk.atomistic.sites
"""
The Sites class for httk-atomistic.
"""
from collections.abc import Iterator
from typing import TYPE_CHECKING
from httk.core import FracVector, VectorLike
from ._vector_guards import to_fracvector
if TYPE_CHECKING:
from .numeric_sites import NumericSites
[docs]
class Sites:
"""
The sites of a crystal structure: the Nx3 matrix of reduced coordinates, held **exactly**.
Reduced (fractional) coordinates are the symmetry-native frame: point-group operations are
integer matrices and translations are rationals, so no radicals ever appear. They are therefore
stored as an exact rational :class:`~httk.core.FracVector` of shape ``(N, 3)``. A Sites object
is iterable and indexable over its length-3 coordinate rows (each a ``FracVector``), with
``len`` giving the number of sites.
Inputs embed exactly: rationals (and rational-valued floats), rational strings, and numpy arrays
all land on their exact rational value. An irrational :class:`~httk.core.SurdVector` input is
reduced deterministically through the vector family's ``fractions`` hub (never raising on data);
the exact Cartesian frame — where radicals belong — is obtained instead via
:meth:`~httk.atomistic.Structure.cartesian_sites`.
"""
_reduced_coords: FracVector
def __init__(self, reduced_coords: VectorLike) -> None:
coords = to_fracvector(reduced_coords)
if coords.dim != () and not (len(coords.dim) == 2 and coords.dim[1] == 3):
raise ValueError("Sites reduced_coords must be an Nx3 vector-like")
self._reduced_coords = coords
@property
[docs]
def reduced_coords(self) -> FracVector:
"""The Nx3 reduced site coordinates as an exact ``FracVector`` (one site per row)."""
return self._reduced_coords
def __len__(self) -> int:
return len(self._reduced_coords)
def __iter__(self) -> Iterator[FracVector]:
return iter(self._reduced_coords)
def __getitem__(self, index: int) -> FracVector:
return self._reduced_coords[index]
[docs]
def numeric(self) -> "NumericSites":
"""A plain-numpy presentation of these sites (requires the ``httk-atomistic[numpy]`` extra)."""
from .numeric_sites import NumericSites
return NumericSites(self)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Sites):
return NotImplemented
return self._reduced_coords == other._reduced_coords
def __repr__(self) -> str:
return f"Sites(reduced_coords={self._reduced_coords!r})"