# Copyright (c) ETH Zurich, SIS ID and HVL D-ITET
#
"""
Unit conversion, within in the same group of units, for example Kelvin <-> Celsius
"""
from __future__ import annotations
import logging
from abc import abstractmethod
from enum import Enum
from typing import Union
from hvl_ccb.utils.typing import ConvertableTypes
from .utils import preserve_type
logger = logging.getLogger(__name__)
[docs]
class Unit(Enum):
@classmethod
@abstractmethod
@preserve_type
def convert(cls, value: ConvertableTypes, source, target) -> ConvertableTypes:
pass # pragma: no cover
[docs]
class Temperature(Unit):
K = "K"
C = "C"
F = "F"
KELVIN = K
CELSIUS = C
FAHRENHEIT = F
@classmethod
@preserve_type
def convert(
cls,
value: ConvertableTypes,
source: Union[str, Temperature] = KELVIN,
target: Union[str, Temperature] = CELSIUS,
) -> ConvertableTypes:
try:
source = Temperature(source)
target = Temperature(target)
except ValueError:
logger.warning(
"One unit or both units for source and / or target temperature "
"are not valid."
)
raise ValueError
if source == target:
return value
# convert source to kelvin
if source == cls.CELSIUS:
value = value + 273.15 # type: ignore
elif source == cls.FAHRENHEIT:
value = (value - 32) / 1.8 + 273.15 # type: ignore
# convert kelvin to target
if target == cls.CELSIUS:
value = value - 273.15 # type: ignore
elif target == cls.FAHRENHEIT:
value = (value - 273.15) * 1.8 + 32 # type: ignore
return value
[docs]
class Pressure(Unit):
PA = "Pa"
BAR = "bar"
ATM = "atm"
PSI = "psi"
MMHG = "mmHg"
TORR = "torr"
PASCAL = PA
ATMOSPHERE = ATM
POUNDS_PER_SQUARE_INCH = PSI
MILLIMETER_MERCURY = MMHG
@classmethod
@preserve_type
def convert(
cls,
value: ConvertableTypes,
source: Union[str, Pressure] = BAR,
target: Union[str, Pressure] = PASCAL,
) -> ConvertableTypes:
try:
source = Pressure(source)
target = Pressure(target)
except ValueError:
logger.warning(
"One unit or both units for source and / or target pressure "
"are not valid."
)
raise ValueError
if source == target:
return value
# convert source to Pascal
if source == cls.BAR:
value = value * 1e5 # type: ignore
elif source == cls.ATMOSPHERE:
value = value * 101_325 # type: ignore
elif source == cls.TORR:
value = value * 101_325 / 760 # type: ignore
elif source == cls.MMHG:
value = value * 101_325 / 760 * 1.000_000_142_466 # type: ignore
elif source == cls.PSI:
value = value * 6_894.75728 # type: ignore
# convert from Pascal to target
if target == cls.BAR:
value = value / 1e5 # type: ignore
elif target == cls.ATMOSPHERE:
value = value / 101_325 # type: ignore
elif target == cls.TORR:
value = value / 101_325 * 760 # type: ignore
elif target == cls.MMHG:
value = value / 101_325 * 760 / 1.000_000_142_466 # type: ignore
elif target == cls.PSI:
value = value / 6_894.75728 # type: ignore
return value