Source code for httk.atomistic.asu_structure_view
"""A view presenting any structure as its asymmetric unit."""
from typing import Any, Self
from httk.core import unwrap
from .asu_recognition import recognize_asu
from .asu_structure import ASUStructure
from .setting_transform import SettingTransform
from .spacegroup import Spacegroup
from .structure_backend import StructureBackend
from .structure_like import StructureLike
from .structure_view import StructureView
[docs]
class ASUStructureView(StructureView, ASUStructure):
"""A view presenting an underlying structure backend as an :class:`~httk.atomistic.ASUStructure`.
This view is a genuine ASUStructure, so it can be passed anywhere one is accepted.
Unlike the other structure views, building it can require *work* rather than a change
of presentation: a backend that already carries an asymmetric unit is adopted as-is,
but a plain list of atoms has to have its symmetry recognized first. That step is
tolerant where everything else in this package is exact — see
:mod:`~httk.atomistic.asu_recognition` — and needs spglib unless the space group is
supplied through ``setting`` or ``standard``/``transform``.
``tolerance`` left unspecified is derived from how precisely the structure was stated.
"""
_backend: StructureBackend
def __new__(
cls,
obj: StructureLike,
*,
setting: Spacegroup | None = None,
standard: Spacegroup | None = None,
transform: SettingTransform | None = None,
tolerance: float | None = None,
**hints: Any,
) -> Self:
if isinstance(obj, cls):
return obj
backend = cls._prepare_backend(obj, hints)
# A backend that already holds an asymmetric unit is passed straight through: no
# recognition, no tolerance, nothing lost. The precedent is CellParamsView reading
# a backend's native parameters when it has them.
asu = getattr(backend, "asu", None)
if asu is None:
asu = recognize_asu(
backend,
setting=setting,
standard=standard,
transform=transform,
tolerance=tolerance,
)
instance = super().__new__(cls)
# ASUStructure is mutable, so its state is initialized here in __new__ (keeping
# __init__ a no-op), so that rewrapping an existing view does not re-initialize it.
ASUStructure.__init__(
instance,
asu.cell,
asu.spacegroup,
asu.asu_sites,
asu.species,
asu.transform,
asu.coordinate_precision,
)
instance._backend = backend
return instance
def __init__(self, obj: StructureLike, **kwargs: Any) -> None:
pass
[docs]
def unwrap(self) -> Any:
return unwrap(self._backend)