Source code for kmcpy.event.hop

"""Fast endpoint-state helpers for KMC hops."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import numpy as np


DEFAULT_HOP_STATE_CODES = (0, 1, 1, 0)
INVALID_STATE = -1


[docs] @dataclass(frozen=True) class HopStateLookup: """Precomputed mobile/vacancy state codes for each active site.""" mobile_state_by_site: np.ndarray vacancy_state_by_site: np.ndarray
[docs] @classmethod def from_active_site_order( cls, active_site_order, mobile_ion_specie: str, ) -> "HopStateLookup": """Build site-indexed state-code arrays from active-site metadata.""" mobile = np.full( active_site_order.active_site_count, INVALID_STATE, dtype=np.int64, ) vacancy = np.full( active_site_order.active_site_count, INVALID_STATE, dtype=np.int64, ) for active_index, primitive_index in enumerate( active_site_order.active_to_primitive ): allowed = active_site_order.allowed_species_by_primitive_site[ int(primitive_index) ] for state_index, specie_label in enumerate(allowed): if _is_mobile_label(specie_label, mobile_ion_specie): mobile[active_index] = int(state_index) if _is_vacancy_label(specie_label): vacancy[active_index] = int(state_index) return cls(mobile_state_by_site=mobile, vacancy_state_by_site=vacancy)
[docs] def annotate_event(self, event: Any) -> None: """Attach hot-loop state codes to an event in compact active-site space.""" from_site, to_site = event.mobile_ion_indices event.hop_state_codes = ( int(self.mobile_state_by_site[int(from_site)]), int(self.vacancy_state_by_site[int(to_site)]), int(self.vacancy_state_by_site[int(from_site)]), int(self.mobile_state_by_site[int(to_site)]), )
[docs] def annotate_event_lib(self, event_lib: Any) -> None: """Attach precomputed state codes to every event in an event library.""" for event in event_lib.events: self.annotate_event(event)
[docs] def event_direction(occupations: Any, event: Any) -> int: """Return +1, -1, or 0 using only endpoint integer state comparisons.""" from_site, to_site = event.mobile_ion_indices codes = getattr(event, "hop_state_codes", DEFAULT_HOP_STATE_CODES) from_occ = int(occupations[int(from_site)]) to_occ = int(occupations[int(to_site)]) return endpoint_direction_from_codes(from_occ, to_occ, codes)
[docs] def endpoint_direction_from_codes( from_occ: int, to_occ: int, codes: tuple[int, int, int, int], ) -> int: """Return direction from endpoint states and precomputed hop state codes.""" if from_occ == codes[0] and to_occ == codes[1]: return 1 if from_occ == codes[2] and to_occ == codes[3]: return -1 return 0
def _is_mobile_label(specie_label: str, mobile_ion_specie: str) -> bool: return str(specie_label) == str(mobile_ion_specie) def _is_vacancy_label(specie_label: str) -> bool: return str(specie_label) in {"X", "Vacancy", "vacancy", "Va", "VA"}