Source code for chemics.gas

"""
Class for gas properties.
"""

import pandas as pd
from pathlib import Path

from .molecular_weight import molecular_weight


def _check_temperature(formula, temperature, limits):
    """
    Check that temperature is within the given limits otherwise raise an error.
    """
    tmin = limits[0]
    tmax = limits[1]
    if temperature < tmin or temperature > tmax:
        msg = f"Temperature {temperature} K is out of range {tmin}-{tmax} K for {formula} gas"
        raise ValueError(msg)


def _get_row(csv_file, formula, cas_number):
    """
    Construct path to CSV data file then get row from the dataframe.
    """
    path = Path(__file__).parent.absolute()
    df = pd.read_csv(path / csv_file)

    if cas_number:
        row = df.query(f"CAS == '{cas_number}'")
        if len(row) == 0:
            raise ValueError(f"CAS number {cas_number} not found")
    else:
        row = df.query(f"Formula == '{formula}'")
        if len(row) > 1:
            m = f"Multiple substances available for {formula}. Include CAS number too."
            raise ValueError(m)
        elif len(row) == 0:
            raise ValueError(f"Formula {formula} not found")

    return row


[docs] class Gas: """ Gas properties class. Parameters ---------- formula : str Molecular formula of the gas. temperature : float Temperature of the gas in kelvin (K). pressure : float, optional Pressure of the gas in pascal (Pa). Default value is 101,325 Pa for standard atmosphere. cas_number : str, optional CAS (Chemical Abstracts Service) number of the gas, may be required for some species. Attributes ---------- formula : str Molecular formula of the gas. temperature : float Temperature of the gas in kelvin (K). pressure : float Pressure of the gas in pascal (Pa). cas_number : str, optional CAS (Chemical Abstracts Service) number of the gas, may be required for some species. molecular_weight : float Molecular weight of the gas in g/mol. """ def __init__(self, formula, temperature, pressure=101325, cas_number=None): self.formula = formula self.temperature = temperature self.pressure = pressure self.cas_number = cas_number self.molecular_weight = molecular_weight(formula) # State of each correlation stored as a dictionary # The state is checked for subsequent runs to avoid lookup time # Expects a dictionary such as # state = {'method': 'yaws', 'coefficients': (1, 2, 3), 'limits': (200, 6000)} self._cp_state = {"method": None, "coefficients": None, "limits": None} self._k_state = {"method": None, "coefficients": None, "limits": None} self._mu_state = {"method": None, "coefficients": None, "limits": None}
[docs] def density(self): r""" Gas density. Calculate gas density using the molecular weight, pressure, and temperature of the gas. Returns ------- rho : float Density of the gas in kg/m\ :sup:`3`. Examples -------- >>> gas = cm.Gas('N2', 773) >>> gas.density() 0.4416... """ mw = self.molecular_weight / 1000 # convert g/mol to kg/mol r = 8.3145 # ideal gas constant in (m^3⋅Pa)/(K⋅mol) rho = (self.pressure * mw) / (r * self.temperature) return rho
[docs] def heat_capacity(self): r""" Gas heat capacity. Calculate gas heat capacity as a function of temperature using Yaws' coefficients [1]_. The CAS (Chemical Abstracts Service) number may be required for some species. .. math:: C_p = A + B\,T + C\,T^2 + D\,T^3 + E\,T^4 + F\,T^5 + G\,T^6 Raises ------ ValueError If provided CAS number is not found. ValueError If multiple substances found for given formula. ValueError If gas chemical formula not found. ValueError If given temperataure is out of range for calculation. Returns ------- cp : float Heat capacity of the gas in J/(mol⋅K). Examples -------- >>> gas = cm.Gas('CBrClF2', 700) >>> gas.heat_capacity() 97.4982... >>> gas = cm.Gas('C5H10O2', 850, cas_number='75-98-9') >>> gas.heat_capacity() 268.4920... >>> gas = cm.Gas('NO2', 900) >>> gas.heat_capacity() 51.0686... References ---------- .. [1] Carl L. Yaws. Heat capacity of gas Tables 39 and 40 in Yaws' Critical Property Data for Chemical Engineers and Chemists. Published by Knovel, 2014. """ # Use coefficients if already set from a previous run # This avoids lookup time when method is called multiple times if self._cp_state["method"] == "yaws": _check_temperature(self.formula, self.temperature, self._cp_state["limits"]) a, b, c, d, e, f, g = self._cp_state["coefficients"] cp = ( a + (b * self.temperature) + (c * self.temperature**2) + (d * self.temperature**3) + (e * self.temperature**4) + (f * self.temperature**5) + (g * self.temperature**6) ) return cp # Lookup coefficients then calculate heat capacity row = _get_row("data/gas-cp-yaws.csv", self.formula, self.cas_number) tmin = row["Tmin"].iloc[0] tmax = row["Tmax"].iloc[0] _check_temperature(self.formula, self.temperature, (tmin, tmax)) a = row["A"].iloc[0] b = row["B"].iloc[0] c = row["C"].iloc[0] d = row["D"].iloc[0] e = row["E"].iloc[0] f = row["F"].iloc[0] g = row["G"].iloc[0] cp = ( a + (b * self.temperature) + (c * self.temperature**2) + (d * self.temperature**3) + (e * self.temperature**4) + (f * self.temperature**5) + (g * self.temperature**6) ) self._cp_state = { "method": "yaws", "coefficients": (a, b, c, d, e, f, g), "limits": (tmin, tmax), } return cp
[docs] def thermal_conductivity(self): """ Gas thermal conductivity. Calculate gas thermal conductivity as a function of temperature using Yaws' coefficients [2]_. The CAS (Chemical Abstracts Service) number may be required for some species. Raises ------ ValueError If provided CAS number is not found. ValueError If multiple substances found for given formula. ValueError If gas chemical formula not found. ValueError If given temperataure is out of range for calculation. Returns ------- k : float Thermal conductivity of the gas in W/(m⋅K). Examples -------- >>> gas = cm.Gas('N2', 773) >>> gas.thermal_conductivity() 0.0535... >>> gas = cm.Gas('C18H38O', 920, cas_number='593-32-8') >>> gas.thermal_conductivity() 0.0417... References ---------- .. [2] Carl L. Yaws. Thermal Conductivity Gas Tables 84 and 85 in Yaws' Critical Property Data for Chemical Engineers and Chemists. Published by Knovel, 2014. """ # Use coefficients if already set from a previous run # This avoids lookup time when method is called multiple times if self._k_state["method"] == "yaws": _check_temperature(self.formula, self.temperature, self._k_state["limits"]) a, b, c, d = self._k_state["coefficients"] k = a + (b * self.temperature) + (c * self.temperature**2) + (d * self.temperature**3) return k # Lookup coefficients then calculate thermal conductivity row = _get_row("data/gas-k-yaws.csv", self.formula, self.cas_number) tmin = row["Tmin"].iloc[0] tmax = row["Tmax"].iloc[0] _check_temperature(self.formula, self.temperature, (tmin, tmax)) a = row["A"].iloc[0] b = row["B"].iloc[0] c = row["C"].iloc[0] d = row["D"].iloc[0] k = a + (b * self.temperature) + (c * self.temperature**2) + (d * self.temperature**3) self._k_state = {"method": "yaws", "coefficients": (a, b, c, d), "limits": (tmin, tmax)} return k
[docs] def viscosity(self, method="yaws"): r""" Gas viscosity. Calculate gas viscosity as a function of temperature using Ludwig's coefficients [3]_ or Yaws' coefficients [4]_. The CAS (Chemical Abstracts Service) number may be required for some species. The Ludwig coefficients are used with the following correlation .. math:: \mu = A + B\,T + C\,T^2 The Yaws coefficients are used with the following correlation .. math:: \mu = A + B\,T + C\,T^2 + D\,T^3 Parameters ---------- method : str, optional Method for determining coefficients, choose yaws or ludwig. Default method is yaws. Raises ------ ValueError If provided CAS number is not found. ValueError If multiple substances found for given formula. ValueError If gas chemical formula not found. ValueError If given temperataure is out of range for calculation. Returns ------- mu : float Gas viscosity in microPoise (μP). Examples -------- >>> gas = cm.Gas('CH4', 810) >>> gas.viscosity(method='yaws') 234.21... >>> gas = cm.Gas('C2Cl2F4', 900, cas_number='374-07-2') >>> gas.viscosity() 314.90... >>> gas = cm.Gas('H2', 404) >>> gas.viscosity() 113.18... >>> gas = cm.Gas('NH3', 850) >>> gas.viscosity(method='ludwig') 300.84... >>> gas = cm.Gas('C2H4O', 920, cas_number='75-07-0') >>> gas.viscosity(method='ludwig') 242.46... References ---------- .. [3] A. Kayode Coker. Table C-2 Viscosity of Gas in Ludwig's Applied Process Design for Chemical and Petrochemical Plants, Volume 2, 4th Edition. Elsevier, 2010. .. [4] Carl L. Yaws. Viscosity Gas Tables 80 and 81 in Yaws' Critical Property Data for Chemical Engineers and Chemists. Published by Knovel, 2014. """ # Use coefficients if already set from a previous run # This avoids lookup time when method is called multiple times if self._mu_state["method"] == "yaws": _check_temperature(self.formula, self.temperature, self._mu_state["limits"]) a, b, c, d = self._mu_state["coefficients"] mu = a + (b * self.temperature) + (c * self.temperature**2) + (d * self.temperature**3) return mu if self._mu_state["method"] == "ludwig": _check_temperature(self.formula, self.temperature, self._mu_state["limits"]) a, b, c = self._mu_state["coefficients"] mu = a + (b * self.temperature) + (c * self.temperature**2) return mu # Lookup coefficients then calculate viscosity if method == "yaws": row = _get_row("data/gas-viscosity-yaws.csv", self.formula, self.cas_number) elif method == "ludwig": row = _get_row("data/gas-viscosity-ludwig.csv", self.formula, self.cas_number) else: raise ValueError("Method not available. Choose yaws or ludwig.") tmin = row["Tmin"].iloc[0] tmax = row["Tmax"].iloc[0] _check_temperature(self.formula, self.temperature, (tmin, tmax)) if method == "yaws": a = row["A"].iloc[0] b = row["B"].iloc[0] c = row["C"].iloc[0] d = row["D"].iloc[0] mu = a + b * self.temperature + c * (self.temperature**2) + d * (self.temperature**3) coeffs = a, b, c, d elif method == "ludwig": a = row["A"].iloc[0] b = row["B"].iloc[0] c = row["C"].iloc[0] mu = a + (b * self.temperature) + (c * self.temperature**2) coeffs = a, b, c self._mu_state = {"method": method, "coefficients": coeffs, "limits": (tmin, tmax)} return mu