Source code for httk.atomistic.models.formula.formula_view

"""Eager reduced-formula presentation view."""

from typing import TYPE_CHECKING, Any, Self, cast

from httk.core import unwrap

from httk.atomistic.models.formula.backend import ChemicalFormulaBackend
from httk.atomistic.models.formula.formula import ChemicalFormula
from httk.atomistic.models.formula.notation import parse_reduced_formula, reduced_coefficients, render_reduced
from httk.atomistic.models.formula.view_base import ChemicalFormulaViewBase

if TYPE_CHECKING:
    from httk.atomistic.models.formula.like import ChemicalFormulaLike


[docs] class ChemicalFormulaView(ChemicalFormulaViewBase, ChemicalFormula): r"""Present a complete composition as an eager canonical reduced formula. :param obj: The chemical-formula-like object to present. :param \*\*hints: Backend-selection hints. """ _backend: ChemicalFormulaBackend def __new__(cls, obj: "ChemicalFormulaLike", **hints: Any) -> Self: if isinstance(obj, cls): return obj backend = cls._prepare_backend(obj, hints) if backend.is_anonymous: raise ValueError("a chemical formula view cannot invent elements for anonymous labels") if not backend.complete: raise ValueError( 'composition is incomplete — species with unknown chemical symbol "X" cannot yield a formula' ) amounts = backend.amounts if not amounts: raise ValueError("an empty composition cannot yield a formula") if type(backend) is ChemicalFormula: text = str(backend) coefficients = backend._coefficients else: reduced = cast( tuple[int, ...], reduced_coefficients(tuple(value for _, value in amounts)), ) coefficients = tuple((element, count) for (element, _), count in zip(amounts, reduced)) text = render_reduced(coefficients) coefficients = parse_reduced_formula(text) instance = str.__new__(cls, text) instance._coefficients = coefficients instance._backend = backend return instance def __init__(self, obj: "ChemicalFormulaLike", **hints: Any) -> None: pass @property
[docs] def amounts(self): """Return the presented elemental amounts.""" return self._backend.amounts
@property
[docs] def uncertainties(self): """Return the presented amount precisions.""" return self._backend.uncertainties
@property
[docs] def complete(self): """Return whether the presented composition is complete.""" return self._backend.complete
@property
[docs] def exact(self): """Return whether the presented amounts are exact.""" return self._backend.exact
@property
[docs] def normalized(self): """Return whether the presented composition is normalized.""" return self._backend.normalized
@property
[docs] def normalization_status(self): """Return the presented composition's normalization status.""" return self._backend.normalization_status
@property
[docs] def diagnostics(self): """Return diagnostics associated with the presented composition.""" return self._backend.diagnostics
@property
[docs] def is_anonymous(self): """Return whether this formula uses anonymous labels.""" return False
[docs] def unview(self) -> ChemicalFormula: """Return the presented formula as a standalone value. :return: The canonical reduced formula value. """ backend = self._backend if type(backend) is ChemicalFormula: return backend return ChemicalFormula(str(self))
[docs] def unwrap(self) -> Any: """Return the raw object behind the backend. :return: The unwrapped source object. """ return unwrap(self._backend)