Source code for httk.atomistic.models.bareprotostructure.bareprotostructure
"""The immutable assigned-species Wyckoff-only classification value."""
from collections.abc import Sequence
from typing import Any, ClassVar
from httk.atomistic.models.bareprotostructure.backend import BareProtostructureBackend
from httk.atomistic.models.protostructure.occupation import WyckoffOccupation
from httk.atomistic.symmetry.spacegroup import Spacegroup
[docs]
class BareProtostructure(BareProtostructureBackend):
"""Store only standard-setting Wyckoff occupations, without geometrical refinement.
:param spacegroup: The standard-setting space group or its IT number.
:param occupations: Occupied Wyckoff positions and their assigned species.
"""
kind: ClassVar[str] = "bare_protostructure"
def __init__(
self, spacegroup: Spacegroup | int, occupations: Sequence[WyckoffOccupation | tuple[str, Any]]
) -> None:
self._spacegroup = spacegroup if isinstance(spacegroup, Spacegroup) else Spacegroup.standard(spacegroup)
if not self._spacegroup.is_standard_setting:
raise ValueError(
f"BareProtostructure records Wyckoff data in the IT standard setting, but was given "
f"{self._spacegroup.setting}; pass Spacegroup.standard({self._spacegroup.it_number}) "
"instead"
)
raw = tuple(
occupation if isinstance(occupation, WyckoffOccupation) else WyckoffOccupation(occupation[0], occupation[1])
for occupation in occupations
)
if not raw:
raise ValueError("BareProtostructure occupations must be non-empty")
species_by_name: dict[str, Any] = {}
for occupation in raw:
try:
self._spacegroup.wyckoff_position(occupation.wyckoff)
except KeyError as exc:
raise ValueError(str(exc)) from exc
previous = species_by_name.get(occupation.species.name)
if previous is not None and previous != occupation.species:
raise ValueError(
f"BareProtostructure occupations naming species {occupation.species.name!r} must carry equal Species"
)
species_by_name[occupation.species.name] = occupation.species
self._occupations = tuple(sorted(raw, key=lambda value: (value.species.name, value.wyckoff)))
@property
def spacegroup(self) -> Spacegroup:
"""Return the standard-setting space group."""
return self._spacegroup
@property
def occupations(self) -> tuple[WyckoffOccupation, ...]:
"""Return the canonical occupied Wyckoff positions."""
return self._occupations
def __eq__(self, other: object) -> bool:
if not isinstance(other, BareProtostructure):
return NotImplemented
return (self.spacegroup, self.occupations) == (other.spacegroup, other.occupations)
def __hash__(self) -> int:
return hash((self.spacegroup, self.occupations))
def __repr__(self) -> str:
pairs = ", ".join(f"{value.wyckoff}:{value.species.name}" for value in self.occupations)
return f"BareProtostructure({self.spacegroup.setting!r}, {pairs})"