Source code for reactord.substance.substance

"""Substance module.

Class to define a substance for ReactorD library.
"""

from typing import Callable, Union

from dill import dumps, loads

import numpy as np
from numpy.typing import NDArray


from .symbolic import Symbolic
from .thermo_substance import thermo_substance_constructor


[docs]class Substance(Symbolic): """Substance object class. Class to define a substance object. Specific attributes definition will be required for the reactors, described in each reactor documentation. For example, an adiabatic reactor will require that substances define a heat capacity function for the substances, on the other hand, when using isothermic reactors this won't be necessary. Substance has the from_thermo_data_base alternative construction method. Substances objects can be saved as pickle files with the method to_pickle. substances can be loaded from a pickle file with the method from_pickle. Example: >>> water = Substance.from_thermo_data_base('water') >>> water.to_pickle('my_water_file') >>> water_pickle = water.from_pickle('my_water_file) Parameters ---------- name : str Name of the substance. molecular_weight : float, optional The molecular weight of the substance [g/mol], by default None. normal_boiling_point : float, optional The normal boiling point of the substance [K], by default None. normal_melting_point : float, optional The normal melting point of the substance [K], by default None. critical_temperature : float, optional The critical temperature of the substance [K], by default None. critical_pressure : float, optional The critical pressure of the substance [Pa], by default None. acentric_factor : float, optional The acentric factor of the substance, by default None. formation_enthalpy : float, optional Standard state molar enthalpy of formation [J/mol], by default None. formation_enthalpy_ig : float, optional Ideal-gas molar enthalpy of formation [J/mol], by default None. vaporization_enthalpy : Callable, optional A function that receives a temperature and returns the vaporization enthalpy at temperature [J/mol], by default None. sublimation_enthalpy : Callable, optional A function that receives temperature and returns the sublimation enthalpy at temperature [J/mol], by default None. volume_solid : Callable, optional A function that receives temperature and pressure, and returns the molar volume of the solid at temperature [m³/mol], by default None. volume_liquid : Callable, optional A function that receives temperature and pressure, and returns the molar volume of liquid at temperature and pressure [m³/mol], by default None. heat_capacity_solid : Callable, optional A function that receives temperature and pressure, and returns the heat capacity of the solid at temperature and pressure [J/mol/K], by default None. heat_capacity_liquid : Callable, optional A function that receives temperature and pressure, and returns the heat capacity of the liquid at temperature and pressure [J/mol/K], by default None. heat_capacity_gas : Callable, optional A function that receives temperature and pressure, and returns the ideal gas heat capacity at temperature and pressure [J/mol/K], by default None. thermal_conductivity_liquid : Callable, optional A function that receives temperature and pressure, and returns the thermal conductivity of the liquid at temperature and pressure [W/m/K], by default None. thermal_conductivity_gas : Callable, optional A function that receives temperature and pressure, and returns the thermal conductivity of the gas at temperature and pressure [W/m/K], by default None. viscosity_liquid : Callable, optional A function that receives temperature and pressure, and returns the viscosity of the liquid at temperature and pressure [Pa*s], by default None. viscosity_gas : Callable, optional A function that receives temperature and pressure, and returns the viscosity of gas at temperature and pressure [Pa*s], by default None. heat_capacity_solid_dt_integral: Callable, optional A function that receives temperature1, temperature2 and pressure, and returns the integral of the solid heat capacity over temperature1 and temperature2 at pressure, by default None. heat_capacity_liquid_dt_integral: Callable, optional A function that receives temperature1, temperature2 and pressure, and returns the integral of the liquid heat capacity over temperature1 and temperature2 at pressure, by default None. heat_capacity_gas_dt_integral: Callable, optional A function that receives temperature1, temperature2 and pressure, and returns the integral of the gas heat capacity over temperature1 and temperature2 at pressure, by default None. vectorize_functions: bool, optional When True, numpy.vectorize() is applied to the temperature and pressure Substance Callable paramaters on Substance object init, by default False. Attributes ---------- name : str Name of the substance, by default None. molecular_weight : float The molecular weight of the substance [g/mol], by default None. normal_boiling_point : float The normal boiling point of the substance [K], by default None. normal_melting_point : float The normal melting point of the substance [K], by default None. critical_temperature : float The critical temperature of the substance [K], by default None. critical_pressure : float The critical pressure of the substance [Pa], by default None. acentric_factor : float The acentric factor of the substance, by default None. formation_enthalpy : float Standard state molar enthalpy of formation [J/mol], by default None. formation_enthalpy_ig : float Ideal-gas molar enthalpy of formation [J/mol], by default None. vectorize_functions: bool When True, numpy.vectorize() is applied to the temperature and pressure Substance functions on Substance object init, by default False. """ def __init__( self, name: str, molecular_weight: float = None, normal_boiling_point: float = None, normal_melting_point: float = None, critical_temperature: float = None, critical_pressure: float = None, acentric_factor: float = None, formation_enthalpy: float = None, formation_enthalpy_ig: float = None, vaporization_enthalpy: Callable = None, sublimation_enthalpy: Callable = None, volume_solid: Callable = None, volume_liquid: Callable = None, heat_capacity_solid: Callable = None, heat_capacity_liquid: Callable = None, heat_capacity_gas: Callable = None, thermal_conductivity_liquid: Callable = None, thermal_conductivity_gas: Callable = None, viscosity_liquid: Callable = None, viscosity_gas: Callable = None, heat_capacity_solid_dt_integral: Callable = None, heat_capacity_liquid_dt_integral: Callable = None, heat_capacity_gas_dt_integral: Callable = None, vectorize_functions: bool = False, ) -> None: # Symbolic init super().__init__(names=name) # Pure compound properties: self.name = name self.molecular_weight = molecular_weight self.normal_boiling_point = normal_boiling_point self.normal_melting_point = normal_melting_point self.critical_temperature = critical_temperature self.critical_pressure = critical_pressure self.acentric_factor = acentric_factor self.formation_enthalpy = formation_enthalpy self.formation_enthalpy_ig = formation_enthalpy_ig # Vectorize option self.vectorize_functions = vectorize_functions # Temperature and pressure-dependent properties calculation functions: # numpy vectorization is not made by default if self.vectorize_functions: self._vaporization_enthalpy = np.vectorize( vaporization_enthalpy, signature="()->()" ) self._sublimation_enthalpy = np.vectorize( sublimation_enthalpy, signature="()->()" ) self._volume_solid = np.vectorize( volume_solid, signature="(),()->()" ) self._volume_liquid = np.vectorize( volume_liquid, signature="(),()->()" ) self._heat_capacity_solid = np.vectorize( heat_capacity_solid, signature="(),()->()" ) self._heat_capacity_liquid = np.vectorize( heat_capacity_liquid, signature="(),()->()" ) self._heat_capacity_gas = np.vectorize( heat_capacity_gas, signature="(),()->()" ) self._thermal_conductivity_liquid = np.vectorize( thermal_conductivity_liquid, signature="(),()->()" ) self._thermal_conductivity_gas = np.vectorize( thermal_conductivity_gas, signature="(),()->()" ) self._viscosity_liquid = np.vectorize( viscosity_liquid, signature="(),()->()" ) self._viscosity_gas = np.vectorize( viscosity_gas, signature="(),()->()" ) self._heat_capacity_solid_dt_integral = np.vectorize( heat_capacity_solid_dt_integral, signature="(),(),()->()" ) self._heat_capacity_liquid_dt_integral = np.vectorize( heat_capacity_liquid_dt_integral, signature="(),(),()->()" ) self._heat_capacity_gas_dt_integral = np.vectorize( heat_capacity_gas_dt_integral, signature="(),(),()->()" ) else: # No numpy vectorization if the user guaranties compatibility with # vectors as arguments. self._vaporization_enthalpy = vaporization_enthalpy self._sublimation_enthalpy = sublimation_enthalpy self._volume_solid = volume_solid self._volume_liquid = volume_liquid self._heat_capacity_solid = heat_capacity_solid self._heat_capacity_liquid = heat_capacity_liquid self._heat_capacity_gas = heat_capacity_gas self._thermal_conductivity_liquid = thermal_conductivity_liquid self._thermal_conductivity_gas = thermal_conductivity_gas self._viscosity_liquid = viscosity_liquid self._viscosity_gas = viscosity_gas self._heat_capacity_solid_dt_integral = ( heat_capacity_solid_dt_integral ) self._heat_capacity_liquid_dt_integral = ( heat_capacity_liquid_dt_integral ) self._heat_capacity_gas_dt_integral = heat_capacity_gas_dt_integral
[docs] @classmethod def from_thermo_database( cls, name: str, thermo_identification: str ) -> "Substance": """Substance instance from Bell Caleb's thermo library. Method that uses Bell Caleb's Thermo library to construct the Substance object. Cite: Caleb Bell and Contributors (2016-2021). Thermo: Chemical properties component of Chemical Engineering Design Library (ChEDL) https://github.com/CalebBell/thermo. Parameters ---------- name : str Name that will be assigned to the Substance object. thermo_identification : str Name or CAS number of the substance that would be used to search in the Thermo library. Returns ------- Substance Instantiated Substance object from thermo database. """ return thermo_substance_constructor(cls, name, thermo_identification)
[docs] @classmethod def from_pickle(cls, name_file: str) -> "Substance": """Read a dill Substance file and return the Substance object. Parameters ---------- name_file : str path/to/file. Returns ------- Substance : Substance Substance object. """ with open(name_file, "rb") as f: return loads(f.read())
[docs] def to_pickle(self, name_file: str) -> __file__: """Serialize an substance object with dill library. This method save an object substance as a file. Parameters ---------- name_file : str Name of file to save the substance object. Returns ------- _file_ A binary file with substance predefine object. """ with open(name_file, "wb") as f: f.write(dumps(self))
[docs] def vaporization_enthalpy( self, temperature: Union[float, NDArray[np.float64]] ) -> Union[float, NDArray[np.float64]]: """Return the vaporization enthalpy at a given temperature. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] Returns ------- Union[float, NDArray[np.float64]] Vaporization enthalpy. [J/mol] """ return self._vaporization_enthalpy(temperature)
[docs] def sublimation_enthalpy( self, temperature: Union[float, NDArray[np.float64]] ) -> Union[float, NDArray[np.float64]]: """Return the sublimation enthalpy at a given temperature. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] Returns ------- Union[float, NDArray[np.float64]] Sublimation enthalpy. [J/mol] """ return self._sublimation_enthalpy(temperature)
[docs] def fusion_enthalpy( self, temperature: Union[float, NDArray[np.float64]] ) -> Union[float, NDArray[np.float64]]: """Return the fusion enthalpy at a given temperature. Uses the sublimation and vaporization enthalpy functions for the fusion enthalpy calculations at a given temperature, by calculating the sublimation and vaporization enthalpy difference. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] Returns ------- Union[float, NDArray[np.float64]] Fusion enthalpy. [J/mol] """ fusion_h = self._sublimation_enthalpy( temperature ) - self._vaporization_enthalpy(temperature) return fusion_h
[docs] def volume_solid( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the solid molar volume at a given temperature and pressure. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Solid molar volume. [m³/mol] """ return self._volume_solid(temperature, pressure)
[docs] def volume_liquid( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the liquid molar volume at a given temperature and pressure. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Liquid molar volume. [m³/mol] """ return self._volume_liquid(temperature, pressure)
[docs] def heat_capacity_solid( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the pure solid heat capacity at a given temperature. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Solid heat capacity. [J/mol/K] """ return self._heat_capacity_solid(temperature, pressure)
[docs] def heat_capacity_liquid( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the pure liquid heat capacity at a given temperature. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Liquid heat capacity. [J/mol/K] """ return self._heat_capacity_liquid(temperature, pressure)
[docs] def heat_capacity_gas( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the ideal gas heat capacity at a given temperature. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Ideal gas heat capacity. [J/mol/K] """ return self._heat_capacity_gas(temperature, pressure)
[docs] def thermal_conductivity_liquid( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the liquid thermal conductivity. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Liquid thermal conductivity. [W/m/K] """ return self._thermal_conductivity_liquid(temperature, pressure)
[docs] def thermal_conductivity_gas( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the gas thermal conductivity. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Gas thermal conductivity. [W/m/K] """ return self._thermal_conductivity_gas(temperature, pressure)
[docs] def viscosity_liquid( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the pure liquid viscosity. Pure liquid viscosity at a given temperature and pressure. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Liquid viscosity. [Pa s] """ return self._viscosity_liquid(temperature, pressure)
[docs] def viscosity_gas( self, temperature: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: """Return the pure gas viscosity. Pure gas viscosity at a given temperature and pressure. Parameters ---------- temperature : Union[float, NDArray[np.float64]] Temperature. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Gas viscosity. [Pa s] """ return self._viscosity_gas(temperature, pressure)
[docs] def heat_capacity_solid_dt_integral( self, temperature1: Union[float, NDArray[np.float64]], temperature2: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: r"""Return the integral of solid heat capacity. Calculate the integral of solid heat capacity between temperature1 and temperature2 .. math:: \int_{T_1}^{T_2} {C_{p_{solid}} (T, P)} \mathrm{d}T | :math:`T_1`: temperature1. | :math:`T_2`: temperature2. | :math:`C_{p_{solid}} (T, P)`: solid heat capacity. Parameters ---------- temperature1 : Union[float, NDArray[np.float64]] Lower temperature integral bound. [K] temperature2 : Union[float, NDArray[np.float64]] Upper temperature integral bound. [K] pressure: Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Integral of solid heat capacity between temperature1 and temperature2. [J/mol] """ integral = self._heat_capacity_solid_dt_integral( temperature1, temperature2, pressure ) return integral
[docs] def heat_capacity_liquid_dt_integral( self, temperature1: Union[float, NDArray[np.float64]], temperature2: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: r"""Return the integral of liquid heat capacity. Calculate the definite integral of liquid heat capacity between temperature1 and temperature2 .. math:: \int_{T_1}^{T_2} {C_{p_{liquid}} (T, P)} \mathrm{d}T | :math:`T_1`: temperature1. | :math:`T_2`: temperature2. | :math:`C_{p_{liquid}} (T, P)`: liquid heat capacity. Parameters ---------- temperature1 : Union[float, NDArray[np.float64]] Lower temperature integral bound. [K] temperature2 : Union[float, NDArray[np.float64]] Upper temperature integral bound. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Definite integral of liquid heat capacity between temperature1 and temperature2. [J/mol] """ integral = self._heat_capacity_liquid_dt_integral( temperature1, temperature2, pressure ) return integral
[docs] def heat_capacity_gas_dt_integral( self, temperature1: Union[float, NDArray[np.float64]], temperature2: Union[float, NDArray[np.float64]], pressure: Union[float, NDArray[np.float64]], ) -> Union[float, NDArray[np.float64]]: r"""Return the integral of gas heat capacity. Calculate the definite integral of gas heat capacity between temperature1 and temperature2. .. math:: \int_{T_1}^{T_2} {C_{p_{gas}} (T, P)} \mathrm{d}T | :math:`T_1`: temperature1. | :math:`T_2`: temperature2. | :math:`C_{p_{gas}} (T, P)`: ideal gas heat capacity. Parameters ---------- temperature1 : Union[float, NDArray[np.float64]] Lower temperature integral bound. [K] temperature2 : Union[float, NDArray[np.float64]] Upper temperature integral bound. [K] pressure : Union[float, NDArray[np.float64]] Pressure. [Pa] Returns ------- Union[float, NDArray[np.float64]] Definite integral of gas heat capacity between temperature1 and temperature2. [J/mol] """ integral = self._heat_capacity_gas_dt_integral( temperature1, temperature2, pressure ) return integral