Source code for thermo.thermal_conductivity

'''Chemical Engineering Design Library (ChEDL). Utilities for process modeling.
Copyright (C) 2016, 2017, 2018, 2019, 2020 Caleb Bell <Caleb.Andrew.Bell@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

This module contains implementations of :obj:`TPDependentProperty <thermo.utils.TPDependentProperty>`
representing liquid and vapor thermal conductivity. A variety of estimation
and data methods are available as included in the `chemicals` library.
Additionally liquid and vapor mixture thermal conductivity predictor objects
are implemented subclassing  :obj:`MixtureProperty <thermo.utils.MixtureProperty>`.

For reporting bugs, adding feature requests, or submitting pull requests,
please use the `GitHub issue tracker <https://github.com/CalebBell/thermo/>`_.


.. contents:: :local:

Pure Liquid Thermal Conductivity
================================
.. autoclass:: ThermalConductivityLiquid
    :members: calculate, calculate_P, test_method_validity, test_method_validity_P,
              name, property_max, property_min,
              units, Tmin, Tmax, ranked_methods, ranked_methods_P
    :undoc-members:
    :show-inheritance:
    :exclude-members:

The following variables are available to specify which method to use.

.. data:: COOLPROP
.. data:: DIPPR_PERRY_8E
.. data:: VDI_PPDS
.. data:: VDI_TABULAR
.. data:: GHARAGHEIZI_L
.. data:: SHEFFY_JOHNSON
.. data:: SATO_RIEDEL
.. data:: LAKSHMI_PRASAD
.. data:: BAHADORI_L
.. data:: NICOLA
.. data:: NICOLA_ORIGINAL

The following variables contain lists of available methods.

.. autodata:: thermal_conductivity_liquid_methods
.. autodata:: thermal_conductivity_liquid_methods_P

Pure Gas Thermal Conductivity
=============================
.. autoclass:: ThermalConductivityGas
    :members: calculate, calculate_P, test_method_validity, test_method_validity_P,
              name, property_max, property_min,
              units, ranked_methods, ranked_methods_P
    :undoc-members:
    :show-inheritance:
    :exclude-members:

.. autodata:: thermal_conductivity_gas_methods
.. autodata:: thermal_conductivity_gas_methods_P


Mixture Liquid Thermal Conductivity
===================================
.. autoclass:: ThermalConductivityLiquidMixture
    :members: calculate, test_method_validity,
              name, property_max, property_min,
              units, ranked_methods
    :undoc-members:
    :show-inheritance:
    :exclude-members:

.. autodata:: thermal_conductivity_liquid_mixture_methods

Mixture Gas Thermal Conductivity
================================
.. autoclass:: ThermalConductivityGasMixture
    :members: calculate, test_method_validity,
              name, property_max, property_min,
              units, Tmin, Tmax, ranked_methods
    :undoc-members:
    :show-inheritance:
    :exclude-members:

.. autodata:: thermal_conductivity_gas_mixture_methods

Pure Solid Thermal Conductivity
=============================
.. autoclass:: ThermalConductivitySolid
    :members: calculate
              name, property_max, property_min,
              units, ranked_methods
    :undoc-members:
    :show-inheritance:
    :exclude-members:

.. autodata:: thermal_conductivity_solid_methods

'''


__all__ = [
 'ThermalConductivityGasMixture', 'ThermalConductivityLiquidMixture',
 'MAGOMEDOV', 'DIPPR_9H', 'FILIPPOV', 'LINDSAY_BROMLEY',
 'thermal_conductivity_liquid_methods', 'ThermalConductivityLiquid',

 'thermal_conductivity_gas_methods',
 'thermal_conductivity_gas_methods_P', 'ThermalConductivityGas',

'GHARAGHEIZI_L', 'NICOLA', 'NICOLA_ORIGINAL', 'SATO_RIEDEL', 'SHEFFY_JOHNSON',
'BAHADORI_L', 'LAKSHMI_PRASAD', 'MISSENARD', 'DIPPR_9G',

'ThermalConductivitySolid',
]


from chemicals import miscdata, thermal_conductivity
from chemicals.dippr import EQ100, EQ102
from chemicals.miscdata import lookup_VDI_tabular_data
from chemicals.thermal_conductivity import (
    DIPPR9B,
    DIPPR9G,
    DIPPR9H,
    Bahadori_gas,
    Bahadori_liquid,
    Chung,
    Chung_dense,
    Eli_Hanley,
    Eli_Hanley_dense,
    Eucken,
    Eucken_modified,
    Filippov,
    Gharagheizi_gas,
    Gharagheizi_liquid,
    Lakshmi_Prasad,
    Lindsay_Bromley,
    Missenard,
    Nicola,
    Nicola_original,
    Sato_Riedel,
    Sheffy_Johnson,
    Stiel_Thodos_dense,
)
from chemicals.utils import mixing_simple, none_and_length_check
from fluids.constants import R
from fluids.numerics import horner, sqrt

from thermo import electrochem
from thermo.coolprop import CoolProp_failing_PT_flashes, CoolProp_T_dependent_property, PhaseSI, PropsSI, coolprop_dict, coolprop_fluids, has_CoolProp
from thermo.electrochem import thermal_conductivity_Magomedov
from thermo.heat_capacity import HeatCapacityGas
from thermo.utils import COOLPROP, DIPPR_PERRY_8E, HO1972, LINEAR, NEGLECT_P, REFPROP_FIT, VDI_PPDS, VDI_TABULAR, MixtureProperty, TDependentProperty, TPDependentProperty
from thermo.viscosity import ViscosityGas
from thermo.volume import VolumeGas

GHARAGHEIZI_L = 'GHARAGHEIZI_L'
NICOLA = 'NICOLA'
NICOLA_ORIGINAL = 'NICOLA_ORIGINAL'
SATO_RIEDEL = 'SATO_RIEDEL'
SHEFFY_JOHNSON = 'SHEFFY_JOHNSON'
BAHADORI_L = 'BAHADORI_L'
LAKSHMI_PRASAD = 'LAKSHMI_PRASAD'
MISSENARD = 'MISSENARD'
DIPPR_9G = 'DIPPR_9G'

thermal_conductivity_liquid_methods = [REFPROP_FIT, COOLPROP, DIPPR_PERRY_8E, VDI_PPDS,
                                       VDI_TABULAR, GHARAGHEIZI_L,
                                       SHEFFY_JOHNSON, SATO_RIEDEL,
                                       LAKSHMI_PRASAD, BAHADORI_L,
                                       NICOLA, NICOLA_ORIGINAL]
"""Holds all low-pressure methods available for the :obj:`ThermalConductivityLiquid`
class, for use in iterating over them."""

thermal_conductivity_liquid_methods_P = [COOLPROP, DIPPR_9G, MISSENARD, NEGLECT_P]
"""Holds all high-pressure methods available for the :obj:`ThermalConductivityLiquid`
class, for use in iterating over them."""

[docs]class ThermalConductivityLiquid(TPDependentProperty): r'''Class for dealing with liquid thermal conductivity as a function of temperature and pressure. For low-pressure (at 1 atm while under the vapor pressure; along the saturation line otherwise) liquids, there is one source of tabular information, one polynomial-based method, 7 corresponding-states estimators, and the external library CoolProp. For high-pressure liquids (also, <1 atm liquids), there are two corresponding-states estimator, and the external library CoolProp. Parameters ---------- CAS : str, optional The CAS number of the compound, [-] MW : float, optional Molecular weight, [g/mol] Tm : float, optional Melting point, [K] Tb : float, optional Boiling point, [K] Tc : float, optional Critical temperature, [K] Pc : float, optional Critical pressure, [Pa] omega : float, optional Acentric factor, [-] Hfus : float, optional Heat of fusion, [J/mol] load_data : bool, optional If False, do not load property coefficients from data sources in files [-] extrapolation : str or None None to not extrapolate; see :obj:`TDependentProperty <thermo.utils.TDependentProperty>` for a full list of all options, [-] method : str or None, optional If specified, use this method by default and do not use the ranked sorting; an exception is raised if this is not a valid method for the provided inputs, [-] Notes ----- To iterate over all methods, use the lists stored in :obj:`thermal_conductivity_liquid_methods` and :obj:`thermal_conductivity_liquid_methods_P` for low and high pressure methods respectively. Low pressure methods: **GHARAGHEIZI_L**: CSP method, described in :obj:`Gharagheizi_liquid <chemicals.thermal_conductivity.Gharagheizi_liquid>`. **SATO_RIEDEL**: CSP method, described in :obj:`Sato_Riedel <chemicals.thermal_conductivity.Sato_Riedel>`. **NICOLA**: CSP method, described in :obj:`Nicola <chemicals.thermal_conductivity.Nicola>`. **NICOLA_ORIGINAL**: CSP method, described in :obj:`Nicola_original <chemicals.thermal_conductivity.Nicola_original>`. **SHEFFY_JOHNSON**: CSP method, described in :obj:`Sheffy_Johnson <chemicals.thermal_conductivity.Sheffy_Johnson>`. **BAHADORI_L**: CSP method, described in :obj:`Bahadori_liquid <chemicals.thermal_conductivity.Bahadori_liquid>`. **LAKSHMI_PRASAD**: CSP method, described in :obj:`Lakshmi_Prasad <chemicals.thermal_conductivity.Lakshmi_Prasad>`. **DIPPR_PERRY_8E**: A collection of 340 coefficient sets from the DIPPR database published openly in [3]_. Provides temperature limits for all its fluids. :obj:`EQ100 <chemicals.dippr.EQ100>` is used for its fluids. **VDI_PPDS**: Coefficients for a equation form developed by the PPDS, published openly in [2]_. Covers a large temperature range, but does not extrapolate well at very high or very low temperatures. 271 compounds. **COOLPROP**: CoolProp external library; with select fluids from its library. Range is limited to that of the equations of state it uses, as described in [1]_. Very slow. **VDI_TABULAR**: Tabular data in [2]_ along the saturation curve; interpolation is as set by the user or the default. **REFPROP_FIT**: A series of higher-order polynomial fits to the calculated results from the equations implemented in REFPROP. High pressure methods: **DIPPR_9G**: CSP method, described in :obj:`DIPPR9G <chemicals.thermal_conductivity.DIPPR9G>`. Calculates a low-pressure thermal conductivity first from the low-pressure method. **MISSENARD**: CSP method, described in :obj:`Missenard <chemicals.thermal_conductivity.Missenard>`. Calculates a low-pressure thermal conductivity first from the low-pressure method. **COOLPROP**: CoolProp external library; with select fluids from its library. Range is limited to that of the equations of state it uses, as described in [1]_. Very slow, but unparalled in accuracy for pressure dependence. See Also -------- chemicals.thermal_conductivity.Sheffy_Johnson chemicals.thermal_conductivity.Sato_Riedel chemicals.thermal_conductivity.Lakshmi_Prasad chemicals.thermal_conductivity.Gharagheizi_liquid chemicals.thermal_conductivity.Nicola_original chemicals.thermal_conductivity.Nicola chemicals.thermal_conductivity.Bahadori_liquid chemicals.thermal_conductivity.DIPPR9G chemicals.thermal_conductivity.Missenard References ---------- .. [1] Bell, Ian H., Jorrit Wronski, Sylvain Quoilin, and Vincent Lemort. "Pure and Pseudo-Pure Fluid Thermophysical Property Evaluation and the Open-Source Thermophysical Property Library CoolProp." Industrial & Engineering Chemistry Research 53, no. 6 (February 12, 2014): 2498-2508. doi:10.1021/ie4033999. http://www.coolprop.org/ .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition. Berlin; New York:: Springer, 2010. .. [3] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook, Eighth Edition. McGraw-Hill Professional, 2007. ''' name = 'liquid thermal conductivity' units = 'W/m/K' interpolation_T = None """No interpolation transformation by default.""" interpolation_P = None """No interpolation transformation by default.""" interpolation_property = None """No interpolation transformation by default.""" interpolation_property_inv = None """No interpolation transformation by default.""" tabular_extrapolation_permitted = True """Allow tabular extrapolation by default.""" property_min = 0.0 """Mimimum valid value of liquid thermal conductivity.""" property_max = 200.0 """Maximum valid value of liquid thermal conductivity. Organics are normally well under 10, however liquid metals are much higher - cooper peaks at around 175.""" ranked_methods = [REFPROP_FIT, COOLPROP, DIPPR_PERRY_8E, VDI_PPDS, VDI_TABULAR, GHARAGHEIZI_L, SHEFFY_JOHNSON, SATO_RIEDEL, LAKSHMI_PRASAD, BAHADORI_L, NICOLA, NICOLA_ORIGINAL] """Default rankings of the low-pressure methods.""" ranked_methods_P = [COOLPROP, DIPPR_9G, MISSENARD, NEGLECT_P] """Default rankings of the high-pressure methods.""" custom_args = ('MW', 'Tm', 'Tb', 'Tc', 'Pc', 'omega', 'Hfus') def __init__(self, CASRN='', MW=None, Tm=None, Tb=None, Tc=None, Pc=None, omega=None, Hfus=None, extrapolation='linear', extrapolation_min=1e-4, **kwargs): self.CASRN = CASRN self.MW = MW self.Tm = Tm self.Tb = Tb self.Tc = Tc self.Pc = Pc self.omega = omega self.Hfus = Hfus if 'extrapolation_min' not in kwargs: kwargs['extrapolation_min'] = extrapolation_min super().__init__(extrapolation, **kwargs) def load_all_methods(self, load_data=True): r'''Method which picks out coefficients for the specified chemical from the various dictionaries and DataFrames storing it. All data is stored as attributes. This method also sets :obj:`Tmin`, :obj:`Tmax`, :obj:`all_methods` and obj:`all_methods_P` as a set of methods for which the data exists for. Called on initialization only. See the source code for the variables at which the coefficients are stored. The coefficients can safely be altered once the class is initialized. This method can be called again to reset the parameters. ''' self.all_methods = set() methods, methods_P = [], [NEGLECT_P] self.T_limits = T_limits = {} CASRN = self.CASRN if load_data and CASRN: if CASRN in miscdata.VDI_saturation_dict: Ts, props = lookup_VDI_tabular_data(CASRN, 'K (l)') self.add_tabular_data(Ts, props, VDI_TABULAR, check_properties=False) del self._method if has_CoolProp() and CASRN in coolprop_dict: CP_f = coolprop_fluids[CASRN] if CP_f.has_k: self.CP_f = CP_f methods.append(COOLPROP) methods_P.append(COOLPROP) T_limits[COOLPROP] = (self.CP_f.Tmin*1.001, self.CP_f.Tc*0.9999) if CASRN in thermal_conductivity.k_data_Perrys_8E_2_315.index: methods.append(DIPPR_PERRY_8E) C1, C2, C3, C4, C5, self.Perrys2_315_Tmin, self.Perrys2_315_Tmax = thermal_conductivity.k_values_Perrys_8E_2_315[thermal_conductivity.k_data_Perrys_8E_2_315.index.get_loc(CASRN)].tolist() self.Perrys2_315_coeffs = [C1, C2, C3, C4, C5] T_limits[DIPPR_PERRY_8E] = (self.Perrys2_315_Tmin, self.Perrys2_315_Tmax) if CASRN in thermal_conductivity.k_data_VDI_PPDS_9.index: A, B, C, D, E = thermal_conductivity.k_values_VDI_PPDS_9[thermal_conductivity.k_data_VDI_PPDS_9.index.get_loc(CASRN)].tolist() self.VDI_PPDS_coeffs = [A, B, C, D, E] self.VDI_PPDS_coeffs.reverse() methods.append(VDI_PPDS) T_limits[VDI_PPDS] = (1e-3, 1e4) if self.MW: methods.extend([BAHADORI_L, LAKSHMI_PRASAD]) T_limits[BAHADORI_L] = (1e-3, 1e4) T_limits[LAKSHMI_PRASAD] = (1e-3, 50.0*(131.0*sqrt(self.MW) + 2771.0)/(50.0*self.MW**0.5 + 197.0)) # Tmin and Tmax are not extended by these simple models, who often # give values of 0; BAHADORI_L even has 3 roots. # LAKSHMI_PRASAD works down to 0 K, and has an upper limit of # 50.0*(131.0*sqrt(M) + 2771.0)/(50.0*M**0.5 + 197.0) # where it becomes 0. if all([self.MW, self.Tm]): methods.append(SHEFFY_JOHNSON) T_limits[SHEFFY_JOHNSON] = (1e-3, self.Tm + 793.65) # Works down to 0, has a nice limit at T = Tm+793.65 from Sympy if all([self.Tb, self.Pc, self.omega]): methods.append(GHARAGHEIZI_L) Tmax = 10000. if self.Tc is None else self.Tc T_limits[GHARAGHEIZI_L] = (self.Tb, Tmax) # Chosen as the model is weird if all([self.Tc, self.Pc, self.omega]): methods.append(NICOLA) T_limits[NICOLA] = (0.01*self.Tc, self.Tc) if all([self.Tb, self.Tc]): methods.append(SATO_RIEDEL) T_limits[SATO_RIEDEL] = (0.01*self.Tb, self.Tc-0.1) if all([self.Hfus, self.Tc, self.omega]): methods.append(NICOLA_ORIGINAL) T_limits[NICOLA_ORIGINAL] = (0.01*self.Tc, self.Tc-0.1) if all([self.Tc, self.Pc]): methods_P.extend([DIPPR_9G, MISSENARD]) self.all_methods.update(methods) self.all_methods_P = set(methods_P) for m in self.ranked_methods_P: if m in self.all_methods_P: self.method_P = m break @staticmethod def _method_indexes(): '''Returns a dictionary of method: index for all methods that use data files to retrieve constants. The use of this function ensures the data files are not loaded until they are needed. ''' return {COOLPROP : [CAS for CAS in coolprop_dict if (coolprop_fluids[CAS].has_k and CAS not in CoolProp_failing_PT_flashes)], VDI_TABULAR: list(miscdata.VDI_saturation_dict.keys()), DIPPR_PERRY_8E: thermal_conductivity.k_data_Perrys_8E_2_315.index, VDI_PPDS: thermal_conductivity.k_data_VDI_PPDS_9.index, }
[docs] def calculate(self, T, method): r'''Method to calculate low-pressure liquid thermal conductivity at tempearture `T` with a given method. This method has no exception handling; see :obj:`T_dependent_property <thermo.utils.TDependentProperty.T_dependent_property>` for that. Parameters ---------- T : float Temperature of the liquid, [K] method : str Name of the method to use Returns ------- kl : float Thermal conductivity of the liquid at T and a low pressure, [W/m/K] ''' if method == SHEFFY_JOHNSON: kl = Sheffy_Johnson(T, self.MW, self.Tm) elif method == SATO_RIEDEL: kl = Sato_Riedel(T, self.MW, self.Tb, self.Tc) elif method == GHARAGHEIZI_L: kl = Gharagheizi_liquid(T, self.MW, self.Tb, self.Pc, self.omega) elif method == NICOLA: kl = Nicola(T, self.MW, self.Tc, self.Pc, self.omega) elif method == NICOLA_ORIGINAL: kl = Nicola_original(T, self.MW, self.Tc, self.omega, self.Hfus) elif method == LAKSHMI_PRASAD: kl = Lakshmi_Prasad(T, self.MW) elif method == BAHADORI_L: kl = Bahadori_liquid(T, self.MW) elif method == DIPPR_PERRY_8E: kl = EQ100(T, *self.Perrys2_315_coeffs) elif method == VDI_PPDS: kl = horner(self.VDI_PPDS_coeffs, T) elif method == COOLPROP: kl = CoolProp_T_dependent_property(T, self.CASRN, 'L', 'l') else: return self._base_calculate(T, method) return kl
[docs] def calculate_P(self, T, P, method): r'''Method to calculate pressure-dependent liquid thermal conductivity at temperature `T` and pressure `P` with a given method. This method has no exception handling; see :obj:`TP_dependent_property <thermo.utils.TPDependentProperty.TP_dependent_property>` for that. Parameters ---------- T : float Temperature at which to calculate liquid thermal conductivity, [K] P : float Pressure at which to calculate liquid thermal conductivity, [K] method : str Name of the method to use Returns ------- kl : float Thermal conductivity of the liquid at T and P, [W/m/K] ''' if method == DIPPR_9G: kl = self.T_dependent_property(T) kl = DIPPR9G(T, P, self.Tc, self.Pc, kl) elif method == MISSENARD: kl = self.T_dependent_property(T) kl = Missenard(T, P, self.Tc, self.Pc, kl) elif method == COOLPROP: kl = PropsSI('L', 'T', T, 'P', P, self.CASRN) else: return self._base_calculate_P(T, P, method) return kl
[docs] def test_method_validity(self, T, method): r'''Method to check the validity of a temperature-dependent low-pressure method. For CSP methods, the models **BAHADORI_L**, **LAKSHMI_PRASAD**, and **SHEFFY_JOHNSON** are considered valid for all temperatures. For methods **GHARAGHEIZI_L**, **NICOLA**, and **NICOLA_ORIGINAL**, the methods are considered valid up to 1.5Tc and down to 0 K. Method **SATO_RIEDEL** does not work above the critical point, so it is valid from 0 K to the critical point. For tabular data, extrapolation outside of the range is used if :obj:`tabular_extrapolation_permitted` is set; if it is, the extrapolation is considered valid for all temperatures. It is not guaranteed that a method will work or give an accurate prediction simply because this method considers the method valid. Parameters ---------- T : float Temperature at which to test the method, [K] method : str Name of the method to test Returns ------- validity : bool Whether or not a method is valid ''' if method == SATO_RIEDEL: if T > self.Tc: return False # Doesn't run, no lower limit though elif method in (GHARAGHEIZI_L, NICOLA, NICOLA_ORIGINAL): if T > self.Tc*1.5: return False # No lower limit, give a wide margin of acceptability here elif method == DIPPR_PERRY_8E: if T < self.Perrys2_315_Tmin or T > self.Perrys2_315_Tmax: return False elif method in (BAHADORI_L, LAKSHMI_PRASAD, SHEFFY_JOHNSON): pass # no limits at all elif method == VDI_PPDS: if self.Tc and T > self.Tc: return False elif method == COOLPROP: if T < self.CP_f.Tt or T > self.CP_f.Tc: return False else: return super().test_method_validity(T, method) return True
[docs] def test_method_validity_P(self, T, P, method): r'''Method to check the validity of a high-pressure method. For **COOLPROP**, the fluid must be both a liquid and under the maximum pressure of the fluid's EOS. **MISSENARD** has defined limits; between 0.5Tc and 0.8Tc, and below 200Pc. The CSP method **DIPPR_9G** is considered valid for all temperatures and pressures. For tabular data, extrapolation outside of the range is used if :obj:`tabular_extrapolation_permitted` is set; if it is, the extrapolation is considered valid for all temperatures and pressures. It is not guaranteed that a method will work or give an accurate prediction simply because this method considers the method valid. Parameters ---------- T : float Temperature at which to test the method, [K] P : float Pressure at which to test the method, [Pa] method : str Name of the method to test Returns ------- validity : bool Whether or not a method is valid ''' validity = True if method == MISSENARD: if T/self.Tc < 0.5 or T/self.Tc > 0.8 or P/self.Pc > 200: validity = False elif method == DIPPR_9G: if T < 0 or P < 0: validity = False elif method == COOLPROP: validity = PhaseSI('T', T, 'P', P, self.CASRN) in ['liquid', 'supercritical_liquid'] else: return super().test_method_validity_P(T, P, method) return validity
MAGOMEDOV = 'MAGOMEDOV' DIPPR_9H = 'DIPPR_9H' FILIPPOV = 'FILIPPOV' thermal_conductivity_liquid_mixture_methods = [MAGOMEDOV, DIPPR_9H, FILIPPOV, LINEAR] """Holds all mixing rules available for the :obj:`ThermalConductivityLiquidMixture` class, for use in iterating over them."""
[docs]class ThermalConductivityLiquidMixture(MixtureProperty): '''Class for dealing with thermal conductivity of a liquid mixture as a function of temperature, pressure, and composition. Consists of two mixing rule specific to liquid thremal conductivity, one coefficient-based method for aqueous electrolytes, and mole weighted averaging. Most but not all methods are shown in [1]_. Prefered method is :obj:`DIPPR_9H <chemicals.thermal_conductivity.DIPPR9H>` which requires mass fractions, and pure component liquid thermal conductivities. This is substantially better than the ideal mixing rule based on mole fractions, **LINEAR**. :obj:`Filippov <chemicals.thermal_conductivity.Filippov>` is of similar accuracy but applicable to binary systems only. Parameters ---------- CASs : str, optional The CAS numbers of all species in the mixture, [-] ThermalConductivityLiquids : list[ThermalConductivityLiquid], optional ThermalConductivityLiquid objects created for all species in the mixture, [-] MWs : list[float], optional Molecular weights of all species in the mixture, [g/mol] correct_pressure_pure : bool, optional Whether to try to use the better pressure-corrected pure component models or to use only the T-only dependent pure species models, [-] Notes ----- To iterate over all methods, use the list stored in :obj:`thermal_conductivity_liquid_mixture_methods`. **DIPPR_9H**: Mixing rule described in :obj:`DIPPR9H <chemicals.thermal_conductivity.DIPPR9H>`. **FILIPPOV**: Mixing rule described in :obj:`Filippov <chemicals.thermal_conductivity.Filippov>`; for two binary systems only. **MAGOMEDOV**: Coefficient-based method for aqueous electrolytes only, described in :obj:`thermo.electrochem.thermal_conductivity_Magomedov`. **LINEAR**: Mixing rule described in :obj:`mixing_simple <chemicals.utils.mixing_simple>`. See Also -------- chemicals.thermal_conductivity.DIPPR9H chemicals.thermal_conductivity.Filippov chemicals.thermal_conductivity.thermal_conductivity_Magomedov References ---------- .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. ''' name = 'liquid thermal conductivity' units = 'W/m/K' property_min = 0 """Mimimum valid value of liquid thermal conductivity.""" property_max = 10 """Maximum valid value of liquid thermal conductivity. Generous limit.""" ranked_methods = [MAGOMEDOV, DIPPR_9H, LINEAR, FILIPPOV] pure_references = ('ThermalConductivityLiquids',) pure_reference_types = (ThermalConductivityLiquid,) pure_constants = ('MWs', ) custom_args = pure_constants def __init__(self, CASs=[], ThermalConductivityLiquids=[], MWs=[], **kwargs): self.CASs = CASs self.ThermalConductivityLiquids = ThermalConductivityLiquids self.MWs = MWs super().__init__(**kwargs) def load_all_methods(self): r'''Method to initialize the object by precomputing any values which may be used repeatedly and by retrieving mixture-specific variables. All data are stored as attributes. This method also sets :obj:`Tmin`, :obj:`Tmax`, and :obj:`all_methods` as a set of methods which should work to calculate the property. Called on initialization only. See the source code for the variables at which the coefficients are stored. The coefficients can safely be altered once the class is initialized. This method can be called again to reset the parameters. ''' methods = [DIPPR_9H, LINEAR] if len(self.CASs) == 2: methods.append(FILIPPOV) if '7732-18-5' in self.CASs and len(self.CASs)>1: wCASs = [i for i in self.CASs if i != '7732-18-5'] if all(i in electrochem.Magomedovk_thermal_cond.index for i in wCASs): methods.append(MAGOMEDOV) self.wCASs = wCASs self.index_w = self.CASs.index('7732-18-5') self.all_methods = all_methods = set(methods) Tmins = [i.Tmin for i in self.ThermalConductivityLiquids if i.Tmin] Tmaxs = [i.Tmax for i in self.ThermalConductivityLiquids if i.Tmax] if Tmins: self.Tmin = max(Tmins) if Tmaxs: self.Tmax = max(Tmaxs)
[docs] def calculate(self, T, P, zs, ws, method): r'''Method to calculate thermal conductivity of a liquid mixture at temperature `T`, pressure `P`, mole fractions `zs` and weight fractions `ws` with a given method. This method has no exception handling; see :obj:`mixture_property <thermo.utils.MixtureProperty.mixture_property>` for that. Parameters ---------- T : float Temperature at which to calculate the property, [K] P : float Pressure at which to calculate the property, [Pa] zs : list[float] Mole fractions of all species in the mixture, [-] ws : list[float] Weight fractions of all species in the mixture, [-] method : str Name of the method to use Returns ------- k : float Thermal conductivity of the liquid mixture, [W/m/K] ''' if method == MAGOMEDOV: k_w = self.ThermalConductivityLiquids[self.index_w](T, P) ws = list(ws) ws.pop(self.index_w) return thermal_conductivity_Magomedov(T, P, ws, self.wCASs, k_w) if method == DIPPR_9H: ks = self.calculate_pures_corrected(T, P, fallback=True) return DIPPR9H(ws, ks) elif method == FILIPPOV: ks = self.calculate_pures_corrected(T, P, fallback=True) return Filippov(ws, ks) return super().calculate(T, P, zs, ws, method)
[docs] def test_method_validity(self, T, P, zs, ws, method): r'''Method to test the validity of a specified method for the given conditions. If **MAGOMEDOV** is applicable (electrolyte system), no other methods are considered viable. Otherwise, there are no easy checks that can be performed here. Parameters ---------- T : float Temperature at which to check method validity, [K] P : float Pressure at which to check method validity, [Pa] zs : list[float] Mole fractions of all species in the mixture, [-] ws : list[float] Weight fractions of all species in the mixture, [-] method : str Method name to use Returns ------- validity : bool Whether or not a specifid method is valid ''' if MAGOMEDOV in self.all_methods: if method in self.all_methods: return method == MAGOMEDOV if method in [LINEAR, DIPPR_9H, FILIPPOV]: return True return super().test_method_validity(T, P, zs, ws, method)
GHARAGHEIZI_G = 'GHARAGHEIZI_G' CHUNG = 'CHUNG' ELI_HANLEY = 'ELI_HANLEY' ELI_HANLEY_DENSE = 'ELI_HANLEY_DENSE' CHUNG_DENSE = 'CHUNG_DENSE' EUCKEN_MOD = 'EUCKEN_MOD' EUCKEN = 'EUCKEN' BAHADORI_G = 'BAHADORI_G' STIEL_THODOS_DENSE = 'STIEL_THODOS_DENSE' DIPPR_9B = 'DIPPR_9B' thermal_conductivity_gas_methods = [REFPROP_FIT, COOLPROP, DIPPR_PERRY_8E, VDI_PPDS, VDI_TABULAR, GHARAGHEIZI_G, DIPPR_9B, CHUNG, ELI_HANLEY, EUCKEN_MOD, EUCKEN, BAHADORI_G] """Holds all low-pressure methods available for the :obj:`ThermalConductivityGas` class, for use in iterating over them.""" thermal_conductivity_gas_methods_P = [COOLPROP, ELI_HANLEY_DENSE, CHUNG_DENSE, STIEL_THODOS_DENSE, NEGLECT_P] """Holds all high-pressure methods available for the :obj:`ThermalConductivityGas` class, for use in iterating over them."""
[docs]class ThermalConductivityGas(TPDependentProperty): r'''Class for dealing with gas thermal conductivity as a function of temperature and pressure. For gases at atmospheric pressure, there are 7 corresponding-states estimators, one source of tabular information, and the external library CoolProp. For gases under the fluid's boiling point (at sub-atmospheric pressures), and high-pressure gases above the boiling point, there are three corresponding-states estimators, and the external library CoolProp. Parameters ---------- CAS : str, optional The CAS number of the compound, [-] MW : float, optional Molecular weight, [g/mol] Tb : float, optional Boiling point, [K] Tc : float, optional Critical temperature, [K] Pc : float, optional Critical pressure, [Pa] Vc : float, optional Critical volume, [m^3/mol] Zc : float, optional Critical compressibility, [-] omega : float, optional Acentric factor, [-] dipole : float, optional Dipole moment of the fluid, [debye] Vmg : float or callable, optional Molar volume of the fluid at a pressure and temperature or callable for the same, [m^3/mol] Cpgm : float or callable, optional Molar constant-pressure heat capacity of the fluid at a pressure and temperature or callable for the same, [J/mol/K] mug : float or callable, optional Gas viscosity of the fluid at a pressure and temperature or callable for the same, [Pa*s] load_data : bool, optional If False, do not load property coefficients from data sources in files [-] extrapolation : str or None None to not extrapolate; see :obj:`TDependentProperty <thermo.utils.TDependentProperty>` for a full list of all options, [-] method : str or None, optional If specified, use this method by default and do not use the ranked sorting; an exception is raised if this is not a valid method for the provided inputs, [-] Notes ----- To iterate over all methods, use the lists stored in :obj:`thermal_conductivity_gas_methods` and :obj:`thermal_conductivity_gas_methods_P` for low and high pressure methods respectively. Low pressure methods: **GHARAGHEIZI_G**: CSP method, described in :obj:`Gharagheizi_gas <chemicals.thermal_conductivity.Gharagheizi_gas>`. **DIPPR_9B**: CSP method, described in :obj:`DIPPR9B <chemicals.thermal_conductivity.DIPPR9B>`. **CHUNG**: CSP method, described in :obj:`Chung <chemicals.thermal_conductivity.Chung>`. **ELI_HANLEY**: CSP method, described in :obj:`Eli_Hanley <chemicals.thermal_conductivity.Eli_Hanley>`. **EUCKEN_MOD**: CSP method, described in :obj:`Eucken_modified <chemicals.thermal_conductivity.Eucken_modified>`. **EUCKEN**: CSP method, described in :obj:`Eucken <chemicals.thermal_conductivity.Eucken>`. **BAHADORI_G**: CSP method, described in :obj:`Bahadori_gas <chemicals.thermal_conductivity.Bahadori_gas>`. **DIPPR_PERRY_8E**: A collection of 345 coefficient sets from the DIPPR database published openly in [3]_. Provides temperature limits for all its fluids. :obj:`chemicals.dippr.EQ102` is used for its fluids. **VDI_PPDS**: Coefficients for a equation form developed by the PPDS, published openly in [2]_. Covers a large temperature range, but does not extrapolate well at very high or very low temperatures. 275 compounds. **COOLPROP**: CoolProp external library; with select fluids from its library. Range is limited to that of the equations of state it uses, as described in [1]_. Very slow. **VDI_TABULAR**: Tabular data in [2]_ along the saturation curve; interpolation is as set by the user or the default. **REFPROP_FIT**: A series of higher-order polynomial fits to the calculated results from the equations implemented in REFPROP. High pressure methods: **STIEL_THODOS_DENSE**: CSP method, described in :obj:`Stiel_Thodos_dense <chemicals.thermal_conductivity.Stiel_Thodos_dense>`. Calculates a low-pressure thermal conductivity first. **ELI_HANLEY_DENSE**: CSP method, described in :obj:`Eli_Hanley_dense <chemicals.thermal_conductivity.Eli_Hanley_dense>`. Calculates a low-pressure thermal conductivity first. **CHUNG_DENSE**: CSP method, described in :obj:`Chung_dense <chemicals.thermal_conductivity.Chung_dense>`. Calculates a low-pressure thermal conductivity first. **COOLPROP**: CoolProp external library; with select fluids from its library. Range is limited to that of the equations of state it uses, as described in [1]_. Very slow, but unparalled in accuracy for pressure dependence. See Also -------- chemicals.thermal_conductivity.Bahadori_gas chemicals.thermal_conductivity.Gharagheizi_gas chemicals.thermal_conductivity.Eli_Hanley chemicals.thermal_conductivity.Chung chemicals.thermal_conductivity.DIPPR9B chemicals.thermal_conductivity.Eucken_modified chemicals.thermal_conductivity.Eucken chemicals.thermal_conductivity.Stiel_Thodos_dense chemicals.thermal_conductivity.Eli_Hanley_dense chemicals.thermal_conductivity.Chung_dense References ---------- .. [1] Bell, Ian H., Jorrit Wronski, Sylvain Quoilin, and Vincent Lemort. "Pure and Pseudo-Pure Fluid Thermophysical Property Evaluation and the Open-Source Thermophysical Property Library CoolProp." Industrial & Engineering Chemistry Research 53, no. 6 (February 12, 2014): 2498-2508. doi:10.1021/ie4033999. http://www.coolprop.org/ .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition. Berlin; New York:: Springer, 2010. .. [3] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook, Eighth Edition. McGraw-Hill Professional, 2007. ''' name = 'gas thermal conductivity' units = 'W/m/K' interpolation_T = None """No interpolation transformation by default.""" interpolation_P = None """No interpolation transformation by default.""" interpolation_property = None """No interpolation transformation by default.""" interpolation_property_inv = None """No interpolation transformation by default.""" tabular_extrapolation_permitted = True """Allow tabular extrapolation by default.""" property_min = 0 """Mimimum valid value of gas thermal conductivity.""" property_max = 10 """Maximum valid value of gas thermal conductivity. Generous limit.""" ranked_methods = [REFPROP_FIT, COOLPROP, VDI_PPDS, DIPPR_PERRY_8E, VDI_TABULAR, GHARAGHEIZI_G, DIPPR_9B, CHUNG, ELI_HANLEY, EUCKEN_MOD, EUCKEN, BAHADORI_G] """Default rankings of the low-pressure methods.""" ranked_methods_P = [COOLPROP, ELI_HANLEY_DENSE, CHUNG_DENSE, STIEL_THODOS_DENSE, NEGLECT_P] """Default rankings of the high-pressure methods.""" obj_references = pure_references = ('mug', 'Vmg', 'Cpgm') obj_references_types = pure_reference_types = (ViscosityGas, VolumeGas, HeatCapacityGas) custom_args = ('MW', 'Tb', 'Tc', 'Pc', 'Vc', 'Zc', 'omega', 'dipole', 'Vmg', 'Cpgm', 'mug') def __init__(self, CASRN='', MW=None, Tb=None, Tc=None, Pc=None, Vc=None, Zc=None, omega=None, dipole=None, Vmg=None, Cpgm=None, mug=None, extrapolation='linear', extrapolation_min=1e-4, **kwargs): self.CASRN = CASRN self.MW = MW self.Tb = Tb self.Tc = Tc self.Pc = Pc self.Vc = Vc self.Zc = Zc self.omega = omega self.dipole = dipole self.Vmg = Vmg self.Cpgm = Cpgm self.mug = mug if 'extrapolation_min' not in kwargs: kwargs['extrapolation_min'] = extrapolation_min super().__init__(extrapolation, **kwargs) def load_all_methods(self, load_data=True): r'''Method which picks out coefficients for the specified chemical from the various dictionaries and DataFrames storing it. All data is stored as attributes. This method also sets :obj:`Tmin`, :obj:`Tmax`, :obj:`all_methods` and obj:`all_methods_P` as a set of methods for which the data exists for. Called on initialization only. See the source code for the variables at which the coefficients are stored. The coefficients can safely be altered once the class is initialized. This method can be called again to reset the parameters. ''' self.all_methods = set() methods, methods_P = [], [NEGLECT_P] self.T_limits = T_limits = {} CASRN = self.CASRN if load_data and CASRN: if CASRN in miscdata.VDI_saturation_dict: Ts, props = lookup_VDI_tabular_data(CASRN, 'K (g)') self.add_tabular_data(Ts, props, VDI_TABULAR, check_properties=False) del self._method if has_CoolProp() and CASRN in coolprop_dict: CP_f = coolprop_fluids[CASRN] if CP_f.has_k: self.CP_f = CP_f methods.append(COOLPROP) methods_P.append(COOLPROP) T_limits[COOLPROP] = (self.CP_f.Tmin, self.CP_f.Tc*0.9999) if CASRN in thermal_conductivity.k_data_Perrys_8E_2_314.index: methods.append(DIPPR_PERRY_8E) C1, C2, C3, C4, self.Perrys2_314_Tmin, self.Perrys2_314_Tmax = thermal_conductivity.k_values_Perrys_8E_2_314[thermal_conductivity.k_data_Perrys_8E_2_314.index.get_loc(CASRN)].tolist() self.Perrys2_314_coeffs = [C1, C2, C3, C4] T_limits[DIPPR_PERRY_8E] = (self.Perrys2_314_Tmin, self.Perrys2_314_Tmax) if CASRN in thermal_conductivity.k_data_VDI_PPDS_10.index: A, B, C, D, E = thermal_conductivity.k_values_VDI_PPDS_10[thermal_conductivity.k_data_VDI_PPDS_10.index.get_loc(CASRN)].tolist() self.VDI_PPDS_coeffs = [A, B, C, D, E] self.VDI_PPDS_coeffs.reverse() methods.append(VDI_PPDS) T_limits[VDI_PPDS] = (1e-3, 10000.0) if all((self.MW, self.Tb, self.Pc, self.omega)): methods.append(GHARAGHEIZI_G) # Turns negative at low T; do not set Tmin T_limits[GHARAGHEIZI_G] = (1e-3, 3000.0) if all((self.Cpgm, self.mug, self.MW, self.Tc)): methods.append(DIPPR_9B) T_limits[DIPPR_9B] = (1e-2, 1e4) if all((self.Cpgm, self.mug, self.MW, self.Tc, self.omega)): methods.append(CHUNG) T_limits[CHUNG] = (1e-2, 1e4) if all((self.Cpgm, self.MW, self.Tc, self.Vc, self.Zc, self.omega)): methods.append(ELI_HANLEY) T_limits[ELI_HANLEY] = (self.Tc*0.4, 1e4) if all((self.Cpgm, self.mug, self.MW)): methods.append(EUCKEN_MOD) methods.append(EUCKEN) T_limits[EUCKEN] = T_limits[EUCKEN_MOD] = (1e-2, 1e4) if self.MW: methods.append(BAHADORI_G) T_limits[BAHADORI_G] = (1e-2, 1e4) # Terrible method, so don't set methods if all([self.MW, self.Tc, self.Vc, self.Zc, self.omega]): methods_P.append(ELI_HANLEY_DENSE) if all([self.MW, self.Tc, self.Vc, self.omega, self.dipole]): methods_P.append(CHUNG_DENSE) if all([self.MW, self.Tc, self.Pc, self.Vc, self.Zc]): methods_P.append(STIEL_THODOS_DENSE) self.all_methods.update(methods) self.all_methods_P = set(methods_P) for m in self.ranked_methods_P: if m in self.all_methods_P: self.method_P = m break @staticmethod def _method_indexes(): '''Returns a dictionary of method: index for all methods that use data files to retrieve constants. The use of this function ensures the data files are not loaded until they are needed. ''' return {COOLPROP : [CAS for CAS in coolprop_dict if (coolprop_fluids[CAS].has_k and CAS not in CoolProp_failing_PT_flashes)], VDI_TABULAR: list(miscdata.VDI_saturation_dict.keys()), DIPPR_PERRY_8E: thermal_conductivity.k_data_Perrys_8E_2_314.index, VDI_PPDS: thermal_conductivity.k_data_VDI_PPDS_10.index, }
[docs] def calculate(self, T, method): r'''Method to calculate low-pressure gas thermal conductivity at tempearture `T` with a given method. This method has no exception handling; see :obj:`T_dependent_property <thermo.utils.TDependentProperty.T_dependent_property>` for that. Parameters ---------- T : float Temperature of the gas, [K] method : str Name of the method to use Returns ------- kg : float Thermal conductivity of the gas at T and a low pressure, [W/m/K] ''' if method in (DIPPR_9B, CHUNG, ELI_HANLEY, EUCKEN_MOD, EUCKEN): Cvgm = self.Cpgm(T)-R if hasattr(self.Cpgm, '__call__') else self.Cpgm - R if method != ELI_HANLEY: mug = self.mug(T, 101325.0) if hasattr(self.mug, '__call__') else self.mug if method == GHARAGHEIZI_G: kg = Gharagheizi_gas(T, self.MW, self.Tb, self.Pc, self.omega) elif method == DIPPR_9B: kg = DIPPR9B(T, self.MW, Cvgm, mug, self.Tc) elif method == CHUNG: kg = Chung(T, self.MW, self.Tc, self.omega, Cvgm, mug) elif method == ELI_HANLEY: kg = Eli_Hanley(T, self.MW, self.Tc, self.Vc, self.Zc, self.omega, Cvgm) elif method == EUCKEN_MOD: kg = Eucken_modified(self.MW, Cvgm, mug) elif method == EUCKEN: kg = Eucken(self.MW, Cvgm, mug) elif method == DIPPR_PERRY_8E: kg = EQ102(T, *self.Perrys2_314_coeffs) elif method == VDI_PPDS: kg = horner(self.VDI_PPDS_coeffs, T) elif method == BAHADORI_G: kg = Bahadori_gas(T, self.MW) elif method == COOLPROP: kg = CoolProp_T_dependent_property(T, self.CASRN, 'L', 'g') else: return self._base_calculate(T, method) return kg
[docs] def calculate_P(self, T, P, method): r'''Method to calculate pressure-dependent gas thermal conductivity at temperature `T` and pressure `P` with a given method. This method has no exception handling; see :obj:`TP_dependent_property <thermo.utils.TPDependentProperty.TP_dependent_property>` for that. Parameters ---------- T : float Temperature at which to calculate gas thermal conductivity, [K] P : float Pressure at which to calculate gas thermal conductivity, [K] method : str Name of the method to use Returns ------- kg : float Thermal conductivity of the gas at T and P, [W/m/K] ''' if method == ELI_HANLEY_DENSE: Vmg = self.Vmg(T, P) if hasattr(self.Vmg, '__call__') else self.Vmg Cpgm = self.Cpgm(T) if hasattr(self.Cpgm, '__call__') else self.Cpgm kg = Eli_Hanley_dense(T, self.MW, self.Tc, self.Vc, self.Zc, self.omega, Cpgm-R, Vmg) elif method == CHUNG_DENSE: Vmg = self.Vmg(T, P) if hasattr(self.Vmg, '__call__') else self.Vmg Cpgm = self.Cpgm(T) if hasattr(self.Cpgm, '__call__') else self.Cpgm mug = self.mug(T, P) if hasattr(self.mug, '__call__') else self.mug kg = Chung_dense(T, self.MW, self.Tc, self.Vc, self.omega, Cpgm-R, Vmg, mug, self.dipole) elif method == STIEL_THODOS_DENSE: kg = self.T_dependent_property(T) Vmg = self.Vmg(T, P) if hasattr(self.Vmg, '__call__') else self.Vmg kg = Stiel_Thodos_dense(T, self.MW, self.Tc, self.Pc, self.Vc, self.Zc, Vmg, kg) elif method == COOLPROP: kg = PropsSI('L', 'T', T, 'P', P, self.CASRN) else: return self._base_calculate_P(T, P, method) return kg
[docs] def test_method_validity(self, T, method): r'''Method to check the validity of a temperature-dependent low-pressure method. For CSP methods, the all methods are considered valid from 0 K and up. For tabular data, extrapolation outside of the range is used if :obj:`tabular_extrapolation_permitted` is set; if it is, the extrapolation is considered valid for all temperatures. It is not guaranteed that a method will work or give an accurate prediction simply because this method considers the method valid. **GHARAGHEIZI_G** and **BAHADORI_G** are known to sometimes produce negative results. Parameters ---------- T : float Temperature at which to test the method, [K] method : str Name of the method to test Returns ------- validity : bool Whether or not a method is valid ''' if method in (GHARAGHEIZI_G, DIPPR_9B, CHUNG, ELI_HANLEY, EUCKEN_MOD, EUCKEN, BAHADORI_G, VDI_PPDS): pass elif method == DIPPR_PERRY_8E: if T < self.Perrys2_314_Tmin or T > self.Perrys2_314_Tmax: return False elif method == COOLPROP: if T < self.CP_f.Tmin or T > self.CP_f.Tmax: return False else: return super().test_method_validity(T, method) return True
[docs] def test_method_validity_P(self, T, P, method): r'''Method to check the validity of a high-pressure method. For **COOLPROP**, the fluid must be both a gas and under the maximum pressure of the fluid's EOS. The CSP method **ELI_HANLEY_DENSE**, **CHUNG_DENSE**, and **STIEL_THODOS_DENSE** are considered valid for all temperatures and pressures. For tabular data, extrapolation outside of the range is used if :obj:`tabular_extrapolation_permitted` is set; if it is, the extrapolation is considered valid for all temperatures and pressures. It is not guaranteed that a method will work or give an accurate prediction simply because this method considers the method valid. Parameters ---------- T : float Temperature at which to test the method, [K] P : float Pressure at which to test the method, [Pa] method : str Name of the method to test Returns ------- validity : bool Whether or not a method is valid ''' validity = True if method in (ELI_HANLEY_DENSE, CHUNG_DENSE, STIEL_THODOS_DENSE): if T < 0 or P < 0: validity = False # no better checks known elif method == COOLPROP: if T < self.CP_f.Tmin or T > self.CP_f.Tmax or P > self.CP_f.Pmax: return False else: return PhaseSI('T', T, 'P', P, self.CASRN) in ['gas', 'supercritical_gas', 'supercritical', 'supercritical_liquid'] else: return super().test_method_validity_P(T, P, method) return validity
LINDSAY_BROMLEY = 'LINDSAY_BROMLEY' thermal_conductivity_gas_mixture_methods = [LINDSAY_BROMLEY, LINEAR] """Holds all mixing rules available for the :obj:`ThermalConductivityGasMixture` class, for use in iterating over them."""
[docs]class ThermalConductivityGasMixture(MixtureProperty): '''Class for dealing with thermal conductivity of a gas mixture as a function of temperature, pressure, and composition. Consists of one mixing rule specific to gas thremal conductivity, and mole weighted averaging. Prefered method is :obj:`Lindsay_Bromley <chemicals.thermal_conductivity.Lindsay_Bromley>` which requires mole fractions, pure component viscosities and thermal conductivities, and the boiling point and molecular weight of each pure component. This is substantially better than the ideal mixing rule based on mole fractions, **LINEAR** which is also available. More information on this topic can be found in [1]_. Parameters ---------- MWs : list[float], optional Molecular weights of all species in the mixture, [g/mol] Tbs : list[float], optional Boiling points of all species in the mixture, [K] CASs : str, optional The CAS numbers of all species in the mixture ThermalConductivityGases : list[ThermalConductivityGas], optional ThermalConductivityGas objects created for all species in the mixture, [-] ViscosityGases : list[ViscosityGas], optional ViscosityGas objects created for all species in the mixture, [-] correct_pressure_pure : bool, optional Whether to try to use the better pressure-corrected pure component models or to use only the T-only dependent pure species models, [-] Notes ----- To iterate over all methods, use the list stored in :obj:`thermal_conductivity_gas_methods`. **LINDSAY_BROMLEY**: Mixing rule described in :obj:`Lindsay_Bromley <chemicals.thermal_conductivity.Lindsay_Bromley>`. **LINEAR**: Mixing rule described in :obj:`mixing_simple <chemicals.utils.mixing_simple>`. See Also -------- chemicals.thermal_conductivity.Lindsay_Bromley References ---------- .. [1] Poling, Bruce E. The Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill Professional, 2000. ''' name = 'gas thermal conductivity' units = 'W/m/K' property_min = 0. """Mimimum valid value of gas thermal conductivity.""" property_max = 10. """Maximum valid value of gas thermal conductivity. Generous limit.""" ranked_methods = [LINDSAY_BROMLEY, LINEAR] pure_references = ('ThermalConductivityGases', 'ViscosityGases', ) pure_reference_types = (ThermalConductivityGas, ViscosityGas) pure_constants = ('MWs', 'Tbs', ) custom_args = pure_constants def __init__(self, MWs=[], Tbs=[], CASs=[], ThermalConductivityGases=[], ViscosityGases=[], **kwargs): self.MWs = MWs self.Tbs = Tbs self.CASs = CASs self.ThermalConductivityGases = ThermalConductivityGases self.ViscosityGases = ViscosityGases super().__init__(**kwargs) def load_all_methods(self): r'''Method to initialize the object by precomputing any values which may be used repeatedly and by retrieving mixture-specific variables. All data are stored as attributes. This method also sets :obj:`Tmin`, :obj:`Tmax`, and :obj:`all_methods` as a set of methods which should work to calculate the property. Called on initialization only. See the source code for the variables at which the coefficients are stored. The coefficients can safely be altered once the class is initialized. This method can be called again to reset the parameters. ''' methods = [] methods.append(LINEAR) if none_and_length_check((self.Tbs, self.MWs)): methods.append(LINDSAY_BROMLEY) self.all_methods = all_methods = set(methods) Tmins = [i.Tmin for i in self.ThermalConductivityGases if i.Tmin] Tmaxs = [i.Tmax for i in self.ThermalConductivityGases if i.Tmax] if Tmins: self.Tmin = max(Tmins) if Tmaxs: self.Tmax = max(Tmaxs)
[docs] def calculate(self, T, P, zs, ws, method): r'''Method to calculate thermal conductivity of a gas mixture at temperature `T`, pressure `P`, mole fractions `zs` and weight fractions `ws` with a given method. This method has no exception handling; see :obj:`mixture_property <thermo.utils.MixtureProperty.mixture_property>` for that. Parameters ---------- T : float Temperature at which to calculate the property, [K] P : float Pressure at which to calculate the property, [Pa] zs : list[float] Mole fractions of all species in the mixture, [-] ws : list[float] Weight fractions of all species in the mixture, [-] method : str Name of the method to use Returns ------- kg : float Thermal conductivity of gas mixture, [W/m/K] ''' if method == LINDSAY_BROMLEY: ks = self.calculate_pures_corrected(T, P, fallback=True) mus = self.calculate_pures_corrected(T, P, fallback=True, objs=self.ViscosityGases) return Lindsay_Bromley(T=T, ys=zs, ks=ks, mus=mus, Tbs=self.Tbs, MWs=self.MWs) return super().calculate(T, P, zs, ws, method)
[docs] def test_method_validity(self, T, P, zs, ws, method): if method in [LINEAR, LINDSAY_BROMLEY]: return True return super().test_method_validity(T, P, zs, ws, method)
thermal_conductivity_solid_methods = [HO1972] """Holds all methods available for the :obj:`ThermalConductivitySolid` class, for use in iterating over them.""" class ThermalConductivitySolid(TDependentProperty): r'''Class for dealing with solid thermal conductivity as a function of temperature. Parameters ---------- CASRN : str, optional The CAS number of the chemical load_data : bool, optional If False, do not load property coefficients from data sources in files [-] extrapolation : str or None None to not extrapolate; see :obj:`TDependentProperty <thermo.utils.TDependentProperty>` for a full list of all options, [-] method : str or None, optional If specified, use this method by default and do not use the ranked sorting; an exception is raised if this is not a valid method for the provided inputs, [-] Notes ----- A string holding each method's name is assigned to the following variables in this module, intended as the most convenient way to refer to a method. To iterate over all methods, use the list stored in :obj:`thermal_conductivity_solid_methods`. See Also -------- Examples -------- >>> obj = ThermalConductivitySolid(CASRN='142-82-5') References ---------- ''' name = 'solid thermal conductivity' units = 'W/m/K' interpolation_T = None """No interpolation transformation by default.""" interpolation_property = None """No interpolation transformation by default.""" interpolation_property_inv = None """No interpolation transformation by default.""" tabular_extrapolation_permitted = True """Allow tabular extrapolation by default; a theoretical solid phase exists for all chemicals at sufficiently high pressures, although few chemicals could stably exist in those conditions.""" property_min = 0.0 """Mimimum valid value of solid thermal conductivity.""" property_max = 1e5 """Maximum valid value of solid thermal conductivity. Diamond 2200, carbon nanotubes maybe 6000. Copper 25000 at 7 K.""" ranked_methods = [HO1972] """Default rankings of the available methods.""" custom_args = tuple() _json_obj_by_CAS = tuple() def __init__(self, CASRN='', extrapolation='linear', **kwargs): self.CASRN = CASRN super().__init__(extrapolation, **kwargs) def load_all_methods(self, load_data): methods = [] self.T_limits = T_limits = {} self.all_methods = set() CASRN = self.CASRN if load_data and CASRN: pass self.all_methods.update(methods) def calculate(self, T, method): r'''Method to calculate thermal conductivity of a solid at temperature `T` with a given method. This method has no exception handling; see :obj:`T_dependent_property <thermo.utils.TDependentProperty.T_dependent_property>` for that. Parameters ---------- T : float Temperature at which to calculate thermal conductivity, [K] method : str Name of the method to use Returns ------- ks : float Thermal conductivity of the solid at T and a low pressure, [W/m/K] ''' return self._base_calculate(T, method)