Source code for kbkit.schema.property_result
"""Structured representation of scalar properties with units and semantic tags."""
from dataclasses import dataclass
from typing import Any
import numpy as np
from kbkit.config.unit_registry import load_unit_registry
[docs]
@dataclass
class PropertyResult:
"""
Container for calculated thermodynamic properties with metadata.
Parameters
----------
name : str
Name of the property (e.g., "density", "kbi", "activity_coefficient")
value : np.ndarray
Calculated property values.
property_type : str, optional
Type of property calculated.
units : str, optional
Units of the property (e.g., "kg/m^3", "kJ/mol").
metadata : dict
Additional calculation metadata (e.g., mixing rules, KBI metadata).
"""
name: str
value: np.ndarray
metadata: dict[str, Any] | None = None
property_type: str | None = None
units: str | None = None
def __post_init__(self):
"""Validate inputs after initialization."""
if not isinstance(self.value, np.ndarray):
self.value = np.asarray(self.value)
if self.metadata is None:
self.metadata = {}
[docs]
def to(self, units: str) -> "PropertyResult":
"""
Convert property to desired units.
For KBI properties, also converts KBIMetadata values.
Parameters
----------
units : str
Target units for conversion.
Returns
-------
PropertyResult
New PropertyResult with converted values and units.
"""
if self.units is None:
raise ValueError(
f"Cannot convert PropertyResult '{self.name}' without units. Original units were not specified."
)
if units == self.units:
# No conversion needed, return self
return self
ureg = load_unit_registry()
try:
# Convert the main value
quantity = ureg.Quantity(self.value, self.units)
new_value = quantity.to(units).magnitude
except Exception as e:
raise ValueError(f"Cannot convert '{self.name}' from '{self.units}' to '{units}': {e}") from e
# Return a new PropertyResult with converted values
return PropertyResult(
name=self.name, value=new_value, property_type=self.property_type, units=units, metadata=self.metadata
)
def __repr__(self) -> str:
"""String representation of PropertyResult."""
value_str = f"shape={self.value.shape}" if self.value.ndim > 0 else f"value={self.value}"
units_str = f", units='{self.units}'" if self.units else ""
type_str = f", type='{self.property_type}'" if self.property_type else ""
return f"PropertyResult(name='{self.name}', {value_str}{units_str}{type_str})"
def __str__(self) -> str:
"""User-friendly string representation."""
return f"{self.name}: {self.value} {self.units or '(dimensionless)'}"