Source code for httk.atomistic.models.structuretype.fundamental

"""The standard-setting dummy-species fundamental-domain value."""

from collections.abc import Sequence
from functools import cached_property
from typing import TYPE_CHECKING, Any, ClassVar

from httk.atomistic.models.cell.cell import Cell
from httk.atomistic.models.cell.like import CellLike
from httk.atomistic.models.cell.view import CellView
from httk.atomistic.models.formula.notation import anonymous_symbol
from httk.atomistic.models.sites.sites import Sites
from httk.atomistic.models.species.like import SpeciesLike
from httk.atomistic.models.species.species import Species
from httk.atomistic.models.species.view import SpeciesView
from httk.atomistic.models.structure.asu import FundamentalDomainStructure, WyckoffSite
from httk.atomistic.models.structuretype.anonymize import dummy_species, is_dummy_species
from httk.atomistic.models.structuretype.backend import StructuretypeBackend
from httk.atomistic.symmetry._periodicity_guard import require_full_periodicity
from httk.atomistic.symmetry.setting_transform import SettingTransform
from httk.atomistic.symmetry.spacegroup import Spacegroup

if TYPE_CHECKING:
    from httk.atomistic.models.bareprototype.bareprototype import BarePrototype


[docs] class FundamentalDomainTemplate(StructuretypeBackend): """Store a standard-setting fundamental domain with dummy species labels. ``FundamentalDomainTemplate`` is the fundamental-domain member of the ``Structuretype`` family, the anonymous-species, exact-geometry cell used as a representative for :class:`~httk.atomistic.models.bareprototype.bareprototype.BarePrototype`. :param cell: The standard-setting cell geometry. :param spacegroup: The standard-setting space group. :param wyckoff_sites: The symmetry-distinct site definitions. :param species: The distinct dummy species definitions. :param coordinate_precision: The precision recorded for the reduced coordinates. """ _cell: Cell _spacegroup: Spacegroup _wyckoff_sites: tuple[WyckoffSite, ...] _species: tuple[Species, ...] _coordinate_precision: Any kind: ClassVar[str] = "asu" def __init__( self, cell: CellLike, spacegroup: Spacegroup | int, wyckoff_sites: Sequence[WyckoffSite], species: Sequence[SpeciesLike] | None = None, coordinate_precision: Any = None, ) -> None: self._cell = cell if isinstance(cell, Cell) else CellView(cell) require_full_periodicity(self._cell, "FundamentalDomainTemplate") self._spacegroup = spacegroup if isinstance(spacegroup, Spacegroup) else Spacegroup.standard(spacegroup) if not self._spacegroup.is_standard_setting: raise ValueError( f"FundamentalDomainTemplate records Wyckoff data in the IT standard setting, but was given " f"{self._spacegroup.setting}; pass Spacegroup.standard({self._spacegroup.it_number}) " "and express the difference as the transform instead" ) raw_sites = tuple(wyckoff_sites) labels = tuple(site.species for site in raw_sites) if species is None: norm_species = tuple(dummy_species(label) for label in dict.fromkeys(labels)) else: norm_species = tuple(value if isinstance(value, Species) else SpeciesView(value) for value in species) if len({value.name for value in norm_species}) != len(norm_species): raise ValueError("FundamentalDomainTemplate species names must be unique") if any(not is_dummy_species(value) for value in norm_species): raise ValueError("FundamentalDomainTemplate species must be dummy species") known = {value.name for value in norm_species} for site in raw_sites: if site.representative is not None: raise ValueError("FundamentalDomainTemplate WyckoffSite representative is not supported") if site.moment is not None: raise ValueError("FundamentalDomainTemplate WyckoffSite moment is not supported") if site.species not in known: raise ValueError( f"FundamentalDomainTemplate WyckoffSite references unknown species name: {site.species!r}" ) position = self._spacegroup.wyckoff_position(site.wyckoff) if site.free_count != position.free_count: raise ValueError( f"Wyckoff position {position.multiplicity}{position.letter} of {self._spacegroup.setting} " f"takes {position.free_count} free parameter(s), but the site supplies {site.free_count}" ) expected = {anonymous_symbol(index) for index in range(len(norm_species))} if {value.name for value in norm_species} != expected: raise ValueError("FundamentalDomainTemplate species labels must be consecutive anonymous symbols from 'A'") self._wyckoff_sites = tuple( sorted(raw_sites, key=lambda site: (site.species, site.wyckoff, site.free_params.to_fractions())) ) self._species = norm_species from httk.atomistic.models._vector_guards import to_precision self._coordinate_precision = to_precision(coordinate_precision) @property def cell(self) -> Cell: """Return the standard-setting cell.""" return self._cell @property def spacegroup(self) -> Spacegroup: """Return the standard-setting space group.""" return self._spacegroup @property def wyckoff_sites(self) -> tuple[WyckoffSite, ...]: """Return the symmetry-distinct site definitions.""" return self._wyckoff_sites @property def species(self) -> tuple[Species, ...]: """Return the distinct dummy species.""" return self._species @property def coordinate_precision(self): """Return the reduced-coordinate precision.""" return self._coordinate_precision @property def basis_precision(self): """Return the cell-basis precision.""" return self._cell.precision @cached_property def _domain(self) -> FundamentalDomainStructure: return FundamentalDomainStructure( self._cell, self._spacegroup, self._wyckoff_sites, self._species, transform=SettingTransform.identity(), coordinate_precision=self._coordinate_precision, ) @property def sites(self) -> Sites: """Return the expanded standard-setting sites.""" return self._domain.sites @property def species_at_sites(self) -> tuple[str, ...]: """Return dummy species names in expanded site order.""" return self._domain.species_at_sites @property def periodicity(self) -> tuple[bool, bool, bool]: """Return the periodic directions.""" return self._cell.periodicity @property def nperiodic_dimensions(self) -> int: """Return the number of periodic directions.""" return self._cell.nperiodic_dimensions @property def nsites(self) -> int: """Return the number of expanded sites.""" return len(self.sites)
[docs] def cartesian_sites(self) -> Any: """Return the exact Cartesian expanded site positions.""" return self._domain.cartesian_sites()
[docs] def multiplicities(self) -> tuple[int, ...]: """Return the standard-setting multiplicity for each Wyckoff site.""" return self._domain.multiplicities()
@property def nsites_conventional(self) -> int: """Return the number of sites in the conventional cell.""" return sum(self.multiplicities()) @cached_property def bare_prototype(self) -> "BarePrototype": """Return the anonymous prototype this fundamental domain folds to. The template keeps this domain's occupied Wyckoff letters and their dummy-species class partition; the exact geometry is discarded. The template's constructor re-canonicalizes the class labels by the pinned group-ordering rule. :return: The folded :class:`~httk.atomistic.models.bareprototype.bareprototype.BarePrototype`. """ from httk.atomistic.models.bareprototype.bareprototype import BarePrototype from httk.atomistic.models.prototype.occupation import PrototypeOccupation return BarePrototype( self._spacegroup, [PrototypeOccupation(site.wyckoff, site.species) for site in self._wyckoff_sites], ) def __eq__(self, other: object) -> bool: if not isinstance(other, FundamentalDomainTemplate): return NotImplemented return ( self._cell == other._cell and self.basis_precision == other.basis_precision and self._spacegroup == other._spacegroup and self._wyckoff_sites == other._wyckoff_sites and self._species == other._species and self.coordinate_precision == other.coordinate_precision ) def __repr__(self) -> str: return f"FundamentalDomainTemplate({self._spacegroup.setting!r}, wyckoff_sites={self._wyckoff_sites!r})"
[docs] class ASUTemplate(FundamentalDomainTemplate): """Assert that a fundamental-domain template is a true asymmetric unit. Mirror :class:`~httk.atomistic.models.structure.asu.ASUStructure`: mark a :class:`FundamentalDomainTemplate` whose Wyckoff sites are known to span a real asymmetric unit rather than merely a fundamental domain. The family exposes no ``site_coordinate_span`` hook, so this marker adds no state and inherits the fundamental-domain equality and representation. """