Source code for encomp.gases

"""
Functions related to gases: normal volume to mass conversion, compressibility, etc...

.. todo::
    Implement for humid air
"""

from typing import Any, Literal, cast, overload

from .constants import CONSTANTS
from .conversion import convert_volume_mass
from .fluids import Fluid
from .units import Quantity
from .utypes import (
    MT,
    Density,
    Mass,
    MassFlow,
    MolarMass,
    Pressure,
    Temperature,
    Volume,
    VolumeFlow,
)

# TODO: this module should use the NormalVolume and NormalVolumeFlow dimensionalities
# TODO: these type annotations and overloads are not correct

R = CONSTANTS.R


[docs] def ideal_gas_density( T: Quantity[Temperature, MT], P: Quantity[Pressure, MT], M: Quantity[MolarMass, MT], ) -> Quantity[Density, MT]: """ Returns the density :math:`\\rho` of an ideal gas. For an ideal gas, density is calculated from the ideal gas law: .. math:: \\rho = \\frac{p M}{R T} The gas constant :math:`R` is :math:`8.3144598 \\; \\frac{\\text{kg} \\, \\text{m}^2}{\\text{s}^2 \\, \\text{K} \\, \\text{mol}}`. Parameters ---------- T : Quantity[Temperature, MT] Temperature of the gas P : Quantity[Pressure, MT] Absolute pressure of the gas M : Quantity[MolarMass, MT] Molar mass of the gas Returns ------- Quantity[Density, MT] Density of the ideal gas at the specified temperature and pressure """ # directly from ideal gas law # override the inferred type here since it's sure to be Density rho = (P * M) / (R * T.to("K").unknown()) return rho.to("kg/m³").asdim(Density)
@overload def convert_gas_volume( V1: Quantity[VolumeFlow, Any], condition_1: (tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal["N", "S"]) = "N", condition_2: (tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal["N", "S"]) = "N", fluid_name: str = "Air", ) -> Quantity[Volume, Any]: ... @overload def convert_gas_volume( V1: Quantity[Volume, Any], condition_1: (tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal["N", "S"]) = "N", condition_2: (tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal["N", "S"]) = "N", fluid_name: str = "Air", ) -> Quantity[VolumeFlow, Any]: ...
[docs] def convert_gas_volume( V1: Quantity[Volume, Any] | Quantity[VolumeFlow, Any], condition_1: (tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal["N", "S"]) = "N", condition_2: (tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal["N", "S"]) = "N", fluid_name: str = "Air", ) -> Quantity[Volume, Any] | Quantity[VolumeFlow, Any]: """ Converts the volume :math:`V_1` (at :math:`T_1, P_1`) to :math:`V_2` (at :math:`T_1, P_1`). Uses compressibility factors from CoolProp. The values for :math:`T_i, P_i` are passed as a tuple using the parameter ``conditions_i``. Optionally, the literal 'N' or 'S' can be passed to indicate normal and standard conditions. Parameters ---------- V1 : Quantity[Volume, Any] | Quantity[VolumeFlow, Any] Volume or volume flow :math:`V_1` at condition 1 condition_1 : tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal['N', 'S'], optional Pressure and temperature at condition 1, by default 'N' condition_2 : tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] | Literal['N', 'S'], optional Pressure and temperature at condition 2, by default 'N' fluid_name : str, optional CoolProp name of the fluid, by default 'Air' Returns ------- Quantity[Volume, Any] | Quantity[VolumeFlow, Any] Volume or volume flow :math:`V_2` at condition 2 """ n_s_conditions = { "N": ( CONSTANTS.normal_conditions_pressure, CONSTANTS.normal_conditions_temperature, ), "S": ( CONSTANTS.standard_conditions_pressure, CONSTANTS.standard_conditions_temperature, ), } if condition_1 in ("N", "S"): condition_1 = n_s_conditions[condition_1] if condition_2 in ("N", "S"): condition_2 = n_s_conditions[condition_2] P1, T1 = condition_1 P2, T2 = condition_2 Z1 = Fluid(fluid_name, T=T1, P=P1).Z Z2 = Fluid(fluid_name, T=T2, P=P2).Z # from ideal gas law PV = nRT: n and R are constant # also considers compressibility factor Z V2 = V1 * (P1 / P2) * (T2.to("K") / T1.to("K")) * (Z2 / Z1) # volume at P2, T2 in same units as V1 return V2.to(V1.u) # pyright: ignore[reportArgumentType]
@overload def mass_to_normal_volume(mass: Quantity[Mass, MT], fluid_name: str = "Air") -> Quantity[Volume, MT]: ... @overload def mass_to_normal_volume(mass: Quantity[MassFlow, MT], fluid_name: str = "Air") -> Quantity[VolumeFlow, MT]: ...
[docs] def mass_to_normal_volume( mass: Quantity[Mass, MT] | Quantity[MassFlow, MT], fluid_name: str = "Air" ) -> Quantity[Volume, MT] | Quantity[VolumeFlow, MT]: """ Convert mass to normal volume. Parameters ---------- mass : Quantity[Mass, MT] | Quantity[MassFlow, MT] Input mass or mass flow fluid_name : str, optional Name of the fluid, by default 'Air' Returns ------- Quantity[Volume, MT] | Quantity[VolumeFlow, MT] Corresponding normal volume or normal volume flow """ rho = Fluid( fluid_name, P=CONSTANTS.normal_conditions_pressure, T=CONSTANTS.normal_conditions_temperature, ).D ret = convert_volume_mass(mass, rho=rho) return cast("Quantity[Volume, MT] | Quantity[VolumeFlow, MT]", ret)
@overload def mass_to_actual_volume( mass: Quantity[Mass, MT], condition: tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]], fluid_name: str = "Air", ) -> Quantity[Volume, MT]: ... @overload def mass_to_actual_volume( mass: Quantity[MassFlow, MT], condition: tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]], fluid_name: str = "Air", ) -> Quantity[VolumeFlow, MT]: ...
[docs] def mass_to_actual_volume( mass: Quantity[Mass, MT] | Quantity[MassFlow, MT], condition: tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]], fluid_name: str = "Air", ) -> Quantity[Volume, MT] | Quantity[VolumeFlow, MT]: """ Convert mass to actual volume. Parameters ---------- mass : Quantity[Mass, MT] | Quantity[MassFlow, MT] Input mass or mass flow condition : tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]] Condition at which to calculate the actual volume fluid_name : str, optional Name of the fluid, by default 'Air' Returns ------- Quantity[Volume, MT] | Quantity[VolumeFlow, MT] Corresponding actual volume or actual volume flow """ rho = Fluid(fluid_name, P=condition[0], T=condition[1]).D ret = convert_volume_mass(mass, rho=rho) return cast("Quantity[Volume, MT] | Quantity[VolumeFlow, MT]", ret)
@overload def mass_from_normal_volume(volume: Quantity[Volume, MT], fluid_name: str = "Air") -> Quantity[Mass, MT]: ... @overload def mass_from_normal_volume(volume: Quantity[VolumeFlow, MT], fluid_name: str = "Air") -> Quantity[MassFlow, MT]: ...
[docs] def mass_from_normal_volume( volume: Quantity[Volume, MT] | Quantity[VolumeFlow, MT], fluid_name: str = "Air" ) -> Quantity[Mass, MT] | Quantity[MassFlow, MT]: """ Convert normal volume to mass. Parameters ---------- volume : Quantity[Volume, MT] | Quantity[VolumeFlow, MT] Input normal volume or normal volume flow fluid_name : str, optional Name of the fluid, by default 'Air' Returns ------- Quantity[Mass, MT] | Quantity[MassFlow, MT] Corresponding mass or mass flow """ rho = Fluid( fluid_name, P=CONSTANTS.normal_conditions_pressure, T=CONSTANTS.normal_conditions_temperature, ).D ret = convert_volume_mass(volume, rho=rho) return cast("Quantity[Mass, MT] | Quantity[MassFlow, MT]", ret)
@overload def mass_from_actual_volume( volume: Quantity[Volume, MT], condition: tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]], fluid_name: str = "Air", ) -> Quantity[Mass, MT]: ... @overload def mass_from_actual_volume( volume: Quantity[VolumeFlow, MT], condition: tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]], fluid_name: str = "Air", ) -> Quantity[MassFlow, MT]: ...
[docs] def mass_from_actual_volume( volume: Quantity[Volume, MT] | Quantity[VolumeFlow, MT], condition: tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]], fluid_name: str = "Air", ) -> Quantity[Mass, MT] | Quantity[MassFlow, MT]: """ Convert actual volume to mass. Parameters ---------- volume : Quantity[Volume, MT] | Quantity[VolumeFlow, MT] Input actual volume or actual volume flow condition : tuple[Quantity[Pressure, MT], Quantity[Temperature, MT]] Condition at which to calculate the mass fluid_name : str, optional Name of the fluid, by default 'Air' Returns ------- Quantity[Mass, MT] | Quantity[MassFlow, MT] Corresponding mass or mass flow """ rho = Fluid(fluid_name, P=condition[0], T=condition[1]).D ret = convert_volume_mass(volume, rho=rho) return cast("Quantity[Mass, MT] | Quantity[MassFlow, MT]", ret)
@overload def actual_volume_to_normal_volume( volume: Quantity[Volume, Any], condition: tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]], fluid_name: str = "Air", ) -> Quantity[Volume, Any]: ... @overload def actual_volume_to_normal_volume( volume: Quantity[VolumeFlow, Any], condition: tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]], fluid_name: str = "Air", ) -> Quantity[VolumeFlow, Any]: ...
[docs] def actual_volume_to_normal_volume( volume: Quantity[Volume, Any] | Quantity[VolumeFlow, Any], condition: tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]], fluid_name: str = "Air", ) -> Quantity[Volume, Any] | Quantity[VolumeFlow, Any]: """ Convert actual volume to normal volume. Parameters ---------- volume : Quantity[Volume, Any] | Quantity[VolumeFlow, Any] Input actual volume or actual volume flow condition : tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] Condition at which to calculate the normal volume fluid_name : str, optional Name of the fluid, by default 'Air' Returns ------- Quantity[Volume, Any] | Quantity[VolumeFlow, Any] Corresponding normal volume or normal volume flow """ return convert_gas_volume(volume, condition_1=condition, condition_2="N", fluid_name=fluid_name)
@overload def normal_volume_to_actual_volume( volume: Quantity[Volume, Any], condition: tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]], fluid_name: str = "Air", ) -> Quantity[Volume, Any]: ... @overload def normal_volume_to_actual_volume( volume: Quantity[VolumeFlow, Any], condition: tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]], fluid_name: str = "Air", ) -> Quantity[VolumeFlow, Any]: ...
[docs] def normal_volume_to_actual_volume( volume: Quantity[Volume, Any] | Quantity[VolumeFlow, Any], condition: tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]], fluid_name: str = "Air", ) -> Quantity[Volume, Any] | Quantity[VolumeFlow, Any]: """ Convert normal volume to actual volume. Parameters ---------- volume : Quantity[Volume, Any] | Quantity[VolumeFlow, Any] Input normal volume or normal volume flow condition : tuple[Quantity[Pressure, Any], Quantity[Temperature, Any]] Condition at which to calculate the actual volume fluid_name : str, optional Name of the fluid, by default 'Air' Returns ------- Quantity[Volume, Any] | Quantity[VolumeFlow, Any] Corresponding actual volume or actual volume flow """ return convert_gas_volume(volume, condition_1="N", condition_2=condition, fluid_name=fluid_name)