Source code for fenicsx_pulse.units

from dataclasses import dataclass, field
from typing import Any, Generic, TypeVar

import dolfinx
import numpy as np
import pint

ureg = pint.UnitRegistry()
T = TypeVar("T", bound=float | dolfinx.fem.Function | dolfinx.fem.Constant)


def mesh_factor(mesh_unit: str) -> float:
    return ureg(mesh_unit).to_base_units().magnitude


def assign(variable: "Variable", value) -> None:
    if isinstance(variable.value, (float, int)) or np.isscalar(variable.value):
        variable.value = value
    elif isinstance(variable.value, dolfinx.fem.Function):
        if isinstance(value, (float, int, np.ndarray)) or np.isscalar(value):
            variable.value.x.array[:] = value
        elif isinstance(value, dolfinx.fem.Function):
            variable.value.x.array[:] = value.x.array
        else:
            raise ValueError(f"Cannot assign value of type {type(value)}")
    elif isinstance(variable.value, dolfinx.fem.Constant):
        variable.value.value = value
    else:
        raise ValueError(f"Cannot assign value of type {type(variable.value)}")


[docs] @dataclass(slots=True) class Variable(Generic[T]): value: T unit: pint.Unit | str | None original_unit: pint.Unit = field(init=False, repr=False) original_value: T = field(init=False, repr=False) factor: float = field(init=False, repr=False) def __post_init__(self): # Check unit if isinstance(self.unit, str): self.original_unit = ureg(self.unit).units elif self.unit is None: self.original_unit = ureg.dimensionless else: self.original_unit = self.unit quantity = (1 * self.original_unit).to_base_units() self.factor = quantity.magnitude self.unit = quantity.units def to_base_units(self) -> float | Any: return self.value * self.factor def __str__(self) -> str: return f"{self.to_base_units()} {self.unit} ({self.value} {self.original_unit})" @classmethod def from_quantity(cls, quantity: pint.Quantity) -> "Variable": return cls(quantity.magnitude, quantity.units) def assign(self, value) -> None: assign(self, value)