Source code for httk.atomistic.models.structure.numeric

"""Backend for numeric unitcell structure presentations."""

from fractions import Fraction
from typing import Any, Self

from httk.atomistic.models.cell.cell import Cell
from httk.atomistic.models.cell.numeric import NumericCell
from httk.atomistic.models.sites.numeric import NumericSites
from httk.atomistic.models.sites.sites import Sites
from httk.atomistic.models.species.species import Species
from httk.atomistic.models.structure.backend import StructureBackend
from httk.atomistic.models.structure.unitcell import UnitcellStructure


[docs] class NumericUnitcellStructure(StructureBackend): """Backend recognizing the plain-numpy structure quartet. The wrapped object must expose ``NumericCell``/``NumericSites`` values through ``cell``/``sites`` and the usual ``species``/``species_at_sites`` attributes. Its exact quartet is taken from an ``exact`` :class:`~httk.atomistic.models.structure.unitcell.UnitcellStructure` when available, then from the component presentations' ``exact`` values. If neither component carries an exact value, the numeric ``basis`` and ``reduced_coords`` arrays are passed through the vector family into ``Cell`` and ``Sites``. That last route is exact embedding of the floats: their binary float64 values, rather than their decimal spellings, become the exact values. :param obj: The numeric structure presentation to wrap. :param \\*\\*hints: Backend-selection hints. """ _object: Any _structure: UnitcellStructure @classmethod def _backend_adopt(cls, obj: Any, **hints: Any) -> Self | None: r"""Adopt a numeric structure presentation. :param obj: The source object to adopt. :param \**hints: Backend-selection hints. :return: An initialized backend, or ``None`` when this backend declines ``obj``. """ if hints.get("kind", "numeric") != "numeric": return None try: cell = obj.cell sites = obj.sites obj.species # noqa: B018 - deliberate attribute access validates the required field obj.species_at_sites # noqa: B018 - deliberate attribute access validates the required field except AttributeError: return None if not isinstance(cell, NumericCell) or not isinstance(sites, NumericSites): return None return cls(obj, **hints) def __init__(self, obj: Any, **hints: Any) -> None: self._object = obj exact = getattr(obj, "exact", None) if isinstance(exact, UnitcellStructure): self._structure = exact return cell = getattr(obj.cell, "exact", None) if not isinstance(cell, Cell): cell = Cell( obj.cell.basis, precision=getattr(obj.cell, "precision", None), periodicity=getattr(obj.cell, "periodicity", None), ) sites = getattr(obj.sites, "exact", None) if not isinstance(sites, Sites): sites = Sites( obj.sites.reduced_coords, precision=getattr(obj.sites, "precision", None), ) raw_charge = getattr(obj, "charge", None) self._structure = UnitcellStructure( cell, sites, obj.species, obj.species_at_sites, molecular=getattr(obj, "molecular", False), assemblies=getattr(obj, "assemblies", None), symmetry=getattr(obj, "symmetry", None), chemical_composition=getattr(obj, "chemical_composition", None), chemical_formula_descriptive=getattr(obj, "chemical_formula_descriptive", None), chemical_formula_hill=getattr(obj, "chemical_formula_hill", None), optimization_type=getattr(obj, "optimization_type", None), charge=None if raw_charge is None else Fraction(raw_charge), ) @property
[docs] def cell(self) -> Cell: """Expose the exact cell quartet component.""" return self._structure.cell
@property
[docs] def sites(self) -> Sites: """Expose the exact sites quartet component.""" return self._structure.sites
@property
[docs] def species(self) -> tuple[Species, ...]: """Expose the exact structure's distinct species.""" return self._structure.species
@property
[docs] def species_at_sites(self) -> tuple[str, ...]: """Expose the exact species name for each site.""" return self._structure.species_at_sites
@property
[docs] def charge(self) -> Fraction | None: """Expose the explicitly assigned exact charge.""" return self._structure.charge
[docs] def unwrap(self) -> Any: """Return the wrapped numeric presentation object.""" return self._object