Source code for r2x_core.units

"""Unit handling for power system models.

This module provides unit-aware field annotations, automatic conversion between
natural units and per-unit values, and configurable display formatting.

Notes
-----
* Annotate numeric fields with ``Annotated[float, Unit("kV"|"MVA"|"pu", base="base_field")]``
* Natural-unit inputs (``{"value": 138, "unit": "kV"}``) are converted to per-unit when ``base`` is set
* Internal storage is always float (device-base per-unit for relative quantities)
* Global display mode (device base, system base, or natural units) affects ``__repr__`` formatting only
"""

from __future__ import annotations

__all__ = [
    "HasPerUnit",
    "HasUnits",
    "Unit",
    "UnitSpec",
    "UnitSystem",
    "get_unit_system",
    "set_unit_system",
    "unit_spec",
    "unit_system",
    "ureg",
]

from collections.abc import Iterator
from contextlib import contextmanager
from enum import Enum

from ._mixins import HasPerUnit, HasUnits
from ._specs import Unit, UnitSpec, unit_spec
from ._utils import ureg


[docs] class UnitSystem(str, Enum): """Display modes for formatted representation. Attributes ---------- DEVICE_BASE : str Display per-unit values relative to device base SYSTEM_BASE : str Display per-unit values relative to system base NATURAL_UNITS : str Display values in their natural units (e.g., kV, MVA) """ DEVICE_BASE = "DEVICE_BASE" SYSTEM_BASE = "SYSTEM_BASE" NATURAL_UNITS = "NATURAL_UNITS"
_current_unit_system: UnitSystem = UnitSystem.DEVICE_BASE
[docs] def get_unit_system() -> UnitSystem: """Get the current global display mode. Returns ------- UnitSystem Current display mode """ return _current_unit_system
[docs] def set_unit_system(unit_system: UnitSystem) -> None: """Set the global display mode. Parameters ---------- unit_system : UnitSystem Display mode to set """ global _current_unit_system _current_unit_system = unit_system
[docs] @contextmanager def unit_system(mode: UnitSystem) -> Iterator[None]: """Context manager for temporary display mode changes. Parameters ---------- mode : UnitSystem Temporary display mode to use within the context Yields ------ None Examples -------- >>> gen = Generator(...) >>> with unit_system(UnitSystem.NATURAL_UNITS): ... print(gen) # Displays in natural units >>> print(gen) # Back to previous mode """ previous = get_unit_system() set_unit_system(mode) try: yield finally: set_unit_system(previous)