Source code for httk.atomistic.models.moments.crystalaxis
"""Crystal-axis per-site magnetic-moment backend and exact frame conversions."""
import fractions
from typing import Any
from httk.core import SurdVector, VectorLike
from httk.atomistic.models._vector_guards import to_precision, to_surdvector
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.moments.backend import SiteMomentsBackend
def _unit_axes(cell: Cell) -> SurdVector:
"""Return the exact matrix whose rows are the cell's unit lattice axes."""
basis = cell.basis
lengths = cell.lengths
rows = [[(basis._element((row, column)) / lengths[row])._as_scalar() for column in range(3)] for row in range(3)]
return SurdVector._from_scalar_grid(rows, (3, 3))
def _cartesian_to_crystalaxis(moments: SurdVector, cell: Cell) -> SurdVector:
"""Convert Cartesian rows to crystal-axis rows as ``moments * B^-1 * diag(lengths)``."""
scaled = moments * cell.basis.inv()
rows = [
[(scaled._element((row, column)) * cell.lengths[column])._as_scalar() for column in range(3)]
for row in range(scaled.dim[0])
]
return SurdVector._from_scalar_grid(rows, scaled.dim)
[docs]
class CrystalAxisSiteMoments(SiteMomentsBackend):
"""Moments along the unit lattice axes ``â``, ``b̂``, ``ĉ``, in Bohr magnetons."""
_crystalaxis_moments: SurdVector
_cell: Cell
def __init__(self, moments: VectorLike, cell: CellLike, precision: Any = None) -> None:
value = to_surdvector(moments)
if len(value.dim) != 2 or value.dim[1] != 3:
raise ValueError("CrystalAxisSiteMoments moments must be an Nx3 vector-like")
self._crystalaxis_moments = value
self._cell = cell if isinstance(cell, Cell) else CellView(cell)
self._precision = to_precision(precision)
@property
[docs]
def crystalaxis_moments(self) -> SurdVector:
"""The exact Nx3 moments along the cell's unit lattice axes."""
return self._crystalaxis_moments
@property
[docs]
def cell(self) -> Cell:
"""The cell defining the crystal-axis frame."""
return self._cell
@property
[docs]
def cartesian_moments(self) -> SurdVector:
"""The exact Cartesian moments, using rows ``moments * U``."""
return self._crystalaxis_moments * _unit_axes(self._cell)
@property
[docs]
def precision(self) -> fractions.Fraction | None:
return self._precision
def __len__(self) -> int:
return self._crystalaxis_moments.dim[0]
def __eq__(self, other: object) -> bool:
if not isinstance(other, CrystalAxisSiteMoments):
return NotImplemented
return self._crystalaxis_moments == other._crystalaxis_moments and self._cell == other._cell
def __repr__(self) -> str:
return f"CrystalAxisSiteMoments(moments={self._crystalaxis_moments!r}, cell={self._cell!r})"