Source code for lib.meos

#!/usr/bin/python3
# -*- coding: utf-8 -*-

r'''Pychemqt, Chemical Engineering Process simulator
Copyright (C) 2009-2025, Juan José Gómez Romera <jjgomera@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.


This module implement high accuracy multiparameter equation of state. The
supported equation include the fundamental equation of state explicit in the
Helmholtz energy and the modified Benedict-Webb-Rubin (mBWR) equation of state.
The module implement too the calculation using the Peng-Robinson cubic
equation of state.


The ideal gas contribution is equal for all equation of state implemented. It
uses the equation for ideal gas specific heat so all fluid must define it
in subclass fluid definition

.. math::
  \begin{array}[t]{l}
  f^o(\rho,T) = h^o(T)-RT-Ts^o(\rho,T)\\
  h^o(T) = \intop_{T_{o}}^{T}C_{p}^{o}dT+h_{0}^{o}\\
  s^o(T) = \intop_{T_o}^{T}\frac{C_{p}^{o}-R}{T}dT -
  R\ln\left(\frac{\rho}{\rho_0^o}\right)+s_{0}^{o}\\
  \end{array}


**Helmholtz**

Most modern, high-accuracy equation of state use this general form explicit
in the free Helmholtz energy as a function of temperature and density.

.. math::
    \frac{A(\rho,T)}{RT} = \phi(\delta,\tau) = \phi^o(\delta,\tau) +
    \phi^r(\delta,\tau)

The residual contribution is a combination of term

.. math::
  \begin{array}[t]{l}
  \phi^r = \phi^r_{Pol}+\phi^r_{Exp}+\phi^r_{GBS}+\phi^r_{NA}+\phi^r_{ass}\\
  \phi^r_{Pol} = \sum_i n_i\delta^{d_i}\tau^{t_i}\\
  \phi^r_{Exp} = \sum_i n_i\delta^{d_i}\tau^{t_i} e^{-\gamma_i\delta^{c_i}}\\
  \phi^r_{GBS} = \sum_i n_i\delta^{d_i}\tau^{t_i} e^{-\alpha(\delta-
  \epsilon_i)^2-\beta_i(\tau-\gamma_i)^2}\\
  \phi^r_{NA} = \sum n\Delta^{b_i}\delta e^{-C_i\left(\delta-1\right)^2-D_i
  \left(\tau-1\right)^2}\\
  \Delta = \theta^2+B_i\left(\left(\delta-1\right)^2\right)^{a_i}\\
  \theta = (1-\tau)+A_i\left(\left(\delta-1\right)^2\right)^{1/2\beta_ i}\\
  \phi^r_{ass} = \sum_i n_i\tau^{t_i}\delta^{d_i}e^{-\alpha_i\left(\delta-
  \epsilon_i\right)^2+\frac{1}{\beta_i\left(\tau-\gamma_i\right)^2+b_i}}\\
  \end{array}

The polynomial and exponential term are common to all equations, the Gaussian
bell shaped are used to improved accuracy in critical region. The nonanalytic
terms are used to represent the steep variation of icochoric heat capacity and
speed of sound near the critical point. They are only used for water and carbon
dioxide reference equation of state, they are very time computing. The
associating term are used only for ammonia for a better representation of
associating fluids.


**MBWR (modified Benedict-Webb-Rubin)**

Pressure explicit equation of state as a function of temperature and density

.. math::
    P = \sum_{n=1}^9a_n\rho^n + \exp\left(-\delta^2\right)
    \sum_{n=10}^{15}a_n\rho^{2n-17}

where:

.. math::
  \begin{array}[t]{l}
  \delta = \rho/\rho_c\\
  a_1 = RT\\
  a_2 = b_1T + b_2T^{1/2} + b_3 + b_4/T + b_5/T^2\\
  a_3 = b_6T+b_7+b_8T+b_9/T^2\\
  a_4 = b_{10}T+b_{11}+b_{12}/T\\
  a_5 = b_{13}\\
  a_6 = b_{14}/T+b_{15}/T^2\\
  a_7 = b_{16}/T\\
  a_8 = b_{17}/T+b_{18}/T^2\\
  a_9 = b_{19}/T^2\\
  a_{10} = b_{20}/T^2+b_{21}/T^3\\
  a_{11} = b_{22}/T^2+b_{23}/T^4\\
  a_{12} = b_{24}/T^2+b_{25}/T^3\\
  a_{13} = b_{26}/T^2+b_{27}/T^4\\
  a_{14} = b_{28}/T^2+b_{29}/T^3\\
  a_{15} = b_{30}/T^2+b_{31}/T^3+b_{32}/T^4\\
  \end{array}

:math:`b_i` are the coefficient of equation saved in dict


**Cubic equation of state**

Cubic pressure-explicit equations of state can be expressed with the general
form:

.. math::
    P = \frac{RT}{V-b}-\frac{\alpha(T)}{\left(v+\Delta_1b\right)
    \left(v+\Delta_2b\right)}

From this formulation it's possible calculate the Helmholtz free energy with
the equation:

.. math::
  \begin{array}[t]{l}
  \alpha^r = \psi^{(-)}-\frac{\tau\alpha}{RT_c}\psi^{(+)}\\
  \psi^{(-)} = -\ln \left(1-b\delta\rho_c\right)\\
  \psi^{(+)} = \frac{\ln\left(\frac{\Delta_1b\rho_c\delta+1}{\Delta_2b\rho_c
  \delta+1}\right)}{b\left(\Delta_1-\Delta_2\right)}\\
  \end{array}


Module Code
-----------

The module include the following functions:

:class:`MEoS`: Main class with all functionality

The module implement too high accuracy correlation for viscosity and thermal
conductivity, see the documentation of its calculation procedure:

    * :func:`MEoS._Viscosity`
    * :func:`MEoS._ThCond`


Other functions used in iteration calculation to try to speed up it:

    * :func:`_Helmholtz_phir`
    * :func:`_Helmholtz_phird`
    * :func:`_Helmholtz_phirt`

    * :func:`_MBWR_phir`
    * :func:`_MBWR_phird`
    * :func:`_MBWR_phirt`

    * :func:`_PR_phir`
    * :func:`_PR_phird`
    * :func:`_PR_phirt`

'''

from concurrent.futures import ProcessPoolExecutor
from itertools import product, repeat
import json
import logging
import os

from numpy import sin, tan, sinh, cosh, tanh, arctan, arccos, exp, log
from scipy.constants import Boltzmann, pi, Avogadro, R, u, epsilon_0
from scipy.optimize import fsolve, newton

from lib import unidades
from lib.config import conf_dir
from lib.compuestos import RhoL_Costald, Pv_Lee_Kesler, MuG_Chung, MuG_P_Chung
from lib.compuestos import ThG_Chung, ThG_P_Chung, Tension_Pitzer
from lib.EoS.cubic import CubicHelmholtz
from lib.EoS.Cubic import PR
from lib.mezcla import Mezcla
from lib.physics import Collision_Neufeld
from lib.thermo import ThermoAdvanced
from lib.utilities import SimpleEq, refDoc
from tools.qt import translate


__doi__ = {
    1:
        {"autor": "Mulero, A., Cachadiña, I., Parra, M.I.",
         "title": "Recommended Correlations for the Surface Tension of "
                  "Common Fluids",
         "ref": "J. Phys. Chem. Ref. Data 41(4) (2012) 043105",
         "doi": "10.1063/1.4768782"},
    2:
        {"autor": "Quiñones-Cisneros, S.E., Deiters, U.K.",
         "title": "Generalization of the Friction Theory for Viscosity "
                  "Modeling",
         "ref": "J. Phys. Chem. B, 110(25) (2006) 12820-12834",
         "doi": "10.1021/jp0618577"},
    3:
        {"autor": "Quiñones-Cisneros, S.E., Huber, M.L., Deiters, U.K.",
         "title": "Correlation for the Viscosity of Sulfur Hexafluoride (SF6) "
                  "from the Triple Point to 1000 K and Pressures to 50 MPa",
         "ref": "J. Phys. Chem. Ref. Data 41(2) (2012) 023102",
         "doi": "10.1063/1.3702441"},
    4:
        {"autor": "Younglove, B.A.",
         "title": "Thermophysical Properties of Fluids. I. Argon, Ethylene, "
                  "Parahydrogen, Nitrogen, Nitrogen Trifluoride, and Oxygen",
         "ref": "J. Phys. Chem. Ref. Data, 11(Suppl. 1) (1982)",
         "doi": ""},
    5:
        {"autor": "Younglove, B.A., Ely, J.F.",
         "title": "Thermophysical Properties of Fluids. II. Methane, Ethane, "
                  "Propane, Isobutane, and Normal Butane",
         "ref": "J. Phys. Chem. Ref. Data 16(4) (1987) 577-798",
         "doi": "10.1063/1.555785"},
    6:
        {"autor": "Lemmon, E.W., Jacobsen, R.T.",
         "title": "Viscosity and Thermal Conductivity Equations for Nitrogen, "
                  "Oxygen, Argon, and Air",
         "ref": "Int. J. Thermophys., 25(1) (2004) 21-69",
         "doi": "10.1023/B:IJOT.0000022327.04529.f3"},
    7:
        {"autor": "Tariq, U., Jusoh, A.R.B., Riesco, N., Vesovic, V.",
         "title": "Reference Correlation of the Viscosity of Cyclohexane from "
                  "the Triple Point to 700K and up to 110 MPa",
         "ref": "J. Phys. Chem. Ref. Data 43(3) (2014) 033101",
         "doi": "10.1063/1.4891103"},
    8:
        {"autor": "Neufeld, P.D., Janzen, A.R., Aziz, R.A.",
         "title": "Empirical Equations to Calculate 16 of the Transport "
                  "Collision Integrals Ω for the Lennard-Jones Potential",
         "ref": "J. Chem. Phys. 57(3) (1972) 1100-1102",
         "doi": "10.1063/1.1678363"},
    9:
        {"autor": "Akasaka, R.",
         "title": "A Reliable and Useful Method to Determine the Saturation "
                  "State from Helmholtz Energy Equations of State",
         "ref": "J. Thermal Sci. Tech. 3(3) (2008) 442-451",
         "doi": "10.1299/jtst.3.442"},
    10:
        {"autor": "Span, R.",
         "title": "Multiparameter Equations of State: An Accurate Source of "
                  "Thermodynamic Property Data",
         "ref": "Springer, 2000",
         "doi": ""},
    11:
        {"autor": "Younglove, B.A., McLinden, M.O.",
         "title": "An International Standard Equation of State for the "
                  "Thermodynamic Properties of Refrigerant 123 "
                  "(2,2-Dichloro-1,1,1-trifluoroethane)",
         "ref": "J. Phys. Chem. Ref. Data, 23(5) (1994) 731-779",
         "doi": "10.1063/1.555950"},
    12:
        {"autor": "Peng, D.-Y., Robinson, D.B.",
         "title": "A New Two-Constant Equation of State",
         "ref": "Ind. Eng. Chem. Fund. 15(1) (1976) 59-64",
         "doi": "10.1021/i160057a011"},
    13:
        {"autor": "Lin, H., Duan, Y.-Y.",
         "title": "Empirical correction to the Peng-Robinson equation of "
                  "state for the saturated region",
         "ref": "Fluid Phase Equilibria 233 (2005) 194-203",
         "doi": "10.1016/j.fluid.2005.05.008"},
    14:
        {"autor": "Bell, I.H., Jäger, A.",
         "title": "Helmholtz Energy Transformations of Common Cubic Equations "
                  "of State for Use with Pure Fluids and Mixtures",
         "ref": "J. Res. of NIST 121 (2016) 236-263",
         "doi": "10.6028/jres.121.011"},
    15:
        {"autor": "Laesecke, A., Perkins, R.A., Howley, J.B.",
         "title": "An improved correlation for the thermal conductivity of "
                  "HCFC123 (2,2-dichloro-1,1,1-trifluoroethane)",
         "ref": "Int. J. Refrigeration 19(4) (1996) 231-238",
         "doi": "10.1016/0140-7007(96)00019-9"},
    16:
        {"autor": "Olchowy, G.A., Sengers, J.V.",
         "title": "A Simplified Representation for the Thermal Conductivity "
                  "of Fluids in the Critical Region",
         "ref": "Int. J. Thermophys. 10(2) (1989) 417-426",
         "doi": "10.1007/bf01133538"},
    17:
        {"autor": "Friend, D.G., Ely, J.F., Ingham, H.",
         "title": "Thermophysical Properties of Methane",
         "ref": "J. Phys. Chem. Ref. Data 18(2) (1989) 583-638",
         "doi": "10.1063/1.555828"},
    18:
        {"autor": "Friend, D.G., Ingham, H., Ely, J.F.",
         "title": "Thermophysical Properties of Ethane",
         "ref": "J. Phys. Chem. Ref. Data 20, 275 (1991)",
         "doi": "10.1063/1.555881"},
    19:
        {"autor": "Hanley H.J.M., McCarty, R.D., Haynes, W.M.",
         "title": "The Viscosity and Thermal Conductivity Coefficient for "
                  "Dense Gaseous and Liquid Argon, Krypton, Xenon, Nitrogen "
                  "and Oxigen",
         "ref": "J. Phys. Chem. Ref. Data 3(4) (1974) 979-1018",
         "doi": "10.1063/1.3253152"},
    20:
        {"autor": "Huber, M.L., Laesecke, A., Perkins, R.A.",
         "title": "Model for the Viscosity and Thermal Conductivity of "
                  "Refrigerants, Including a New Correlation for the "
                  "Viscosity of R134a",
         "ref": "Ind. Eng. Chem. Res., 42(13) (2003) 3163-3178",
         "doi": "10.1021/ie0300880"},
    21:
        {"autor": "Estela-Uribe, J.F., Trusler, J.P.M.",
         "title": "Extended corresponding states model for fluids and fluid"
                  "mixtures I. Shape factor model for pure fluids",
         "ref": "Fluid Phase Equilibria 204 (2003) 15-40",
         "doi": "10.1016/s0378-3812(02)00190-5"},
    22:
        {"autor": "McLinden, M.O., Klein, S.A., Perkins, R.A.",
         "title": "An Extended corresponding states model for the thermal "
                  "conductivity of refrigerants and refrigerant mixtures",
         "ref": "Int. J. Refrigeration 23 (2000) 43-63",
         "doi": "10.1016/s0140-7007(99)00024-9"},
    23:
        {"autor": "Jaeschke, M., Schley, P.",
         "title": "Ideal-Gas Thermodynamic Properties for Natural Gas "
                  "Applications",
         "ref": "Int. J. Thermophys. 16(6) (1995) 1381-1392",
         "doi": "10.1007/bf02083547"},
    24:
        {"autor": "Harvey, A.H., Lemmon, E.W.",
         "title": "Method for Estimating the Dielectric Constant of "
                  "Natural Gas Mixtures ",
         "ref": "Int. J. Thermophys. 26(1) (2005) 31-46",
         "doi": "10.1007/s10765-005-2351-5"},
    25:
        {"autor": "Bhattacharjee, J.K., Ferrell, R.A., Basu, R.S., Sengers, "
                  "J.V.",
         "title": "Crossover function for the critical viscosity of a "
                  "classical fluid",
         "ref": "Physical Review A 24(3) (1981) 1469-1475",
         "doi": "10.1103/PhysRevA.24.1469"},
    26:
        {"autor": "Gao, K., Wu, J., Bell, I.H., Harvey, A.H., Lemmon E.W.",
         "title": "A Reference Equation of State with an Associating Term for "
                  "the Thermodynamic Properties of Ammonia",
         "ref": "J. Phys. Chem. Ref. Data 52 (2023) 013102",
         "doi": "10.1063/5.0128269"},
    27:
        {"autor": "Thorade, M., Saadat, A.",
         "title": "Partial derivatives of thermodynamic state properties for "
                  "dynamic simulation",
         "ref": "Environ Eartth Sci 70(8) (2013) 3497-3503",
         "doi": "10.1007/s12665-013-2394-z"},
    28:
        {"autor": "Piazza, L., Span, R.",
         "title": "An equation of state for acetic acid including the "
                  "association term of SAFT",
         "ref": "Fluid Phase Equilib. 303 (2011) 134-149",
         "doi": "10.1016/j.fluid.2011.01.008"},
    29:
        {"autor": "Harvey, A.H., Mountain, R.D.",
         "title": "Correlations for the Dielectric Constants of H2S, SO2 "
                  "and SF6",
         "ref": "Int. J. Thermophys. 38 (2017) 147",
         "doi": "10.1007/s10765-017-2279-6"},
    30:
        {"autor": "",
         "title": "",
         "ref": "",
         "doi": ""},
    }


[docs] def _Helmholtz_phir(tau, delta, coef): r"""Residual contribution to the free Helmholtz energy Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] coef : dict Parameters of multiparameter equation of state Returns ------- fir : float :math:`\phi^r`, adimensional free Helmholtz energy, [-] """ fir = 0 if delta: # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) t1 = coef.get("t1", []) for n, d, t in zip(nr1, d1, t1): fir += n*delta**d*tau**t # Exponential terms nr2 = coef.get("nr2", []) d2 = coef.get("d2", []) g2 = coef.get("gamma2", []) t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): fir += n*delta**d*tau**t*exp(-g*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) d3 = coef.get("d3", []) t3 = coef.get("t3", []) a3 = coef.get("alfa3", []) e3 = coef.get("epsilon3", []) b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) exp1 = coef.get("exp1", [2]*len(nr3)) exp2 = coef.get("exp2", [2]*len(nr3)) for n, d, t, a, e, b, g, ex1, ex2 in zip( nr3, d3, t3, a3, e3, b3, g3, exp1, exp2): expr = exp(-a*(delta-e)**ex1-b*(tau-g)**ex2) fir += n*delta**d*tau**t * expr # Non analitic terms ni = coef.get("nr4", []) ai = coef.get("a4", []) bi = coef.get("b4", []) Ai = coef.get("A", []) Bi = coef.get("B", []) Ci = coef.get("C", []) Di = coef.get("D", []) b_ = coef.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(ni, ai, bi, Ai, Bi, Ci, Di, b_): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Delta = Tita**2+B*((delta-1)**2)**a fir += n*Delta**b*delta*F # Associative term from Gao correlation for ammonia if "nr_ass" in coef: nr_ass = coef.get("nr_ass", []) d5 = coef.get("d_ass", []) t5 = coef.get("t_ass", []) a5 = coef.get("alfa_ass", []) e5 = coef.get("epsilon_ass", []) bt5 = coef.get("beta_ass", []) g5 = coef.get("gamma_ass", []) b5 = coef.get("b_ass", []) for n, d, t, a, e, bt, g, b in zip( nr_ass, d5, t5, a5, e5, bt5, g5, b5): expr = exp(-a*(delta-e)**2+1/(bt*(tau-g)**2+b)) fir += n*delta**d*tau**t * expr # Associative term from Piazza correlations if "type_ass" in coef: m = coef.get("m_ass") vn = coef.get("v_ass") kappa = coef.get("k_ass") epsilon = coef.get("e_ass") nu = vn*delta gnu = (2-nu)/2/(1-nu)**3 Delta = gnu*(exp(epsilon*tau)-1)*kappa X = (-1 + (1+4*Delta*delta)**0.5)/2/Delta/delta fass = log(X) - X/2 + 0.5 if coef.get("type_ass") == "2B": fass *= 2 fir += m*fass # Special form from Saul-Wagner Water 58 coefficient equation if "nr_saul" in coef: if delta < 0.2: factor = 1.6*delta**6*(1-1.2*delta**6) else: factor = exp(-0.4*delta**6)-exp(-2*delta**6) nr5 = coef.get("nr_saul", []) d5 = coef.get("d_saul", []) t5 = coef.get("t_saul", []) fr = 0 for n, d, t in zip(nr5, d5, t5): fr += n*delta**d*tau**t fir += factor*fr return fir
[docs] def _Helmholtz_phird(tau, delta, coef): r"""Residual contribution to the free Helmholtz energy, delta derivative Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] coef : dict Parameters of multiparameter equation of state Returns ------- fird : float :math:`\left.\frac{\partial \phi^r}{\partial \delta}\right|_{\tau}` """ fird = 0 if delta: # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) t1 = coef.get("t1", []) for n, d, t in zip(nr1, d1, t1): fird += n*d*delta**(d-1)*tau**t # Exponential terms nr2 = coef.get("nr2", []) d2 = coef.get("d2", []) g2 = coef.get("gamma2", []) t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): fird += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) d3 = coef.get("d3", []) t3 = coef.get("t3", []) a3 = coef.get("alfa3", []) e3 = coef.get("epsilon3", []) b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) exp1 = coef.get("exp1", [2]*len(nr3)) exp2 = coef.get("exp2", [2]*len(nr3)) for n, d, t, a, e, b, g, ex1, ex2 in zip( nr3, d3, t3, a3, e3, b3, g3, exp1, exp2): expr = exp(-a*(delta-e)**ex1-b*(tau-g)**ex2) fird += expr * (n*d*delta**(d-1)*tau**t - n*a*delta**d*(delta-e)**(ex1-1)*ex1*tau**t) # Non analitic terms ni = coef.get("nr4", []) ai = coef.get("a4", []) bi = coef.get("b4", []) Ai = coef.get("A", []) Bi = coef.get("B", []) Ci = coef.get("C", []) Di = coef.get("D", []) b_ = coef.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(ni, ai, bi, Ai, Bi, Ci, Di, b_): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Fd = -2*C*F*(delta-1) Delta = Tita**2+B*((delta-1)**2)**a Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + 2*B*a*((delta-1)**2)**(a-1)) DeltaBd = b*Delta**(b-1)*Deltad fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) # Associative term from Gao correlation for ammonia if "nr_ass" in coef: nr_ass = coef.get("nr_ass", []) d5 = coef.get("d_ass", []) t5 = coef.get("t_ass", []) a5 = coef.get("alfa_ass", []) e5 = coef.get("epsilon_ass", []) bt5 = coef.get("beta_ass", []) g5 = coef.get("gamma_ass", []) b5 = coef.get("b_ass", []) for n, d, t, a, e, bt, g, b in zip( nr_ass, d5, t5, a5, e5, bt5, g5, b5): expr = exp(-a*(delta-e)**2+1/(bt*(tau-g)**2+b)) expr2 = d*delta**(d-1)-2*a*(delta-e)*delta**d fird += n*tau**t * expr * expr2 # Associative term from Piazza correlations if "type_ass" in coef: m = coef.get("m_ass") vn = coef.get("v_ass") kappa = coef.get("k_ass") epsilon = coef.get("e_ass") nu = vn*delta gnu = (2-nu)/2/(1-nu)**3 Delta = gnu*(exp(epsilon*tau)-1)*kappa X = (-1 + (1+4*Delta*delta)**0.5)/2/Delta/delta dgnu = 0.5*(5-2*nu)/(1-nu)**4 alfa = dgnu * (exp(epsilon*tau)-1)*kappa*vn # Eq A35 Xd = -X**2/(2*Delta*delta*X+1)*(Delta+delta*alfa) # Eq A36 fassd = (1/X-0.5)*Xd if coef.get("type_ass") == "2B": fassd *= 2 fird += m*fassd # Special form from Saul-Wagner Water 58 coefficient equation if "nr_saul" in coef: if delta < 0.2: factor = 1.6*delta**6*(1-1.2*delta**6) else: factor = exp(-0.4*delta**6)-exp(-2*delta**6) nr5 = coef.get("nr_saul", []) d5 = coef.get("d_saul", []) t5 = coef.get("t_saul", []) frd1, frd2 = 0, 0 for n, d, t in zip(nr5, d5, t5): frd1 += n*delta**(d+5)*tau**t frd2 += n*d*delta**(d-1)*tau**t fird += (-2.4*exp(-0.4*delta**6)+12*exp(-2*delta**6))*frd1 + \ factor*frd2 return fird
[docs] def _Helmholtz_phirt(tau, delta, coef): r"""Residual contribution to the free Helmholtz energy, tau derivative Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] coef : dict Parameters of multiparameter equation of state Returns ------- firt : float :math:`\left.\frac{\partial \phi^r}{\partial \tau}\right|_{\delta}` """ firt = 0 if delta: # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) t1 = coef.get("t1", []) for n, d, t in zip(nr1, d1, t1): firt += n*t*delta**d*tau**(t-1) # Exponential terms nr2 = coef.get("nr2", []) d2 = coef.get("d2", []) g2 = coef.get("gamma2", []) t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) d3 = coef.get("d3", []) t3 = coef.get("t3", []) a3 = coef.get("alfa3", []) e3 = coef.get("epsilon3", []) b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) exp1 = coef.get("exp1", [2]*len(nr3)) exp2 = coef.get("exp2", [2]*len(nr3)) for n, d, t, a, e, b, g, ex1, ex2 in zip( nr3, d3, t3, a3, e3, b3, g3, exp1, exp2): expr = exp(-a*(delta-e)**ex1-b*(tau-g)**ex2) firt += expr * (n*delta**d*t*tau**(t-1) - n*b*delta**d*ex2*tau**t*(tau-g)**(ex2-1)) # Non analitic terms ni = coef.get("nr4", []) ai = coef.get("a4", []) bi = coef.get("b4", []) Ai = coef.get("A", []) Bi = coef.get("B", []) Ci = coef.get("C", []) Di = coef.get("D", []) b_ = coef.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(ni, ai, bi, Ai, Bi, Ci, Di, b_): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Ft = -2*D*F*(tau-1) Delta = Tita**2+B*((delta-1)**2)**a DeltaBt = -2*Tita*b*Delta**(b-1) firt += n*delta*(DeltaBt*F+Delta**b*Ft) # Associative term from Gao correlation for ammonia if "nr_ass" in coef: nr_ass = coef.get("nr_ass", []) d5 = coef.get("d_ass", []) t5 = coef.get("t_ass", []) a5 = coef.get("alfa_ass", []) e5 = coef.get("epsilon_ass", []) bt5 = coef.get("beta_ass", []) g5 = coef.get("gamma_ass", []) b5 = coef.get("b_ass", []) for n, d, t, a, e, bt, g, b in zip( nr_ass, d5, t5, a5, e5, bt5, g5, b5): expr = exp(-a*(delta-e)**2+1/(bt*(tau-g)**2+b)) expr2 = t/tau - 2*bt*(tau-g)/(bt*(tau-g)**2+b)**2 firt += n*delta**d*tau**t * expr * expr2 # Associative term from Piazza correlations if "type_ass" in coef: m = coef.get("m_ass") vn = coef.get("v_ass") kappa = coef.get("k_ass") epsilon = coef.get("e_ass") nu = vn*delta gnu = (2-nu)/2/(1-nu)**3 Delta = gnu*(exp(epsilon*tau)-1)*kappa X = (-1 + (1+4*Delta*delta)**0.5)/2/Delta/delta beta = gnu*kappa*exp(epsilon*tau)*epsilon # Eq A55 Xt = -delta*X**2/(2*Delta*delta*X+1)*beta # Eq A56 fasst = (1/X-0.5)*Xt if coef.get("type_ass") == "2B": fasst *= 2 firt += m*fasst # Special form from Saul-Wagner Water 58 coefficient equation if "nr_saul" in coef: if delta < 0.2: factor = 1.6*delta**6*(1-1.2*delta**6) else: factor = exp(-0.4*delta**6)-exp(-2*delta**6) nr5 = coef.get("nr_saul", []) d5 = coef.get("d_saul", []) t5 = coef.get("t_saul", []) frt = 0 for n, d, t in zip(nr5, d5, t5): frt += n*delta**d*t*tau**(t-1) firt += factor*frt return firt
[docs] def _MBWR_phir(T, rho, rhoc, M, coef): r"""Residual contribution to the free Helmholtz energy for MBWR EoS Parameters ---------- T : float Temperature, [K] rho : float Density, [kg/m³] rhoc : float Critical density, [kg/m³] M : float Molecular weight, [g/mol] coef : dict Parameters of MBWR equation of state Returns ------- fir : float :math:`\phi^r`, adimensional free Helmholtz energy, [-] """ rhom = rho/M rhocm = rhoc/M delta = rho/rhoc b = coef["b"] R = coef["R"] # Equation B2 a = [None] # Use the gas constant in l·bar/mol·K a.append(R/100*T) a.append(b[1]*T + b[2]*T**0.5 + b[3] + b[4]/T + b[5]/T**2) a.append(b[6]*T + b[7] + b[8]/T + b[9]/T**2) a.append(b[10]*T + b[11] + b[12]/T) a.append(b[13]) a.append(b[14]/T + b[15]/T**2) a.append(b[16]/T) a.append(b[17]/T + b[18]/T**2) a.append(b[19]/T**2) a.append(b[20]/T**2 + b[21]/T**3) a.append(b[22]/T**2 + b[23]/T**4) a.append(b[24]/T**2 + b[25]/T**3) a.append(b[26]/T**2 + b[27]/T**4) a.append(b[28]/T**2 + b[29]/T**3) a.append(b[30]/T**2 + b[31]/T**3 + b[32]/T**4) # Eq B6 A = 0 for n in range(2, 10): A += a[n]/(n-1)*rhom**(n-1) A -= 0.5*a[10]*rhocm**2*(exp(-delta**2)-1) A -= 0.5*a[11]*rhocm**4*(exp(-delta**2)*(delta**2+1)-1) A -= 0.5*a[12]*rhocm**6*(exp(-delta**2)*( delta**4+2*delta**2+2)-2) A -= 0.5*a[13]*rhocm**8*(exp(-delta**2)*( delta**6+3*delta**4+6*delta**2+6)-6) A -= 0.5*a[14]*rhocm**10*(exp(-delta**2)*( delta**8+4*delta**6+12*delta**4+24*delta**2+24)-24) A -= 0.5*a[15]*rhocm**12*(exp(-delta**2)*( delta**10+5*delta**8+20*delta**6+60*delta**4+120*delta**2+120)-120) A = A*100 # Convert from L·bar/mol to J/mol return A/R/T
[docs] def _MBWR_phird(T, rho, rhoc, M, coef): r"""Residual contribution to the free Helmholtz energy for MBWR EoS, delta derivative Parameters ---------- T : float Temperature, [K] rho : float Density, [kg/m³] rhoc : float Critical density, [kg/m³] M : float Molecular weight, [g/mol] coef : dict Parameters of MBWR equation of state Returns ------- fird : float :math:`\left.\frac{\partial \phi^r}{\partial \delta}\right|_{\tau}` """ rhom = rho/M delta = rho/rhoc b = coef["b"] R = coef["R"] # Equation B2 a = [None] # Use the gas constant in l·bar/mol·K a.append(R/100*T) a.append(b[1]*T + b[2]*T**0.5 + b[3] + b[4]/T + b[5]/T**2) a.append(b[6]*T + b[7] + b[8]/T + b[9]/T**2) a.append(b[10]*T + b[11] + b[12]/T) a.append(b[13]) a.append(b[14]/T + b[15]/T**2) a.append(b[16]/T) a.append(b[17]/T + b[18]/T**2) a.append(b[19]/T**2) a.append(b[20]/T**2 + b[21]/T**3) a.append(b[22]/T**2 + b[23]/T**4) a.append(b[24]/T**2 + b[25]/T**3) a.append(b[26]/T**2 + b[27]/T**4) a.append(b[28]/T**2 + b[29]/T**3) a.append(b[30]/T**2 + b[31]/T**3 + b[32]/T**4) # Eq B1 P = sum([a[n]*rhom**n for n in range(1, 10)]) P += exp(-(delta**2))*sum([a[n]*rhom**(2*n-17) for n in range(10, 16)]) P *= 100 # Convert from bar to kPa return (P/rhom/T/R-1)/delta
[docs] def _MBWR_phirt(T, Tc, rho, rhoc, M, coef): r"""Residual contribution to the free Helmholtz energy, tau derivative Parameters ---------- T : float Temperature, [K] Tc : float Critical temperature, [K] rho : float Density, [kg/m³] rhoc : float Critical density, [kg/m³] M : float Molecular weight, [g/mol] coef : dict Parameters of MBWR equation of state Returns ------- firt : float :math:`\left.\frac{\partial \phi^r}{\partial \tau}\right|_{\delta}` """ rhom = rho/M rhocm = rhoc/M tau = Tc/T delta = rho/rhoc b = coef["b"] R = coef["R"] # Equation B2 a = [None] # Use the gas constant in l·bar/mol·K a.append(R/100*T) a.append(b[1]*T + b[2]*T**0.5 + b[3] + b[4]/T + b[5]/T**2) a.append(b[6]*T + b[7] + b[8]/T + b[9]/T**2) a.append(b[10]*T + b[11] + b[12]/T) a.append(b[13]) a.append(b[14]/T + b[15]/T**2) a.append(b[16]/T) a.append(b[17]/T + b[18]/T**2) a.append(b[19]/T**2) a.append(b[20]/T**2 + b[21]/T**3) a.append(b[22]/T**2 + b[23]/T**4) a.append(b[24]/T**2 + b[25]/T**3) a.append(b[26]/T**2 + b[27]/T**4) a.append(b[28]/T**2 + b[29]/T**3) a.append(b[30]/T**2 + b[31]/T**3 + b[32]/T**4) # Eq B6 A = 0 for n in range(2, 10): A += a[n]/(n-1)*rhom**(n-1) A -= 0.5*a[10]*rhocm**2*(exp(-delta**2)-1) A -= 0.5*a[11]*rhocm**4*(exp(-delta**2)*(delta**2+1)-1) A -= 0.5*a[12]*rhocm**6*(exp(-delta**2)*( delta**4+2*delta**2+2)-2) A -= 0.5*a[13]*rhocm**8*(exp(-delta**2)*( delta**6+3*delta**4+6*delta**2+6)-6) A -= 0.5*a[14]*rhocm**10*(exp(-delta**2)*( delta**8+4*delta**6+12*delta**4+24*delta**2+24)-24) A -= 0.5*a[15]*rhocm**12*(exp(-delta**2)*( delta**10+5*delta**8+20*delta**6+60*delta**4+120*delta**2+120)-120) A = A*100 # Convert from L·bar/mol to J/mol # Eq B4 # Use the gas constant in l·bar/mol·K adT = [None, R/100] adT.append(b[1] + b[2]/2/T**0.5 - b[4]/T**2 - 2*b[5]/T**3) adT.append(b[6] - b[8]/T**2 - 2*b[9]/T**3) adT.append(b[10] - b[12]/T**2) adT.append(0) adT.append(-b[14]/T**2 - 2*b[15]/T**3) adT.append(-b[16]/T**2) adT.append(-b[17]/T**2 - 2*b[18]/T**3) adT.append(-2*b[19]/T**3) adT.append(-2*b[20]/T**3 - 3*b[21]/T**4) adT.append(-2*b[22]/T**3 - 4*b[23]/T**5) adT.append(-2*b[24]/T**3 - 3*b[25]/T**4) adT.append(-2*b[26]/T**3 - 4*b[27]/T**5) adT.append(-2*b[28]/T**3 - 3*b[29]/T**4) adT.append(-2*b[30]/T**3 - 3*b[31]/T**4 - 4*b[32]/T**5) # Eq B7 dAT = 0 for n in range(2, 10): dAT += adT[n]/(n-1)*rhom**(n-1) dAT -= 0.5*adT[10]*rhocm**2*(exp(-delta**2)-1) dAT -= 0.5*adT[11]*rhocm**4*(exp(-delta**2)*(delta**2+1)-1) dAT -= 0.5*adT[12]*rhocm**6*(exp(-delta**2)*( delta**4+2*delta**2+2)-2) dAT -= 0.5*adT[13]*rhocm**8*(exp(-delta**2)*( delta**6+3*delta**4+6*delta**2+6)-6) dAT -= 0.5*adT[14]*rhocm**10*(exp(-delta**2)*( delta**8+4*delta**6+12*delta**4+24*delta**2+24)-24) dAT -= 0.5*adT[15]*rhocm**12*(exp(-delta**2)*( delta**10+5*delta**8+20*delta**6+60*delta**4+120*delta**2+120)-120) dAT = dAT*100 # Convert from L·bar/mol·K to J/mol·K return (A/T-dAT)/R/tau
[docs] def _PR_phir(tau, delta, **kw): r"""Residual contribution to the free Helmholtz energy from a generic cubic equation of state with the form: Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] kw : list Aditional parameters specific of cubic equation of state. The parameters include: rhoc, Tc, b, alfa, Delta1, Delta2 Returns ------- fir : float :math:`\phi^r`, adimensional free Helmholtz energy, [-] """ rhoc = kw.get("rhoc", 1) Tc = kw.get("Tc", 1) b = kw["b"] alfa = kw["a"] Delta1 = kw["Delta1"] Delta2 = kw["Delta2"] phi1 = -log(1-b*delta*rhoc) if Delta1 == Delta2: # Special case using the l'Hôpital's rule phi2 = log((Delta1*b*rhoc*delta+1)/(Delta2*b*rhoc*delta+1)) / \ b/(Delta1-Delta2) else: phi2 = rhoc*delta fir = phi1-tau*alfa/R/Tc*phi2 return fir
[docs] def _PR_phird(tau, delta, **kw): r"""Residual contribution to the free Helmholtz energy from a generic cubic equation of state, delta derivative Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] kw : list Aditional parameters specific of cubic equation of state. The parameters include: rhoc, Tc, b, alfa, Delta1, Delta2 Returns ------- fird : float :math:`\left.\frac{\partial \phi^r}{\partial \delta}\right|_{\tau}` """ rhoc = kw.get("rhoc", 1) Tc = kw.get("Tc", 1) b = kw["b"] a = kw["a"] Delta1 = kw["Delta1"] Delta2 = kw["Delta2"] phi1d = b*rhoc/(1-b*delta*rhoc) PI12 = (1+Delta1*b*rhoc*delta) * (1+Delta2*b*rhoc*delta) phi2d = rhoc/PI12 fird = phi1d - tau*a/R/Tc*phi2d return fird
[docs] def _PR_phirt(tau, delta, **kw): r"""Residual contribution to the free Helmholtz energy from a generic cubic equation of state, tau derivative Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] kw : list Aditional parameters specific of cubic equation of state. The parameters include: rhoc, Tc, b, alfa, Delta1, Delta2 Returns ------- firt : float :math:`\left.\frac{\partial \phi^r}{\partial \tau}\right|_{\delta}` """ rhoc = kw.get("rhoc", 1) b = kw["b"] alfa = kw["a"] dat = kw["at"] Delta1 = kw["Delta1"] Delta2 = kw["Delta2"] if Delta1 == Delta2: # Special case using the l'Hôpital's rule phi2 = log((Delta1*b*rhoc*delta+1)/(Delta2*b*rhoc*delta+1)) / \ b/(Delta1-Delta2) else: phi2 = rhoc*delta dtat = tau*dat + alfa firt = -dtat/R*tau * phi2 return firt
[docs] def _instanceBuilder(p2val, *args): """Instance builder function""" cls, p1name, p1val, p2name = args return cls(**{p1name: p1val, p2name: p2val})
[docs] class MEoS(ThermoAdvanced): r"""General class for implement multiparameter equation of state Each child class must define the parameters for the calculations Compound definition: * name: Name of component * CASNumber: CAS Number of component * formula: Empiric formula * synonym: Alternate formula (Refrigerant name) * id: index of component in pychemqt database * _refPropName = Codename of compound in RefProp * _coolPropName = Coedename of compound in coolProp Physical properties: * rhoc: Critical density, [kg/m³] * Tc: Critical temperature, [K] * Pc: Critical pressure, [Pa] * M: Molecular weigth, [g/mol] * Tt: Temperature of triple point, [K] * Tb: Normal boiling point temperature, [K] * f_acent: Acentric factor, [-] * momentoDipolar: Depole moment, [C·m] Parameters of mEoS and transport correlation: * eq: List of pointer for mEoS correlations * _viscosity: List of pointer for viscosity correlations * _thermal: List of pointer for thermal conductivity correlations Other properties correlations: * _vapor_Pressure: Parameters for vapor pressure ancillary equation * _liquid_Density: Parameters for liquid density ancillary equation * _vapor_Density: Parameters for vapor density ancillary equation * _dielectric: Parameters for dielectric constant calculation * _melting: Parameters for melting line calculation * _sublimation: Parameters for sublimation line calculation * _surface: Parameters for surface tension calculation Parameters necessary only for special EoS: * _PR: Lin-Duan volume correction for Peng-Robinson equation of state * _Tr: Temperature parameter for generalized equation * _rhor: Density parameter for generalized equation * _w: Acentric factor for generalized equation """ id = None _refPropName = "" _coolPropName = "" _Tr = None _rhor = None _w = None eq = () _PR = None _dielectric = None _melting = None _sublimation = None _surface = None _vapor_Pressure = None _liquid_Density = None _vapor_Density = None _omega = None _viscosity = None _thermal = None _critical = None # Conformal ecs calculated properties, saved here to avoid recalculate _T0_ecs = None _rho0_ecs = None _ecs_msg = "" _test = [] kwargs = {"T": 0.0, "P": 0.0, "rho": None, "h": None, "s": None, "u": None, "x": None, "v": 0.0, "eq": 0, "visco": 0, "thermal": 0, "ref": None, "refvalues": None, "rho0": 0, "T0": 0} status = 0 msg = translate("MEoS", "Unknown Variables")
[docs] @classmethod def from_list(cls, p1name, p1val, p2name, p2val): """Speed up method using multiprocessing for multiple point calculation with a fixed input and changing other input parameter Parameters ---------- p1name : str string with name of fixed input parameter p1val : float fixed input parameter value p2name : str string with name of changing input parameter p2val : list iterable with values of changing input parameter Returns ------- states : list list with calculated states """ lst = [] with ProcessPoolExecutor() as executor: states = executor.map( _instanceBuilder, *(p2val, repeat(cls), repeat(p1name), repeat(p1val), repeat(p2name))) for state in states: lst.append(state) return lst
[docs] def __init__(self, **kwargs): """ Constructor of instance, the definition can be done with any of this input pair: * T-P : Only for single phase region difinition * T-x : For two phase region definition with known temperature * P-x : For two phase region definition with known pressure * T-rho * T-s * T-u * P-rho * P-h * P-u * rho-h * rho-s * rho-u * h-s * s-u Volume can be used as alternate input for density Other input pair like T-h, P-s, h-u are supported but it isn't recommended because they are bad state definition, there are several point with same T-h value. >>> from lib.mEoS import H2O >>> st1 = H2O(T=300, P=101325) >>> st2 = H2O(T=300, h=st1.h) >>> "%0.2f %0.2f" % (st1.T, st2.T) '300.00 300.00' >>> "%0.4f %0.4f" % (st1.x, st2.x) '0.0000 0.0000' >>> "%0.4f %0.4f" % (st1.h, st2.h) '112654.8997 112654.8997' As we can see, there are two point with same T-h values, so as input pair they are not a complete definition of state point. The calculated instance has the following properties * T: Temperature, [K] * Tr: Reduced temperature, [-] * P: Pressure, [Pa] * Pr: Reduced Pressure, [-] * x: Quality, [-] * rho: Density, [kg/m³] * rhoM: Molar Density, [kmol/m³] * v: Volume, [m³/kg] * h: Enthalpy, [kJ/kg] * hM: Molar Enthalpy, [kJ/kmol] * s: Entropy, [kJ/kg·K] * sM: Molar Entropy, [kJ/kmol·K] * u: Internal Energy, [kJ/kg] * uM: Molar Internal Energy, [kJ/kmol] * a: Helmholtz Free Energy, [kJ/kg] * aM: Molar Helmholtz Free Energy, [kJ/kmol] * g: Gibbs Free Energy, [kJ/kg] * gM: Molar Gibbs Free Energy, [kJ/kmol] * cv: Specific isochoric heat capacity, [J/kg·K] * cvM: Molar Specific isochoric heat capacity, [J/kmol·K] * cp: Specific isobaric heat capacity, [J/kg·K] * cpM: Molar Specific isobaric heat capacity, [J/kmol·K] * cp_cv: Heat capacities ratio, [-] * w: Speed sound, [m/s] * Z: Compresibility, [-] * fi: Fugacity coefficient, [-] * f: Fugacity, [Pa] * gamma: Isoentropic exponent, [-] * alfav: Volume Expansivity, [1/K] * kappa: Isothermal compresibility, [1/Pa] * kappas: Adiabatic compresibility, [1/Pa] * alfap: Relative pressure coefficient, [1/K] * batap: Isothermal stress coefficient, [kg/m³] * joule: Joule-Thomson coefficient, [K/Pa] * deltat: Isothermal throttling coefficient, [kJ/kgPa] * Hvap: Vaporization heat, [kJ/kg] * Svap: Vaporization entropy, [kJ/kg·K] * betas: Isentropic temperature-pressure, [K/Pa] * Gruneisen: Gruneisen parameter, [-] * virialB: 2nd virial coefficient, [m³/kg] * virialC: 3er virial coefficient, [m⁶/kg²] * virialD: 4th virial coefficient, [m¹²/kg³] * dpdT_rho: (dp/dT)_rho, [Pa/K] * dpdrho_T: (dp/drho)_T, [Pam³/kg] * drhodT_P: (drho/dT)_P, [kg/m³·K] * drhodP_T: (drho/dP)_T, [kg/Pam³] * dhdT_rho: (dh/dT)_rho, [J/kg·K] * dhdP_T: (dh/dP)_T, [J/kgPa] * dhdT_P: (dh/dT)_P, [J/kg·K] * dhdrho_T: (dh/drho)_T, [kJm³/kg²] * dhdrho_P: (dh/drho)_P, [kJm³/kg²] * dhdP_rho: (dh/dP)_rho, [kJ/kgPa] * kt: Isothermal expansion coefficient, [-] * ks: Isentropic expansion coefficient, [-] * Ks: Adiabatic bulk modulus, [Pa] * Kt: Isothermal bulk modulus, [Pa] * IntP: Internal pressure, [Pa] * invT: Negative reciprocal temperature, [1/K] * hInput: Specific heat input, [J/kg] * epsilon: Dielectric constant, [-] * mu: Viscosity, [Pa·s] * k: Thermal conductivity, [W/m·K] * nu: Kinematic viscosity, [m²/s] * alfa: Thermal diffusivity, [m²/s] * sigma: Surface tension, [N/m] * Prandt: Prandtl number, [-] * v0: Ideal gas Specific volume, [m³/kg] * rho0: Ideal gas Density, [kg/m³] * h0: Ideal gas Specific enthalpy, [J/kg] * u0: Ideal gas Specific internal energy, [J/kg] * s0: Ideal gas Specific entropy, [J/kg·K] * a0: Ideal gas Specific Helmholtz free energy, [J/kg] * g0: Ideal gas Specific Gibbs free energy, [J/kg] * cp0: Ideal gas Specific isobaric heat capacity, [J/kg·K] * cv0: Ideal gas Specific isochoric heat capacity, [J/kg·K] * cp0_cv: Ideal gas heat capacities ratio, [-] * gamma0: Ideal gas Isoentropic exponent, [-] * d2Pdrho2: [∂²P/∂ρ²]T * d2PdrhodT: [∂²P/∂ρ∂T] * d2PdT2: [∂²P/∂∂T²] * d2sdrho2: [∂²s/∂ρ²] * d2sdrhodT: [∂²s/∂ρ∂T] * d2sdT2: [∂²s/∂T²] * d2udrho: [∂²u/∂ρ²] * d2udrhodT: [∂²u/∂ρ∂T] * d2udT2: [∂²u/∂T²] * d2hdrho2: [∂²h/∂ρ²] * d2hdrhodT: [∂²h/∂ρ∂T] * d2hdT2: [∂²h/∂ρ∂T²] * d2gdrho2: [∂²g/∂ρ²] * d2gdrhodT: [∂²g/∂ρ∂T] * d2gdT2: [∂²g/∂T²] * PIP: Phase identification parameter, [-] Parameters ---------- T : float Temperature, [K] P : float Pressure, [Pa] rho : float Density, [kg/m³] v : float Specific volume, [m³/kg] h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kg·K] u : float Specific internal energy, [kJ/kg·K] x : float Quality, [-] eq : int, default 0 Index of equation to use. This variable can be too string with several option: * Codename of equation to use, the name of equation dict * PR: To use the Peng-Robinson cubic equation * Generalised: To use a generalized mEoS * GERG: To use the GERG-2008 equation of Kunz-Wagner visco : int, default 0 Index of correlation for viscosity calculation thermal : int, default 0 Index of correlation for thermal conductivity calculation ref : str Code with enthalpy-entropy reference state: * OTO: h,s=0 at 25ºC and 1 atm * NBP: h,s=0 saturated liquid at Tb * IIR: h=200,s=1 saturated liquid 0ºC * ASHRAE: h,s=0 saturated liquid at -40ºC * CUSTOM: custom user defined reference state refvalues: list List with custom values of reference state, only necessary if ref has *CUSTOM* value. The list must be the variables in the order: * Tref: Reference temperature, [K] * Pref: Reference pressure, [kPa] * ho: Enthalpy in reference state, [kJ/kg] * so: Entropy in reference state, [kJ/kg·K] rho0 : float Initial density value for improve iteration convergence, [kg/m³] T0 : float Initial teperature value for improve iteration convergence, [K] """ self.kwargs = MEoS.kwargs.copy() self.__call__(**kwargs) # Define general documentation if self._surface and "__doi__" not in self._surface: self._surface["__doi__"] = __doi__[1] if self._dielectric and "__doi__" not in self._dielectric: self._dielectric["__doi__"] = __doi__[24]
def __call__(self, **kwargs): """Make instance callable to let definition one parameters for one""" # Let user refer to equation using the internal name of equation eq = kwargs.get("eq", 0) if isinstance(eq, str) and eq in self.__class__.__dict__: eq = self.eq.index(self.__class__.__dict__[eq]) kwargs["eq"] = eq elif isinstance(eq, str) and eq not in self.__class__.__dict__ and \ eq not in ["PR", "GERG", "Generalised"]: raise ValueError("Unknown equation") self.kwargs.update(kwargs) self._code = "" if eq == "PR": self._constants = self.eq[0] self._code = "PR" elif eq == "Generalised": self._Generalised() self._code = "Generalised" elif eq == "GERG": try: self._constants = self.GERG except AttributeError: self._constants = self.eq[0] elif self.eq[eq]["__type__"] == "Helmholtz": self._constants = self.eq[eq] elif self.eq[eq]["__type__"] == "MBWR": self._constants = self.eq[eq] if not self._code: self._code = str(eq) visco = self.kwargs["visco"] thermal = self.kwargs["thermal"] if self._viscosity: self._viscosity = self.__class__._viscosity[visco] if self._thermal: self._thermal = self.__class__._thermal[thermal] # Configure custom parameter from eq if "M" in self._constants: self.M = self._constants["M"] if "Tc" in self._constants: self.Tc = unidades.Temperature(self._constants["Tc"]) if "Pc" in self._constants: self.Pc = unidades.Pressure(self._constants["Pc"], "kPa") if "rhoc" in self._constants: self.rhoc = unidades.Density(self._constants["rhoc"]*self.M) if "Tt" in self._constants: self.Tt = unidades.Temperature(self._constants["Tt"]) self.R = unidades.SpecificHeat(self._constants["R"]/self.M, "kJkgK") self.Zc = self.Pc/self.rhoc/self.R/self.Tc self.cleanOldValues(**kwargs) if self.calculable: self.calculo() if self.status in (1, 3): converge = True for input in self._mode.split("-"): inp = self.kwargs[input] out = self.__getattribute__(input)._data if input in ("P", "h", "u", "s"): maxError = 1 else: maxError = 1e-3 if abs(inp-out) > maxError: converge = False break else: converge = False if not converge: self.status = 5 self.msg = translate("MEoS", "Solution don´t converge") msg = "%s state don't converge" % (self.__class__.__name__) logging.debug(msg)
[docs] def cleanOldValues(self, **kwargs): """Convert alternative input parameters""" # Alternative rho input if "rhom" in kwargs: kwargs["rho"] = kwargs["rhom"]*self.M del kwargs["rhom"] elif kwargs.get("v", 0): kwargs["rho"] = 1./kwargs["v"] del kwargs["v"] elif kwargs.get("vm", 0): kwargs["rho"] = self.M/kwargs["vm"] del kwargs["vm"] elif "P" in kwargs and kwargs["P"] == 0: kwargs["rho"] = 0 del kwargs["P"] self.kwargs.update(kwargs)
@property def calculable(self): """Check if instance has enough input to be calculated""" # Define _mode variable to know in calculo procedure the input pair self._mode = "" if self.kwargs["T"] and self.kwargs["P"] > 0: self._mode = "T-P" elif self.kwargs["T"] and self.kwargs["rho"] is not None: self._mode = "T-rho" elif self.kwargs["T"] and self.kwargs["h"] is not None: self._mode = "T-h" elif self.kwargs["T"] and self.kwargs["s"] is not None: self._mode = "T-s" elif self.kwargs["T"] and self.kwargs["u"] is not None: self._mode = "T-u" elif self.kwargs["P"] and self.kwargs["rho"] is not None: self._mode = "P-rho" elif self.kwargs["P"] and self.kwargs["h"] is not None: self._mode = "P-h" elif self.kwargs["P"] and self.kwargs["s"] is not None: self._mode = "P-s" elif self.kwargs["P"] and self.kwargs["u"] is not None: self._mode = "P-u" elif self.kwargs["rho"] is not None and self.kwargs["h"] is not None: self._mode = "rho-h" elif self.kwargs["rho"] is not None and self.kwargs["s"] is not None: self._mode = "rho-s" elif self.kwargs["rho"] is not None and self.kwargs["u"] is not None: self._mode = "rho-u" elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: self._mode = "h-s" elif self.kwargs["h"] is not None and self.kwargs["u"] is not None: self._mode = "h-u" elif self.kwargs["s"] is not None and self.kwargs["u"] is not None: self._mode = "s-u" elif self.kwargs["T"] and self.kwargs["x"] is not None: self._mode = "T-x" elif self.kwargs["P"] and self.kwargs["x"] is not None: self._mode = "P-x" return bool(self._mode)
[docs] def _TP(self): """Temperature-Pressure input definition""" # Get input parameters T = self.kwargs["T"] P = self.kwargs["P"] if self._code == "PR": # Using direct rho calculation from cubic EoS mix = Mezcla(2, ids=[self.id], caudalUnitarioMolar=[1]) eq = PR(T, P, mix) if eq.x: rho = eq.rhoG else: rho = eq.rhoL rho *= self.M else: tau = self.Tc/T rhoo = [] if self.kwargs["rho0"]: rhoo.append(self.kwargs["rho0"]) if T < self.Tc: Pv = self._Vapor_Pressure(T) rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) if P > Pv: rhoo.append(rhol) else: rhoo.append(rhov) else: rhoo.append(self._Liquid_Density(self.Tc)) if "rhomax" in self._constants: rhoo.append(self._constants["rhomax"]*self.M) rhoo.append(self.rhoc) rhoo.append(P/T/self.R) def f(rho): delta = rho/self.rhoc fird = self._phird(tau, delta) return (1+delta*fird)*self.R.kJkgK*T*rho - P/1000 prop = self.fsolve(f, **{"P": P, "T": T, "rho0": rhoo}) if prop: rho = prop["rho"] else: self.status = 4 return rho
[docs] def _Th(self): """Temperature-enthalpy input definition This input pair isn't a good pair state definition Temperature and enthalpy don't represent totally independent variables, for examples there is isobar lines crossing in the region near to saturated liquid. In other words, there are several point with equal enthalpy value at same temperature, one as saturated liquid and other in two phases region near to saturation >>> from lib.mEoS import H2O >>> st1 = H2O(T=300, P=101325) >>> def f(x): ... return H2O(T=300, x=x).h-st1.h >>> x = newton(f, 0.1) >>> st2 = H2O(T=300, x=x) >>> abs(round(st1.h-st2.h, 5)) 0.0 Both point has same enthalpy so if we defined the point with that temperature and enthalpy, what point do we need the function return? """ # Get input parameters T = self.kwargs["T"] h = self.kwargs["h"] prop = {} tau = self.Tc/T offset = (self.href-self.hoffset)*1000 def f(rho): if rho < 0: rho = 0 delta = rho/self.rhoc ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird)+offset return ho - h if T < self.Tc: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) deltaL = rhol/self.rhoc deltaG = rhov/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL)+offset hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG)+offset if hoL <= h <= hoG: rhoL, rhoG, Ps = self._saturation(T) deltaL = rhoL/self.rhoc deltaG = rhoG/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL)+offset hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG)+offset x = (h-hoL)/(hoG-hoL) rho = 1/(x/rhoG+(1-x)/rhoL) prop["rhoG"] = rhoG prop["rhoL"] = rhoL prop["x"] = x prop["P"] = Ps else: if h > hoG: rhoo = rhov else: rhoo = rhol # rho = (f, rhoo)[0] prop = self.fsolve(f, **{"T": T, "h": h, "rho0": rhoo}) else: prop = self.fsolve(f, **{"T": T, "h": h, "rho0": rhoo}) # rho = fsolve(f, self.rhoc)[0] return prop
[docs] def _Ts(self): """Temperature-entropy input definition""" # Get input parameters T = self.kwargs["T"] s = self.kwargs["s"] prop = {} tau = self.Tc/T offset = (self.sref-self.soffset)*1000 def f(rho): if rho < 0: rho = 0 delta = rho/self.rhoc ideal = self._phi0(self._constants["cp"], tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = self._phir(tau, delta) firt = self._phirt(tau, delta) so = self.R*(tau*(fiot+firt)-fio-fir)+offset return so-s if T < self.Tc: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) deltaL = rhol/self.rhoc deltaG = rhov/self.rhoc idealL = self._phi0(self._constants["cp"], tau, deltaL) idealG = self._phi0(self._constants["cp"], tau, deltaG) fioL = idealL["fio"] fioG = idealG["fio"] fiot = idealL["fiot"] firL = self._phir(tau, deltaL) firtL = self._phirt(tau, deltaL) sl = self.R*(tau*(fiot+firtL)-fioL-firL)+offset firG = self._phir(tau, deltaG) firtG = self._phirt(tau, deltaG) sv = self.R*(tau*(fiot+firtG)-fioG-firG)+offset if sl <= s <= sv: rhoL, rhoG, Ps = self._saturation(T) deltaL = rhol/self.rhoc deltaG = rhov/self.rhoc idealL = self._phi0(self._constants["cp"], tau, deltaL) idealG = self._phi0(self._constants["cp"], tau, deltaG) fioL = idealL["fio"] fioG = idealG["fio"] fiot = idealL["fiot"] firL = self._phir(tau, deltaL) firtL = self._phirt(tau, deltaL) sl = self.R*(tau*(fiot+firtL)-fioL-firL)+offset firG = self._phir(tau, deltaG) firtG = self._phirt(tau, deltaG) sv = self.R*(tau*(fiot+firtG)-fioG-firG)+offset x = (s-sl)/(sv-sl) rho = 1/(x/rhoG+(1-x)/rhoL) prop["rhoG"] = rhoG prop["rhoL"] = rhoL prop["x"] = x prop["P"] = Ps else: if s > sv: rhoo = rhov else: rhoo = rhol prop = self.fsolve(f, **{"T": T, "s": s, "rho0": rhoo}) else: prop = self.fsolve(f, **{"T": T, "s": s, "rho0": self.rhoc}) return prop
[docs] def _Tu(self): """Temperature-internal energy input definition""" # Get input parameters T = self.kwargs["T"] u = self.kwargs["u"] prop = {} tau = self.Tc/T offset = (self.href-self.hoffset)*1000 def f(rho): if rho < 0: rho = 0 delta = rho/self.rhoc ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) Po = self.R.kJkgK*T*(1+delta*fird)*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird)+offset return ho-Po*1e3/rho - u if T < self.Tc: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) deltaL = rhol/self.rhoc deltaG = rhov/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) Po = self.R.kJkgK*T*(1+deltaL*firdL)*rhol hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL)+offset hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG)+offset lu = hoL-Po*1e3/rhol vu = hoG-Po*1e3/rhov if lu <= u <= vu: rhoL, rhoG, Ps = self._saturation(T) deltaL = rhoL/self.rhoc deltaG = rhoG/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) Po = self.R.kJkgK*T*(1+deltaL*firdL)*rhoL hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL)+offset hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG)+offset lu = hoL-Po*1e3/rhoL vu = hoG-Po*1e3/rhoG x = (u-lu)/(vu-lu) rho = 1/(x/rhoG+(1-x)/rhoL) prop["rhoG"] = rhoG prop["rhoL"] = rhoL prop["x"] = x prop["P"] = Ps else: if u > vu: rhoo = rhov else: rhoo = rhol prop = self.fsolve(f, **{"T": T, "u": u, "rho0": rhoo}) else: prop = self.fsolve(f, **{"T": T, "u": u, "rho0": self.rhoc}) return prop
[docs] def _Prho(self): """Pressure-density input definition""" # Get input parameters rho = self.kwargs["rho"] P = self.kwargs["P"] def f(T): delta = rho/self.rhoc if T < 1: T = 1 tau = self.Tc/T fird = self._phird(tau, delta) return (1+delta*fird)*self.R.kJkgK*T*rho - P/1000 def f2(parr): T, rhol, rhog = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-9 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) # (1./rho-1/rhol)/(1/rhog-1/rhol) - x, return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, Ps - P/1000) prop = self.fsolve(f, f2, **{"P": P, "rho": rho}) return prop
[docs] def _Ph(self): # Get input parameters P = self.kwargs["P"] h = self.kwargs["h"] prop = {} offset = (self.href-self.hoffset)*1000 def f(parr): rho, T = parr if rho < 0: rho = 0 if T < 1: T = 1 delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) Po = self.R.kJkgK*T*(1+delta*fird)*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird)+offset return Po-P/1e3, ho-h def f2(parr): T, rhol, rhog, x = parr # print("f2", parr) if T <= 0: T = 0.1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 if x < 0: x = 0 if x > 1: x = 1 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL)+offset firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG)+offset Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x) + hoG*x - h, Ps - P/1e3) prop = self.fsolve(f, f2, **{"P": P, "h": h, "T0": self.kwargs["T0"]}) return prop
[docs] def calculo(self): """Calculate procedure""" # Get input parameters T = self.kwargs["T"] rho = self.kwargs["rho"] P = self.kwargs["P"] s = self.kwargs["s"] h = self.kwargs["h"] u = self.kwargs["u"] x = self.kwargs["x"] # Define reference state ref = self.kwargs["ref"] refvalues = self.kwargs["refvalues"] self._ref(ref, refvalues) propiedades = None vapor = None liquido = None # Special rhoc for MBWR with gamma defined if self._constants["__type__"] == "MBWR" and \ "gamma" in self._constants: rhocm = 1/(-self._constants["gamma"])**0.5 self.rhoc = rhocm*self.M # Procedure for each input option if self._mode == "T-P": rho = self._TP() elif self._mode == "T-rho": # In this mode only check possible two phases region rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T > self.Tc: x = 1 elif rho == 0: x = 1 elif rho >= rhol: x = 0 elif rho <= rhov: x = 1 else: rhoL, rhoG, Ps = self._saturation(T) if rho >= rhoL: x = 0 elif rho <= rhoG: x = 1 else: x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) x = min(x, 1) x = max(x, 0) elif self._mode == "T-h": prop = self._Th() if "x" in prop: x = prop["x"] rhoG = prop["rhoG"] rhoL = prop["rhoL"] else: rho = prop["rho"] elif self._mode == "T-s": prop = self._Ts() if "x" in prop: x = prop["x"] rhoG = prop["rhoG"] rhoL = prop["rhoL"] else: rho = prop["rho"] elif self._mode == "T-u": prop = self._Tu() if "x" in prop: x = prop["x"] rhoG = prop["rhoG"] rhoL = prop["rhoL"] else: rho = prop["rho"] elif self._mode == "P-rho": prop = self._Prho() if "T" in prop: T = prop["T"] if "x" in prop: x = prop["x"] rhoG = prop["rhoG"] rhoL = prop["rhoL"] else: self.status = 4 elif self._mode == "P-h": prop = self._Ph() if "T" in prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] else: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = prop["x"] else: self.status = 4 elif self._mode == "P-s": def f(parr): rho, T = parr if rho < 0: rho = 0 if T < 1: T = 1 delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = self._phir(tau, delta) fird = self._phird(tau, delta) firt = self._phirt(tau, delta) Po = self.R.kJkgK*T*(1+delta*fird)*rho so = self.R*(tau*(fiot+firt)-fio-fir) return Po-P/1e3, so-s def f2(parr): T, rhol, rhog, x = parr if T < 1: T = 1 if rhol < 0: rhol = 0 if rhog < 0: rhog = 0 if x < 0: x = 0 if x > 1: x = 1 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(self._constants["cp"], tau, deltaL) fioL = idealL["fio"] fiot = idealL["fiot"] idealG = self._phi0(self._constants["cp"], tau, deltaG) fioG = idealG["fio"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, soL*(1-x)+soG*x - s, Ps - P/1000) prop = self.fsolve(f, f2, **{"P": P, "s": s}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] else: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = prop["x"] else: self.status = 4 elif self._mode == "P-u": def f(parr): rho, T = parr if rho < 0: rho = 1e-10 if T < 1: T = 1 delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) Po = self.R.kJkgK*T*(1+delta*fird)*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return Po-P/1e3, ho-Po*1e3/rho - u def f2(parr): T, rhol, rhog, x = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 if x < 0: x = 0 if x > 1: x = 1 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps*1000/rhog lu = hoL-Ps*1000/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, lu*(1-x)+vu*x - u, Ps - P/1000) prop = self.fsolve(f, f2, **{"P": P, "u": u}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] else: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = prop["x"] else: self.status = 4 elif self._mode == "rho-h": delta = rho/self.rhoc def f(T): if T < 1: T = 1 tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho - h def f2(parr): T, rhol, rhog = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h) prop = self.fsolve(f, f2, **{"h": h, "rho": rho}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] elif "rhoG" in prop: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) else: self.status = 4 elif self._mode == "rho-s": delta = rho/self.rhoc def f(T): if T < 1: T = 1 tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = self._phir(tau, delta) firt = self._phirt(tau, delta) so = self.R*(tau*(fiot+firt)-fio-fir) return so-s def f2(parr): T, rhol, rhog = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(self._constants["cp"], tau, deltaL) fioL = idealL["fio"] fiot = idealL["fiot"] idealG = self._phi0(self._constants["cp"], tau, deltaG) fioG = idealG["fio"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, soL*(1-x)+soG*x - s) prop = self.fsolve(f, f2, **{"s": s, "rho": rho}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] elif "rhoG" in prop: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) else: self.status = 4 elif self._mode == "rho-u": delta = rho/self.rhoc def f(T): if T < 1: T = 1 tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) Po = self.R.kJkgK*T*(1+delta*fird)*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po*1e3/rho - u def f2(parr): T, rhol, rhog = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) x = (1./rho-1/rhol)/(1/rhog-1/rhol) vu = hoG-Ps*1000/rhog lu = hoL-Ps*1000/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, lu*(1-x)+vu*x - u) prop = self.fsolve(f, f2, **{"u": u, "rho": rho}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] elif "rhoG" in prop: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) else: self.status = 4 elif self._mode == "h-s": def f(parr): rho, T = parr if rho < 0: rho = 1e-10 if T < 1: T = 1 delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = self._phir(tau, delta) fird = self._phird(tau, delta) firt = self._phirt(tau, delta) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) so = self.R*(tau*(fiot+firt)-fio-fir) return ho-h, so-s def f2(parr): T, rhol, rhog, x = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 if x < 0: x = 0 if x > 1: x = 1 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(self._constants["cp"], tau, deltaL) fioL = idealL["fio"] fiot = idealL["fiot"] idealG = self._phi0(self._constants["cp"], tau, deltaG) fioG = idealG["fio"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h, soL*(1-x)+soG*x - s) prop = self.fsolve(f, f2, **{"h": h, "s": s, "To": self.Tt}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] else: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = prop["x"] else: self.status = 4 elif self._mode == "h-u": def f(parr): rho, T = parr if rho < 0: rho = 1e-10 if T < 1: T = 1 delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fiot = ideal["fiot"] fird = self._phird(tau, delta) firt = self._phirt(tau, delta) Po = self.R.kJkgK*T*(1+delta*fird)*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h, ho-Po*1e3/rho - u def f2(parr): T, rhol, rhog, x = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 if x < 0: x = 0 if x > 1: x = 1 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(self._constants["cp"], tau, deltaL) fiot = ideal["fiot"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps*1000/rhog lu = hoL-Ps*1000/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h, lu*(1-x)+vu*x - u) prop = self.fsolve(f, f2, **{"h": h, "u": u}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] else: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = prop["x"] else: self.status = 4 elif self._mode == "s-u": def f(parr): rho, T = parr if rho < 0: rho = 0 if T < 1: T = 1 delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = self._phir(tau, delta) fird = self._phird(tau, delta) firt = self._phirt(tau, delta) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) so = self.R*(tau*(fiot+firt)-fio-fir) Po = self.R.kJkgK*T*(1+delta*fird)*rho return so-s, ho-Po*1e3/rho - u def f2(parr): T, rhol, rhog, x = parr if T < 1: T = 1 if rhol < 0: rhol = 1e-9 if rhog < 0: rhog = 1e-10 if x < 0: x = 0 if x > 1: x = 1 tau = self.Tc/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(self._constants["cp"], tau, deltaL) fioL = idealL["fio"] fiot = idealL["fiot"] idealG = self._phi0(self._constants["cp"], tau, deltaG) fioG = idealG["fio"] firL = self._phir(tau, deltaL) firdL = self._phird(tau, deltaL) firtL = self._phirt(tau, deltaL) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = self._phir(tau, deltaG) firdG = self._phird(tau, deltaG) firtG = self._phirt(tau, deltaG) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R.kJkgK*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps*1000/rhog lu = hoL-Ps*1000/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, soL*(1-x)+soG*x - s, lu*(1-x)+vu*x - u) prop = self.fsolve(f, f2, **{"s": s, "u": u}) if prop: T = prop["T"] if "rho" in prop: rho = prop["rho"] else: rhoG = prop["rhoG"] rhoL = prop["rhoL"] x = prop["x"] else: self.status = 4 elif self._mode == "T-x": # Check input T in saturation range if self.Tt > T or self.Tc < T: raise ValueError("Wrong input values") rhoL, rhoG, Ps = self._saturation(T) rho = 1/(1/rhoG*x+1/rhoL*(1-x)) P = Ps self.status = 1 elif self._mode == "P-x": # Iterate over saturation routine to get T def funcion(T): T = float(T) rhol, rhov, Ps = self._saturation(T) return Ps-P try: T, rinput = newton(funcion, 0.99*self.Tc, full_output=True) except RuntimeError: self.status = 0 return rhoL, rhoG, Ps = self._saturation(T) rho = 1/(1/rhoG*x+1/rhoL*(1-x)) self.status = 1 # Common functionality if self.status == 4: return if x is None: if T > self.Tc: x = 1 else: rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) rhom = (rhol+rhov)/2 if rho > rhom: x = 0 else: x = 1 elif 0 < x < 1 or rho is None: rho = 1/(1/rhoG*x+1/rhoL*(1-x)) if self._mode == "T-rho" and self.kwargs["rho"] == 0: self.status = 3 self.msg = translate("MEoS", "Ideal condition at zero pressure") elif self._constants["Tmin"] <= T <= self._constants["Tmax"] and \ 0 < rho: # <= self._constants["rhomax"]*self.M: self.status = 1 self.msg = "" # elif self._constants["Tmin"] > T or T > self._constants["Tmax"]: # # rho > self._constants["rhomax"]*self.M: # self.status = 3 # self.msg = "Point out of limit of range of equation" else: self.status = 5 self.msg = translate("MEoS", "input out of range") return if x == 0: rhoL = rho liquido = self._eq(rhoL, T) if self._code == "PR": v = self.vtPR(rhoL, T) liquido["v"] = v propiedades = liquido elif x == 1: rhoG = rho vapor = self._eq(rhoG, T) propiedades = vapor else: liquido = self._eq(rhoL, T) vapor = self._eq(rhoG, T) if self._code == "PR": v = self.vtPR(rhoL, T) liquido["v"] = v if self.kwargs["P"]: P = self.kwargs["P"] elif 0 < x < 1: P = vapor["P"] else: P = propiedades["P"] # Discard point with negative pressure, sametimes in region near to # liquid triple point if P < 0: self.status = 4 return if P > self._constants["Pmax"]*1000: self.status = 3 self.msg = translate("MEoS", "State with pressure above maximum") self.T = unidades.Temperature(T) self.Tr = unidades.Dimensionless(T/self.Tc) self.P = unidades.Pressure(P) self.Pr = unidades.Dimensionless(self.P/self.Pc) self.x = unidades.Dimensionless(x) # Ideal properties cp0 = self._prop0(rho, self.T) self.v0 = unidades.SpecificVolume(cp0["v"]) self.rho0 = unidades.Density(1./self.v0) self.rhoM0 = unidades.MolarDensity(self.rho0/self.M) self.h0 = unidades.Enthalpy(cp0["h"]) self.hM0 = unidades.MolarEnthalpy(self.h0/self.M) self.u0 = unidades.Enthalpy(self.h0-self.P*self.v0) self.uM0 = unidades.MolarEnthalpy(self.u0/self.M) self.s0 = unidades.SpecificHeat(cp0["s"]) self.sM0 = unidades.MolarSpecificHeat(self.s0/self.M) self.a0 = unidades.Enthalpy(self.u0-self.T*self.s0) self.aM0 = unidades.MolarEnthalpy(self.a0/self.M) self.g0 = unidades.Enthalpy(self.h0-self.T*self.s0) self.gM0 = unidades.MolarEnthalpy(self.g0/self.M) self.cp0 = unidades.SpecificHeat(cp0["cp"]) self.cpM0 = unidades.MolarSpecificHeat(self.cp0/self.M) self.cv0 = unidades.SpecificHeat(cp0["cv"]) self.cvM0 = unidades.MolarSpecificHeat(self.cv0/self.M) self.cp0_cv = unidades.Dimensionless(self.cp0/self.cv0) self.gamma0 = self.cp0_cv self.Liquido = ThermoAdvanced() self.Gas = ThermoAdvanced() if x == 0: # liquid phase self.fill(self.Liquido, propiedades) self.fill(self, propiedades) self.fillNone(self.Gas) elif x == 1: # vapor phase self.fill(self.Gas, propiedades) self.fill(self, propiedades) self.fillNone(self.Liquido) else: self.fillNone(self) self.fill(self.Liquido, liquido) self.fill(self.Gas, vapor) self.v = unidades.SpecificVolume(x*self.Gas.v+(1-x)*self.Liquido.v) self.rho = unidades.Density(1./self.v) self.h = unidades.Enthalpy(x*self.Gas.h+(1-x)*self.Liquido.h) self.s = unidades.SpecificHeat(x*self.Gas.s+(1-x)*self.Liquido.s) self.u = unidades.Enthalpy(x*self.Gas.u+(1-x)*self.Liquido.u) self.a = unidades.Enthalpy(x*self.Gas.a+(1-x)*self.Liquido.a) self.g = unidades.Enthalpy(x*self.Gas.g+(1-x)*self.Liquido.g) self.rhoM = unidades.MolarDensity(self.rho/self.M) self.hM = unidades.MolarEnthalpy(self.h*self.M) self.sM = unidades.MolarSpecificHeat(self.s*self.M) self.uM = unidades.MolarEnthalpy(self.u*self.M) self.aM = unidades.MolarEnthalpy(self.a*self.M) self.gM = unidades.MolarEnthalpy(self.g*self.M) # Calculate special properties useful only for one phase if x < 1 and self.Tt <= T <= self.Tc: self.sigma = unidades.Tension(self._Surface(T)) else: self.sigma = unidades.Tension(None) if 0 < self.x < 1: self.Hvap = unidades.Enthalpy(self.Gas.h-self.Liquido.h) self.Svap = unidades.SpecificHeat(self.Gas.s-self.Liquido.s) else: self.Hvap = unidades.Enthalpy(None) self.Svap = unidades.SpecificHeat(None) self.invT = unidades.InvTemperature(-1/self.T) # Returned the real rhoc value for MBWR with gamma defined if self._constants["__type__"] == "MBWR" and \ "gamma" in self._constants: if "rhoc" in self._constants: self.rhoc = unidades.Density(self._constants["rhoc"]*self.M) else: self.rhoc = self.__class__.rhoc
[docs] def fsolve(self, f, f2=None, **kwargs): """Procedure to iterate to calculate T and rho in input pair without some of that unknown Parameters ---------- f : callable function to iterate in single phase region f2 : callable function to iterate in two phases region kwargs : dict Other parameters like: * T : Known temperature,[K] * P : Known pressure, [Pa] * rho : Known density, [kg/m³] * h : Known enthalpy, [kJ/kg] * s : Known entropy, [kJ/kgK] * u : Known internal energy, [kJ/kg] * T0 : initial values for temperature, [K] * rho0 : initial values for density, [kg/m³] Returns ------- prop : dict Dict with the calculated properties: * T : Calculated temperature,[K] * rho : Calculated bulk density, [kg/m³] * rhoG : Calculated gas phase density, [kg/m³] * rhoL : Calculated liquid phase density, [kg/m³] * x : Calculated quality, [-] """ # Set initial value for iteration if "T" not in kwargs: to = [self._constants["Tmin"], (self.Tt+self.Tc)/2, self.Tc, self._constants["Tmax"]] if "T0" in kwargs: if isinstance(kwargs["T0"], list): for t in kwargs["T0"][-1::-1]: to.insert(0, t) else: to.insert(0, kwargs["T0"]) if "rho" not in kwargs: rhov = self._Vapor_Density(self.Tt) rhol = self._Liquid_Density(self.Tt) ro = [rhov, rhol, self.rhoc] if "rhomax" in self._constants: ro.append(self._constants["rhomax"]*self.M) if "rho0" in kwargs and kwargs["rho0"]: if isinstance(kwargs["rho0"], list): for rho in kwargs["rho0"][-1::-1]: ro.insert(0, rho) else: ro.insert(0, kwargs["rho0"]) prop = {} rinput = None rho, T = 0, 0 converge = False if "T" in kwargs: # Calculate only density T = kwargs["T"] for r in ro: try: rho, rinput = newton(f, r, full_output=True) except RuntimeError: pass else: if self._liquid_Density and self._vapor_Density: rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if self._mode == "T-P": twophas = False else: twophas = self.Tt < T < self.Tc \ and rhov < rho < rhol else: twophas = False if 0 < rho < self._constants.get("rhomax", 1e5)*self.M \ and abs(f(rho)) < 1e-3 and not twophas \ and rinput.converged: converge = True break elif "rho" in kwargs: # Calculate only temperature rho = kwargs["rho"] for t in to: try: T, rinput = newton(f, t, full_output=True) except RuntimeError: pass else: if self._liquid_Density and self._vapor_Density: rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) twophas = self.Tt < T < self.Tc and rhov < rho < rhol else: twophas = False t = self._constants["Tmin"] <= T <= self._constants["Tmax"] if t and abs(f(T)) < 1e-3 and not twophas \ and rinput.converged: converge = True break else: # Both density and temperature unknowns for r, t in product(ro, to): try: rinput = fsolve(f, [r, t], full_output=True) rho, T = rinput[0] except: pass else: f1 = sum(abs(rinput[1]["fvec"])) if self._liquid_Density and self._vapor_Density: rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) twophas = self.Tt <= T <= self.Tc and rhov < rho < rhol else: twophas = False if 0 < rho and f1 < 1e-2 and not twophas: converge = True break elif (rho != r or T != t) and 0 < rho and f1 < 1e-5: converge = False # Two phase region calculation if f2 is not None and not converge: from numpy import linspace to = list(linspace(self.Tt, self.Tc, 10)) if "T0" in kwargs and kwargs["T0"]: if isinstance(kwargs["T0"], list): for t in kwargs["T0"][-1::-1]: to.insert(0, t) else: to.insert(0, kwargs["T0"]) for t in to: # print("to", t) rLo = self._Liquid_Density(t) rGo = self._Vapor_Density(t) if "rho" in kwargs: rinput = fsolve(f2, [t, rLo, rGo], full_output=True) T, rhoL, rhoG = rinput[0] if sum(abs(rinput[1]["fvec"])) < 1e-4: prop["T"] = T prop["rhoL"] = rhoL prop["rhoG"] = rhoG prop["x"] = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) break else: rinput = fsolve( f2, [t, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = rinput[0] # Same input pair are very inestable to converge, specially # in region near the triple point, so check too the # reported values as saturation coherent state rGo = self._Vapor_Density(T) if sum(abs(rinput[1]["fvec"])) < 1e-2 and 0 <= x <= 1 \ and rGo*0.95 < rhoG < rGo*1.05: prop["T"] = T prop["rhoL"] = rhoL prop["rhoG"] = rhoG prop["x"] = x break else: if "T" in kwargs: prop["rho"] = rho elif "rho" in kwargs: prop["T"] = T else: prop["rho"] = rho prop["T"] = T return prop
[docs] @refDoc(__doi__, [27], tab=8) def fill(self, fase, estado): """Fill phase properties""" fase._bool = True fase.M = unidades.Dimensionless(self.M) fase.v = unidades.SpecificVolume(estado["v"]) fase.rho = unidades.Density(1/fase.v) if fase.rho: fase.Z = unidades.Dimensionless(self.P*fase.v/self.T/self.R) else: fase.Z = 1 tau = estado["tau"] delta = estado["delta"] fio = estado["fio"] fiot = estado["fiot"] fiott = estado["fiott"] fiodt = estado["fiodt"] fiottt = estado["fiottt"] fir = estado["fir"] firt = estado["firt"] firtt = estado["firtt"] fird = estado["fird"] firdd = estado["firdd"] firdt = estado["firdt"] firddd = estado["firddd"] firddt = estado["firddt"] firdtt = estado["firdtt"] firttt = estado["firttt"] if "Bt" in estado: Bt = estado["Bt"] else: Bt = 0 fase.fir = fir fase.fird = fird fase.firdd = firdd fase.firt = firt fase.firtt = firtt fase.firdt = firdt fase.firddd = firddd fase.firddt = firddt fase.firdtt = firdtt fase.firttt = firdtt h = self.R.kJkgK*self.T*(1+tau*(fiot+firt)+delta*fird) \ + self.href-self.hoffset s = self.R.kJkgK*(tau*(fiot+firt)-fio-fir)+self.sref-self.soffset cv = -self.R.kJkgK*tau**2*(fiott+firtt) cp = self.R.kJkgK*( (1+delta*fird-delta*tau*firdt)**2/(1+2*delta*fird+delta**2*firdd) - tau**2*(fiott+firtt)) w = (self.R*self.T*( 1 + 2*delta*fird+delta**2*firdd - (1+delta*fird-delta*tau*firdt)**2/tau**2/(fiott+firtt)))**0.5 if delta*fird <= -1: fugacity = None self.status = 3 self.msg = "Point at limit of range of equation" else: fugacity = exp(fir+delta*fird-log(1+delta*fird)) alfap = (1-delta*tau*firdt/(1+delta*fird))/self.T betap = fase.rho*(1 + (delta*fird+delta**2*firdd)/(1 + delta*fird)) fase.h = unidades.Enthalpy(h, "kJkg") fase.s = unidades.SpecificHeat(s, "kJkgK") fase.u = unidades.Enthalpy(fase.h-self.P*fase.v) fase.a = unidades.Enthalpy(fase.u-self.T*fase.s) fase.g = unidades.Enthalpy(fase.h-self.T*fase.s) fase.fi = [unidades.Dimensionless(fugacity)] fase.f = [unidades.Pressure(f*self.P) for f in fase.fi] fase.cp = unidades.SpecificHeat(cp, "kJkgK") fase.cv = unidades.SpecificHeat(cv, "kJkgK") fase.cp_cv = unidades.Dimensionless(fase.cp/fase.cv) # fase.cps = estado["cps"] fase.w = unidades.Speed(w) fase.rhoM = unidades.MolarDensity(fase.rho/self.M) fase.hM = unidades.MolarEnthalpy(fase.h*self.M) fase.sM = unidades.MolarSpecificHeat(fase.s*self.M) fase.uM = unidades.MolarEnthalpy(fase.u*self.M) fase.aM = unidades.MolarEnthalpy(fase.a*self.M) fase.gM = unidades.MolarEnthalpy(fase.g*self.M) fase.cvM = unidades.MolarSpecificHeat(fase.cv*self.M) fase.cpM = unidades.MolarSpecificHeat(fase.cp*self.M) fase.alfap = unidades.InvTemperature(alfap) fase.betap = unidades.Density(betap) if fase.rho: fase.gamma = unidades.Dimensionless( -fase.v/self.P*self.derivative("P", "v", "s", fase)) else: fase.gamma = self.gamma0 fase.joule = unidades.TemperaturePressure( self.derivative("T", "P", "h", fase)) fase.Gruneisen = unidades.Dimensionless( fase.v/fase.cv*self.derivative("P", "T", "v", fase)) fase.dpdT_rho = unidades.PressureTemperature( self.derivative("P", "T", "rho", fase)) fase.IntP = unidades.Pressure(self.derivative("u", "v", "T", fase)) # Several second-order partial derivatives from ref #27 fase.d2PdrhodT = self.R*(1 + 2*delta*fird + delta**2*firdd - 2*delta*tau*firdt - tau*delta**2*firddt) fase.d2PdT2 = fase.rho*self.R/self.T*(tau**2*delta*firdtt) fase.d2sdT2 = self.R/self.T**2*( tau**3*(fiottt+firttt) + 3*tau**2*(fiott+firtt)) fase.d2udT2 = self.R/self.T*( tau**3*(fiottt+firttt)+2*tau**2*(fiott+firtt)) fase.d2hdT2 = self.T/self.T*( tau**3*(fiottt+firttt) + 2*tau**2*(fiott+firtt)+tau*delta*firdtt) fase.d2gdT2 = self.R/self.T*(tau**2*(fiott+firtt)+tau**2*delta*firdtt) if fase.rho: fase.alfav = unidades.InvTemperature( self.derivative("v", "T", "P", fase)/fase.v) fase.kappa = unidades.InvPressure( -self.derivative("v", "P", "T", fase)/fase.v) fase.kappas = unidades.InvPressure( -1/fase.v*self.derivative("v", "P", "s", fase)) fase.betas = unidades.TemperaturePressure( self.derivative("T", "P", "s", fase)) fase.kt = unidades.Dimensionless( -fase.v/self.P*self.derivative("P", "v", "T", fase)) fase.ks = unidades.Dimensionless( -fase.v/self.P*self.derivative("P", "v", "s", fase)) fase.Ks = unidades.Pressure( -fase.v*self.derivative("P", "v", "s", fase)) fase.Kt = unidades.Pressure( -fase.v*self.derivative("P", "v", "T", fase)) fase.dhdT_rho = unidades.SpecificHeat( self.derivative("h", "T", "rho", fase)) fase.dhdT_P = unidades.SpecificHeat( self.derivative("h", "T", "P", fase)) fase.dhdP_T = unidades.EnthalpyPressure( self.derivative("h", "P", "T", fase)) # deltat fase.deltat = fase.dhdP_T fase.dhdP_rho = unidades.EnthalpyPressure( self.derivative("h", "P", "rho", fase)) dpdrho = self.R*self.T*(1+2*delta*fird+delta**2*firdd) drhodt = -fase.rho*(1+delta*fird-delta*tau*firdt) / \ (self.T*(1+2*delta*fird+delta**2*firdd)) dhdrho = self.R*self.T/fase.rho * \ (tau*delta*(fiodt+firdt)+delta*fird+delta**2*firdd) fase.dhdrho_T = unidades.EnthalpyDensity(dhdrho) fase.dhdrho_P = unidades.EnthalpyDensity( dhdrho+fase.dhdT_rho/drhodt) fase.dpdrho_T = unidades.PressureDensity(dpdrho) fase.drhodP_T = unidades.DensityPressure(1/dpdrho) fase.drhodT_P = unidades.DensityTemperature(drhodt) fase.Z_rho = unidades.SpecificVolume((fase.Z-1)/fase.rho) fase.hInput = unidades.Enthalpy( fase.v*self.derivative("h", "v", "P", fase)) fase.d2Pdrho2 = self.R*self.T/fase.rho*( 2*delta*fird + 4*delta**2*firdd + delta**3*firddd) fase.d2sdrho2 = self.R/fase.rho**2*( 1 - delta**2*firdd + tau*delta**2*firddt) fase.d2sdrhodT = self.R/self.T/fase.rho*(-tau**2*delta*firdtt) fase.d2udrho = self.T*self.R/fase.rho**2*(tau*delta**2*firddt) fase.d2udrhodT = self.R/fase.rho*(-tau**2*delta*firdtt) fase.d2hdrho2 = self.T*self.R/fase.rho*( tau*delta**2*firddt + 2*delta**2*firdd + delta**3*firddd) fase.d2hdrhodT = self.R/fase.rho * ( delta**2*firdd - tau**2*delta*firdtt + delta*fird - tau*delta**2*firddt - tau*delta*firdt) fase.d2gdrho2 = self.T*self.R/fase.rho**2 * ( -1 + 3*delta**2*firdd + delta**3*firddd) fase.d2gdrhodT = self.R/fase.rho * ( 1 + 2*delta*fird - 2*tau*delta*firdt + delta**2*firdd - tau*delta**2*firddt) # Phase identification parameter fase.PIP = 2-fase.rho*( fase.d2PdrhodT/fase.dpdT_rho-fase.d2Pdrho2/fase.dpdrho_T) fase.virialB = unidades.SpecificVolume(estado["B"]/self.rhoc) fase.dBt = -Bt/self.rhoc*self.Tc/self.T**2 fase.virialC = unidades.SpecificVolume_square( estado["C"]/self.rhoc**2) fase.virialD = unidades.Dimensionless( estado["D"]/self.rhoc**3) fase.invT = unidades.InvTemperature(-1/self.T) try: fase.mu = self._Viscosity(fase.rho, self.T, fase) except OverflowError: fase.mu = None try: fase.k = self._ThCond(fase.rho, self.T, fase) except TypeError: fase.k = None if fase.mu and fase.rho: fase.nu = unidades.Diffusivity(fase.mu/fase.rho) else: fase.nu = unidades.Diffusivity(None) if fase.k and fase.rho: fase.alfa = unidades.Diffusivity(fase.k/fase.rho/fase.cp) else: fase.alfa = unidades.Diffusivity(None) if fase.mu and fase.k: fase.Prandt = unidades.Dimensionless(fase.mu*fase.cp/fase.k) else: fase.Prandt = unidades.Dimensionless(None) fase.epsilon = unidades.Dimensionless( self._Dielectric(fase.rho, self.T)) fase.fraccion = [1] fase.fraccion_masica = [1]
# dbt=-phi11/rho/t # propiedades["cps"] = propiedades["cv"]-self.R*(1+delta*fird-delta*tau # *firdt)*T/rho*propiedades["drhodt"] # propiedades["cps"] = self.R*(-tau**2*(fiott+firtt)+(1+delta*fird-delta # *tau*firdt)/(1+2*delta*fird+delta**2*firdd)* # ((1+delta*fird-delta*tau*firdt)-self.rhoc/self.R/delta* # self.derivative("P", "T", "rho", propiedades))) # propiedades["cps"] = propiedades["cv"] Add cps from Argon pag.27
[docs] @refDoc(__doi__, [9], tab=8) def _saturation(self, T=None): """ Saturation calculation for two phase search """ if not T: T = self.T if T > self.Tc: T = self.Tc T = float(T) rhoLo = self._Liquid_Density(T) rhoGo = self._Vapor_Density(T) def f(parr): rhol, rhog = parr deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc liquidofird = self._phird(self.Tc/T, deltaL) liquidofir = self._phir(self.Tc/T, deltaL) vaporfird = self._phird(self.Tc/T, deltaG) vaporfir = self._phir(self.Tc/T, deltaG) Jl = deltaL*(1+deltaL*liquidofird) Jv = deltaG*(1+deltaG*vaporfird) Kl = deltaL*liquidofird+liquidofir+log(deltaL) Kv = deltaG*vaporfird+vaporfir+log(deltaG) return Kv-Kl, Jv-Jl rhoL, rhoG = fsolve(f, [rhoLo, rhoGo]) if rhoL == rhoG: Ps = self.Pc else: liquido = self._eq(rhoL, T) vapor = self._eq(rhoG, T) deltaL = rhoL/self.rhoc deltaG = rhoG/self.rhoc Ps = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"] - vapor["fir"] + log(deltaL/deltaG)) return rhoL, rhoG, Ps
[docs] def _eq(self, rho, T): """Define the calculation method to use""" delta = rho/self.rhoc tau = self.Tc/T prop = self._phi0(self._constants["cp"], tau, delta) if self._code == "PR": res = self._PengRobinson(rho, T) delta *= 1000/self.M prop["P"] = (1+delta*res["fird"])*self.R*T*rho elif self._constants["__type__"] == "Helmholtz": res = self._Helmholtz(tau, delta) prop["P"] = (1+delta*res["fird"])*self.R*T*rho elif self._constants["__type__"] == "MBWR": res = self._MBWR(rho, T) prop.update(res) prop["tau"] = tau prop["delta"] = delta prop["T"] = T if rho: v = 1./rho else: v = float("inf") prop["v"] = v return prop
[docs] def _phir(self, tau, delta): """Residual contribution to the free Helmholtz energy""" if self._code == "PR": kw = {} kw["rhoc"] = self.rhoc kw["Tc"] = self.Tc kw["b"] = 0.0778*R*self.Tc/self.Pc kw["Delta1"] = 1+2**0.5 kw["Delta2"] = 1-2**0.5 a = 0.457235*R**2*self.Tc**2/self.Pc Tr = 1/tau m = 0.37464+1.54226*self.f_acent-0.26992*self.f_acent**2 alfa = a*(1+m*(1-Tr**0.5))**2 kw["a"] = alfa fir = _PR_phir(tau, delta, **kw) elif self._constants["__type__"] == "Helmholtz": fir = _Helmholtz_phir(tau, delta, self._constants) elif self._constants["__type__"] == "MBWR": T = self.Tc/tau if "gamma" in self._constants: rhocm = 1/(-self._constants["gamma"])**0.5 rhoc = rhocm*self.M else: rhoc = self.rhoc rho = delta*rhoc fir = _MBWR_phir(T, rho, rhoc, self.M, self._constants) return fir
[docs] def _phird(self, tau, delta): """Residual contribution to the free Helmholtz energy, delta derivative""" if self._code == "PR": kw = {} kw["rhoc"] = self.rhoc/self.M kw["Tc"] = self.Tc kw["b"] = 0.0778*R*self.Tc/self.Pc kw["Delta1"] = 1+2**0.5 kw["Delta2"] = 1-2**0.5 a = 0.457235*R**2*self.Tc**2/self.Pc Tr = 1/tau m = 0.37464+1.54226*self.f_acent-0.26992*self.f_acent**2 alfa = a*(1+m*(1-Tr**0.5))**2 kw["a"] = alfa fir = _PR_phird(tau, delta, **kw) elif self._constants["__type__"] == "Helmholtz": fir = _Helmholtz_phird(tau, delta, self._constants) elif self._constants["__type__"] == "MBWR": T = self.Tc/tau if "gamma" in self._constants: rhocm = 1/(-self._constants["gamma"])**0.5 rhoc = rhocm*self.M else: rhoc = self.rhoc rho = delta*rhoc fir = _MBWR_phird(T, rho, rhoc, self.M, self._constants) return fir
[docs] def _phirt(self, tau, delta): """Residual contribution to the free Helmholtz energy, tau derivative""" if self._code == "PR": kw = {} kw["rhoc"] = self.rhoc kw["Tc"] = self.Tc kw["b"] = 0.0778*R*self.Tc/self.Pc kw["Delta1"] = 1+2**0.5 kw["Delta2"] = 1-2**0.5 a = 0.457235*R**2*self.Tc**2/self.Pc Tr = 1/tau m = 0.37464+1.54226*self.f_acent-0.26992*self.f_acent**2 alfa = a*(1+m*(1-Tr**0.5))**2 kw["a"] = alfa fir = _PR_phirt(tau, delta, **kw) elif self._constants["__type__"] == "Helmholtz": fir = _Helmholtz_phirt(tau, delta, self._constants) elif self._constants["__type__"] == "MBWR": T = self.Tc/tau if "gamma" in self._constants: rhocm = 1/(-self._constants["gamma"])**0.5 rhoc = rhocm*self.M else: rhoc = self.rhoc rho = delta*rhoc fir = _MBWR_phirt(T, self.Tc, rho, rhoc, self.M, self._constants) return fir
[docs] @refDoc(__doi__, [10], tab=8) def _Generalised(self): """ Generalised mEoS based in Helmholtz free energy. Referenced in [10]_, section 7.2.2, pag. 300 """ # It use the specific critical values cited in Table 7.6, if this # values are not available use the normal critical properties if self._Tr: Tref = self._Tr else: Tref = self.Tc if self._rhor: rhoref = self._rhor else: rhoref = self.rhoc if self._w: w = self._w else: w = self.f_acent # Define the general dict with mEoS generalized parameter, Eq 7.20 helmholtz = { "R": 8.31451, "Tc": Tref, "rhoc": rhoref, "cp": self.eq[0]["cp"], "d1": [1, 1, 2, 3, 8], "t1": [0.125, 1.125, 1.25, 0.25, 0.75], "d2": [2, 3, 1, 4, 3], "t2": [0.625, 2, 4.125, 4.125, 17], "c2": [1, 1, 2, 2, 3], "gamma2": [1]*5} # Table 7.2 c1 = [0.636479524, -0.174667493e1, -0.144442644e-1, 0.6799731e-1, 0.767320032e-4, 0.218194143, 0.810318494e-1, -0.907368899e-1, 0.25312225e-1, -0.209937023e-1] c2 = [0.82247342, -0.954932692, -0.745462328, 0.182685593, 0.547120142e-4, 0.761697913, 0.415691324, -0.825206373, -0.240558288, -0.643818403e-1] c3 = [-0.186193063e1, 0.105083555e2, 0.16403233e1, -0.613747797, -0.69318829e-3, -0.705727791e1, -0.290006245e1, -0.232497527, -0.282346515, 0.254250643e1] # Define generalized compound specific parameters nr = [c1[i]+c2[i]*w+c3[i]*w**4 for i in range(10)] helmholtz["nr1"] = nr[:5] helmholtz["nr2"] = nr[5:] self._constants = helmholtz
[docs] def _ref(self, ref, refvalues=None): """Define reference state Parameters ---------- ref: str Name of standard OTO | NBP | IIR | ASHRAE | CUSTOM None to use the default reference state in EoS False to no use reference state offset refvalues: list Only necessary when ref is CUSTOM. List with custom refvalues: * Tref: Reference temperature, [K] * Pref: Reference pressure, [kPa] * ho: Enthalpy in reference state, [kJ/kg] * so: Entropy in reference state, [kJ/kg·K] """ # Variable to avoid rewrite and save the h-s offset status application applyOffset = "ao_log" not in self._constants["cp"] or ref is not None if ref is None: rf = self._constants["ref"] if isinstance(rf, str): ref = rf elif isinstance(rf, dict): ref = "CUSTOM" refvalues = (rf["Tref"], rf["Pref"], rf["ho"], rf["so"]) else: ref = "OTO" self.href = 0 self.sref = 0 # Apply h-s offset if reference state is same as equation used or if # ideal cp expression is used if applyOffset: if ref in ["OTO", "OTH", "NBP", "ASHRAE"]: self.href = 0 self.sref = 0 elif ref == "IIR": self.href = 200 self.sref = 1 elif refvalues: self.href = refvalues[2]/self.M self.sref = refvalues[3]/self.M self._refOffset(ref, refvalues) else: self._refOffset(False, refvalues)
[docs] def _refOffset(self, ref, refvalues): name = "%s-%s" % (self.__class__.__name__, self._code) if ref == "CUSTOM": if refvalues is None: refvalues = [298.15, 101325., 0., 0.] ref = "CUSTOM-%s-%s-%s-%s" % refvalues # Skip reference state checking to avoid recursion if ref is False: self.hoffset = 0 self.soffset = 0 return filename = conf_dir+"MEoSref.json" if os.path.isfile(filename): with open(filename, "r") as archivo: dat = json.load(archivo) else: dat = {} if name in dat and ref in dat[name]: self.hoffset = dat[name][ref]["h"] self.soffset = dat[name][ref]["s"] else: if name not in dat: dat[name] = {} kw = {"ref": False} kw["eq"] = self.kwargs["eq"] kw["visco"] = self.kwargs["visco"] kw["thermal"] = self.kwargs["thermal"] if ref == "OTO": st = self.__class__(T=298.15, P=101325, **kw) self.hoffset = st.h0.kJkg self.soffset = st.s0.kJkgK elif ref == "OTH": st = self.__class__(T=298.15, P=101325, **kw) self.hoffset = st.h.kJkg self.soffset = st.s.kJkgK elif ref == "NBP": st = self.__class__(P=101325, x=0, **kw) self.hoffset = st.h.kJkg self.soffset = st.s.kJkgK elif ref == "IIR": st = self.__class__(T=273.15, x=0, **kw) self.hoffset = st.h.kJkg self.soffset = st.s.kJkgK elif ref == "ASHRAE": st = self.__class__(T=233.15, x=0, **kw) self.hoffset = st.h.kJkg self.soffset = st.s.kJkgK elif ref[:6] == "CUSTOM": # First check if the custum state is in database code = "%s-%s-%s-%s" % refvalues if code not in dat[name]: T = refvalues[0] P = refvalues[1]*1e3 st = self.__class__(T=T, P=P, **kw) self.hoffset = st.h.kJkg self.soffset = st.s.kJkgK dat[name][ref] = {"h": self.hoffset, "s": self.soffset} with open(filename, "w") as archivo: json.dump(dat, archivo)
[docs] def _prop0(self, rho, T): """Ideal gas properties""" delta = rho/self.rhoc tau = self.Tc/T ideal = self._phi0(self._constants["cp"], tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fiott = ideal["fiott"] propiedades = {} if rho: propiedades["v"] = self.R*T/self.P else: propiedades["v"] = float("inf") propiedades["h"] = self.R*T*(1+tau*fiot) propiedades["s"] = self.R*(tau*fiot-fio) propiedades["cv"] = -self.R*tau**2*fiott propiedades["cp"] = self.R*(-tau**2*fiott+1) return propiedades
[docs] def _PHIO(self, cp): """Convert cp dict in phi0 dict when the cp expression isn't in Helmholtz free energy terms""" co = cp.get("ao", 0) - 1 ti = [] ci = [] taulogtau = 0 if "an" in cp: for n, t in zip(cp["an"], cp["pow"]): if t == -1: # Special case of tau*logtau term taulogtau = -n/self.Tc else: ti.append(-t) ci.append(-n/(t*(t+1))*self.Tc**t) titao = [] if "exp" in cp: titao = [fi/self.Tc for fi in cp["exp"]] sinh = [fi/self.Tc for fi in cp.get("sinh", [])] cosh = [fi/self.Tc for fi in cp.get("cosh", [])] # The integration constant are difficult to precalculate as depend of # resitual Helmholtz free energy. It's easier use a offset system # saved the values in database and retrieve for each reference state cI = 0 cII = 0 Fi0 = {"ao_log": [1, co], "pow": [0, 1] + ti, "ao_pow": [cII, cI] + ci, "ao_exp": cp.get("ao_exp", []), "titao": titao, "ao_sinh": cp.get("ao_sinh", []), "sinh": sinh, "ao_cosh": cp.get("ao_cosh", []), "cosh": cosh} if taulogtau: Fi0["tau*logtau"] = taulogtau return Fi0
[docs] def _phi0(self, cp, tau, delta): r"""Ideal gas Helmholtz free energy and derivatives The ideal gas specific heat can have different contributions .. math:: \frac{C_p^o}{R} = c_o + \sum_i c_iT_r^i + \sum_jc_j\frac{e^{\theta T_r}} {\left(1-e^{\theta T_r}\right)^2} + \sum_k \gamma_k\frac{\xi/T_r}{\sinh(\xi/T_r)} + \sum_l \delta_l\frac{\epsilon_l/T_r}{\cosh(\epsilon_l/T_r)} The dict with the definition of ideal gas specific heat must define the parameters: * ao: Independent of temperature coefficient * an: Polynomial term coefficient * pow: Polynomial term temperature exponent * ao_exp: Exponential term coefficient * exp: Exponential term exponent * ao_sinh: Hyperbolic sine term coefficient * sinh: Hyperbolic sine term exponent * ao_cosh: Hyperbolic cosine term coefficient * cosh: Hyperbolic cosine term exponent Parameters ---------- cp : dict Ideal gas properties parameters, can be in Cp term of directly in helmholtz free energy tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] Returns ------- prop : dictionary with ideal adimensional helmholtz energy and deriv fio [-] fiot: [∂fio/∂τ]δ [-] fiod: [∂fio/∂δ]τ [-] fiott: [∂²fio/∂τ²]δ [-] fiodt: [∂²fio/∂τ∂δ] [-] fiodd: [∂²fio/∂δ²]τ [-] """ if "ao_log" in cp: Fi0 = cp else: Fi0 = self._PHIO(cp) fio = Fi0["ao_log"][1]*log(tau) fiot = Fi0["ao_log"][1]/tau fiott = -Fi0["ao_log"][1]/tau**2 try: fiottt = 2*Fi0["ao_log"][1]/tau**3 except ZeroDivisionError: fiottt = 0 if delta: fiod = 1/delta fiodd = -1/delta**2 else: fiod, fiodd = 0, 0 fiodt = 0 R_ = cp.get("R", self._constants["R"]) if "pow" in Fi0: for n, t in zip(Fi0["ao_pow"], Fi0["pow"]): fio += n*tau**t if t != 0: fiot += t*n*tau**(t-1) if t not in [0, 1]: fiott += n*t*(t-1)*tau**(t-2) if t not in [0, 1, 2]: fiottt += n*t*(t-1)*(t-2)*tau**(t-3) if "ao_exp" in Fi0: for n, g in zip(Fi0["ao_exp"], Fi0["titao"]): fio += n*log(1-exp(-g*tau)) fiot += n*g*((1-exp(-g*tau))**-1-1) fiott -= n*g**2*exp(-g*tau)*(1-exp(-g*tau))**-2 fiottt += n*g**3*((exp(g*tau) - 1)**2 \ + 3*exp(g*tau) - 1)/(exp(g*tau) - 1)**3 # Special case for τ·ln(τ) terms (i.e. undecane, D2O) if "tau*logtau" in Fi0: fio += Fi0["tau*logtau"]*tau*log(tau) fiot += Fi0["tau*logtau"]*(log(tau)+1) fiott += Fi0["tau*logtau"]/tau fiottt -= Fi0["tau*logtau"]/tau**2 if "tau*logdelta" in Fi0 and delta: fio += Fi0["tau*logdelta"]*tau*log(delta) fiot += Fi0["tau*logdelta"]*log(delta) fiod += Fi0["tau*logdelta"]*tau/delta fiodd -= Fi0["tau*logdelta"]*tau/delta**2 fiodt += Fi0["tau*logdelta"]/delta # Special case for Lemmon-Jacobsen mEoS for air if "ao_exp2" in Fi0: for n, g, C in zip(Fi0["ao_exp2"], Fi0["titao2"], Fi0["sum2"]): fio += n*log(C+exp(g*tau)) fiot += n*g/(C*exp(-g*tau)+1) fiott += C*n*g**2*exp(-g*tau)/(C*exp(-g*tau)+1)**2 fiottt += g**3*n*((C + exp(g*tau))**2 \ - 3*(C + exp(g*tau))*exp(g*tau) \ + 2*exp(2*g*tau))*exp(g*tau)/(C+exp(g*tau))**3 # Hyperbolic terms if "ao_sinh" in Fi0: for n, c in zip(Fi0["ao_sinh"], Fi0["sinh"]): fio += n*log(abs(sinh(c*tau))) fiot += n*c/tanh(c*tau) fiott -= n*c**2/sinh(c*tau)**2 fiottt += 2*c**3*n*cosh(c*tau)/sinh(c*tau)**3 if "ao_cosh" in Fi0: for n, c in zip(Fi0["ao_cosh"], Fi0["cosh"]): fio -= n*log(abs(cosh(c*tau))) fiot -= n*c*tanh(c*tau) fiott -= n*c**2/cosh(c*tau)**2 fiottt -= -2*c**3*n*sinh(c*tau)/cosh(c*tau)**3 R_ = cp.get("R", self._constants["R"]) factor = R_/self._constants["R"] if delta: fio = Fi0["ao_log"][0]*log(delta)+factor*fio else: fio *= factor prop = {} prop["fio"] = fio prop["fiot"] = fiot*factor prop["fiott"] = fiott*factor prop["fiottt"] = fiottt*factor prop["fiod"] = fiod prop["fiodd"] = fiodd prop["fiodt"] = fiodt return prop
[docs] def _Helmholtz(self, tau, delta): r"""Residual contribution to the free Helmholtz energy The dict with equation of state definition must define the parameters: * nr1: Polynomial term coefficient * d1: Polynomial term delta exponent * t1: Polynomial term tau exponent * nr2: Exponential term coefficient * d2: Exponential term delta exponent * t2: Exponential term tau exponent * c2: Exponential term delta exponent in exponential * gamma2: Exponential term exponential coefficient * nr3: Gaussian term coefficient * d3: Gaussian term delta exponent * t3: Gaussian term tau exponent * epsilon3: Gaussian term delta correction in exponential * gamma3: Gaussian term tau correction in exponential * alfa3: Gaussian term exponential tau term coefficient * beta3: Gaussian term exponential tau term coefficient * exp1: Gaussian term exponential delta term exponential, default 2 * exp2: Gaussian term exponential tau term exponential, default 2 * nr4: Nonanalytic term coefficient * a4: Nonanalytic term exponent in Δ expression * b4: Nonanalytic term Δ exponent * B: Nonanalytic term coefficient in Δ expression * C: Nonanalytic term delta coefficient in exponential * D: Nonanalytic term tau coefficient in exponential * A: Nonanalytic term coefficient in θ expression * beta4: Nonanalytic term exponent in θ expression * nr_ass: Association term coefficient * d_ass: Association term delta exponent * t_ass: Association term tau exponent * epsilon_ass: Association term delta correction in exponential * gamma_ass: Association term tau correction in exponential * alfa_ass: Association term exponential tau term coefficient * beta_ass: Association term exponential tau term coefficient * b_ass: Association special last term exp1 and exp2 are used only for Lemmon-Jacobsen correlation for R125, normally don't used and using the default value 2. Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] Returns ------- prop : dict Dictionary with residual adimensional helmholtz energy and derivatives: * fir [-] * firt: [∂fir/∂τ]δ,x [-] * fird: [∂fir/∂δ]τ,x [-] * firtt: [∂²fir/∂τ²]δ,x [-] * firdt: [∂²fir/∂τ∂δ]x [-] * firdd: [∂²fir/∂δ²]τ,x [-] """ fir = fird = firdd = firt = firtt = firdt = 0 firddd = firdtt = firddt = firttt = 0 delta_0 = 1e-100 B = C = D = 0 Bt = 0 # Ct = 0 if delta: # Polinomial terms nr1 = self._constants.get("nr1", []) d1 = self._constants.get("d1", []) t1 = self._constants.get("t1", []) for n, d, t in zip(nr1, d1, t1): fir += n*delta**d*tau**t fird += n*d*delta**(d-1)*tau**t firdd += n*d*(d-1)*delta**(d-2)*tau**t firt += n*t*delta**d*tau**(t-1) firtt += n*t*(t-1)*delta**d*tau**(t-2) firdt += n*t*d*delta**(d-1)*tau**(t-1) firddd += n*d*(d-1)*(d-2)*delta**(d-3)*tau**t firdtt += n*t*d*(t-1)*delta**(d-1)*tau**(t-2) firddt += n*d*(d-1)*delta**(d-2)*t*tau**(t-1) firttt += n*t*(t-1)*(t-2)*delta**d*tau**(t-3) B += n*d*delta_0**(d-1)*tau**t C += n*d*(d-1)*delta_0**(d-2)*tau**t D += n*d*(d-1)*(d-2)*delta_0**(d-3)*tau**t Bt += n*t*d*delta_0**(d-1)*tau**(t-1) # Ct += n*d*(d-1)*delta_0**(d-2)*t*tau**(t-1) # Exponential terms nr2 = self._constants.get("nr2", []) d2 = self._constants.get("d2", []) g2 = self._constants.get("gamma2", []) t2 = self._constants.get("t2", []) c2 = self._constants.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): fir += n*delta**d*tau**t*exp(-g*delta**c) fird += n * delta**(d-1) * tau**t * exp(-delta**c*g) \ * (d-c*delta**c*g) firdd += n * delta**(d-2) * tau**t * exp(-delta**c*g) \ * (c**2*delta**(2*c)*g**2 - c**2*delta**c*g - 2*c*d*delta**c*g + c*delta**c*g + d**2 - d) firt += n * delta**d * t * tau**(t-1) * exp(-delta**c*g) firtt += n * delta**d*t*tau**(t - 2)*(t - 1)*exp(-delta**c*g) firdt += n * delta**(d-1) * t * tau**(t-1) * exp(-delta**c*g) \ * (d - c*delta**c*g) firddd += n * delta**(d-3) * tau**t * exp(-delta**c*g) \ * (2*d - c**3*delta**(3*c)*g**3 + 3*c**3*delta**(2*c)*g**2 - c**3*delta**c*g + 3*c**2*d*delta**(2*c)*g**2 - 3*c**2*d*delta**c*g - 3*c**2*delta**(2*c)*g**2 + 3*c**2*delta**c*g - 3*c*d**2*delta**c*g + 6*c*d*delta**c*g - 2*c*delta**c*g + d**3 - 3*d**2) firddt += n * delta**(d-2) * t*tau**(t-1) * exp(-delta**c*g) \ * (c**2*delta**(2*c)*g**2 - c**2*delta**c*g - 2*c*d*delta**c*g + c*delta**c*g + d**2 - d) firdtt += n * delta**(d-1) * t*tau**(t-2) * exp(-delta**c*g) \ * (-c*delta**c*g*t + c*delta**c*g + d*t - d) firttt += n * delta**d * t * tau**(t-3) * exp(-delta**c*g) \ * (t**2 - 3*t + 2) B += n * delta_0**(d-1) * tau**t * exp(-delta_0**c*g) \ * (d-c*delta_0**c*g) C += n * delta_0**(d-2) * tau**t * exp(-delta_0**c*g) \ * (c**2*delta_0**(2*c)*g**2 - c**2*delta_0**c*g - 2*c*d*delta_0**c*g + c*delta_0**c*g + d**2 - d) D += n * delta_0**(d-3) * tau**t * exp(-delta_0**c*g) \ * (- c**3*delta_0**(3*c)*g**3 + 3*c**3*delta_0**(2*c)*g**2 - c**3*delta_0**c*g + 3*c**2*d*delta_0**(2*c)*g**2 - 3*c**2*d*delta_0**c*g - 3*c**2*delta_0**(2*c)*g**2 + 3*c**2*delta_0**c*g - 3*c*d**2*delta_0**c*g + 2*d + 6*c*d*delta_0**c*g - 2*c*delta_0**c*g + d**3 - 3*d**2) Bt += n * delta_0**(d-1) * t * tau**(t-1) * exp(-delta_0**c*g) \ * (d - c*delta_0**c*g) # Ct += n*t*delta_0**(d-2)*tau**(t-1)*exp(-g*delta_0**c) * ( # c**2*delta_0**(2*c)*g**2 - 2*c*d*delta_0**c*g - # c**2*delta_0**c*g + c*delta_0**c*g + d**2 - d) # Gaussian terms nr3 = self._constants.get("nr3", []) d3 = self._constants.get("d3", []) t3 = self._constants.get("t3", []) a3 = self._constants.get("alfa3", []) e3 = self._constants.get("epsilon3", []) b3 = self._constants.get("beta3", []) g3 = self._constants.get("gamma3", []) exp1 = self._constants.get("exp1", [2]*len(nr3)) exp2 = self._constants.get("exp2", [2]*len(nr3)) for n, d, t, a, e, b, g, ex1, ex2 in zip( nr3, d3, t3, a3, e3, b3, g3, exp1, exp2): expr = exp(-a*(delta-e)**ex1-b*(tau-g)**ex2) fir += expr * n*delta**d*tau**t fird += expr * n*tau**t * ( d*delta**(d-1) - a*delta**d*ex1*(delta-e)**(ex1-1)) firt += expr * n*delta**d * ( t*tau**(t-1) - b*ex2*tau**t*(-g + tau)**(ex2-1)) firdd += expr * n*tau**t * ( a**2*delta**d*ex1**2*(delta-e)**(2*ex1-2) - 2*a*d*delta**(d-1)*ex1*(delta-e)**(ex1-1) - a*delta**d*ex1**2*(delta-e)**(ex1-2) + a*delta**d*ex1*(delta-e)**(ex1-2) + d**2*delta**(d-2) - d*delta**(d-2)) firtt += expr * n*delta**d * ( b**2*ex2**2*tau**t*(-g+tau)**(2*ex2-2) - b*ex2**2*tau**t*(-g+tau)**(ex2-2) - 2*b*ex2*t*tau**(t-1)*(-g+tau)**(ex2-1) + b*ex2*tau**t*(-g+tau)**(ex2-2) + (t**2-t)*tau**(t-2)) firdt += expr * n * ( a*b*delta**d*ex1*ex2*tau**t*(delta-e)**(ex1-1) * (-g+tau)**(ex2-1) - a*delta**d*ex1*t*tau**(t-1)*(delta - e)**(ex1-1) - b*d*delta**(d-1)*ex2*tau**t*(-g + tau)**(ex2-1) + d*delta**(d-1)*t*tau**(t-1)) if delta != e: firddd += expr * n*tau**t * ( -a**3*delta**d*ex1**3*(delta-e)**(3*ex1-3) + 3*a**2*d*delta**(d-1)*ex1**2*(delta-e)**(2*ex1-2) + 3*a**2*delta**d*ex1**3*(delta-e)**(2*ex1-3) - 3*a**2*delta**d*ex1**2*(delta-e)**(2*ex1-3) - 3*a*d**2*delta**(d-2)*ex1*(delta-e)**(ex1-1) - 3*a*d*delta**(d-1)*ex1**2*(delta-e)**(ex1-2) + 3*a*d*delta**(d-1)*ex1*(delta-e)**(ex1-2) + 3*a*d*delta**(d-2)*ex1*(delta-e)**(ex1-1) - a*delta**d*ex1**3*(delta-e)**(ex1-3) + 3*a*delta**d*ex1**2*(delta-e)**(ex1-3) - 2*a*delta**d*ex1*(delta-e)**(ex1-3) + (d**3-3*d**2+2*d)*delta**(d-3)) firddt += expr * n * ( -a**2*b*delta**d*ex1**2*ex2*tau**t*(delta-e)**(2*ex1-2)*(tau-g)**(ex2-1) + a**2*delta**d*ex1**2*t*tau**(t-1)*(delta-e)**(2*ex1-2) + 2*a*b*d*delta**(d-1)*ex1*ex2*tau**t*(delta-e)**(ex1-1)*(tau-g)**(ex2-1) + a*b*delta**d*ex1**2*ex2*tau**t*(delta-e)**(ex1-2)*(tau-g)**(ex2-1) - a*b*delta**d*ex1*ex2*tau**t*(delta - e)**(ex1-2)*(tau-g)**(ex2-1) - 2*a*d*delta**(d-1)*ex1*t*tau**(t-1)*(delta-e)**(ex1-1) - a*delta**d*ex1**2*t*tau**(t-1)*(delta-e)**(ex1-2) + a*delta**d*ex1*t*tau**(t-1)*(delta-e)**(ex1-2) - b*d**2*delta**(d-2)*ex2*tau**t*(tau-g)**(ex2-1) + b*d*delta**(d-2)*ex2*tau**t*(tau-g)**(ex2-1) + (d**2*t-d)*delta**(d-2)*tau**(t-1)) firdtt += expr * n * ( -a*b**2*delta**d*ex1*ex2**2*tau**t*(delta-e)**(ex1-1)*(tau-g)**(2*ex2-1) + a*b*delta**d*ex1*ex2**2*tau**t*(delta-e)**(ex1-1)*(tau-g)**(ex2-2) + 2*a*b*delta**d*ex1*ex2*t*tau**(t-1)*(delta-e)**(ex1-1)*(tau-g)**(ex2-1) - a*b*delta**d*ex1*ex2*tau**t*(delta-e)**(ex1-1)*(tau-g)**(ex2-2) - a*delta**d*ex1*t**2*tau**(t-2)*(delta-e)**(ex1-1) + a*delta**d*ex1*t*tau**(t-2)*(delta-e)**(ex1-1) + b**2*d*delta**(d-1)*ex2**2*tau**t*(tau-g)**(2*ex2-2) - b*d*delta**(d-1)*ex2**2*tau**t*(tau-g)**(ex2-2) - 2*b*d*delta**(d-1)*ex2*t*tau**(t-1)*(tau-g)**(ex2-1) + b*d*delta**(d-1)*ex2*tau**t*(tau-g)**(ex2-2) + (d*t**2 - d*t)*delta**(d-1)*tau**(t-2)) firttt += delta**d*n*tau**(t - 3)*( -3*b*ex2*t*tau**2*(tau-g)**(ex2 + 1) * (b*ex2*(tau-g)**ex2 - ex2 + 1) + 3*b*ex2*t*tau*(tau-g)**(ex2 + 2) * (t - 1) + b*ex2*tau**3*(tau-g)**ex2*( b**2*ex2**2*(tau-g)**(2*ex2) - 3*b*ex2**2*(tau-g)**ex2 + 3*b*ex2*(tau-g)**ex2 + ex2**2 - 3*ex2 + 2) + t*(g-tau)**3*(t**2-3*t+2))*expr/(g-tau)**3 expr_ = exp(-a*(delta_0-e)**ex1-b*(tau-g)**ex2) B += expr_ * n*tau**t * ( d*delta_0**(d-1) - a*delta_0**d*ex1*(delta_0-e)**(ex1-1)) C += expr_ * n*tau**t * ( a**2*delta_0**d*ex1**2*(delta_0-e)**(2*ex1-2) - 2*a*d*delta_0**(d-1)*ex1*(delta_0-e)**(ex1-1) - a*delta_0**d*ex1**2*(delta_0-e)**(ex1-2) + a*delta_0**d*ex1*(delta_0-e)**(ex1-2) + d**2*delta_0**(d-2) - d*delta_0**(d-2)) D += expr_ * n*tau**t * ( -a**3*delta_0**d*ex1**3*(delta_0-e)**(3*ex1-3) + 3*a**2*d*delta_0**(d-1)*ex1**2*(delta_0-e)**(2*ex1-2) + 3*a**2*delta_0**d*ex1**3*(delta_0-e)**(2*ex1-3) - 3*a**2*delta_0**d*ex1**2*(delta_0-e)**(2*ex1-3) - 3*a*d**2*delta_0**(d-2)*ex1*(delta_0-e)**(ex1-1) - 3*a*d*delta_0**(d-1)*ex1**2*(delta_0-e)**(ex1-2) + 3*a*d*delta_0**(d-1)*ex1*(delta_0-e)**(ex1-2) + 3*a*d*delta_0**(d-2)*ex1*(delta_0-e)**(ex1-1) - a*delta_0**d*ex1**3*(delta_0-e)**(ex1-3) + 3*a*delta_0**d*ex1**2*(delta_0-e)**(ex1-3) - 2*a*delta_0**d*ex1*(delta_0-e)**(ex1-3) + (d**3-3*d**2+2*d)*delta_0**(d-3)) Bt += expr_ * ( n*a*b*delta_0**d*(delta_0-e)**(ex1-1)*ex1*ex2*tau**t * (tau-g)**(ex2-1) - n*b*d*delta_0**(d-1)*ex2*tau**t*(tau-g)**(ex2-1) - n*a*delta_0**d*(delta_0-e)**(ex1-1)*ex1*t*tau**(t-1) + n*d*delta_0**(d-1)*t*tau**(t-1)) # Non analitic terms # FIXME: Invalid value in critical point with this term ni = self._constants.get("nr4", []) ai = self._constants.get("a4", []) bi = self._constants.get("b4", []) Ai = self._constants.get("A", []) Bi = self._constants.get("B", []) Ci = self._constants.get("C", []) Di = self._constants.get("D", []) b_ = self._constants.get("beta4", []) for n, a, b, A, B_, C_, D_, bt in zip( ni, ai, bi, Ai, Bi, Ci, Di, b_): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C_*(delta-1)**2-D_*(tau-1)**2) Fd = -2*C_*F*(delta-1) Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) Ft = -2*D_*F*(tau-1) Ftt = 2*D_*F*(2*D_*(tau-1)**2-1) Fdt = 4*C_*D_*F*(delta-1)*(tau-1) Fdtt = 4*C_*D_*F*(delta-1)*(2*D_*(tau-1)**2-1) Delta = Tita**2+B_*((delta-1)**2)**a Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + 2*B_*a*((delta-1)**2)**(a-1)) if delta == 1: Deltadd = 0 else: Deltadd = Deltad/(delta-1)+(delta-1)**2*( 4*B_*a*(a-1)*((delta-1)**2)**(a-2) + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) if Delta == 0: DeltaBd = 0 DeltaBdd = 0 DeltaBt = 0 DeltaBtt = 0 DeltaBdt = 0 else: DeltaBd = b*Delta**(b-1)*Deltad DeltaBdd = b*(Delta**(b-1)*Deltadd + (b-1)*Delta**(b-2)*Deltad**2) DeltaBt = -2*Tita*b*Delta**(b-1) DeltaBtt = 2*b*Delta**(b-1)+4*Tita**2*b*(b-1)*Delta**(b-2) DeltaBdt = -A*b*2/bt*Delta**(b-1)*(delta-1)*((delta-1)**2)**( 0.5/bt-1)-2*Tita*b*(b-1)*Delta**(b-2)*Deltad DeltaBdtt = 2*b*(b-1)*Delta**(b-2) * \ (Deltad*(1+2*Tita**2*(b-2)/Delta)+4*Tita*A * (delta-1)/bt*((delta-1)**2)**(0.5/bt-1)) DeltaBddd = 0 DeltaBddt = 0 DeltaBttt = 0 Fddd = 0 Fddt = 0 Fttt = 0 fir += n*Delta**b*delta*F fird += n*(Delta**b*(F+delta*Fd) + DeltaBd*delta*F) firdd += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) + DeltaBdd*delta*F) firt += n*delta*(DeltaBt*F+Delta**b*Ft) firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) firddd += n*(delta*Delta**b*Fddd + delta*F*DeltaBddd + 3*delta*DeltaBd*Fdd + 3*delta*DeltaBdd*Fd + 3*Delta**b*Fdd + 3*F*DeltaBdd + 6*DeltaBd*Fd) firddt += n*( delta*Delta**b*Fddt + delta*F*DeltaBddt + 2*delta*DeltaBd*Fdt + delta*DeltaBdd*Ft + delta*DeltaBt*Fdd + 2*delta*Fd*DeltaBdt + 2*Delta**b*Fdt + 2*F*DeltaBdt + 2*DeltaBd*Ft + 2*DeltaBt*Fd) firdtt += n*( Delta**b*Ftt + F*DeltaBtt + 2*DeltaBt*Ft + delta*(Delta**b*Fdtt + F*DeltaBdtt + DeltaBd*Ftt + 2*DeltaBt*Fdt + DeltaBtt*Fd + 2*Ft*DeltaBdt)) firttt += delta*n*(Delta**b*Fttt + F*DeltaBttt + 3*DeltaBt*Ftt + 3*DeltaBtt*Ft) Tita_ = (1-tau)+A*((delta_0-1)**2)**(0.5/bt) Delta_ = Tita_**2+B_*((delta_0-1)**2)**a Deltad_ = (delta_0-1)*(A*Tita_*2/bt*((delta_0-1)**2)**( 0.5/bt-1)+2*B_*a*((delta_0-1)**2)**(a-1)) Deltadd_ = Deltad_/(delta_0-1) + (delta_0-1)**2*( 4*B_*a*(a-1)*((delta_0-1)**2)**(a-2) + 2*A**2/bt**2*(((delta_0-1)**2)**(0.5/bt-1))**2 + A*Tita_*4/bt*(0.5/bt-1)*((delta_0-1)**2)**(0.5/bt-2)) DeltaBd_ = b*Delta_**(b-1)*Deltad_ DeltaBdd_ = b*(Delta_**(b-1)*Deltadd_ + (b-1)*Delta_**(b-2)*Deltad_**2) F_ = exp(-C_*(delta_0-1)**2-D_*(tau-1)**2) Fd_ = -2*C_*F_*(delta_0-1) Fdd_ = 2*C_*F_*(2*C_*(delta_0-1)**2-1) B += n*(Delta_**b*(F_+delta_0*Fd_)+DeltaBd_*delta_0*F_) C += n*(Delta_**b*(2*Fd_+delta_0*Fdd_)+2*DeltaBd_ * (F_+delta*Fd_) + DeltaBdd_*delta_0*F_) Bt += n*(Delta_**b*(Ft+delta_0*Fdt)+delta_0*DeltaBd_*Ft + DeltaBt*(F+delta_0*Fd)+DeltaBdt*delta_0*F_) # Associative term from Gao correlation for ammonia if "nr_ass" in self._constants: nr_ass = self._constants.get("nr_ass", []) d5 = self._constants.get("d_ass", []) t5 = self._constants.get("t_ass", []) a5 = self._constants.get("alfa_ass", []) e5 = self._constants.get("epsilon_ass", []) bt5 = self._constants.get("beta_ass", []) g5 = self._constants.get("gamma_ass", []) b5 = self._constants.get("b_ass", []) for n, d, t, a, e, bt, g, b in zip( nr_ass, d5, t5, a5, e5, bt5, g5, b5): expr = exp(-a*(delta-e)**2+1/(bt*(tau-g)**2+b)) expr_ = exp(-a*(delta_0-e)**2+1/(bt*(tau-g)**2+b)) expr_d = d*delta**(d-1) - 2*a*(delta-e)*delta**d expr_dd = d*(d-1)*delta**(d-2) \ - 4*a*(delta-e)*d*delta**(d-1) \ - (2*a-4*a**2*(delta-e)**2)*delta**d expr_ddd = d*(d-1)*(d-2)*delta**(d-3) \ - 6*a*(delta-e)*d*(d-1)*delta**(d-2) \ - 6*a*(1-2*a*(delta-e)**2)*d*delta**(d-1) \ + 4*a**2*(delta-e)*(3-2*a*(delta-e)**2)*delta**d expr_t = t/tau - 2*bt*(tau-g)/(bt*(tau-g)**2+b)**2 expr_tt = expr_t**2 - t/tau**2 \ - 2*bt/(bt*(tau-g)**2+b)**2 \ + 8*bt**2*(tau-g)**2/(bt*(tau-g)**2+b)**3 expr_ttt = 4*bt**2*(g-tau)/(b + bt*(g-tau)**2)**3*( 12*bt*(g-tau)**2/(b + bt*(g-tau)**2) + 12*bt*(g-tau)**2/(b + bt*(g-tau)**2)**2 + 2*bt*(g-tau)**2/(b + bt*(g-tau)**2)**3 - 6 - 3/(b + bt*(g-tau)**2)) \ + 6*bt*t/(tau*(b + bt*(g - tau)**2)**2)*( 4*bt*(g-tau)**2/(b + bt*(g-tau)**2) + 2*bt*(g-tau)**2/(b + bt*(g-tau)**2)**2 - 1) \ + 6*bt*t*(g-tau)*(t-1)/(tau**2*(b+bt*(g-tau)**2)**2) \ + t*(t**2 - 3*t + 2)/tau**3 expr_d0 = d*delta_0**(d-1)-2*a*(delta_0-e)*delta_0**d expr_dd0 = d*(d-1)*delta_0**(d-2) \ - 4*a*(delta_0-e)*d*delta_0**(d-1) \ - (2*a-4*a**2*(delta_0-e)**2)*delta_0**d expr_ddd0 = d*(d-1)*(d-2)*delta_0**(d-3) \ - 6*a*(delta_0-e)*d*(d-1)*delta_0**(d-2) \ - 6*a*(1-2*a*(delta_0-e)**2)*d*delta_0**(d-1) \ + 4*a**2*(delta_0-e)*(3-2*a*(delta_0-e)**2)*delta_0**d fir += n*delta**d*tau**t * expr fird += n*tau**t * expr * expr_d firdd += n*tau**t * expr * expr_dd firt += n*delta**d*tau**t * expr * expr_t firtt += n*delta**d*tau**t * expr * expr_tt firdt += n*tau**t * expr * expr_d * expr_t firddd += n*tau**t * expr * expr_ddd firddt += n*tau**t * expr * expr_dd * expr_t firdtt += n*tau**t * expr * expr_d * expr_tt firttt += n*delta**d*tau**t * expr * expr_ttt B += n*tau**t * expr_ * expr_d0 C += n*tau**t * expr_ * expr_dd0 D += n*tau**t * expr_ * expr_ddd0 Bt += n*tau**t * expr_ * expr_d0 * expr_t # Associative term from Piazza correlations if "type_ass" in self._constants: m = self._constants["m_ass"] vn = self._constants["v_ass"] kappa = self._constants["k_ass"] epsilon = self._constants["e_ass"] nu = vn*delta gnu = (2-nu)/2/(1-nu)**3 Delta = gnu*(exp(epsilon*tau)-1)*kappa X = (-1 + (1+4*Delta*delta)**0.5)/2/Delta/delta fass = log(X) - X/2 + 0.5 dgnu = 0.5*(5-2*nu)/(1-nu)**4 d2gnu = 3*(3-nu)/(1-nu)**5 alfa = dgnu * (exp(epsilon*tau)-1)*kappa*vn # Eq A35 Xd = -X**2/(2*Delta*delta*X+1)*(Delta+delta*alfa) # Eq A36 fassd = (1/X-0.5)*Xd beta = gnu*kappa*exp(epsilon*tau)*epsilon # Eq A55 Xt = -delta*X**2/(2*Delta*delta*X+1)*beta # Eq A56 fasst = (1/X-0.5)*Xt gamma = d2gnu * (exp(epsilon*tau)-1)*kappa*vn**2 # Eq A76 # Eq A77 Xdd = X**2*(2*Delta**2*X-alfa)/(2*delta*Delta*X+1)**2 \ + 2*Delta*X**2*(Delta+alfa*delta)*(Delta*delta*X**2+X) \ / (2*delta*Delta*X+1)**3 \ + 2*delta*X**2*(Delta+alfa*delta)*(Delta*delta*X**2+X) \ * alfa / (2*delta*Delta*X+1)**3 \ + X**2*(2*delta**2*X*alfa-1)*alfa/(2*delta*Delta*X+1)**2 \ - delta*X**2*gamma/(2*delta*Delta*X+1) fassdd = (1/X-0.5)*Xdd - Xd**2/X**2 eta = gnu*kappa*exp(epsilon*tau)*epsilon**2 # Eq A83 # Eq A84 Xtt = -2*beta*delta*X*(Delta*delta*X+1)/(1+2*Delta*delta*X)**2 \ * (-delta*X**2/(2*Delta*delta*X+1))*beta \ + 2*delta**2*X**3/(1+2*Delta*delta*X)**2 * beta**2 \ - delta*X**2/(2*Delta*delta*X+1)*eta fasstt = (1/X-0.5)*Xtt - Xt**2/X**2 teta = dgnu*exp(epsilon*tau)*epsilon*kappa*vn # Eq A89 # Eq A90 Xdt = 2*delta*X**2*(Delta+delta*alfa)*(Delta*delta*X**2+X) \ * beta / (2*delta*Delta*X+1)**3 \ + X**2*(2*delta**2*X*alfa-1)*beta/(2*delta*Delta*X+1)**2 \ - delta*X**2*teta/(2*delta*Delta*X+1) fassdt = -Xt/X**2*Xd + Xdt*(1/X-0.5) if self._constants["type_ass"] == "2B": fass *= 2 fassd *= 2 fasst *= 2 fassdd *= 2 fasstt *= 2 fassdt *= 2 fir += m*fass fird += m*fassd firt += m*fasst firdd += m*fassdd firtt += m*fasstt firdt += m*fassdt # Special form from Saul-Wagner Water 58 coefficient equation if "nr_saul" in self._constants: nr5 = self._constants.get("nr_saul", []) d5 = self._constants.get("d_saul", []) t5 = self._constants.get("t_saul", []) for n, d, t in zip(nr5, d5, t5): fir += exp(-0.4*delta**6) \ - delta**d*n*tau**t*exp(-2*delta**6) fird += 12*delta**5*delta**d*n*tau**t*exp(-2*delta**6) \ - d*delta**d*n*tau**t*exp(-2*delta**6)/delta \ - 2.4*delta**5*exp(-0.4*delta**6) firt -= delta**d*n*t*tau**t*exp(-2*delta**6)/tau firdd += 24*d*delta**4*delta**d*n*tau**t*exp(-2*delta**6) \ - d**2*delta**d*n*tau**t*exp(-2*delta**6)/delta**2 \ + d*delta**d*n*tau**t*exp(-2*delta**6)/delta**2 \ - 144*delta**10*delta**d*n*tau**t*exp(-2*delta**6) \ + 5.76*delta**10*exp(-0.4*delta**6) \ + 60*delta**4*delta**d*n*tau**t*exp(-2*delta**6) \ - 12.0*delta**4*exp(-0.4*delta**6) firtt += delta**d*n*t*tau**t*(1-t)*exp(-2*delta**6)/tau**2 firttt += delta**d*n*t*tau**t*(-t**2 + 3*t - 2) \ * exp(-2*delta**6)/tau**3 firdt += exp(a*(delta - e)**2 - 1/(b + bt*(-g + tau)**2)) \ / (n*tau**t) * ( 12*delta**5*delta**d*n*t*tau**t*exp(-2*delta**6)/tau - d*delta**d*n*t*tau**t*exp(-2*delta**6)/(delta*tau)) firddd += - 48.0*delta**3*exp(-0.4*delta**6) \ -d**3*delta**d*n*tau**t*exp(-2*delta**6)/delta**3 \ + 36*d**2*delta**3*delta**d*n*tau**t*exp(-2*delta**6) \ + 3*d**2*delta**d*n*tau**t*exp(-2*delta**6)/delta**3 \ - 432*d*delta**9*delta**d*n*tau**t*exp(-2*delta**6) \ + 144*d*delta**3*delta**d*n*tau**t*exp(-2*delta**6) \ - 2*d*delta**d*n*tau**t*exp(-2*delta**6)/delta**3 \ + 1728*delta**15*delta**d*n*tau**t*exp(-2*delta**6) \ - 13.824*delta**15*exp(-0.4*delta**6) \ - 2160*delta**9*delta**d*n*tau**t*exp(-2*delta**6) \ + 86.4*delta**9*exp(-0.4*delta**6) \ + 240*delta**3*delta**d*n*tau**t*exp(-2*delta**6) firddt += 24*d*delta**4*delta**d*n*t*tau**t*exp(-2*delta**6)/tau \ - d**2*delta**d*n*t*tau**t*exp(-2*delta**6)/(delta**2*tau) \ + d*delta**d*n*t*tau**t*exp(-2*delta**6)/(delta**2*tau) \ - 144*delta**10*delta**d*n*t*tau**t*exp(-2*delta**6)/tau \ + 60*delta**4*delta**d*n*t*tau**t*exp(-2*delta**6)/tau firdtt += delta**d*n*t*tau**t * exp(-2*delta**6)/tau**2 \ * (-d*t/delta + d/delta + 12*delta**5*t - 12*delta**5) firdtt += d*delta**d*n*t*tau**t*exp(-2*delta**6)/(delta*tau**2) \ -d*delta**d*n*t**2*tau**t*exp(-2*delta**6)/(delta*tau**2) \ + 12*delta**5*delta**d*n*t**2*tau**t*exp(-2*delta**6)/tau**2 \ - 12*delta**5*delta**d*n*t*tau**t*exp(-2*delta**6)/tau**2 firttt += 3*delta**d*n*t**2*tau**t*exp(-2*delta**6)/tau**3 \ -delta**d*n*t**3*tau**t*exp(-2*delta**6)/tau**3 \ - 2*delta**d*n*t*tau**t*exp(-2*delta**6)/tau**3 B += 12*delta_0**5*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ - d*delta_0**d*n*tau**t*exp(-2*delta_0**6)/delta_0 \ - 2.4*delta_0**5*exp(-0.4*delta_0**6) C += 24*d*delta_0**4*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ - d**2*delta_0**d*n*tau**t*exp(-2*delta_0**6)/delta_0**2 \ + d*delta_0**d*n*tau**t*exp(-2*delta_0**6)/delta_0**2 \ - 144*delta_0**10*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ + 5.76*delta_0**10*exp(-0.4*delta_0**6) \ + 60*delta_0**4*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ - 12.0*delta_0**4*exp(-0.4*delta_0**6) D += - 48.0*delta_0**3*exp(-0.4*delta_0**6) \ -d**3*delta_0**d*n*tau**t*exp(-2*delta_0**6)/delta_0**3 \ + 36*d**2*delta_0**3*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ + 3*d**2*delta_0**d*n*tau**t*exp(-2*delta_0**6)/delta_0**3 \ - 432*d*delta_0**9*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ + 144*d*delta_0**3*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ - 2*d*delta_0**d*n*tau**t*exp(-2*delta_0**6)/delta_0**3 \ + 1728*delta_0**15*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ - 13.824*delta_0**15*exp(-0.4*delta_0**6) \ - 2160*delta_0**9*delta_0**d*n*tau**t*exp(-2*delta_0**6) \ + 86.4*delta_0**9*exp(-0.4*delta_0**6) \ + 240*delta_0**3*delta_0**d*n*tau**t*exp(-2*delta_0**6) prop = {} prop["fir"] = fir prop["firt"] = firt prop["firtt"] = firtt prop["fird"] = fird prop["firdd"] = firdd prop["firdt"] = firdt prop["firddd"] = firddd prop["firddt"] = firddt prop["firdtt"] = firdtt prop["firttt"] = firttt prop["B"] = B prop["C"] = C prop["D"] = D prop["Bt"] = Bt return prop
[docs] @refDoc(__doi__, [11], tab=8) def _MBWR(self, rho, T): r"""Residual contribution to the free Helmholtz energy and derivatives for modified Benedict-Webb-Rubin (mBWR) equation of state. Derived calculation defined in Appendix B in [11]_ The dict with equation of state definition must define the parameters: * b: coefficient of :math:`a_i` equations * gamma: optional reducing density value in exponential term Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- prop : dict Dictionary with residual adimensional helmholtz energy and derivatives: * fir [-] * firt: [∂fir/∂τ]δ,x [-] * fird: [∂fir/∂δ]τ,x [-] * firtt: [∂²fir/∂τ²]δ,x [-] * firdt: [∂²fir/∂τ∂δ]x [-] * firdd: [∂²fir/∂δ²]τ,x [-] """ rhom = rho/self.M if "gamma" in self._constants: rhocm = 1/(-self._constants["gamma"])**0.5 rhoc = rhocm*self.M else: rhoc = self.rhoc rhocm = rhoc/self.M delta = rho/rhoc b = self._constants["b"] R = self._constants["R"] # Equation B2 a = [None] # Use the gas constant in l·bar/mol·K a.append(R/100*T) a.append(b[1]*T + b[2]*T**0.5 + b[3] + b[4]/T + b[5]/T**2) a.append(b[6]*T + b[7] + b[8]/T + b[9]/T**2) a.append(b[10]*T + b[11] + b[12]/T) a.append(b[13]) a.append(b[14]/T + b[15]/T**2) a.append(b[16]/T) a.append(b[17]/T + b[18]/T**2) a.append(b[19]/T**2) a.append(b[20]/T**2 + b[21]/T**3) a.append(b[22]/T**2 + b[23]/T**4) a.append(b[24]/T**2 + b[25]/T**3) a.append(b[26]/T**2 + b[27]/T**4) a.append(b[28]/T**2 + b[29]/T**3) a.append(b[30]/T**2 + b[31]/T**3 + b[32]/T**4) # Eq B1 P = sum([a[n]*rhom**n for n in range(1, 10)]) P += exp(-(delta**2))*sum([a[n]*rhom**(2*n-17) for n in range(10, 16)]) P *= 100 # Convert from bar to kPa # Eq B6 A = 0 for n in range(2, 10): A += a[n]/(n-1)*rhom**(n-1) A -= 0.5*a[10]*rhocm**2*(exp(-delta**2)-1) A -= 0.5*a[11]*rhocm**4*(exp(-delta**2)*(delta**2+1)-1) A -= 0.5*a[12]*rhocm**6*(exp(-delta**2)*( delta**4+2*delta**2+2)-2) A -= 0.5*a[13]*rhocm**8*(exp(-delta**2)*( delta**6+3*delta**4+6*delta**2+6)-6) A -= 0.5*a[14]*rhocm**10*(exp(-delta**2)*( delta**8+4*delta**6+12*delta**4+24*delta**2+24)-24) A -= 0.5*a[15]*rhocm**12*(exp(-delta**2)*( delta**10+5*delta**8+20*delta**6+60*delta**4+120*delta**2+120)-120) A = A*100 # Convert from L·bar/mol to J/mol # Eq B4 # Use the gas constant in l·bar/mol·K adT = [None, R/100] adT.append(b[1] + b[2]/2/T**0.5 - b[4]/T**2 - 2*b[5]/T**3) adT.append(b[6] - b[8]/T**2 - 2*b[9]/T**3) adT.append(b[10] - b[12]/T**2) adT.append(0) adT.append(-b[14]/T**2 - 2*b[15]/T**3) adT.append(-b[16]/T**2) adT.append(-b[17]/T**2 - 2*b[18]/T**3) adT.append(-2*b[19]/T**3) adT.append(-2*b[20]/T**3 - 3*b[21]/T**4) adT.append(-2*b[22]/T**3 - 4*b[23]/T**5) adT.append(-2*b[24]/T**3 - 3*b[25]/T**4) adT.append(-2*b[26]/T**3 - 4*b[27]/T**5) adT.append(-2*b[28]/T**3 - 3*b[29]/T**4) adT.append(-2*b[30]/T**3 - 3*b[31]/T**4 - 4*b[32]/T**5) # Eq B7 dAT = 0 for n in range(2, 10): dAT += adT[n]/(n-1)*rhom**(n-1) dAT -= 0.5*adT[10]*rhocm**2*(exp(-delta**2)-1) dAT -= 0.5*adT[11]*rhocm**4*(exp(-delta**2)*(delta**2+1)-1) dAT -= 0.5*adT[12]*rhocm**6*(exp(-delta**2)*( delta**4+2*delta**2+2)-2) dAT -= 0.5*adT[13]*rhocm**8*(exp(-delta**2)*( delta**6+3*delta**4+6*delta**2+6)-6) dAT -= 0.5*adT[14]*rhocm**10*(exp(-delta**2)*( delta**8+4*delta**6+12*delta**4+24*delta**2+24)-24) dAT -= 0.5*adT[15]*rhocm**12*(exp(-delta**2)*( delta**10+5*delta**8+20*delta**6+60*delta**4+120*delta**2+120)-120) dAT = dAT*100 # Convert from L·bar/mol·K to J/mol·K # Eq B9 adTT = [None, 0] adTT.append(-b[2]/4/T**1.5 + 2*b[4]/T**3 + 6*b[5]/T**4) adTT.append(2*b[8]/T**3 + 6*b[9]/T**4) adTT.append(2*b[12]/T**3) adTT.append(0) adTT.append(2*b[14]/T**3 + 6*b[15]/T**4) adTT.append(2*b[16]/T**3) adTT.append(2*b[17]/T**3 + 6*b[18]/T**4) adTT.append(6*b[19]/T**4) adTT.append(6*b[20]/T**4 + 12*b[21]/T**5) adTT.append(6*b[22]/T**4 + 20*b[23]/T**6) adTT.append(6*b[24]/T**4 + 12*b[25]/T**5) adTT.append(6*b[26]/T**4 + 20*b[27]/T**6) adTT.append(6*b[28]/T**4 + 12*b[29]/T**5) adTT.append(6*b[30]/T**4 + 12*b[31]/T**5 + 20*b[32]/T**6) # Eq B8 d2AT = 0 for n in range(2, 10): d2AT += adTT[n]*rhom**(n-1)/(n-1) d2AT -= 0.5*adTT[10]*rhocm**2*(exp(-delta**2)-1) d2AT -= 0.5*adTT[11]*rhocm**4*(exp(-delta**2)*(delta**2+1)-1) d2AT -= 0.5*adTT[12]*rhocm**6*(exp(-delta**2)*( delta**4+2*delta**2+2)-2) d2AT -= 0.5*adTT[13]*rhocm**8*(exp(-delta**2)*( delta**6+3*delta**4+6*delta**2+6)-6) d2AT -= 0.5*adTT[14]*rhocm**10*(exp(-delta**2)*( delta**8+4*delta**6+12*delta**4+24*delta**2+24)-24) d2AT -= 0.5*adTT[15]*rhocm**12*(exp(-delta**2)*( delta**10+5*delta**8+20*delta**6+60*delta**4+120*delta**2+120)-120) d2AT = d2AT*100 # Convert from L·bar/mol·K² to J/mol·K² # Eq B5 dPdrho = sum([a[n]*n*rhom**(n-1) for n in range(1, 10)]) dPdrho += exp(-delta**2)*sum( [(2*n-17-2*delta**2)*a[n]*rhom**(2*n-18) for n in range(10, 16)]) dPdrho = dPdrho*100 # Convert L·bar/mol to kPa-L/mol d2Prho = sum([a[n]*n*(n-1)*rhom**(n-2) for n in range(1, 10)]) d2Prho += exp(-delta**2)*sum( [(-35*n+2*n**2+153+33*delta**2+2*delta**4-4*n*delta**2)*2*a[n] * rhom**(2*n-19) for n in range(10, 16)]) d2Prho *= 100 # Eq B3 dPdT = sum([adT[n]*rhom**n for n in range(1, 10)]) dPdT += exp(-delta**2)*sum( [adT[n]*rhom**(2*n-17) for n in range(10, 16)]) dPdT *= 100 tau = self.Tc/T prop = {} prop["P"] = P*1e3 # Report value in Pa prop["A"] = A prop["dAT"] = dAT prop["d2AT"] = d2AT prop["dPdrho"] = dPdrho prop["d2Prho"] = d2Prho prop["dPdT"] = dPdT prop["fir"] = A/R/T prop["firt"] = (A/T-dAT)/R/tau prop["firtt"] = d2AT*T/R/tau**2 prop["fird"] = (P/rhom/T/R-1)/delta prop["firdd"] = ((dPdrho-2*P/rhom)/R/T+1)/delta**2 prop["firdt"] = (P/T-dPdT)/R/rhom/tau/delta prop["firddd"] = (d2Prho*rhom-4*dPdrho+6*P/rhom)/R/T-2 # TODO: B, C, D = 0, 0, 0 firddt, firdtt, firttt = 0, 0, 0 prop["firddt"] = firddt prop["firdtt"] = firdtt prop["firttt"] = firttt prop["B"] = B prop["C"] = C prop["D"] = D return prop
[docs] @refDoc(__doi__, [12, 13, 14], tab=8) def _PengRobinson(self, rho, T): r"""Residual contribution to the free Helmholtz energy and derivatives for Peng-Robinson cubic equation of state as explain in [12]_. Optionally can use the Lin-Duan volume correction as explain in [13]_ Helmholtz energy and derivatives calculation defined in [14]_. Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- prop : dict Dictionary with residual adimensional helmholtz energy and derivatives: * fir [-] * firt: [∂fir/∂τ]δ,x [-] * fird: [∂fir/∂δ]τ,x [-] * firtt: [∂²fir/∂τ²]δ,x [-] * firdt: [∂²fir/∂τ∂δ]x [-] * firdd: [∂²fir/∂δ²]τ,x [-] """ Tc = self.Tc delta = rho/self.rhoc/self.M*1000 tau = Tc/T kw = {} kw["rhoc"] = self.rhoc kw["Tc"] = self.Tc kw["b"] = 0.0778*R*self.Tc/self.Pc kw["Delta1"] = 1+2**0.5 kw["Delta2"] = 1-2**0.5 a = 0.457235*R**2*self.Tc**2/self.Pc m = 0.37464+1.54226*self.f_acent-0.26992*self.f_acent**2 alfa = a*(1+m*(1-(T/Tc)**0.5))**2 B = 1+m*(1-1/tau**0.5) kw["a"] = alfa kw["dat"] = a*m*B/tau**1.5 kw["datt"] = a*m/2*(m*Tc/tau**3/Tc-3*B/tau**2.5) kw["dattt"] = 3*a*m/4*(-3*m*Tc/tau**4/Tc+5*B/tau**3.5) prop = CubicHelmholtz(tau, delta, **kw) return prop
[docs] @refDoc(__doi__, [13], tab=8) def vtPR(self, rho, T): """Volume translation for Peng-Robinson equation of state for liquid phase as explain in [13]_ Returns ------- v : float Specific volume, [m³/kg] """ from lib.EoS.Cubic.PRLinDuan import dat if self.id in dat: b, g = dat[self.id] else: # Generalized correlation b = -2.8431*exp(-64.2184*(0.3074-self.Zc))+0.1735 # Eq 12 g = -99.2558+301.6201*self.Zc # Eq 13 Tr = T/self.Tc f = b+(1-b)*exp(g*abs(1-Tr)) # Eq 10 cc = (0.3074-self.Zc)*self.R*self.Tc/self.Pc # Eq 9 c = cc * f # Eq 8 v = 1./rho-c # Eq 2 return v
[docs] def derivative(self, z, x, y, fase): """Calculate generic partial derivative: (δz/δx)y where x, y, z can be: P, T, v, u, h, s, g, a""" dT = {"P": self.P*fase.alfap, "T": 1, "v": 0, "rho": 0, "u": fase.cv, "h": fase.cv+self.P*fase.v*fase.alfap, "s": fase.cv/self.T, "g": self.P*fase.v*fase.alfap-fase.s, "a": -fase.s} dv = {"P": -self.P*fase.betap, "T": 0, "v": 1, "rho": -1, "u": self.P*(self.T*fase.alfap-1), "h": self.P*(self.T*fase.alfap-fase.v*fase.betap), "s": self.P*fase.alfap, "g": -self.P*fase.v*fase.betap, "a": -self.P} return (dv[z]*dT[y]-dT[z]*dv[y])/(dv[x]*dT[y]-dT[x]*dv[y])
[docs] def _Vapor_Pressure(self, T): """Vapor Pressure ancillary equation""" if self._vapor_Pressure: Tc = self._vapor_Pressure.get("Tc", self.Tc) Pr = SimpleEq(Tc, T, self._vapor_Pressure) Pv = unidades.Pressure(Pr*self.Pc) else: # If no available data use the Lee-Kesler correlation Pv = Pv_Lee_Kesler(T, self.Tc, self.Pc, self.f_acent) return Pv
[docs] def _Liquid_Density(self, T): """Saturated liquid density ancillary equation""" if T > self.Tc: T = self.Tc if self._liquid_Density: if T < self.Tt: T = self.Tt if T > self.Tc: T = self.Tc Pr = SimpleEq(self.Tc, T, self._liquid_Density) rho = unidades.Density(Pr*self.rhoc) else: # Use the Costald method to calculate saturated liquid density rho = RhoL_Costald(T, self.Tc, self.f_acent, 1/self.rhoc) return rho
[docs] def _Vapor_Density(self, T): """Saturated vapor density ancillary equation""" if self._vapor_Density: if T < self.Tt: T = self.Tt if T > self.Tc: T = self.Tc Pr = SimpleEq(self.Tc, T, self._vapor_Density) rho = unidades.Density(Pr*self.rhoc) else: # If no available data use the ideal gas correlation P = self._Vapor_Pressure(T) rho = P*1e-3/T/R*self.M return rho
[docs] @refDoc(__doi__, [1], tab=8) def _Surface(self, T): r"""Equation for the surface tension .. math:: \sigma(T) = \sum_i \sigma_i\left(1-\frac{T}{T_c}\right)^{n_i} The subclass must define the parameters of correlation in _surface: * sigma: Coefficient of polynomial term * exp: Exponential of polynomial term * Tc: Optional to define a different reducing parameter than Tc """ if self.Tt <= self.T <= self.Tc: if self._surface: Tc = self._surface.get("Tc", self.Tc) tau = 1-T/Tc tension = 0 for sigma, n in zip(self._surface["sigma"], self._surface["exp"]): tension += sigma*tau**n sigma = unidades.Tension(tension) else: # If no available data use the Pitzer correlation sigma = Tension_Pitzer(T, self.Tc, self.Pc, self.f_acent) else: # Undefined, out of range, not in two phase region sigma = None return sigma
[docs] @refDoc(__doi__, [24, 29], tab=8) def _Dielectric(self, rho, T): r"""Calculate the dielectric constant as explain in [24]_. Calculate first the electric polarization .. math:: \begin{array}[t]{l} \frac{P}{\rho} = A_{\epsilon}+\frac{A_{\mu}}{T}+B_{\epsilon}\rho + C\rho^D\\ A_{\epsilon} = a_0+a_1\left(\frac{T}{T_0}-1\right)\\ B_{\epsilon} = b_0+b_1\left(\frac{T_0}{T}-1\right)\\ C_{\epsilon} = c_0+c_1\left(\frac{T_0}{T}-1\right)\\ \end{array} and then calculate the dielectric constant using the appropiate correlation .. math:: \begin{array}[t]{l} P_{CM} = \frac{\epsilon-1}{\epsilon+2}\\ P_{K} = \frac{(\epsilon-1)(2\epsilon+1}{9\epsilon}\\ \end{array} The Clausius-Mosotti (CM} is more appropiate for nonpolar fluids, the Kirkwood is for polar fluids. The dict with coefficient must define the properties: * eq: Type of equation * ai: Parameter of virial coefficient :math:`A_{\epsilon}` * bi: Parameter of virial coefficient :math:`B_{\epsilon}` * ci: Parameter of parameter C * Au: Parameter :math:`A_{mu}` * D: Exponential of density in last term Parameters ---------- rho : float Density [kg/m³] T : float Temperature [K] Returns ------- epsilon : float Static dielectric constant, [-] """ # Discard calculation in fluids with no available correlation if not self._dielectric: return unidades.Dimensionless(None) # density in mol/cc rhom = rho/self.M/1000 if rho: if self._dielectric["eq"] == 3: alfa = unidades.Volume(self._dielectric["alfa"], "cc") mu = unidades.DipoleMoment(self._dielectric["mu"], "Debye") Tc = self._dielectric["Tc"] rhoc = self._dielectric["rhoc"] cu = self._dielectric["cu"] au = self._dielectric["au"] nu = self._dielectric["nu"] cg = self._dielectric["cg"] a1 = self._dielectric["a1"] n1 = self._dielectric["n1"] a2 = self._dielectric["a2"] n2 = self._dielectric["n2"] Tr = T/Tc rhor = rhom/rhoc fu = cu*(1-exp(-au*rhor**nu)) # Eq 6 g1 = exp(-a1*Tr**n1) # Eq 7 g2 = 1 - exp(-a2*rhor**n2) # Eq 8 g = 1 + cg*g1*g2 # Eq 4 mueff = mu*(1+fu) # Eq 3 Au_eff = Avogadro*mueff**2/9/epsilon_0/Boltzmann P = rhom*1e6*(4*pi*Avogadro*alfa/3 + g*Au_eff/T) # Eq 2 e = 0.25*(1+9*P+3*(9*P**2+2*P+1)**0.5) else: ai = self._dielectric["a"] bi = self._dielectric["b"] ci = self._dielectric["c"] D = self._dielectric["D"] Au = self._dielectric["Au"] T0 = self._dielectric.get("T0", 273.16) Ae = ai[0] + ai[1]*(T/T0-1) # Eq 6a Be = bi[0] + bi[1]*(T0/T-1) # Eq 6b C = ci[0] + ci[1]*(T0/T-1) # Eq 6c # Eq 5 P = rhom*(Ae + Au/T + Be*rhom + C*rhom**D) if self._dielectric["eq"] == 1: # Clausius-Mosotti expression, for nonpolar fluids e = (1+2*P)/(1-P) elif self._dielectric["eq"] == 2: # Kirwood expression, for polar fluid e = 0.25*(1+9*P+3*(9*P**2+2*P+1)**0.5) else: e = 1 return unidades.Dimensionless(e)
[docs] @classmethod def _Melting_Pressure(cls, T, melting=None): r"""Calculate the melting pressure. .. math:: \begin{array}[t]{l} \frac{P_m}{P_r} = a_o + \sum a_{1i}\theta^{t_{1i}} + \sum a_{2i}\left(\theta^{t_{2i}}-1\right) + \sum a_{3i}\log \theta^{t_{3i}} + \sum a_{4i}\left(\theta-1\right)^{t_{4i}}\\ P_m - P_r = a_o + \sum a_{1i}\theta^{t_{1i}} + \sum a_{2i}\left(\theta^{t_{2i}}-1\right) + \sum a_{3i}\log \theta^{t_{3i}} + \sum a_{4i}\left(\theta-1\right)^{t_{4i}}\\ \ln\frac{P_m}{P_r} = a_o + \sum a_{1i}\theta^{t_{1i}} + \sum a_{2i}\left(\theta^{t_{2i}}-1\right) + \sum a_{3i}\log \theta^{t_{3i}} + \sum a_{4i}\left(\theta-1\right)^{t_{4i}}\\ \theta = \frac{T}{T_r}\\ \end{array} The dict with coefficient must define the properties: * eq: Type of equation * __doi__: Dict with reference of correlation * Tmin: Lower temperature limit, [K] * Tmax: Upper temperature limit, [K] * Tref: Reducing temperature, [K] * Pref: Reducing pressure, [Pa] * a0: Zero dependence coefficient * a1: Polynomial term coefficient * exp1: Polynomial term exponent * a2: Polynomial θ^t-1 term coefficient * exp2: Polynomial θ^t-1 term exponent * a3: Logarithmic term coefficient * exp3: Logarithmic term exponent * a4: Polynomial (θ-1)^t term coefficient * exp4: Polynomial (θ-1)^t term exponent Parameters ---------- T : float Temperature, [K] Returns ------- P : float Melting pressure, [Pa] """ if melting is None and not cls._melting: return None elif cls._melting: melting = cls._melting Tref = melting["Tref"] Pref = melting["Pref"] Tita = T/Tref suma = 0 if "a0" in melting: suma += melting["a0"] if "a1" in melting: for a, t in zip(melting["a1"], melting["exp1"]): suma += a*Tita**t if "a2" in melting: for a, t in zip(melting["a2"], melting["exp2"]): suma += a*(Tita**t-1) if "a3" in melting: for a, t in zip(melting["a3"], melting["exp3"]): suma += a*log(Tita)**t if "a4" in melting: for a, t in zip(melting["a4"], melting["exp4"]): suma += a*(Tita-1)**t if melting["eq"] == 1: P = suma*Pref elif melting["eq"] == 2: # Simon-Glatzel formulation P = suma+Pref elif melting["eq"] == 2: P = exp(suma)*Pref return unidades.Pressure(P)
[docs] @classmethod def _Sublimation_Pressure(cls, T): r"""Calculate the sublimation pressure. .. math:: \begin{array}[t]{l} \frac{P}{P_r} = a_o + \sum a_{1i}\theta^{t_{1i}} + \sum a_{2i}\left(1-\theta\right)^{t_{2i}} + \sum a_{3i}\log \theta^{t_{3i}}\\ P - P_r = a_o + \sum a_{1i}\theta^{t_{1i}} + \sum a_{2i}\left(1-\theta\right)^{t_{2i}} + \sum a_{3i}\log \theta^{t_{3i}}\\ \ln\frac{P}{P_r} = a_o + \sum a_{1i}\theta^{t_{1i}} + \sum a_{2i}\left(1-\theta\right)^{t_{2i}} + \sum a_{3i}\log \theta^{t_{3i}}\\ \theta = \frac{T}{T_r}\\ \end{array} The dict with coefficient must define the properties: * eq: Type of equation * __doi__: Dict with reference of correlation * Tmin: Lower temperature limit, [K] * Tmax: Upper temperature limit, [K] * Tref: Reducing temperature, [K] * Pref: Reducing pressure, [Pa] * a0: Zero dependence coefficient * a1: Polynomial term coefficient * exp1: Polynomial term exponent * a2: Polynomial 1-θ term coefficient * exp2: Polynomial 1-θ term exponent * a3: Logarithmic term coefficient * exp3: Logarithmic term exponent Parameters ---------- T : float Temperature, [K] Returns ------- P : float Sublimation pressure, [Pa] """ if cls._sublimation: coef = cls._sublimation Tref = coef["Tref"] Pref = coef["Pref"] Tita = T/Tref suma = 0 if "a0" in coef: suma += coef["a0"] if "a1" in coef: for a, t in zip(coef["a1"], coef["exp1"]): suma += a*Tita**t if "a2" in coef: for a, t in zip(coef["a2"], coef["exp2"]): suma += a*(1-Tita)**t if "a3" in coef: for a, t in zip(coef["a3"], coef["exp3"]): suma += a*log(Tita)**t if coef["eq"] == 1: P = suma*Pref elif coef["eq"] == 2: P = exp(suma)*Pref elif coef["eq"] == 3: P = exp(Tref/T*suma)*Pref return unidades.Pressure(P) else: return None
# Viscosity calculation methods
[docs] @refDoc(__doi__, [2, 3, 4, 5, 20, 22], tab=8) def _Viscosity(self, rho, T, fase, coef=False, residual=False): r"""Viscosity calculation procedure, implement several general method The derived class must define a dict object with the parameters for the method. The key eq define the procedure to use: * 0 - Hardcoded for special procedures (i.e.: R23, H2O, ...) * 1 - General formulation with different contribution * 2 - Younglove formulation * 3 - Extended corresponding states correlation * 4 - Quiñones-Cisneros friction theory model **Hardcoded procedures** Special procedures easier to implement as harcoded in subclasses, used in component as: He, D2O, H2, H20, R23, Ethylene * method: Name of procedure with code **General formulation** Normal formulation with several contribution, so the more flexible for implement correlation .. math:: \eta = \eta^o(T)+\eta^1(T)\rho+\eta^r(\tau,\delta)+\eta^{CP} *Initial density terms, second virial coefficient* .. math:: \begin{array}[t]{l} \eta^1(T) = B_\eta \eta^0\\ B_\eta = \eta_r B^*_\eta\\ B^*_\eta = \sum_in_i\tau^t\\ \end{array} * Tref_virial: Initial density reference temperature * muref_virial: Initial density reference viscosity * n_virial: Initial density parameter * t_virial: Initial density tau exponent *Residual fluid contribution* .. math:: \eta^r(\tau,\delta) = \sum_{i=1}^nN_i\tau^{t_i}\delta^{d_i} \exp\left(-\gamma_i\delta^{c_i}\right) + \frac{\sum_{i} ^nN_i\tau^{t_i}\delta^{d_i}\exp\left(-\gamma_i\delta^{c_i} \right)}{\sum_{i}^nN_i\tau^{t_i}\delta^{d_i}\exp\left( -\gamma_i\delta^{c_i}\right)} * Tref_res: Residual viscosity reference temperature * rhoref_res: Residual viscosity reference density * muref_res: Residual viscosity reference viscosity * nr: Residual viscosity parameter * tr: Residual viscosity tau exponent * dr: Residual viscosity delta exponent * gr: Residual viscosity exponential parameter * cr: Reisidual viscosity delta exponent in exponential term * nr_num: Fractional numerator coefficient * tr_num: Fractional numerator temperature exponent * dr_num: Fractional numerator density exponent * gr_num: Fractional numerator exponential coefficient * cr_num: Fractional numerator exponential density exponent * nr_den: Fractional denominator coefficient * tr_den: Fractional denominator temperature exponent * dr_den: Fractional denominator density exponent * gr_den: Fractional denominator exponential coefficient * cr_den: Fractional denominator exponential density exponent *Modified Batschinkski-Hildebrand contribution* .. math:: \begin{array}[t]{l} \eta^{CP} = f\left(\frac{\delta}{\delta_0(\tau)-\delta}- \frac{\delta}{\delta_0(\tau)}\right)\\ \delta_0(\tau) = g_1\left(1+\sum_i g_i\tau^{t_i}\right)\\ \end{array} * CPf: f parameter for closed packed term * CPg1: g1 parameter for closed packed term * CPgi: g parameter for aditional term of closed packed term * CPti: tau exponent for aditional term of closed packed term *Special terms* A hardcoded term for any non standard formulation term * special: Name of procedure with hardcoded method **Younglove formulation** Formulation as explain in [4]_ and [5]_ .. math:: \begin{array}[t]{l} \eta = \eta^o(T)+\eta^1(T)\rho+\eta^r(\tau,\delta)\\ \eta^1 = F_{[1]}+F_{[2]}\left(F_{[3]}-\ln\left(\frac{T} {F_{[4]}}\right)\right)^2\\ \eta^2 = \exp(F)-\exp(G)\\ G = E_{[1]}+\frac{E_{[2]}}{T}\\ H = \frac{\rho^{0.5}\left(\rho-\rho_c\right)}{\rho_c}\\ F_{4} = E_{[1]} + E_{[2]} H + \left(E_{[3]} + \frac{E_{[4]}}{T^{1.5}}\right)\rho^{0.1} + H \left(E_{[5]} + \frac{E_{[6]}}{T}+\frac{E_{[7]}}{T^2}\right)\\ F_{5} = G + \left(E_{[3]}+\frac{E_{[4]}}{T^{1.5}}\right)\rho^ {0.1}+ H \left(E_{[5]}+\frac{E_{[6]}}{T}+\frac{E_{[7]}}{T^2} \right)\\ \end{array} The derived class must define the variables: * mod: Boolean with the reference from correlation, True if [4]_, False if [5]_ for minor changes in correlation, default False * F: η1 contribution parameters (4 terms) * E: η2 contribution parameters (7 terms) * rhoc: Reducing density, [mol/l] Although both references use (almost) same correlation the density is in g/cm³ in [4]_ and mol/l in [5]_, the parameters are maintain with values in references. **Extended corresponding states (ECS) model** Formulation as explain in [20]_ and [22]_. .. math:: \begin{array}[t]{l} \eta = \eta^o(T) + \Delta\eta_o(T_o,\rho_o)F_{\eta}(T,\rho)\\ \eta^o=\frac{5\sqrt{\pi Mk_bT}}{16\pi\sigma^2\Omega^{(2,2)}}\\ T_o = T/f\\ \rho_o = \rho h\\ f = \frac{T_c}{T_{c0}}\vartheta\\ h = \frac{\rho_{c0}}{\rho_c}\varphi\\ F_{\eta} = \frac{f^{1/2}}{h^{3/2}}\left(\frac{M}{M_0}\right)^ {1/2}\\ \end{array} where :math:`\Omega^{(2,2)}` is the collision integral, see :func:`lib.physics.Collision_Neufeld` The residual contribution to the viscosity is calculated using the correlation of reference fluid at conformal temperature and density. These are calculated by iteration to meet the conditions .. math:: \begin{array}[t]{l} \alpha^r(T, \rho) = \alpha_0^r(T_0, \rho_0)\\ Z(T, \rho) = Z_0(T_0, \rho_0)\\ \end{array} So it necessary accurate mEoS for both reference fluid and fluid to calculate viscosity. Furthermore the method can be based in experimental data using a correction factor for the conformal density .. math:: \begin{array}[t]{l} \rho_{0,\eta}(T, \rho) = \rho_0(T, \rho)\psi(\rho_r)\\ \psi = \sum_k C_k\rho_r^k \end{array} **Quiñones-Cisneros formulation** Formulation as explain in [2]_ and [3]_ .. math:: \begin{array}[t]{l} \eta = \eta^o + \kappa_iP_{id} + \kappa_r\Delta P_r + \kappa_aP_a + \kappa_{ii}P_{id}^2 + \kappa_{rr}\Delta P_r^2 + \kappa_{aa}P_a^2 + \kappa_{rrr}P_r^3 + \kappa_{aaa}P_a^3\\ \kappa_a = \Gamma\left(a_0+a_1\psi_1+a_2\psi_2\right)\\ \kappa_{aa} = \Gamma^3\left(A_0+A_1\psi_1+A_2\psi_2\right)\\ \kappa_r = \Gamma\left(b_0+b_1\psi_1+b_2\psi_2\right)\\ \kappa_{rr} = \Gamma^3\left(B_0+B_1\psi_1+B_2\psi_2\right)\\ \kappa_i = \Gamma\left(c_0+c_1\psi_1+c_2\psi_2\right)\\ \kappa_{ii} = \Gamma^3\left(C_0+C_1\psi_1+C_2\psi_2\right)\\ \kappa_{rrr} = \Gamma\left(D_0+D_1\psi_1+D_2\psi_2\right)\\ \kappa_{aaa} = \Gamma\left(E_0+E_1\psi_1+E_2\psi_2\right)\\ \Gamma = \frac{T_c}{T}\\ \psi_1 = \exp(\Gamma)-1\\ \psi_2 = \exp(\Gamma^2)-1\\ \end{array} The derived class must define the variables: * a: Ka correlation coefficients * A: Kaa correlation coefficients * b: Kr correlation coefficients * B: Krr correlation coefficients * c: Ki correlation coefficients * C: Kii correlation coefficients * D: Krrr correlation coefficients * E: Kaaa correlation coefficients In all cases the dilute-gas limit density is calculate in a separate procedure _Visco0, see its docs for its parameters Parameters ---------- rho : float Density [kg/m³] T : float Temperature [K] fase : dict phase properties coef : dict dictionary with correlation parameters residual : boolean return only the residual contribution. Used in ecs correlation Returns ------- mu : float Viscosity of fluid, [Pa·s] If residual options is True the returned value would be the residual contribution to viscosity in μPas """ if coef is False: coef = self._viscosity if coef: M = coef.get("M", self.M) if coef["eq"] == 0: # Hardcoded method method = self.__getattribute__(coef["method"]) mu = method(rho, T, fase).muPas elif coef["eq"] == 1: muo = self._Visco0(T, coef) # Initial-density term, second virial coefficient mud = 0 if rho and "n_virial" in coef: Tc = coef.get("Tref_virial", self.Tc) if "muref_virial" in coef: mur = coef["muref_virial"] else: mur = Avogadro*(coef["sigma"]*1e-9)**3 tau = T/Tc B_ = 0 for n, t in zip(coef["n_virial"], coef["t_virial"]): B_ += n*tau**t mud = mur*B_*1e3*rho/M*muo # Residual term Tr = coef.get("Tref_res", self.Tc) tau = Tr/T rhor = coef.get("rhoref_res", self.rhoc) delta = rho/rhor mured = coef.get("muref_res", 1) mur = 0 # polynomial term if rho and "nr" in coef: if "cr" in coef: for n, t, d, c, g in zip( coef["nr"], coef["tr"], coef["dr"], coef["cr"], coef["gr"]): mur += n*tau**t*delta**d*exp(-g*delta**c) else: for n, t, d in zip(coef["nr"], coef["tr"], coef["dr"]): mur += n*tau**t*delta**d # numerator of rational poly; denominator of rat. poly; if rho and "nr_num" in coef: num = 0 den = 0 if "cr_num" in coef: for n, t, d, c, g in zip( coef["nr_num"], coef["tr_num"], coef["dr_num"], coef["cr_num"], coef["gr_num"]): num += n*tau**t*delta**d*exp(-g*delta**c) else: for n, t, d in zip(coef["nr_num"], coef["tr_num"], coef["dr_num"]): num += n*tau**t*delta**d if "nr_den" in coef: if "cr_den" in coef: for n, t, d, c, g in zip( coef["nr_den"], coef["tr_den"], coef["dr_den"], coef["cr_den"], coef["gr_den"]): den += n*tau**t*delta**d*exp(-g*delta**c) else: for n, t, d in zip(coef["nr_den"], coef["tr_den"], coef["dr_den"]): den += n*tau**t*delta**d else: den = 1. mur += num/den # Gaussian terms # Reference: Propane, ethane correlation from Vogel if rho and "nr_gaus" in coef: for n, b, e in zip(coef["nr_gaus"], coef["br_gaus"], coef["er_gaus"]): mur += n*tau*delta*exp(-b*(delta-1)**2-e*abs(tau-1)) mur *= mured # Modified Batschinkski-Hildebrand terms with reduced # close-packed density muCP = 0 if "CPf" in coef: f = coef["CPf"] g1 = coef["CPg1"] gi = coef["CPgi"] ti = coef["CPti"] rest = 0 for g, t in zip(gi, ti): rest += g*tau**t delta0 = g1*(1+rest) muCP = f*(delta/(delta0-delta)-delta/delta0) # Special term hardcoded in component class mue = 0 if "special" in coef: method = self.__getattribute__(coef["special"]) mue = method(rho, T, fase) # Return the residual contribution if it's requested # i.e. in ecs viscosity correlations if residual: return mud+mur+muCP+mue mu = muo+mud+mur+muCP+mue if rho and "critical" in coef: muc = self. _ViscoCritical(rho, T, fase, coef) mu *= muc elif coef["eq"] == 2: # Younglove form f = coef["F"] e = coef["E"] mod = coef.get("mod", False) rhoc = coef["rhoc"] # Be careful, the fluids I reference use rho and rhoc in g/cm³ # But fluids II reference use values in mol/l if mod: rhogcc = rho/1000 rhoc *= self.M/1000 else: rhogcc = rho/self.M muo = self._Visco0(T) mu1 = f[0]+f[1]*(f[2]-log(T/f[3]))**2 # Eq 21 G = e[0]+e[1]/T # Eq 23 H = rhogcc**0.5*(rhogcc-rhoc)/rhoc # Eq 25 if mod: # Eq 23 in ref 2 F = e[0] + e[1]*H + e[2]*rhogcc**0.1 + e[3]*H/T**2 + \ e[4]*rhogcc**0.1/T**1.5 + e[5]/T + e[6]*H/T else: # Eq 24 in ref 1 F = G + (e[2]+e[3]/T**1.5)*rhogcc**0.1 + \ H*(e[4]+e[5]/T+e[6]/T**2) mu2 = exp(F)-exp(G) # Eq 22 mu = muo+mu1*rhogcc+mu2 # Eq 18 elif coef["eq"] == 3 or coef["eq"] == "ecs": # Huber ECS model # FIXME: Nitrogen as reference fluid work fine, C3 has a tiny # desviation over testing values and R134a don't work # It's a problem with Reference fixed propertes M, Tc and rhoc rhoc = coef.get("rhoc", self.rhoc) Tc = coef.get("Tc", self.Tc) M = coef.get("M", self.M) tau = Tc/T delta = rho/rhoc # Reference fluid ref = coef["ref"] if "visco" in coef: visco0 = ref.__getattribute__(ref, coef["visco"]) else: visco0 = ref._viscosity[0] M0 = visco0.get("M", ref.M) # Using the critical variables if defined if "Tc" in visco0: Tc0 = visco0["Tc"] # Using the criticial variables of fundamental equation if # defined elif "Tc" in ref().eq[0]: Tc0 = ref.eq[0]["Tc"] else: Tc0 = ref.Tc if "rhoc" in visco0: rhoc0 = visco0["rhoc"]*M0 elif "rhoc" in ref.eq[0]: rhoc0 = ref.eq[0]["rhoc"]*M0 else: rhoc0 = ref.rhoc # Define the coef data for calculate the dilute gas viscosity visco = {} if "omega" in coef: visco["omega"] = coef["omega"] else: # Neufeld correlation visco["omega"] = 5 visco["ek"] = coef["ek"] visco["sigma"] = coef["sigma"] if "n_chapman" in coef: visco["n_chapman"] = coef["n_chapman"] if "Fc" in coef: visco["Fc"] = coef["Fc"] if "M" in coef: visco["M"] = coef["M"] muo = self._Visco0(T, visco) mu = muo # Calculate residual contribution only if density is not 0 if rho > 0: # Calculate the conformal temperature and density def f(parr): T0, rho0 = parr tau0 = Tc0/T0 delta0 = rho0/rhoc0 ar = self._phir(tau, delta) ar0 = ref()._phir(tau0, delta0) fird = self._phird(tau, delta) fird0 = ref()._phird(tau0, delta0) Z = 1+delta*fird Z0 = 1+delta0*fird0 return ar-ar0, Z-Z0 # Initial values fixing shape factor to 1 to = T*Tc0/Tc rho_o = rho*rhoc0/rhoc rinput = fsolve(f, [to, rho_o], full_output=True) if sum(abs(rinput[1]["fvec"])) > 1e-5: rinput = fsolve(f, [T, rho], full_output=True) if sum(abs(rinput[1]["fvec"])) < 1e-5: T0, rho0 = rinput[0] # Avoid use negative values, and use other stimation # Not very error prone code, maybe necessary improve # For now not necessary because only fail in C1Oleate if T0 <= ref.eq[0]["Tmin"]: rinput = fsolve(f, [T, rho], full_output=True) T0, rho0 = rinput[0] f = T/T0 h = rho0/M0/rho*M else: # If solution don't converge use the generalised # correlation for shape factor gives in Estela-Uribe self._ecs_msg = "Iteration don't converge" prop = self._ECSEstela(delta, tau, ref) teta = prop["teta"] phi = prop["phi"] f = Tc/Tc0*teta T0 = T/f h = rhoc0/M0 * M/rhoc * phi rho0 = rho/M*h*M0 self._T0_ecs = T0 self._rho0_ecs = rho0 # Eq 9 psi = 0 for n, d in zip(coef["psi"], coef["psi_d"]): psi += n*delta**d # Eq 8 F = f**0.5/h**(2/3)*(M/M0)**0.5 if T0 <= ref.eq[0]["Tmin"]: T0 = ref.eq[0]["Tmin"] mur = ref()._Viscosity(rho0*psi, T0, None, visco0, True) mu += mur*F elif coef["eq"] == 4: # Quiñones-Cisneros correlations muo = self._Visco0(T) Gamma = self.Tc/T # Eq 35 psi1 = exp(Gamma)-1.0 # Eq 33 psi2 = exp(Gamma**2)-1.0 # Eq 34 a = coef["a"] b = coef["b"] c = coef["c"] A = coef["A"] B = coef["B"] C = coef["C"] ka = (a[0] + a[1]*psi1 + a[2]*psi2) * Gamma # Eq 27 kaa = (A[0] + A[1]*psi1 + A[2]*psi2) * Gamma**3 # Eq 28 kr = (b[0] + b[1]*psi1 + b[2]*psi2) * Gamma # Eq 29 krr = (B[0] + B[1]*psi1 + B[2]*psi2) * Gamma**3 # Eq 30 ki = (c[0] + c[1]*psi1 + c[2]*psi2) * Gamma # Eq 31 kii = (C[0] + C[1]*psi1 + C[2]*psi2) * Gamma**3 # Eq 32 # All parameters has pressure units of bar Patt = -fase.IntP.bar Prep = T*fase.dpdT_rho.barK Pid = rho*self.R*self.T/1e5 delPr = Prep-Pid # Eq 26 mur = ki*Pid + kr*delPr + ka*Patt + kii*Pid**2 + \ krr*delPr**2 + kaa*Patt**2 # 3rd terms only necessary en SF6 Quiñones corelation if "D" in coef: D = coef["D"] E = coef["E"] krrr = (D[0] + D[1]*psi1 + D[2]*psi2) * Gamma # Eq 17 kaaa = (E[0] + E[1]*psi1 + E[2]*psi2) * Gamma # Eq 18 mur += krrr*Prep**3 + kaaa*Patt**3 mu = (muo+mur*1e3) else: # Use the Chung method as default method for no high quality method muo = MuG_Chung(T, self.Tc, 1/self.rhoc, self.M, self.f_acent, self.momentoDipolar.Debye, 0) mu = MuG_P_Chung(T, self.Tc, 1/self.rhoc, self.M, self.f_acent, self.momentoDipolar.Debye, 0, rho, muo).muPas return unidades.Viscosity(mu, "muPas")
[docs] def _Visco0(self, T, coef=None): r"""Dilute gas viscosity calculation .. math:: \begin{array}[t]{l} \eta^o(T) = \frac{N_{chapman}\left(MT\right)^{t_{chapman}}} {\sigma^2\Omega(T^*)} + \sum_{i}^nN_i\tau^{t_i} + \frac{\sum_{i}^nN_i\tau^{t_i}}{\sum_{i}^nN_i\tau^{t_i}} + \exp \left(\sum_{i}^n a_i\left(\ln(\tau)\right)^t_i\right) + \eta_{hc}^o\\ T^* = \frac{T}{ε/k}\\ \tau = \frac{T}{T_r}\\ \end{array} The collision integral is calculated in separate procedure _Omega, see its docs for parameters Notes ----- The derived class must define a dict object with the parameters for the method Champman-Enskop: * ek: Lennard-Jones energy parameter, [K] * sigma: Lennard-Jones size parameter, [nm] * Tref: Dilute gas viscosity reference temperature, default=1 * rhoref: Dilute gas viscosity reference density, default=1 * n_chapman: Dilute gas viscosity parameter, default=0.0266958 * t_chapman: Dilute gas viscosity temperature exponent, default=0.5 Polynomial terms: * Toref: Polynomial terms reference temperature, default=1 * no: Polynomial terms coefficient * to: Polynomial terms tau exponent Fractional terms: * no_num: Fractional numerator coefficient for dilute gas viscosity * to_num: Fractional numerator temperature exponent * no_den: Fraction denominator coefficient for dilute gas viscosity * to_den: Fraction denominator temperature exponent Exponential terms: * no_exp: Exponential term coefficient * to_exp: Exponential term exponent * logo_exp: 1 to use ln in sum term Custom Hardcoded terms: * special0: Name of procedure with hardcoded method Returns ------- muo : float Viscosity of ideal gas, [μPa·s] """ if coef is None: coef = self._viscosity if not coef: # Special case for no available viscosity, i.e. in case thermal # conductivity is available indeep muo = MuG_Chung(T, self.Tc, 1/self.rhoc, self.M, self.f_acent, self.momentoDipolar.Debye, 0) return muo muo = 0 M = coef.get("M", self.M) # Collision integral calculation if "omega" in coef and coef["omega"]: omega = self._Omega(T, coef) N_chap = coef.get("n_chapman", 0.0266958) t_chap = coef.get("t_chapman", 0.5) Tr = coef.get("Tref", 1.) Fc = coef.get("Fc", 1) muo += N_chap*(M*T/Tr)**t_chap/(coef["sigma"]**2*omega)*Fc tau = T/coef.get("Toref", 1.) # other aditional polynomial terms if "no" in coef: for n, t in zip(coef["no"], coef["to"]): muo += n*tau**t # Other fractional terms if "no_num" in coef: num = 0 den = 0 for n, t in zip(coef["no_num"], coef["to_num"]): num += n*tau**t if "no_den" in coef: for n, t, in zip(coef["no_den"], coef["to_den"]): den += n*tau**t else: den = 1 muo += num/den if "no_exp" in coef: term = 0 for n, t, x in zip(coef["no_exp"], coef["to_exp"], coef["logo_exp"]): if x: term += n*log(tau)**t else: term += n*tau**t muo += exp(term) # Special hardcoded method: if "special0" in coef: method = self.__getattribute__(coef["special0"]) muo += method(T) if "muo_ref" in coef: muo *= coef["muo_ref"] return muo
[docs] @refDoc(__doi__, [6, 5, 7, 3, 8], tab=8) def _Omega(self, T, coef): r"""Collision integral calculations The derived class must define a dict object with the parameters for the method: * omega: Collision integral procedure calculation * 0 - None * 1 - Lemmon expression from [6]_: Air, N2, O2... .. math:: \ln \Omega = \sum_i^nb_i\ln\left(T/εk\right)^i * 2 - Younglove expression from [5]_: C1, C2, C3, iC4, nC4 .. math:: \Omega = \frac{1}{\sum_i^n\left(b_i\frac{εk}{T} \right)^{(n+2)/3}} * 3 - Inverse temperature polinomial form exponential [7]_ (cC6) .. math:: \ln \Omega = \sum_i^n \frac{b_i}{T_r^i} * 4 - Inverse temperature polinomial form [3]_ (H2S) .. math:: \Omega = \sum_i^n \frac{b_i}{T_r^i}\\ * 5 - Neufeld correlation for Lennard-Jones 6-12 potential [8]_ .. math:: \Omega_5 = \frac{1.16145}{T_r^{0.14874}} + \frac {0.52487}{\exp(0.7732T_r)} + \frac{2.16178} {\exp(2.4378T_r)} - 6.435e^{-4} T_r^{0.14874}\sin \left(\frac{18.0323}{T_r^{0.76830}}-7.27371\right) * collision: Alternate contributions values for collision integral """ b = coef.get("collision", None) if coef["omega"] == 1: if not b: b = [0.431, -0.4623, 0.08406, 0.005341, -0.00331] T_ = log(T/coef["ek"]) suma = 0 for i, bi in enumerate(b): suma += bi*T_**i omega = exp(suma) elif coef["omega"] == 2: if not b: # Pag 580, Table 2 from [2] b = [-3.0328138281, 16.918880086, -37.189364917, 41.288861858, -24.615921140, 8.9488430959, -1.8739245042, 0.20966101390, -0.0096570437074] T_ = coef["ek"]/T suma = 0 for i, bi in enumerate(b): suma += bi*T_**((3.-i)/3.) omega = 1./suma elif coef["omega"] == 3: Tr = T/coef.get("ek", 1) suma = 0 for i, bi in enumerate(b): suma += bi/Tr**i omega = exp(suma) elif coef["omega"] == 4: Tr = T/coef.get("ek", 1) omega = 0 for i, bi in enumerate(b): omega += bi/Tr**i elif coef["omega"] == 5: T_ = T/coef["ek"] omega = Collision_Neufeld(T_) elif coef["omega"] == 6: # Simple version of neufeld T_ = T/coef["ek"] omega = Collision_Neufeld(T_, simple=True) return omega
[docs] @refDoc(__doi__, [25], tab=8) def _ViscoCritical(self, rho, T, fase, coef=False): r"""Critical Enhancement viscosity calculation In general the critical enhancement for viscosity correlation only are significative in a narrow region near the critical region. Implemented only for very few compounds as water or xenon The model is defined in _visco["critical"]. The defined models are: * 0 : No critical enhancement * 1 : Bhattacharjee-Ferrell **Bhattacharjee-Ferrell** Method defined in [25]_ .. math:: \Delta\eta_c = \exp\left(x_{\mu}Y\right) where :math:`x_\mu` is the critical exponent and the function *Y* is defined for two ranges of correlation length ξ. .. math:: Y = \frac{1}{5}q_C\xi (q_D\xi)^5 \left(1-q_C\xi +(q_C\xi)^2-\frac{765}{504}\left(q_D\xi\right)^2\right) .. math:: \begin{array}[t]{c} Y = \frac{1}{12}\sin \left(3\psi_D\right) - \frac{1}{4q_C\xi} \sin \left(2\psi_D\right) + \frac{1}{\left(q_C\xi\right)^2} \left[1-\frac{5}{4} \left(q_C\xi\right)^2\right]\sin(\psi_D)\\ -\frac{1}{\left(q_C\xi\right)^3} \left\{\left[1-\frac{3}{2} \left(q_C\xi\right)^2\right]\psi_D - \left| \left(q_c\xi\right) ^2-1\right|^{3/2} L(w)\right\} \end{array} with: .. math:: \begin{array}[t]{l} \Phi_D = \arccos\left(\left(1+q_D^2\xi^2\right)^{-1/2}\right)\\ L\left(w\right)=\begin{cases}\begin{array}{ll} ln\frac{1+w}{1-w}, & q_{C}\xi>1\\ 2\arctan|w|, & q_{C}\xi\leq1\\ \end{array}\end{cases}\\ \xi = \xi_0\left(\frac{\Delta\tilde{\chi}}{\Gamma}\right) ^{v/\gamma}\\ \Delta\tilde{\chi} = \tilde{\chi}(T,\rho) - \tilde{\chi} (T_R,\rho)\frac{T_R}{T}\\ \tilde{\chi}(T,\rho) = \frac{P_c\rho}{\rho_c^2}\left(\frac {\partial\rho}{\partial P}\right)_T\\ \end{array} The derived class must define the variables: * Tcref: Reference temperature far above the Tc, [K] * gnu: critical exponent parameter, [-] * gam0: critical exponent parameter, [-] * Xio: Amplitude of the asymptotic power laws for ξ, [m] * Xic: Critical value for ξ to use the Y correlation, [m] * gamma: Amplitude of the asymptotic power laws for χ, [-] * qd : finite wave-number cutoff, [m] * qc : finite upper cutoff, [m] * xu: Critical exponent, [-] Water and heavy water has the Bhattacharjee-Ferrell method hardcoded in iapws library. """ # Optional parameter to disable in kwargs the critical enhancement if "viscocritical" in self.kwargs \ and self.kwargs["viscocritical"] == False: return 1 if coef is False: coef = self._viscosity if coef["critical"] == 0: # No critical enhancement muc = 1 elif coef["critical"] == 1: # Bhattacharjee-Ferrell qd = 1/coef["qd"] qc = 1/coef["qc"] Tref = coef["Tcref"] Xio = coef["Xio"] Xic = coef["Xic"] gam0 = coef["gam0"] gnu = coef["gnu"] gamma = coef["gamma"] xu = coef["xu"] # Optional critical parameters Pc = coef.get("Pc", self.Pc) rhoc = coef.get("rhoc", self.rhoc) Xi = Pc*rho/rhoc**2*fase.drhodP_T st = self._eq(rho, Tref) delta = st["delta"] fird = st["fird"] firdd = st["firdd"] dpdrho = self.R*Tref*(1+2*delta*fird+delta**2*firdd) drho = 1/dpdrho Xi_Tr = Pc*rho/rhoc**2*drho DeltaX = Xi-Xi_Tr*Tref/T DeltaX = max(DeltaX, 0) X = Xio*(DeltaX/gam0)**(gnu/gamma) # Eq 4.1 # Optional parameter to use the powr law expression if "viscocriticallineal" in self.kwargs: X = Xio*((T-self.Tc)/self.Tc)**-gnu if X < Xic: Y = qc/5*X*(qd*X)**5*(1-qc*X+(qc*X)**2-765/504*(qd*X)**2) else: Fid = arccos((1+qd**2*X**2)**-0.5) # Eq 2.17 w = abs((qc*X-1)/(qc*X+1))**0.5*tan(Fid/2) # Eq 2.20 # Eq 2.19 if qc*X > 1: Lw = log((1+w)/(1-w)) else: Lw = 2*arctan(abs(w)) # Eq 2.18 Y = sin(3*Fid)/12 - sin(2*Fid)/4/qc/X \ + (1-5/4*(qc*X)**2)/(qc*X)**2*sin(Fid) \ - ((1-3/2*(qc*X)**2)*Fid-abs((qc*X)**2-1)**1.5*Lw)/(qc*X)**3 muc = exp(xu*Y) # Eq 3.2 return muc
# Thermal conductivity methods
[docs] @refDoc(__doi__, [6, 4, 5, 17, 18, 20, 22], tab=8) def _ThCond(self, rho, T, fase, coef=False, contribution=False): r"""Thermal conductivity calculation procedure The derived class must define a dict object with the parameters for the method. The key eq define the procedure to use: * 0 - Hardcoded for special procedures (i.e.: R23, H2O, ...) * 1 - General formulation with different contribution * 2 : Younglove #1 form, used in N2, O2, Ar. * 3 : Younglove #2 form, used in CH4, C2, C3, C4, iC4. * 4 - Extended corresponding states correlation **Hardcoded procedures** Special procedures easier to implement as harcoded in subclasses, used in component as: * method: Name of procedure with code **General formulation** Normal formulation with several contribution, so the more flexible for implement correlations .. math:: \lambda = \lambda_o + \lambda_r + \lambda_c *Dilute gas thermal conductivity* .. math:: \lambda_o = N_o\mu_o + N_o\mu_o\left(3.75+\sum_i n_i\tau^{t_i}\left(\frac{Cp^o}{R} -2.5\right)\right) + \sum_i N_i\tau^{t_i} + \frac{\sum_i ^nN_i\tau^{t_i}}{\sum_{i}^nN_i\tau^{t_i}} * Toref: Dilute gas reference temperature, default 1 * no_visco: Dilute gas viscosity term coefficient * no_viscoCP: Dilute gas specific heat term coefficient * to_viscoCP: Dilute gas specific heat term τ exponent * no: Dilute gas polynomial parameter * to: Dilute gas polynomial tau exponent * no_num: Fractional numerator coefficient * to_num: Fractional numerator τ exponent * no_den: Fractional denominator coefficient * to_den: Fractional denominator τ exponent *Background term* .. math:: \frac{\lambda^b}{\lambda_r} = \sum_{i}N_i\tau^{t_i}\delta^ {d_i}\exp\left(-\gamma_i\delta^{c_i}\right) * Tref_res: Background reference temperature * rhoref_res: Background reference density * kref_res: Background reference thermal conductivity * nr: Background thermal conductivity parameter * tr: Background thermal conductivity tau exponent * dr: Background thermal conductivity delta exponent * gr: Background thermal conductivity exponential parameter * cr: Background thermal conductivity delta exponent in exponential term *Special terms* A hardcoded term for any non standard formulation term * special: Name of procedure with hardcoded method *Critical enhancement* See thermal conductivity critical enhancement procedure documentation, :func:`MEoS._KCritical` **Younglove formulation #1** Formulation as explain in [4]_ .. math:: \begin{array}[t]{l} \lambda = \lambda^o(T)+\lambda^1(T)\rho+\lambda^2(\tau,\delta) +\lambda_c(\tau,\delta)\\ \lambda^o = \sum_iG_iT^{(4-1)/3}\\ \lambda^1 = F_{[1]}+F_{[2]}\left(F_{[3]}-\ln\left(\frac{T} {F_{[4]}}\right)\right)^2\\ \lambda^2 = \exp(F)-\exp(G)\\ G = E_{[1]}+\frac{E_{[2]}}{T}\\ H = \frac{\rho^{0.5}\left(\rho-\rho_c\right)}{\rho_c}\\ F = G + \left(E_{[3]}+\frac{E_{[4]}}{T^{1.5}}\right)\rho^{0.1}+ H \left(E_{[5]}+\frac{E_{[6]}}{T}+\frac{E_{[7]}}{T^2}\right)\\ \end{array} The derived class must define the variables: * F: η1 contribution parameters (4 terms) * E: η2 contribution parameters (7 terms) * rhoc: Reducing density, [mol/l] **Younglove formulation #2** Formulation as explain in [5]_ .. math:: \lambda = \lambda_0 + \frac{\left(F_0+F_1\rho\right)\rho} {1-F_2\rho}+\lambda_c .. math:: \lambda_0 = \eta_0\left(3.75R+\left(C_p^0-2.5R\right) \left(G_1+G_2\epsilon/kT\right)\right) .. math:: F_0 = \sum_{n=1}^3E_nT^{1-n} .. math:: F_1 = \sum_{n=4}^6E_nT^{4-n} .. math:: F_2 = \sum_{n=7}^8E_nT^{7-n} The derived class must define the variables: * ek: Lennard-Jones energy parameter, [K] * G: λ0 contribution parameters (2 terms) * E: λ1 contribution parameters (8 terms) **Extended corresponding states (ECS) model** Formulation as explain in [20]_ and [22]_. .. math:: \begin{array}[t]{l} \lambda = \lambda^{int}(T)+\lambda^{trans}(T, \rho)\\ \lambda^{int} = \frac{f_{int}\eta^o}{M}\left(C_p^o-\frac{5}{2} R\right)\\ f_{int}=a_0+a_1T\\ \lambda^{trans} = \lambda^o+\lambda^r+\lambda^c\\ \lambda^o = \frac{15}{4}R\eta^o\\ \lambda_r(T,\rho) = \lambda_0^r(T_0,\rho_0)F_{\lambda}\\ F_{\lambda} = \frac{f^{1/2}}{h^{3/2}}\left(\frac{M_0}{M} \right)^{1/2}\\ \end{array} The residual contribution to the thermal conductivity is calculated using the correlation of reference fluid at conformal temperature and density. These are calculated by iteration to meet the conditions .. math:: \begin{array}[t]{l} \alpha^r(T, \rho) = \alpha_0^r(T_0, \rho_0)\\ Z(T, \rho) = Z_0(T_0, \rho_0)\\ \end{array} So it necessary accurate mEoS for both reference fluid and fluid to calculate thermal conductivity. Furthermore the method can be based in experimental data using a correction factor for the conformal density .. math:: \begin{array}[t]{l} \rho_{0,\lambda}(T, \rho) = \rho_0(T, \rho)\chi(\rho_r)\\ \chi = \sum_k b_k\rho_r^k \end{array} The critical enhancement is calculated with the Olchowy and Sengers model, see :func:`MEoS._KCritical`. Parameters ---------- rho : float Density [kg/m³] T : float Temperature [K] fase: dict phase properties coef : dict dictionary with correlation parameters contribution : boolean return the contribution Returns ------- k : float Thermal conductivity, [W/m·K] """ if coef is False: coef = self._thermal if coef: # Let define viscosity coefficient to use in thermal conductivity if "visco" in coef: visco = coef["visco"] else: visco = None if coef["eq"] == 0: # Hardcoded method method = self.__getattribute__(coef["method"]) k = method(rho, T, fase) elif coef["eq"] == 1: Tr = T/coef.get("Toref", 1) # Dilute gas terms kg = 0 # Special term with dilute-gas limit viscosity value # Reference from Lemmon for Air, N2, O2... if "no_visco" in coef: muo = self._Visco0(T, visco) kg += coef["no_visco"]*muo # Special term with dilute-gas viscosity and ideal gas isobaric # heat capacity # Reference From Friend ethane correlation if "no_viscoCp" in coef: # Contribution, Eq 14 f = 0 for n, t in zip(coef["no_viscoCp"], coef["to_viscoCp"]): f += n*Tr**t muo = self._Visco0(T, visco) # 1e-6 factor because viscosity is in μPa·s n = 1e-6*self.R/u/Avogadro kg += muo*n*(3.75+f*(self.cp0/self.R-2.5)) # Eq 13a # Polynomial terms if "to" in coef: for n, t in zip(coef["no"], coef["to"]): kg += n*Tr**t # Fractional terms if "no_num" in coef: num = 0 for n, t in zip(coef["no_num"], coef["to_num"]): num += n*Tr**t den = 0 for n, t in zip(coef["no_den"], coef["to_den"]): den += n*Tr**t kg += num/den kg *= coef.get("koref", 1) # Backgraund terms kr = 0 kc = 0 if rho > 0: Tr = coef.get("Tref_res", self.Tc) tau = Tr/T rhor = coef.get("rhoref_res", self.rhoc) delta = rho/rhor if "nr" in coef: if "cr" in coef: for n, t, d, c, g in zip( coef["nr"], coef["tr"], coef["dr"], coef["cr"], coef["gr"]): kr += n*tau**t*delta**d*exp(-g*delta**c) else: for n, t, d, in zip( coef["nr"], coef["tr"], coef["dr"]): kr += n*tau**t*delta**d # numerator of rational poly; denominator of rat. poly; if "nr_num" in coef: num = 0 den = 0 if "cr_num" in coef: for n, t, d, c, g in zip( coef["nr_num"], coef["tr_num"], coef["dr_num"], coef["cr_num"], coef["gr_num"]): num += n*tau**t*delta**d*exp(-g*delta**c) else: for n, t, d in zip( coef["nr_num"], coef["tr_num"], coef["dr_num"]): num += n*tau**t*delta**d if "nr_den" in coef: if "cr_den" in coef: for n, t, d, c, g in zip( coef["nr_den"], coef["tr_den"], coef["dr_den"], coef["cr_den"], coef["gr_den"]): den += n*tau**t*delta**d*exp(-g*delta**c) else: for n, t, d in zip( coef["nr_den"], coef["tr_den"], coef["dr_den"]): den += n*tau**t*delta**d else: den = 1. kr += num/den # Special term with density of saturated vapor factor # Rererence from Friend correlation for methane if "nr_s" in coef: # Eq 16 if T < self.Tc and rho < rhor: delta_s = self._Vapor_Density(T)/rhor else: # Typo in paper, may be 1, not 11 delta_s = 1 # Eq 17 for n, t, d, in zip( coef["nr_s"], coef["tr_s"], coef["dr_s"]): kr += n*tau**t*delta**d/delta_s kr *= coef.get("kref_res", 1) # Critical enhancement kc = self._KCritical(rho, T, fase) # Special term hardcoded in component class ke = 0 if "special" in coef: method = self.__getattribute__(coef["special"]) ke = method(rho, T, fase) if contribution: return kr+ke k = kg+kr+kc+ke elif coef["eq"] == 2: # Younglove #1 form as explain in [4]_ rhogcc = rho/1000 # Use the density in g/cm³ f = coef["F"] e = coef["E"] # Eq 20 ko = 0 for n, t in zip(coef["no"], coef["to"]): ko += n*T**t k1 = f[0]+f[1]*(f[2]-log(T/f[3]))**2 # Eq 21 G = e[0]+e[1]/T # Eq 24 H = rhogcc**0.5*(rhogcc-e[7])/e[7] # Eq 25 # Eq 23 F = e[0] + e[1]*H + e[2]*rhogcc**0.1 + e[3]*H/T**2 + \ e[4]*rhogcc**0.1/T**1.5 + e[5]/T + e[6]*H/T k2 = exp(F)-exp(G) # Eq 22 # Critical enhancement kc = self._KCritical(rho, T, fase) k = ko + k1*rhogcc + k2 + kc elif coef["eq"] == 3: # Younglove #2 form as explain in [5]_ # Several typo in paper muo = self._Visco0(T) # Eq 27 kg = 1e-6*muo*(3.75*self.R+(self.cp0-2.5*self.R) * (coef["G"][0]+coef["G"][1]*coef["ek"]/T)) if rho: E = coef["E"] F0 = E[0] + E[1]/T + E[2]/T**2 # Eq 28 F1 = E[3] + E[4]/T + E[5]/T**2 # Eq 29 F2 = E[6] + E[7]/T # Eq 30 rhom = rho/self.M kb = (F0+F1*rhom)*rhom/(1+F2*rhom) # Critical enhancement kc = self._KCritical(rho, T, fase) else: kb = 0 kc = 0 k = kg+kb+kc elif coef["eq"] == 4 or coef["eq"] == "ecs": # Huber ECS model Tr = T/self.Tc rhor = rho/self.rhoc tau = 1/Tr delta = rhor muo = self._Visco0(T) # Reference fluid ref = coef["ref"] if "thermo" in coef: thermo0 = ref.__getattribute__(ref, coef["visco"]) else: thermo0 = ref._thermal[0] M0 = thermo0.get("M", ref.M) # Using the criticial variables of fundamental equation if # defined if "Tc" in ref().eq[0]: Tc0 = ref.eq[0]["Tc"] else: Tc0 = ref.Tc if "rhoc" in ref.eq[0]: rhoc0 = ref.eq[0]["rhoc"]*M0 else: rhoc0 = ref.rhoc # If viscosity correlation use too a ecs method restore # conformal state and avoid repeat iteration if self._T0_ecs: T0 = self._T0_ecs rho0 = self._rho0_ecs f = T/T0 h = rho0/ref.M/rho*self.M else: # Calculate the conformal temperature and density def f(parr): T0, rho0 = parr tau0 = Tc0/T0 delta0 = rho0/rhoc0 ar = self._phir(tau, delta) ar0 = ref()._phir(tau0, delta0) fird = self._phird(tau, delta) fird0 = ref()._phird(tau0, delta0) Z = 1+delta*fird Z0 = 1+delta0*fird0 return ar-ar0, Z-Z0 rinput = fsolve(f, [T, rho], full_output=True) if sum(abs(rinput[1]["fvec"])) < 1e-5: T0, rho0 = rinput[0] f = T/T0 h = rho0/ref.M/rho*self.M rho0 = rho/self.M*h*ref.M else: # If solution don't converge use the generalised # correlation for shape factor gives in Estela-Uribe self._ecs_msg = "Iteration don't converge" prop = self._ECSEstela(delta, tau, ref) teta = prop["teta"] phi = prop["phi"] f = self.Tc/Tc0*teta T0 = T/f h = rhoc0/ref.M * self.M/self.rhoc * phi rho0 = rho/self.M*h*ref.M # Calculate the internal contribution to thermal conductivity fint = 0 for n, t in zip(coef["fint"], coef["fint_t"]): fint += n*T**t kg = muo*fint*(self.cp0.kJkgK-2.5*self.R.kJkgK) # Eq 24 # Calculate the dilute gas thermal conductivity ko = 15/4*self.R.kJkgK*muo*1e-3 # Eq 27 kr, kc = 0, 0 if rho: # Eq 31 chi = 0 for n, d in zip(coef["chi"], coef["chi_d"]): chi += n*rhor**d F = f**0.5/h**(2/3)*(ref.M/self.M)**0.5 # Eq 29 if T0 <= ref.eq[0]["Tmin"]: T0 = ref.eq[0]["Tmin"] # Residual contribution using the ecs method kr = F * ref()._ThCond(rho0*chi, T0, fase, thermo0, True) # Critical enhancement kc = self._KCritical(rho, T, fase) k = ko + kg + kr + kc else: # Use the Chung method as default method when no high quality # correlation available muo = MuG_Chung(T, self.Tc, 1/self.rhoc, self.M, self.f_acent, self.momentoDipolar.Debye, 0) ko = ThG_Chung(T, self.Tc, self.M, self.f_acent, fase.cv, muo) k = ThG_P_Chung(T, self.Tc, 1/self.rhoc, self.M, self.f_acent, self.momentoDipolar.Debye, 0, rho, ko) # Avoid error for complex thermal conductivity if type(k) == complex: k = None return unidades.ThermalConductivity(k)
[docs] @refDoc(__doi__, [4, 5, 15, 16, 19], tab=8) def _KCritical(self, rho, T, fase): r"""Enchancement thermal conductivity calculation for critical region The model is defined in _thermal["critical"]. The defined models are: * 0 : No critical enhancement * 1 : Younglove #1 form, used in N2, O2, Ar. * 2 : Younglove #2 form, used in CH4, C2, C3, C4, iC4. * 3 : Olchowy-Sengers * 4 : Gaussian term, used in Laesecke correlation for R123 Furthermore, each thermal conductivity correlation can define a special critical enhancement method hardoded as a procedure in its class. For that use the name of procedure in _thermal["critical" must be the name of procedure. See Friend correlation for methane as example. **Younglove #1 form** Method used in [4]_ and [19]_ .. math:: \begin{array}[t]{l} \Delta \lambda_c = \Delta \lambda' e^{-18.66\left( \frac{T-T_c}{T_c}\right)^2-4.25\left(\frac{\rho-\rho_c} {\rho_c}\right)}\\ \Delta \lambda' = \frac{kT^2}{Y} \left(\frac{\partial P} {\partial T} \right)_{\rho} K_T^{1/2}\\ Y = 6\pi\eta l\left(kT\rho\frac{N_a}{M}\right)^{1/2}\\ l = f(\gamma_m^5\rho\frac{N_a}{M}\frac{e/k}{T})^{1/2}\\ K_T = \frac{1}{\rho}\left(\frac{\partial \rho}{\partial P} \right)_T\\ \end{array} where: * k: Boltzmann constant * Na: Avogadro constant The derived class must define in the correlation dictionary the variables: * rhoc: Critical density, [g/cm³} * Tc: Critical temperature, [K] * ek: Lennard-Jones energy parameter, [K] * f: Potencial function parameter, [-] * gm: Molecular separation parameter, [m] This method don't work nowadays, a tiny bug relevant only in region near to critical point. **Younglove #2 form** Method used in [5]_ .. math:: \begin{array}[t]{l} \lambda_c = \frac{\Delta\lambda'}{6Z\pi\eta} e^{X_1\Delta T^4-X_2\Delta\rho^4}\\ \Delta\lambda' = X_4k_bP_c\left(\frac{T^*}{\rho^*} \frac{\partial\rho^*}{\partial T^*}\right)^2\xi^{X_2}\\ \xi = (\xi^*)^{X_5}\\ \xi^* = \rho^*\frac{\partial\rho^*}{\partial P^*}\\ P^* = \frac{P}{P_c}\\ T^* = \frac{T}{T_c}\\ \rho^* = \frac{\rho}{\rho_c}\\ \Delta T = \frac{|T-T_c|}{T_c}\\ \Delta\rho = \frac{|\rho-\rho_c|}{\rho_c}\\ \end{array} The derived class must define in the correlation dictionary the variables: * rhoc: Critical density, [g/cm³} * Tc: Critical temperature, [K] * X: Array with for parameter Xi of correlation, [-] * Z: Parameter of denominator term, [-] **Olchowy-Sengers** Method defined in [16]_, and very popular in the state-of-art thermal conductivity correlations. .. math:: \begin{array}[t]{l} \lambda_c = \rho c_p \frac{R_ok_BT}{6\pi\eta\xi} \left(\bar{\Omega}-\bar{\Omega}_0\right)\\ \bar{\Omega} = \frac{2}{\pi}\left[\left(\frac{c_p-c_v}{c_p} \right)\arctan\left(q_D\xi\right)+\frac{c_v}{c_p}q_D\xi\right]\\ \bar{\Omega}_0 = \frac{2}{\pi}\left[1-\exp\left(-\frac{1} {\frac{1}{q_D\xi}+\frac{(q_D\xi\rho_c)^2}{\rho^23}}\right) \right]\\ \xi = \xi_0\left(\frac{\Delta\tilde{\chi}}{\Gamma}\right) ^{v/\gamma}\\ \Delta\tilde{\chi} = \tilde{\chi}(T,\rho) - \tilde{\chi} (T_R,\rho)\frac{T_R}{T}\\ \tilde{\chi}(T,\rho) = \frac{P_c\rho}{\rho_c^2}\left(\frac {\partial\rho}{\partial P}\right)_T\\ \end{array} The derived class must define the variables: * Tcref: Reference temperature far above the Tc, [K] * gnu: critical exponent parameter, [-] * gam0: critical exponent parameter, [-] * Xio: Amplitude of the asymptotic power laws for ξ, [m] * gamma: Amplitude of the asymptotic power laws for χ, [-] * R0: Amplitude parameter, [-] * qd : finite upper cutoff, [m] **Gaussian terms** Really only used in [15]_ for R123, but implemented here as a general method for possible future use .. math:: \ln\frac{\lambda_c}{\lambda_r} = \sum n\left(\tau-\alpha\right) ^t \left(\delta-\beta\right)^d The derived class must define the variables: * Trefc: Reference temperature, [K] * rhorefc: Reference density, [kg/m³] * krefc: Reference thermal conductivity, [W/m·K] * nc: Polynomial coefficient * alfac: τ term translation * tc: τ exponent * betac: δ term translation * dc: δ exponent """ if "critical" not in self._thermal or self._thermal["critical"] == 0: # No critical enhancement tc = 0 elif self._thermal["critical"] == 1: # Younglove form for fluids I, Ar, N2, O2, explain without typo in # Hanley H.J.M., McCarty, R.D., Haynes, W.M. # The Viscosity and Thermal Conductivity Coefficient for Dense # Gaseous and Liquid Argon, Krypton, Xenon, Nitrogen and Oxigen # J. Phys. Chem. Ref. Data 3(4) (1974) 979-1018 # doi: 10.1063/1.3253152 # FIXME: Dont work, maybe units, maybe typo in paper. I can't find # the problem rhogcc = rho/1000 # Use the density in g/cm³ rhoc = self._thermal["rhoc"] Tc = self._thermal["Tc"] f = self._thermal["f"] gm = self._thermal["gm"] # length in m ek = self._thermal["ek"] Kt = self.derivative("rho", "P", "T", fase)/fase.rho # Eq D4 l = f*(gm**5*rho*Avogadro/self.M*ek/T)**0.5 # Eq D3 Y = 6*pi*fase.mu*l*(1e-3*Boltzmann*T*rho*Avogadro/self.M)**0.5 if Kt > 0: # Eq D2 dL = Boltzmann*T**2*fase.dpdT_rho**2*Kt**0.5/Y else: dL = 0.0 # Eq D1 tc = dL*exp(-4.25*(abs(rhogcc-rhoc)/rhoc)**4) * \ exp(-18.66*(abs(T-Tc)/Tc)**2)*1e-2 elif self._thermal["critical"] == 2: # Younglove form for fluids II, CH4, C2, C3, C4 Tc = self._thermal.get("Tc", self.Tc) rhoc = self._thermal.get("rhoc", self.rhoc) X = self._thermal["X"] Z = self._thermal["Z"] # Eq D4 delT = abs(T-Tc)/Tc delrho = abs(rho-rhoc)/rhoc xi = self.Pc*rho/rhoc**2/fase.dpdrho_T # Eq D3 # Eq D2 DLc = X[3]*Boltzmann/self.Pc * \ (T*fase.dpdT_rho*self.rhoc/rho)**2*xi**X[2] # Eq D1 # The denominator term 6Zπμ is missing in reference tc = DLc*exp(-X[0]*delT**4 - X[1]*delrho**4)/(6*pi*fase.mu*Z) elif self._thermal["critical"] == 3: # Olchowy-Sengers qd = self._thermal["qd"] Tref = self._thermal["Tcref"] Xio = self._thermal["Xio"] gam0 = self._thermal["gam0"] gnu = self._thermal["gnu"] gamma = self._thermal["gamma"] R0 = self._thermal["R0"] # Optional critical parameters Pc = self._thermal.get("Pc", self.Pc) rhoc = self._thermal.get("rhoc", self.rhoc) Xi = Pc*rho/rhoc**2*fase.drhodP_T st = self._eq(rho, Tref) delta = st["delta"] fird = st["fird"] firdd = st["firdd"] dpdrho = self.R*Tref*(1+2*delta*fird+delta**2*firdd) drho = 1/dpdrho Xi_Tr = Pc*rho/rhoc**2*drho delchi = Xi-Xi_Tr*Tref/T # Eq 10 if delchi <= 0: tc = 0 else: Xi = Xio*(delchi/gam0)**(gnu/gamma) # Eq 9 Xq = Xi/qd # Eq 7 omega = 2/pi*((fase.cp-fase.cv)/fase.cp*arctan(Xq) + fase.cv/fase.cp*Xq) # Eq 8 omega0 = 2/pi*(1-exp(-1/(1/Xq+Xq**2/3*(rhoc/rho)**2))) # Eq 6 Kb = 1.380658e-23 tc = rho*fase.cp*Kb*R0*T/(6*pi*Xi*fase.mu) * \ (omega-omega0) elif self._thermal["critical"] == 4: # Empirical gaussian formulation, referenced in Laesecke for R123 tau = self._thermal["Trefc"]/T delta = rho/self._thermal["rhorefc"] expo = 0 for n, alfa, t, beta, d in zip( self._thermal["nc"], self._thermal["alfac"], self._thermal["tc"], self._thermal["betac"], self._thermal["dc"]): expo += n*(tau+alfa)**t*(delta+beta)**d tc = self._thermal["krefc"]*exp(expo) elif isinstance(self._thermal["critical"], str): # Hardcoded method method = self.__getattribute__(self._thermal["critical"]) tc = method(rho, T, fase) return tc
[docs] @refDoc(__doi__, [21], tab=8) def _ECSEstela(self, delta, tau, ref): r"""Calculation of shape factor for conformal state as explain in [21]_ The correlation is only recommended for nonpolar fluids so it´s use may be very inaccuracy .. math:: \begin{array}[t]{l} \vartheta = 1+(\omega-\omega_0)(A_1+A_2e^{-\delta^2}+\Psi_ {\vartheta})\\ \varphi = \frac{Z_{c0}}{Z_c}(1+(\omega-\omega_0)(A_3+A_4e^ {-\delta^2}+\Psi_{\varphi}))\\ A_i = a_{i,1}-a_{i,2}\ln\tau\\ \Psi_{\vartheta} = b_1\delta e^{-b_2\Delta^2}\\ \Psi_{\varphi} = c_1\delta e^{-c_2\Delta^2}\\ \Delta = (\delta-1)^2+(\frac{1}{\tau}-1)^2\\ \end{array} Parameters ---------- tau : float Inverse reduced temperature, Tc/T [-] delta : float Reduced density, rho/rhoc [-] ref : lib.meos.MEoS Class with the reference fluid Returns ------- prop : dict Calculated shape factor: teta, phi. """ # Parameters, Table 3, pag 25 a = [[0.05899028, -0.93046626], [-0.08809157, 0.18165944], [0.01301722, 0.28587945], [0.00436092, 0.41092573]] b = [0.21343372, -0.64441400] c = [-0.12147697, 0.12392723] # Critical compressibility factor Zc = self.Pc/self.rhoc/self.R/self.Tc R = ref.eq[0]["R"]/ref.M*1000 Zc0 = ref.Pc/ref.rhoc/R/ref.Tc w = self.f_acent w0 = ref.f_acent Delta = (delta-1)**2+(1/tau-1)**2 # Eq 23 # Eq 20 A1 = a[0][0] - a[0][1]*log(tau) A2 = a[1][0] - a[1][1]*log(tau) A3 = a[2][0] - a[2][1]*log(tau) A4 = a[3][0] - a[3][1]*log(tau) phi_teta = b[0]*delta*exp(-b[1]*Delta**2) # Eq 21 phi_phi = c[0]*delta*exp(-c[1]*Delta**2) # Eq 22 # Eq 18 teta = 1+(w-w0)*(A1+A2*exp(-delta**2)+phi_teta) # Eq 19 phi = Zc0/Zc*(1+(w-w0)*(A3+A4*exp(-delta**2)+phi_phi)) prop = {"teta": teta, "phi": phi} return prop
[docs] @refDoc(__doi__, [10], tab=8) def _IdealCurve(self, name, T, rho0=None): r"""Ideal curve pressure calculation procedure. The ideal curves are used as a test for extrapolation behaviour of a EoS. There are curves where the real fluid has a property equal to the value for the ideal gas, compressibility factor and its first derivatives. * Classical ideal curve, Z=1 .. math:: \left(\frac{\partial \alpha^r}{\partial \delta}\right)_{\tau} = 0 * Boyle curve .. math:: \left(\frac{\partial Z}{\partial \rho}\right)_T .. math:: \left(\frac{\partial \alpha^r}{\partial \delta}\right)_{\tau} + \delta \left(\frac{\partial^2 \alpha^r}{\partial \delta^2}\right) _{\tau} = 0 * Joule-Thomson inversion curve .. math:: \left(\frac{\partial Z}{\partial T}\right)_P .. math:: \left(\frac{\partial \alpha^r}{\partial \delta}\right)_{\tau} + \delta \left(\frac{\partial^2 \alpha^r}{\partial \delta^2}\right) _{\tau} + \tau \left(\frac{\partial^2 \alpha^r} {\partial \delta \partial \tau}\right) = 0 * Joule inversion curve .. math:: \left(\frac{\partial Z}{\partial T}\right)_{\rho} .. math:: \left(\frac{\partial^2\alpha^r}{\partial \delta \partial \tau} \right) = 0 Definition and equation based in residual Helmholtz energy from Table 4.11, pag.168 in reference [10]_ Parameters ---------- name : str Name of curve to calculate: * ideal * boyle * joule-thomson * joule T : float Temperature of point to calculate, [K] Returns ------- P : float Pressure of point, [Pa] """ tau = self.Tc/T if name == "ideal": def f(rho): delta = rho/self.rhoc return self._phird(tau, delta) elif name == "boyle": def f(rho): delta = rho/self.rhoc prop = self._eq(rho, T) return prop["fird"]+delta*prop["firdd"] elif name == "joule-thomson": def f(rho): delta = rho/self.rhoc prop = self._eq(rho, T) return prop["fird"]+delta*prop["firdd"]+tau*prop["firdt"] elif name == "joule": def f(rho): prop = self._eq(rho, T) return prop["firdt"] if rho0 is None and T < self.Tc: # rho0 = self._Liquid_Density(self._constants["Tmin"]) rho0 = self._Liquid_Density(T) # elif rho0 is None and T < self.Tc: # rho0 = self.rhoc elif rho0 is None: rho0 = self.rhoc/5 try: rho, rinput = newton(f, rho0, full_output=True) except RuntimeError: return None else: if rho > 0 and rinput.converged and abs(f(rho)) < 1e-5: delta = rho/self.rhoc P = (1+delta*self._phird(tau, delta))*self.R*T*rho return P else: return None
[docs] class MEoSBlend(MEoS): """Special meos class to implement pseudocomponent blend and defining its ancillary dew and bubble point"""
[docs] @classmethod def _dewP(cls, T, eq=0): """Using ancillary equation return the pressure of dew point""" c = cls.eq[eq]["dew"] Tj = cls.eq[eq]["Tj"] Pj = cls.eq[eq]["Pj"] Tita = 1-T/Tj suma = 0 for i, n in zip(c["i"], c["n"]): suma += n*Tita**(i/2.) P = Pj*exp(Tj/T*suma) return unidades.Pressure(P, "MPa")
[docs] @classmethod def _bubbleP(cls, T, eq=0): """Using ancillary equation return the pressure of bubble point""" c = cls.eq[eq]["bubble"] Tj = cls.eq[eq]["Tj"] Pj = cls.eq[eq]["Pj"] Tita = 1-T/Tj suma = 0 for i, n in zip(c["i"], c["n"]): suma += n*Tita**(i/2.) P = Pj*exp(Tj/T*suma) return unidades.Pressure(P, "MPa")
[docs] @classmethod def _Vapor_Pressure(cls, T, eq=0): # Use a mean value between dew and bubble pressure to get a correct # initial phase checking dew = cls._dewP(T, eq) bubble = cls._bubbleP(T, eq) Pv = unidades.Pressure((dew+bubble)/2) return Pv
data = MEoS.properties() propiedades = [p[0] for p in data] keys = [p[1] for p in data] units = [p[2] for p in data] properties = dict(list(zip(keys, propiedades))) inputData = [data[0], data[2], data[4], data[5], data[6], data[7], data[8], data[9]] if __name__ == "__main__": #Calculate estado estandard OTO (h,s=0 at 25ºC and 1 atm) # import pickle # std={} # for compuesto in __all__: # method={} # for metodo in range(len(compuesto.eq)): # cmp=compuesto(T=298.15, P=0.101325, eq=metodo, ref=None) # method[str(metodo)]=(cmp.h.kJkg, cmp.s.kJkgK) # std[compuesto.__name__]=method # cPickle.dump(std, open("/home/jjgomera/Programacion/pychemqt/oto.pkl", "w")) #Calculate estado estandard NBP (h,s=0 saturated liquid at Tb) # std={} # for compuesto in __all__: # method={} # for metodo in range(len(compuesto.eq)): # try: # cmp=compuesto(T=compuesto.Tb, x=0.,ref=None) # method[str(metodo)]=(cmp.h.kJkg, cmp.s.kJkgK) # except: # print compuesto.__name__, metodo # method[str(metodo)]=(0, 0) # std[compuesto.__name__]=method # cPickle.dump(std, open("/home/jjgomera/Programacion/pychemqt/oto.pkl", "w")) #Calculate estado estandard IIR (h=200,s=1 saturated liquid 0ºC) # std={} # for compuesto in __all__: # cmp=compuesto(T=273.15, x=0., ref=None) # std[compuesto.__name__]=(cmp.h.kJkg+200, cmp.s.kJkgK+1) # cPickle.dump(std, open("/home/jjgomera/Programacion/pychemqt/IIR.pkl", "w")) #Calculate estado estandard ASHRAE (h,s=0 saturated liquid at -40ºC) # std={} # for compuesto in __all__: # try: # cmp=compuesto(T=233.15, x=0., ref=None) # std[compuesto.__name__]=(cmp.h.kJkg, cmp.s.kJkgK) # except: # print compuesto.__name__ # std[compuesto.__name__]=(0, 0) # cPickle.dump(std, open("/home/jjgomera/Programacion/pychemqt/ASHRAE.pkl", "w")) # from lib.mEoS import Ethylene # st = Ethylene(T=105, P=1e5) # print(st.rho) # st2 = Ethylene(T=105, rho=653.7636, eq="PR") # print(st.x, st.h.kJkg, st.s.kJkgK, st.msg) # print(st2.x, st2.h.kJkg, st2.s.kJkgK, st2.msg) # from lib.mEoS import nC5 # st1 = nC5(T=300, P=1e6) # st2 = nC5(T=300, P=1e6, eq="PR") # for key in st1.propertiesPhase(): # p1 = st1.__getattribute__(key) # p2 = st2.__getattribute__(key) # if isinstance(p1, list): # print(key, p1, p2) # elif p2 != 0: # print(key, p1, p2, "%0.2f%s" % ((p1-p2)/p2*100, "%")) # else: # print(key, p1, p2) # from lib.mEoS import H2O # from lib.refProp import RefProp # ref = RefProp(ids=[H2O.id], T=40+273.15, P=1e5) # st = H2O(T=40+273.15, P=1e5) # print(ref.virialC*ref.M**2, st.virialC*st.M**2) from lib.mEoS import H2O # Two phases region T = 470 x = 0.3 f_tx = H2O(T=T, x=x) f_px = H2O(P=f_tx.P, x=f_tx.x) f_trho = H2O(T=f_px.T, rho=f_px.rho) f_ts = H2O(T=f_trho.T, s=f_trho.s) f_tu = H2O(T=f_ts.T, u=f_ts.u) print(f_tu.P, f_tu.rho, f_tu.x) f_prho = H2O(P=f_tu.P, rho=f_tu.rho) f_ph = H2O(P=f_prho.P, h=f_prho.h) f_pu = H2O(P=f_ph.P, u=f_ph.u) f_rhoh = H2O(rho=f_pu.rho, h=f_pu.h) f_rhos = H2O(rho=f_rhoh.rho, s=f_rhoh.s) f_rhou = H2O(rho=f_rhos.rho, u=f_rhos.u) f_hs = H2O(h=f_rhou.h, s=f_rhou.s) f_su = H2O(s=f_hs.s, u=f_hs.u) print(f_prho.T-T) print(f_prho.x-x) print(f_prho.P-f_tx.P)