#!/usr/bin/python3
# -*- coding: utf-8 -*-
'''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/>.'''
###############################################################################
# Implementation of GERG-2004 and 2008 update
# Multiparameter equation of state for mixtures with
# Metane, nitrogen, carbon dioxide, ethane, propane, n-butane, i-butane,
# n-pentane, i-pentane, hexane, heptane, octane, hydrogen, oxygen, carbon
# monoxide, water, helium, argón
# hydrogen sulfide, nonane, decane from 2008 update
###############################################################################
# TODO: Not implemented gas-liquid equilibrium yet
import os
import json
from math import exp, log
from numpy import zeros, r_
from scipy.constants import R
from scipy.optimize import fsolve
from lib import unidades
from lib import mEoS
from lib.thermo import ThermoAdvanced
__doi__ = {
1:
{"autor": "Kunz, O., Klimeck, R., Wagner, W., Jaeschke, M.",
"title": "The GERG-2004 Wide-Range Equation of State for Natural "
"Gases and Other Mixtures",
"ref": "GERG TM15 2007",
"doi": ""},
2:
{"autor": "Kunz, O., Wagner, W.",
"title": "The GERG-2008 Wide-Range Equation of State for Natural "
"Gases and Other Mixtures: An Expansion of GERG-2004",
"ref": "J. Chem.Eng. Data 57(11) (2012) 3032-3091",
"doi": "10.1021/je300655b"}}
Tref = 298.15
Pref = 101325.
# so=0
# ho=0
[docs]
class GERG():
"""Multiparameter equation of state GERG 2008
ref http://dx.doi.org/10.1021/je300655b"""
__title__ = "GERG (2008)"
__status__ = "GERG08"
kwargs = {"componente": [],
"fraccion": [],
"T": 0.0,
"rho": 0.0,
"P": 0.0,
"v": 0.0,
"h": None,
"s": None,
"u": None,
"x": None,
"mezcla": None}
componentes = [mEoS.CH4, mEoS.N2, mEoS.CO2, mEoS.C2, mEoS.C3, mEoS.nC4,
mEoS.iC4, mEoS.nC5, mEoS.iC5, mEoS.nC6, mEoS.nC7, mEoS.nC8,
mEoS.H2, mEoS.O2, mEoS.CO, mEoS.H2O, mEoS.He, mEoS.Ar,
mEoS.H2S, mEoS.nC9, mEoS.nC10]
fname_Fij = os.path.join(os.environ["pychemqt"], "dat", "mEoS_Fij.json")
with open(fname_Fij, encoding="utf-8") as file:
Fij = json.load(file)
fname_Prop = os.path.join(os.environ["pychemqt"], "dat", "mEoS_Tc.json")
with open(fname_Prop, encoding="utf-8") as file:
Prop_c = json.load(file)
fir_ij = {
"0-1": {
"nr1": [-0.98038985517335e-2, 0.42487270143005e-3],
"d1": [1, 4],
"t1": [0.000, 1.850],
"nr2": [-.34800214576142e-1, -.13333813013896, -.11993694974627e-1,
0.69243379775168e-1, -0.31022508148249, 0.24495491753226,
0.22369816716981],
"d2": [1, 2, 2, 2, 2, 2, 3],
"t2": [7.850, 5.400, 0.000, 0.750, 2.800, 4.450, 4.250],
"n2": [1, 1, 0.25, 0, 0, 0, 0],
"e2": [0.5]*7,
"b2": [1, 1, 2.5, 3, 3, 3, 3],
"g2": [0.5]*7},
"0-2": {
"nr1": [-.10859387354942, .80228576727389e-1, -.93303985115717e-2],
"d1": [1, 2, 3],
"t1": [2.6, 1.95, 0],
"nr2": [0.40989274005848e-1, -0.24338019772494, 0.23855347281124],
"d2": [1, 2, 3],
"t2": [3.95, 7.95, 8],
"n2": [1, 0.5, 0],
"e2": [0.5]*3,
"b2": [1, 2, 3],
"g2": [0.5]*3},
"0-3": {
"nr1": [-0.80926050298746e-3, -0.75381925080059e-3],
"d1": [3, 4],
"t1": [0.65, 1.55],
"nr2": [-0.41618768891219e-1, -0.23452173681569, 0.14003840584586,
.63281744807738e-1, -.34660425848809e-1, -.23918747334251,
0.19855255066891e-2, 0.61777746171555e1,
-0.69575358271105e1, 0.10630185306388e1],
"d2": [1, 2, 2, 2, 2, 2, 2, 3, 3, 3],
"t2": [3.1, 5.9, 7.05, 3.35, 1.2, 5.8, 2.7, 0.45, 0.55, 1.95],
"n2": [1, 1, 1, 0.875, 0.75, 0.5, 0, 0, 0, 0],
"e2": [0.5]*10,
"b2": [1, 1, 1, 1.25, 1.5, 2, 3, 3, 3, 3],
"g2": [0.5]*10},
"0-4": {
"nr1": [.13746429958576e-1, -.74425012129552e-2,
-.45516600213685e-2, -0.54546603350237e-2,
0.23682016824471e-2],
"d1": [3, 3, 4, 4, 4],
"t1": [1.85, 3.95, 0, 1.85, 3.85],
"nr2": [0.18007763721438, -0.44773942932486, 0.19327374888200e-1,
-0.30632197804624],
"d2": [1, 1, 1, 2],
"t2": [5.25, 3.85, 0.2, 6.5],
"n2": [0.25, 0.25, 0, 0],
"e2": [0.5, 0.5, 0.5, 0.5],
"b2": [0.75, 1, 2, 3],
"g2": [0.5, 0.5, 0.5, 0.5]},
"1-2": {
"nr1": [0.28661625028399, -0.10919833861247],
"d1": [2, 3],
"t1": [1.85, 1.4],
"nr2": [-0.11374032082270e1, 0.76580544237358, 0.42638000926819e-2,
0.17673538204534],
"d2": [1, 1, 1, 2],
"t2": [3.2, 2.5, 8, 3.75],
"n2": [0.25, 0.25, 0, 0],
"e2": [0.5, 0.5, 0.5, 0.5],
"b2": [0.75, 1., 2., 3.],
"g2": [0.5, 0.5, 0.5, 0.5]},
"1-3": {
"nr1": [-0.47376518126608, 0.48961193461001, -0.57011062090535e-2],
"d1": [2, 2, 3],
"t1": [0, 0.05, 0],
"nr2": [-0.19966820041320, -0.69411103101723, 0.69226192739021],
"d2": [1, 2, 2],
"t2": [3.65, 4.9, 4.45],
"n2": [1, 1, 0.875],
"e2": [0.5, 0.5, 0.5],
"b2": [1, 1, 1.25],
"g2": [0.5, 0.5, 0.5]},
"0-12": {
"nr1": [-.25157134971934, -.62203841111983e-2, .88850315184396e-1,
-0.35592212573239e-1],
"d1": [1, 3, 3, 4],
"t1": [2, -1, 1.75, 1.4],
"nr2": []},
"0-5": {
"nr1": [.25574776844118e1, -.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.700, 0.250, 1.350, 0.0, 1.250, 0.0, 0.7, 5.4],
"nr2": []},
"0-6": {
"nr1": [.25574776844118e1, -.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.55, 1.70, 0.25, 1.35, 0.0, 1.25, 0.0, 0.70, 5.40],
"nr2": []},
"3-4": {
"nr1": [0.25574776844118e1, -.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.700, 0.250, 1.350, 0.0, 1.250, 0.0, 0.7, 5.4],
"nr2": []},
"3-5": {
"nr1": [.25574776844118e1, -.79846357136353e1, .47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.700, 0.250, 1.350, 0.0, 1.250, 0.0, 0.7, 5.4],
"nr2": []},
"3-6": {
"nr1": [.25574776844118e1, -0.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.7, 0.250, 1.350, 0.0, 1.250, 0.0, 0.70, 5.4],
"nr2": []},
"4-5": {
"nr1": [0.25574776844118e1, -.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.7, 0.250, 1.350, 0.0, 1.250, 0.0, 0.7, 5.4],
"nr2": []},
"4-6": {
"nr1": [.25574776844118e1, -0.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.7, 0.250, 1.350, 0.0, 1.250, 0.0, 0.7, 5.4],
"nr2": []},
"5-6": {
"nr1": [.25574776844118e1, -0.79846357136353e1, 0.47859131465806e1,
-0.73265392369587, 0.13805471345312e1, 0.28349603476365,
-0.49087385940425, -0.10291888921447, 0.11836314681968,
0.55527385721943e-4],
"d1": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"t1": [1.0, 1.550, 1.7, 0.250, 1.350, 0.0, 1.250, 0.0, 0.7, 5.400],
"nr2": []}}
[docs]
def __init__(self, **kwargs):
"""Constructor
To define it need specified composition:
-componente: array with index of fluids
-fraccion: molar fraction
It need to specified state define two properties from this:
-T: temperature, K
-rho: density, kg/m3
-P: pressure, Pa
-v: specific volume, m3/kg
-h: enthalpy, J/kg
-s: entropy, J/kgK
-u: internal energy, J/kg
-x: quality
"""
self._definition = False
self.kwargs = GERG.kwargs.copy()
self.__call__(**kwargs)
def __call__(self, **kwargs):
self.kwargs.update(kwargs)
if self.calculable:
self.status = 1
self.calculo()
self.msg = ""
@property
def calculable(self):
"""Check input available to decide if is enough to solve state"""
if self.kwargs["componente"] and self.kwargs["fraccion"]:
self._definition = True
else:
self._definition = False
thermo = 0
for key in ("T", "P", "rho", "v"):
if self.kwargs[key]:
thermo += 1
for key in ("h", "s", "u", "x"):
if self.kwargs[key] is not None:
thermo += 1
return self._definition and thermo >= 2
[docs]
def calculo(self):
"""Calculate procedure"""
T = self.kwargs["T"]
rho = self.kwargs["rho"]
P = self.kwargs["P"]
v = self.kwargs["v"]
h = self.kwargs["h"]
s = self.kwargs["s"]
u = self.kwargs["u"]
x = self.kwargs["x"]
self.comp = []
for i in self.kwargs["componente"]:
c = self.componentes[i](eq="GERG", **self.kwargs)
self.comp.append(c)
self.id = self.kwargs["componente"]
self.xi = self.kwargs["fraccion"]
# Critic properties for mixture,
# eq. 7.9, 7.10 pag.125, Tabla 7.10 pag 136
bt = self.Prop_c["beta_t"]
bv = self.Prop_c["beta_v"]
gt = self.Prop_c["gamma_t"]
gv = self.Prop_c["gamma_v"]
c_T = zeros((len(self.comp), len(self.comp)))
c_rho = zeros((len(self.comp), len(self.comp)))
for i, cmpi in enumerate(self.comp):
for j, cmpj in enumerate(self.comp):
c_T[i, j] = 2*bt[i][j]*gt[i][j]*(cmpi.Tc*cmpj.Tc)**0.5
c_rho[i, j] = 2*bv[i][j]*gv[i][j]/8. * \
(1./cmpi.rhoc**(1./3)+1./cmpj.rhoc**(1./3))**3
f_T = zeros((len(self.comp), len(self.comp)))
f_rho = zeros((len(self.comp), len(self.comp)))
dFT_ik = zeros((len(self.comp), len(self.comp)))
dFT_ki = zeros((len(self.comp), len(self.comp)))
dFrho_ik = zeros((len(self.comp), len(self.comp)))
dFrho_ki = zeros((len(self.comp), len(self.comp)))
for i, x_i in enumerate(self.xi):
for j, x_j in enumerate(self.xi):
f_T[i, j] = x_i*x_j*(x_i+x_j)/(bt[i][j]**2*x_i+x_j)
f_rho[i, j] = x_i*x_j*(x_i+x_j)/(bv[i][j]**2*x_i+x_j)
dFT_ik[i, j] = x_j*(x_j+x_i)/(bt[i][j]**2*x_i+x_j) + \
x_j*x_i/(bt[i][j]**2*x_i+x_j) * \
(1-bt[i][j]**2*(x_j+x_i)/(bt[i][j]**2*x_i+x_j))
dFrho_ik[i, j] = x_j*(x_j+x_i)/(bv[i][j]**2*x_i+x_j) + \
x_j*x_i/(bv[i][j]**2*x_i+x_j) * \
(1-bv[i][j]**2*(x_j+x_i)/(bv[i][j]**2*x_i+x_j))
dFT_ki[j, i] = x_j*(x_j+x_i)/(bt[i][j]**2*x_j+x_i)+x_j*x_i / \
(bt[i][j]**2*x_j+x_i)*(1-(x_j+x_i)/(bt[i][j]**2*x_j+x_i))
dFrho_ki[j, i] = x_j*(x_j+x_i)/(bv[i][j]**2*x_j+x_i)+x_j*x_i /\
(bv[i][j]**2*x_j+x_i)*(1-(x_j+x_i)/(bv[i][j]**2*x_j+x_i))
sumai_v = sumaij_v = sumai_T = sumaij_T = m = 0
for i, componentei in enumerate(self.comp):
sumai_v += self.xi[i]**2/componentei.rhoc
sumai_T += self.xi[i]**2*componentei.Tc
m += self.xi[i]*componentei.M
for j, componentej in enumerate(self.comp):
if j > i:
sumaij_v += c_rho[i, j]*f_rho[i, j]
sumaij_T += c_T[i, j]*f_T[i, j]
self.rhoc = unidades.Density(1./(sumai_v+sumaij_v))
self.Tc = unidades.Temperature(sumai_T+sumaij_T)
self.M = m # g/mol
self.R = unidades.SpecificHeat(R/self.M, "kJkgK")
Tcxi = rhocxi = []
for i, componentei in enumerate(self.comp):
sumav1 = sumat1 = 0
for k in range(i):
sumav1 += c_rho[k, i]*dFrho_ki[k, i]
sumat1 += c_T[k, i]*dFT_ki[k, i]
sumav2 = sumat2 = 0
for k in range(i+1, len(self.xi)):
sumav2 += c_rho[i, k]*dFrho_ik[i, k]
sumat2 += c_T[i, k]*dFT_ik[i, k]
Tcxi.append(2*self.xi[i]*componentei.Tc+sumat1+sumat2)
rhocxi.append(2*self.xi[i]/componentei.rhoc+sumav1+sumav2)
self.Tcxi = Tcxi
self.rhocxi = rhocxi
if v and not rho:
rho = 1./v
if T and x is not None:
pass
else:
if T and P:
rhoo = 2.
rho = fsolve(lambda rho: self._solve(rho, T)["P"]-P*1e6, rhoo)
elif T and rho:
pass
elif T and h is not None:
rho = fsolve(lambda rho: self._solve(rho, T)["h"]-h, 200)
elif T and s is not None:
rho = fsolve(lambda rho: self._solve(rho, T)["s"]-s, 200)
elif T and u is not None:
rho = fsolve(lambda rho: self._solve(rho, T)["u"]-u, 200)
elif P and rho:
T = fsolve(lambda T: self._solve(rho, T)["P"]-P*1e6, 600)
elif P and h is not None:
rho, T = fsolve(lambda par: (
self._solve(par[0], par[1])["P"]-P*1e6, self._solve(
par[0], par[1])["h"]-h), [200, 600])
elif P and s is not None:
rho, T = fsolve(lambda par: (
self._solve(par[0], par[1])["P"]-P*1e6, self._solve(
par[0], par[1])["s"]-s), [200, 600])
elif P and u is not None:
rho, T = fsolve(lambda par: (
self._solve(par[0], par[1])["P"]-P*1e6, self._solve(
par[0], par[1])["u"]-u), [200, 600])
elif rho and h is not None:
T = fsolve(lambda T: self._solve(rho, T)["h"]-h, 600)
elif rho and s is not None:
T = fsolve(lambda T: self._solve(rho, T)["s"]-s, 600)
elif rho and u is not None:
T = fsolve(lambda T: self._solve(rho, T)["u"]-u, 600)
elif h is not None and s is not None:
rho, T = fsolve(lambda par: (
self._solve(par[0], par[1])["h"]-h, self._solve(
par[0], par[1])["s"]-s), [200, 600])
elif h is not None and u is not None:
rho, T = fsolve(lambda par: (
self._solve(par[0], par[1])["h"]-h, self._solve(
par[0], par[1])["u"]-u), [200, 600])
elif s is not None and u is not None:
rho, T = fsolve(lambda par: (
self._solve(par[0], par[1])["s"]-s, self._solve(
par[0], par[1])["u"]-u), [200, 600])
else:
raise IOError
fio, fiot, fiott, fiod, fiodd, fiodt, fir, firt, firtt, fird, firdd,\
firdt, firdtt, nfioni, nfirni = self._eq(rho, T)
# Tabla 7.1 pag 127
tau = self.Tc/T
delta = rho/self.rhoc
self.T = unidades.Temperature(T)
self.rho = unidades.Density(rho)
self.v = unidades.SpecificVolume(1./rho)
self.P = unidades.Pressure((1+delta*fird)*self.R.JkgK*T*rho)
self.Z = 1+delta*fird
self.s = unidades.SpecificHeat(self.R.kJkgK*(tau*(fiot+firt)-fio-fir))
self.u = unidades.Enthalpy(self.R*T*tau*(fiot+firt))
self.h = unidades.Enthalpy(self.R*T*(1+tau*(fiot+firt)+delta*fird))
self.cp = unidades.SpecificHeat(self.R*(
-tau**2*(fiott+firtt)+(1+delta*fird-delta*tau*firdt)**2 /
(1+2*delta*fird+delta**2*firdd)))
self.cv = unidades.SpecificHeat(-self.R*tau**2*(fiott+firtt))
self.g = unidades.Enthalpy(self.R*T*(1+fio+fir+delta*fird))
self.w = unidades.Speed((self.R*T*(
1+2*delta*fird+delta**2*firdd-(1+delta*fird-delta*tau*firdt)**2 /
tau**2/(fiott+firtt)))**0.5)
FI = self.fug(rho, T, nfirni)
Ki, xi, yi, Q = self.flash()
self.x = unidades.Dimensionless(Q)
self.xl = xi
self.xv = yi
if self.kwargs["mezcla"]:
self.Pc = self.kwargs["mezcla"].Pc
self.Liquido = ThermoAdvanced()
self.Gas = ThermoAdvanced()
[docs]
def fug(self, rho, T, nfirni=None):
if not nfirni:
tau = self.Tc/T
delta = rho/self.rhoc
nfirni = self._phir(tau, delta)[-1]
FI = []
for xi, dn in zip(self.xi, nfirni):
FI.append(exp(dn-log(self.Z)))
return FI
# firn=delta*fird*(1-1./self.rhoc*n*rhodn)+tau*firt/self.Tc*n*Tcdn
# nfirn=fir+n*dfirn
# f
# propiedades["alfap"]=(1-delta*tau*firdt/(1+delta*fird))/T
# propiedades["betap"]=rho*(1+(delta*fird+delta**2*firdd)/(1+delta*fird))
# propiedades["fugacity"]=exp(fir+delta*fird-log(1+delta*fird))
# propiedades["B"]=B
# propiedades["C"]=C
# propiedades["dpdrho"]=self.R*T*(1+2*delta*fird+delta**2*firdd)
# propiedades["dpdT"]=self.R*rho*(1+delta*fird+delta*tau*firdt)
#
# self.a=unidades.Enthalpy(self.u-self.T*self.s)
# self.Z=self.P*self.v/self.T/self.R.kJkgK/1000
# self.alfap=propiedades["alfap"] #inversa de la temperatura
# self.betap=unidades.Density(propiedades["betap"])
#
# self.Tr=T/self.Tc
#
# self.cp0=self._Cp0(self._constants["cp"])
# self.gamma=-self.v/self.P.kPa*self.derivative("P", "v", "s")
# self.fi=propiedades["fugacity"]
# self.f=unidades.Pressure(self.fi*self.P)
# self.virialB=propiedades["B"]
# self.virialC=propiedades["C"]
[docs]
def _eq(self, rho, T):
tau = self.Tc/T
delta = rho/self.rhoc
phi0 = self._phi0(tau, delta)
# fio, fiot, fiott, fiod, fiodd, fiodt, nfioni = self._phi0(tau, delta)
fir, firt, firtt, fird, firdd, firdt, firdtt, nfirni = self._phir(tau, delta)
return (fio, fiot, fiott, fiod, fiodd, fiodt, fir, firt, firtt, fird,
firdd, firdt, firdtt, nfioni, nfirni)
[docs]
def _solve(self, rho, T):
tau = self.Tc/T
delta = rho/self.rhoc
fio, fiot, fiott, fiod, fiodd, fiodt, nfioni = self._phi0(tau, delta)
fir, firt, firtt, fird, firdd, firdt, firdtt, nfirni = self._phir(tau, delta)
propiedades = {}
propiedades["P"] = (1+delta*fird)*self.R.JkgK*T*rho
propiedades["s"] = self.R.kJkgK*(tau*(fiot+firt)-fio-fir)
propiedades["u"] = self.R.kJkgK*T*tau*(fiot+firt)
propiedades["h"] = self.R.kJkgK*T*(1+tau*(fiot+firt)+delta*fird)
return propiedades
[docs]
def _phi0(self, tau, delta):
"""Ideal contribution to dimensionless Helmholtz free energy α and
their derivatives"""
# Table 7.5
ph0 = {
"fio": 0,
"fiot": 0,
"fiott": 0,
"fiod": 0,
"fiodd": 0,
"fiodt": 0,
"nfioni": []}
for i, (cmp, xi) in enumerate(zip(self.comp, self.xi)):
# Each component contribution is at its specific reduced properties
deltai = delta*self.rhoc/cmp.rhoc
taui = cmp.Tc*tau/self.Tc
p = cmp._phi0(cmp.GERG["cp"], taui, deltai)
ph0["fio"] += xi*(p["fio"]+log(xi)) # Eq 7.20a
ph0["fiod"] += xi*self.rhoc/cmp.rhoc*p["fiod"] # Eq 7.20b
ph0["fiodd"] += xi*(self.rhoc/cmp.rhoc)**2*p["fiodd"] # Eq 7.20c
# Eq 7.20d
ph0["fiodt"] += xi*self.rhoc/cmp.rhoc*cmp.Tc/self.Tc*p["fiodt"]
ph0["fiot"] += xi*cmp.Tc/self.Tc*p["fiot"] # Eq 7.20e
ph0["fiott"] += xi*(cmp.Tc/self.Tc)**2*p["fiott"] # Eq 7.20f
# Eq 7.14, ∂nao/∂ni
ph0["nfioni"].append(ph0["fio"]+1+log(xi))
return ph0
[docs]
def _phir(self, tau, delta):
"""Residual contribution to dimensionless Helmholtz free energy α and
their derivatives"""
fir = firt = firtt = fird = firdd = firdt = firdtt = 0
firxi = []
for i, (cmp, x) in enumerate(zip(self.comp, self.xi)):
deltai = delta*self.rhoc/cmp.rhoc
taui = cmp.Tc*tau/self.Tc
phir = cmp._Helmholtz(taui, deltai)
fir += x*phir["fir"]
firt += x*phir["firt"]
firtt += x*phir["firtt"]
fird += x*phir["fird"]
firdd += x*phir["firdd"]
firdt += x*phir["firdt"]
firxi.append(phir["fir"])
# Contribución residual cruzada , Table 7.8
for i, x_i in enumerate(self.xi):
for j, x_j in enumerate(self.xi):
if j > i:
(fir_, firt_, firtt_, fird_, firdd_, firdt_, firdtt_, B_,
C_) = self._phijr(i, j, tau, delta)
fir += x_i*x_j*self.Fij[self.id[i]][self.id[j]]*fir_
firt += x_i*x_j*self.Fij[self.id[i]][self.id[j]]*firt_
firtt += x_i*x_j*self.Fij[self.id[i]][self.id[j]]*firtt_
fird += x_i*x_j*self.Fij[self.id[i]][self.id[j]]*fird_
firdd += x_i*x_j*self.Fij[self.id[i]][self.id[j]]*firdd_
firdt += x_i*x_j*self.Fij[self.id[i]][self.id[j]]*firdt_
firxi[i] += x_j*self.Fij[self.id[i]][self.id[j]]*fir_
suma = suma_rho = suma_T = 0
for i, x_i in enumerate(self.xi):
suma += x_i*firxi[i]
suma_rho += x_i*self.rhocxi[i]
suma_T += x_i*self.Tcxi[i]
n_rhocni = []
n_Tcni = []
for i, x_i in enumerate(self.xi):
n_rhocni.append(self.rhocxi[i]-suma_rho)
n_Tcni.append(self.Tcxi[i]-suma_T)
n_firni = [] # ðar/ðni
nfirni = [] # ðnar/ðni
for i, componente in enumerate(self.comp):
n_firni.append(delta*fird*(1-1./self.rhoc*n_rhocni[i])
+ tau*firt/self.Tc*n_Tcni[i]+firxi[i]-suma)
nfirni.append(fir_+n_firni[i])
return fir, firt, firtt, fird, firdd, firdt, firdtt, nfirni
[docs]
def _phijr(self, i, j, tau, delta):
txt = str(i)+"-"+str(j)
constants = self.fir_ij.get(txt, 0)
fir = fird = firdd = firt = firtt = firdt = firdtt = B = C = 0
if constants:
delta_0 = 1e-50
nr1 = constants["nr1"]
d1 = constants["d1"]
t1 = constants["t1"]
for n, d, t in zip(nr1, d1, t1):
# Polinomial terms
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)
firdtt += n * t * d * (t-1) * delta**(d-1) * tau**(t-2)
B += n * d * delta_0**(d-1) * tau**t
C += n * d * (d-1) * delta_0**(d-2) * tau**t
nr2 = constants["nr2"]
d2 = constants["d2"]
t2 = constants["t2"]
n2 = constants["n2"]
e2 = constants["e2"]
b2 = constants["b2"]
g2 = constants["g2"]
for nr, d, t, n, e, b, g in zip(nr2, d2, t2, n2, e2, b2, g2):
# Gaussian terms
fir += nr * delta**d * tau**t * \
exp(-n*(delta-e)**2 - b*(tau-g)**(2))
fird += nr * delta**d * tau**t * (d/delta - 2*n*(delta-e)) * \
exp(-n*(delta-e)**2-b*(tau-g)**(2))
firdd += nr * tau**t * exp(-n*(delta-e)**2-b*(tau-g)**(2)) * \
(-2*n*delta**d + 4*n**2*delta**d*(delta-e)**2
- 4*d*n*delta**2*(delta-e) + d*2*delta)
firt += nr*delta**d*tau**t * (t/tau - 2*b*(tau-g)) * \
exp(-n*(delta-e)**2 - b*(tau-g)**(2))
firtt += nr*delta**d*tau**t * \
((t/tau - 2*b*(tau-g))**2 - t/tau**2 - 2*b) * \
exp(-n*(delta-e)**2 - b*(tau-g)**(2))
firdt += nr*delta**d*tau**t * (t/tau - 2*b*(tau-g)) * \
(d/delta - 2*n*(delta-e)) * \
exp(-n*(delta-e)**2-b*(tau-g)**2)
firdtt += nr*delta**d*tau**t * \
exp(-n*(delta-e)**2 - b*(tau-g)**2) * \
((t/tau - 2*b*(tau-g))**2 - t/tau**2 - 2*b) * \
(d/delta - 2*n*(delta-e))
B += nr * delta_0**d * tau**t * (d/delta_0-2*n*(delta_0-e)) * \
exp(-n*(delta_0-e)**2-b*(tau-g)**(2))
C += nr * tau**t * exp(-n*(delta_0-e)**2-b*(tau-g)**(2)) * \
(-2*n*delta_0**d + 4*n**2*delta_0**d*(delta_0-e)**2
- 4*d*n*delta_0**2*(delta_0-e) + d*2*delta_0)
return fir, firt, firtt, fird, firdd, firdt, firdtt, B, C
[docs]
def flash(self):
"""Calculate liquid-vapour phase equilibrium"""
# Initial estimation using Wilson correlation, Eq 19
Ki = []
for c in self.comp:
Ki.append(c.Pc/self.P*exp(5.373*(1.+c.f_acent)*(1.-c.Tc/self.T)))
def f(Q):
sum = 0
for i, x in enumerate(self.xi):
sum += x*(Ki[i]-1.)/(1.+Q+Q*Ki[i])
return sum
if f(0) > 0 and f(1) > 0:
# x>1, vapor only
xi = self.xi
yi = self.xi
Q = 1
elif f(0) < 0 and f(1) < 0:
# x<0, liquid only
xi = self.xi
yi = self.xi
Q = 0
else:
# two phases
Qo = 0.5
while True:
Q = Qo
Qo = fsolve(Vr, Q)
xi = []
yi = []
for i, fraccion in enumerate(self.xi):
xi.append(fraccion/(1+Qo*(Ki[i]-1)))
yi.append(fraccion*Ki[i]/(1+Qo*(Ki[i]-1)))
fi, Fi = self.fug(self.rho, self.T)
fiv = r_[yi]*r_[self.titaiv]*self.P
fil = r_[xi]*r_[self.titail]*self.P
# criterio de convergencia Eq 21
if sum((fil/fiv-1)**2) < 1e-15 and (Q-Qo)**2 < 1e-15:
break
else:
Ki = r_[self.titail]/r_[self.titaiv]
return Ki, xi, yi, Q
id_GERG = [i.id for i in GERG.componentes]
if __name__ == "__main__":
# import doctest
# doctest.testmod()
t_ = unidades.Temperature(205, "F")
p = unidades.Pressure(315, "psi")
aire = GERG(T=t_, P=p, componente=[0, 3, 4, 5, 7, 9], fraccion=[0.26, 0.09, 0.25, 0.17, 0.11, 0.12])
# print "%0.1f %0.4f %0.3f %0.3f %0.5f %0.4f %0.2f" % (aire.T, aire.rho, aire.h.kJkg, aire.s.kJkgK, aire.cv.kJkgK, aire.cp.kJkgK, aire.w), aire.P.MPa
# aire=GERG([0], [1.], P=0.1, T=300)
# print "%0.1f %0.4f %0.3f %0.3f %0.5f %0.4f %0.2f" % (aire.T, aire.rho, aire.h.kJkg, aire.s.kJkgK, aire.cv.kJkgK, aire.cp.kJkgK, aire.w), aire.P.MPa
# aire=GERG([1], [1.], P=0.1, T=300)
# print "%0.1f %0.4f %0.3f %0.3f %0.5f %0.4f %0.2f" % (aire.T, aire.rho, aire.h.kJkg, aire.s.kJkgK, aire.cv.kJkgK, aire.cp.kJkgK, aire.w), aire.P.MPa
# aire=GERG([15], [1.], P=0.1, T=500)
# print "%0.1f %0.4f %0.3f %0.3f %0.5f %0.4f %0.2f" % (aire.T, aire.rho, aire.h.kJkg, aire.s.kJkgK, aire.cv.kJkgK, aire.cp.kJkgK, aire.w), aire.P.MPa